@sienklogic/plan-build-run 2.19.0 → 2.19.2
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/CHANGELOG.md +1287 -303
- package/CLAUDE.md +74 -39
- package/LICENSE +2 -1
- package/README.md +412 -177
- package/bin/install.js +2752 -0
- package/dashboard/bin/cli.cjs +96 -0
- package/dashboard/bin/stop.cjs +129 -0
- package/dashboard/eslint.config.js +37 -0
- package/dashboard/index.html +20 -0
- package/dashboard/package.json +27 -25
- package/dashboard/server/index.js +151 -0
- package/dashboard/server/lib/frontmatter.js +92 -0
- package/dashboard/server/middleware/static.js +35 -0
- package/dashboard/server/package.json +16 -0
- package/dashboard/server/routes/agents.js +234 -0
- package/dashboard/server/routes/config.js +64 -0
- package/dashboard/server/routes/health.js +98 -0
- package/dashboard/server/routes/incidents.js +78 -0
- package/dashboard/server/routes/intel.js +69 -0
- package/dashboard/server/routes/memory.js +107 -0
- package/dashboard/server/routes/planning.js +234 -0
- package/dashboard/server/routes/progress.js +77 -0
- package/dashboard/server/routes/projects.js +36 -0
- package/dashboard/server/routes/requirements.js +40 -0
- package/dashboard/server/routes/roadmap.js +69 -0
- package/dashboard/server/routes/sessions.js +70 -0
- package/dashboard/server/routes/status.js +25 -0
- package/dashboard/server/routes/telemetry.js +233 -0
- package/dashboard/server/services/file-watcher.js +105 -0
- package/dashboard/server/services/planning-reader.js +727 -0
- package/dashboard/server/test/cli.test.js +34 -0
- package/dashboard/server/test/frontmatter.test.js +104 -0
- package/dashboard/server/test/isolation.test.js +32 -0
- package/dashboard/server/test/planning-reader.test.js +151 -0
- package/dashboard/server/test/routes.test.js +91 -0
- package/dashboard/server/test/ws.test.js +81 -0
- package/dashboard/server/ws.js +96 -0
- package/dashboard/src/App.jsx +165 -0
- package/dashboard/src/components/charts/BudgetBars.jsx +42 -0
- package/dashboard/src/components/charts/ContextRadar.jsx +34 -0
- package/dashboard/src/components/charts/PhaseDonut.jsx +66 -0
- package/dashboard/src/components/charts/SuccessTrend.jsx +45 -0
- package/dashboard/src/components/charts/TokenChart.jsx +55 -0
- package/dashboard/src/components/charts/index.js +5 -0
- package/dashboard/src/components/config/CfgSection.jsx +93 -0
- package/dashboard/src/components/layout/Header.jsx +89 -0
- package/dashboard/src/components/layout/ProjectSwitcher.jsx +160 -0
- package/dashboard/src/components/layout/Sidebar.jsx +161 -0
- package/dashboard/src/components/ui/AutoModeBanner.jsx +138 -0
- package/dashboard/src/components/ui/BackButton.jsx +27 -0
- package/dashboard/src/components/ui/Badge.jsx +27 -0
- package/dashboard/src/components/ui/Card.jsx +23 -0
- package/dashboard/src/components/ui/ChartTooltip.jsx +48 -0
- package/dashboard/src/components/ui/CheckpointBox.jsx +110 -0
- package/dashboard/src/components/ui/CodeBlock.jsx +27 -0
- package/dashboard/src/components/ui/ConfidenceBadge.jsx +20 -0
- package/dashboard/src/components/ui/ConfirmModal.jsx +161 -0
- package/dashboard/src/components/ui/ConnectionBanner.jsx +60 -0
- package/dashboard/src/components/ui/ErrorBoundary.jsx +106 -0
- package/dashboard/src/components/ui/ErrorBox.jsx +107 -0
- package/dashboard/src/components/ui/KeyValue.jsx +33 -0
- package/dashboard/src/components/ui/LoadingSkeleton.jsx +84 -0
- package/dashboard/src/components/ui/MetricCard.jsx +58 -0
- package/dashboard/src/components/ui/NextUpBlock.jsx +92 -0
- package/dashboard/src/components/ui/NumberInput.jsx +44 -0
- package/dashboard/src/components/ui/PBRBanner.jsx +47 -0
- package/dashboard/src/components/ui/PipelineView.jsx +130 -0
- package/dashboard/src/components/ui/ProgressBar.jsx +28 -0
- package/dashboard/src/components/ui/ProgressDisplay.jsx +47 -0
- package/dashboard/src/components/ui/QualityGateBadge.jsx +15 -0
- package/dashboard/src/components/ui/SectionTitle.jsx +35 -0
- package/dashboard/src/components/ui/SelectInput.jsx +45 -0
- package/dashboard/src/components/ui/StatusDot.jsx +51 -0
- package/dashboard/src/components/ui/StatusSymbol.jsx +49 -0
- package/dashboard/src/components/ui/TabBar.jsx +41 -0
- package/dashboard/src/components/ui/TextInput.jsx +42 -0
- package/dashboard/src/components/ui/Toast.jsx +117 -0
- package/dashboard/src/components/ui/Toggle.jsx +70 -0
- package/dashboard/src/components/ui/index.js +29 -0
- package/dashboard/src/hooks/useDocumentTitle.js +16 -0
- package/dashboard/src/hooks/useFetch.js +50 -0
- package/dashboard/src/hooks/useToast.jsx +43 -0
- package/dashboard/src/hooks/useWebSocket.js +103 -0
- package/dashboard/src/lib/api.js +112 -0
- package/dashboard/src/lib/configSchema.js +189 -0
- package/dashboard/src/lib/constants.js +22 -0
- package/dashboard/src/main.jsx +15 -0
- package/dashboard/src/pages/AgentsPage.jsx +191 -0
- package/dashboard/src/pages/ConfigPage.jsx +298 -0
- package/dashboard/src/pages/HooksPage.jsx +412 -0
- package/dashboard/src/pages/IncidentsPage.jsx +135 -0
- package/dashboard/src/pages/IntelPage.jsx +193 -0
- package/dashboard/src/pages/LiveFeed.jsx +274 -0
- package/dashboard/src/pages/MemoryPage.jsx +107 -0
- package/dashboard/src/pages/OnboardingPage.jsx +117 -0
- package/dashboard/src/pages/Overview.jsx +360 -0
- package/dashboard/src/pages/PhaseDetailView.jsx +216 -0
- package/dashboard/src/pages/PlanningPage.jsx +181 -0
- package/dashboard/src/pages/ProgressPage.jsx +249 -0
- package/dashboard/src/pages/ResearchPage.jsx +129 -0
- package/dashboard/src/pages/RoadmapPage.jsx +251 -0
- package/dashboard/src/pages/SessionsPage.jsx +117 -0
- package/dashboard/src/pages/Telemetry.jsx +166 -0
- package/dashboard/src/pages/planning/DecisionsTab.jsx +153 -0
- package/dashboard/src/pages/planning/FilesTab.jsx +420 -0
- package/dashboard/src/pages/planning/MilestoneDetail.jsx +319 -0
- package/dashboard/src/pages/planning/MilestonesTab.jsx +151 -0
- package/dashboard/src/pages/planning/NotesTab.jsx +251 -0
- package/dashboard/src/pages/planning/PhasesTab.jsx +218 -0
- package/dashboard/src/pages/planning/QuickTab.jsx +50 -0
- package/dashboard/src/pages/planning/ResearchTab.jsx +103 -0
- package/dashboard/src/pages/planning/TodosTab.jsx +297 -0
- package/dashboard/src/theme/ThemeProvider.jsx +38 -0
- package/dashboard/src/theme/tokens.js +17 -0
- package/dashboard/tests/components/ConfirmModal.test.jsx +179 -0
- package/dashboard/tests/components/ConnectionBanner.test.jsx +37 -0
- package/dashboard/tests/components/ErrorBoundary.test.jsx +59 -0
- package/dashboard/tests/components/LoadingSkeleton.test.jsx +46 -0
- package/dashboard/tests/components/ToastContainer.test.jsx +47 -0
- package/dashboard/tests/components/Toggle.test.jsx +61 -0
- package/dashboard/tests/hooks/useFetch.test.jsx +77 -0
- package/dashboard/tests/hooks/useToast.test.jsx +78 -0
- package/dashboard/tests/hooks/useWebSocket.test.jsx +128 -0
- package/dashboard/tests/pages/ConfigPage.test.jsx +199 -0
- package/dashboard/tests/pages/PlanningPage.test.jsx +119 -0
- package/dashboard/tests/pages/planning/FilesTab.test.jsx +198 -0
- package/dashboard/tests/pages/planning/NotesTab.test.jsx +178 -0
- package/dashboard/tests/pages/planning/TodosTab.test.jsx +188 -0
- package/dashboard/tests/performance.test.jsx +46 -0
- package/dashboard/tests/routes/config.test.js +98 -0
- package/dashboard/tests/routes/health.test.js +40 -0
- package/dashboard/tests/routes/planning.test.js +112 -0
- package/dashboard/tests/routes/roadmap.test.js +91 -0
- package/dashboard/tests/routes/status.test.js +131 -0
- package/dashboard/tests/server/planning-reader.test.js +153 -0
- package/dashboard/tests/setup.js +7 -0
- package/dashboard/vite.config.js +41 -0
- package/package.json +55 -40
- package/plan-build-run/bin/config-schema.json +1298 -0
- package/plugins/pbr/.claude-plugin/plugin.json +1 -1
- package/plugins/pbr/CLAUDE.md +19 -0
- package/plugins/pbr/UI-CONSISTENCY-GAPS.md +1 -1
- package/plugins/pbr/agents/advisor-researcher.md +101 -0
- package/plugins/pbr/agents/audit.md +205 -89
- package/plugins/pbr/agents/codebase-mapper.md +158 -23
- package/plugins/pbr/agents/debugger.md +212 -34
- package/plugins/pbr/agents/dev-sync.md +206 -0
- package/plugins/pbr/agents/executor.md +717 -39
- package/plugins/pbr/agents/general.md +71 -6
- package/plugins/pbr/agents/integration-checker.md +146 -30
- package/plugins/pbr/agents/intel-updater.md +332 -0
- package/plugins/pbr/agents/nyquist-auditor.md +253 -0
- package/plugins/pbr/agents/plan-checker.md +265 -65
- package/plugins/pbr/agents/planner.md +440 -42
- package/plugins/pbr/agents/researcher.md +219 -36
- package/plugins/pbr/agents/roadmapper.md +397 -0
- package/plugins/pbr/agents/synthesizer.md +166 -26
- package/plugins/pbr/agents/ui-checker.md +203 -0
- package/plugins/pbr/agents/ui-researcher.md +224 -0
- package/plugins/pbr/agents/verifier.md +495 -47
- package/plugins/pbr/commands/add-phase.md +75 -0
- package/plugins/pbr/commands/add-todo.md +8 -0
- package/plugins/pbr/commands/audit-fix.md +5 -0
- package/plugins/pbr/commands/audit-milestone.md +8 -0
- package/plugins/pbr/commands/autonomous.md +5 -0
- package/plugins/pbr/commands/backlog.md +6 -0
- package/plugins/pbr/commands/check-todos.md +8 -0
- package/plugins/pbr/commands/complete-milestone.md +8 -0
- package/plugins/pbr/commands/config.md +1 -1
- package/plugins/pbr/commands/discuss-phase.md +6 -0
- package/plugins/pbr/commands/do.md +5 -0
- package/plugins/pbr/commands/execute-phase.md +6 -0
- package/plugins/pbr/commands/fast.md +6 -0
- package/plugins/pbr/commands/forensics.md +6 -0
- package/plugins/pbr/commands/import.md +1 -1
- package/plugins/pbr/commands/insert-phase.md +65 -0
- package/plugins/pbr/commands/intel.md +5 -0
- package/plugins/pbr/commands/join-discord.md +11 -0
- package/plugins/pbr/commands/list-phase-assumptions.md +5 -0
- package/plugins/pbr/commands/map-codebase.md +6 -0
- package/plugins/pbr/commands/milestone-summary.md +6 -0
- package/plugins/pbr/commands/new-milestone.md +8 -0
- package/plugins/pbr/commands/new-project.md +6 -0
- package/plugins/pbr/commands/pause-work.md +5 -0
- package/plugins/pbr/commands/plan-milestone-gaps.md +7 -0
- package/plugins/pbr/commands/plan-phase.md +6 -0
- package/plugins/pbr/commands/plant-seed.md +6 -0
- package/plugins/pbr/commands/profile-user.md +5 -0
- package/plugins/pbr/commands/profile.md +5 -0
- package/plugins/pbr/commands/progress.md +6 -0
- package/plugins/pbr/commands/quick.md +1 -1
- package/plugins/pbr/commands/reapply-patches.md +47 -0
- package/plugins/pbr/commands/release.md +6 -0
- package/plugins/pbr/commands/remove-phase.md +66 -0
- package/plugins/pbr/commands/research-phase.md +59 -0
- package/plugins/pbr/commands/resume-work.md +5 -0
- package/plugins/pbr/commands/seed.md +6 -0
- package/plugins/pbr/commands/session-report.md +5 -0
- package/plugins/pbr/commands/set-profile.md +6 -0
- package/plugins/pbr/commands/settings.md +5 -0
- package/plugins/pbr/commands/setup.md +1 -1
- package/plugins/pbr/commands/ship.md +5 -0
- package/plugins/pbr/commands/stats.md +6 -0
- package/plugins/pbr/commands/test.md +5 -0
- package/plugins/pbr/commands/thread.md +6 -0
- package/plugins/pbr/commands/todo.md +1 -1
- package/plugins/pbr/commands/ui-phase.md +5 -0
- package/plugins/pbr/commands/ui-review.md +5 -0
- package/plugins/pbr/commands/undo.md +5 -0
- package/plugins/pbr/commands/update.md +37 -0
- package/plugins/pbr/commands/validate-phase.md +5 -0
- package/plugins/pbr/commands/verify-work.md +6 -0
- package/plugins/pbr/dashboard/package-lock.json +6 -0
- package/plugins/pbr/dist/architecture-guard.js +59 -0
- package/plugins/pbr/dist/audit-dimensions.js +556 -0
- package/plugins/pbr/dist/auto-continue.js +277 -0
- package/plugins/pbr/dist/block-skill-self-read.js +124 -0
- package/plugins/pbr/dist/check-agent-state-write.js +63 -0
- package/plugins/pbr/dist/check-config-change.js +155 -0
- package/plugins/pbr/dist/check-cross-plugin-sync.js +93 -0
- package/plugins/pbr/dist/check-dangerous-commands.js +193 -0
- package/plugins/pbr/dist/check-direct-state-write.js +37 -0
- package/plugins/pbr/dist/check-doc-sprawl.js +102 -0
- package/plugins/pbr/dist/check-phase-boundary.js +191 -0
- package/plugins/pbr/dist/check-plan-format.js +209 -0
- package/plugins/pbr/dist/check-read-first.js +345 -0
- package/plugins/pbr/dist/check-roadmap-sync.js +507 -0
- package/plugins/pbr/dist/check-skill-workflow.js +354 -0
- package/plugins/pbr/dist/check-state-sync.js +658 -0
- package/plugins/pbr/dist/check-subagent-output.js +396 -0
- package/plugins/pbr/dist/check-summary-gate.js +188 -0
- package/plugins/pbr/dist/context-bridge.js +425 -0
- package/plugins/pbr/dist/context-budget-check.js +442 -0
- package/plugins/pbr/dist/context-quality.js +271 -0
- package/plugins/pbr/dist/enforce-context-budget.js +138 -0
- package/plugins/pbr/dist/enforce-pbr-workflow.js +277 -0
- package/plugins/pbr/dist/event-handler.js +202 -0
- package/plugins/pbr/dist/event-logger.js +125 -0
- package/plugins/pbr/dist/feedback-loop.js +155 -0
- package/plugins/pbr/dist/graph-update.js +422 -0
- package/plugins/pbr/dist/hook-logger.js +114 -0
- package/plugins/pbr/dist/hook-server-client.js +361 -0
- package/plugins/pbr/dist/hook-server.js +658 -0
- package/plugins/pbr/dist/hooks-schema.json +87 -0
- package/plugins/pbr/dist/instructions-loaded.js +173 -0
- package/plugins/pbr/dist/intercept-plan-mode.js +81 -0
- package/plugins/pbr/dist/log-notification.js +131 -0
- package/plugins/pbr/dist/log-subagent.js +349 -0
- package/plugins/pbr/dist/log-tool-failure.js +140 -0
- package/plugins/pbr/dist/milestone-learnings.js +519 -0
- package/plugins/pbr/dist/pbr-tools.js +1961 -0
- package/plugins/pbr/dist/post-bash-triage.js +96 -0
- package/plugins/pbr/dist/post-compact.js +135 -0
- package/plugins/pbr/dist/post-hoc.js +237 -0
- package/plugins/pbr/dist/post-write-dispatch.js +243 -0
- package/plugins/pbr/dist/post-write-quality.js +208 -0
- package/plugins/pbr/dist/pre-bash-dispatch.js +212 -0
- package/plugins/pbr/dist/pre-skill-dispatch.js +114 -0
- package/plugins/pbr/dist/pre-task-dispatch.js +269 -0
- package/plugins/pbr/dist/pre-write-dispatch.js +234 -0
- package/plugins/pbr/dist/progress-tracker.js +173 -0
- package/plugins/pbr/dist/prompt-guard.js +114 -0
- package/plugins/pbr/dist/prompt-routing.js +209 -0
- package/plugins/pbr/dist/quick-status.js +179 -0
- package/plugins/pbr/dist/record-incident.js +37 -0
- package/plugins/pbr/dist/run-hook.js +144 -0
- package/plugins/pbr/dist/session-cleanup.js +653 -0
- package/plugins/pbr/dist/session-tracker.js +124 -0
- package/plugins/pbr/dist/status-line.js +849 -0
- package/plugins/pbr/dist/suggest-compact.js +307 -0
- package/plugins/pbr/dist/sync-context-to-claude.js +100 -0
- package/plugins/pbr/dist/task-completed.js +206 -0
- package/plugins/pbr/dist/track-context-budget.js +432 -0
- package/plugins/pbr/dist/track-user-gates.js +88 -0
- package/plugins/pbr/dist/trust-tracker.js +193 -0
- package/plugins/pbr/dist/validate-commit.js +215 -0
- package/plugins/pbr/dist/validate-skill-args.js +222 -0
- package/plugins/pbr/dist/validate-task.js +271 -0
- package/plugins/pbr/dist/worktree-create.js +144 -0
- package/plugins/pbr/dist/worktree-remove.js +147 -0
- package/plugins/pbr/hooks/hooks.json +143 -60
- package/plugins/pbr/references/agent-contracts.md +39 -8
- package/plugins/pbr/references/agent-teams.md +3 -3
- package/plugins/pbr/references/archive/checkpoints.md +189 -0
- package/plugins/pbr/references/archive/context-quality-tiers.md +45 -0
- package/plugins/pbr/references/archive/hook-ordering.md +89 -0
- package/plugins/pbr/references/archive/limitations.md +106 -0
- package/plugins/pbr/references/archive/pbr-rules.md +194 -0
- package/plugins/pbr/references/archive/pbr-tools-cli.md +415 -0
- package/plugins/pbr/references/archive/pretooluse-jsonl-behavior.md +58 -0
- package/plugins/pbr/references/archive/signal-files.md +41 -0
- package/plugins/pbr/references/archive/tmux-setup.md +288 -0
- package/plugins/pbr/references/archive/verification-matrix.md +34 -0
- package/plugins/pbr/references/archive/verification-patterns.md +277 -0
- package/plugins/pbr/references/archive/worktree-sparse-checkout.md +86 -0
- package/plugins/pbr/references/checkpoints.md +723 -104
- package/plugins/pbr/references/config-reference.md +376 -10
- package/plugins/pbr/references/continuation-format.md +1 -0
- package/plugins/pbr/references/decimal-phase-calculation.md +65 -0
- package/plugins/pbr/references/deviation-rules.md +12 -0
- package/plugins/pbr/references/git-integration.md +110 -27
- package/plugins/pbr/references/git-planning-commit.md +35 -0
- package/plugins/pbr/references/model-profile-resolution.md +34 -0
- package/plugins/pbr/references/model-profiles.md +90 -7
- package/plugins/pbr/references/model-selection.md +1 -1
- package/plugins/pbr/references/node-repair.md +48 -0
- package/plugins/pbr/references/plan-authoring.md +65 -0
- package/plugins/pbr/references/plan-format.md +161 -10
- package/plugins/pbr/references/questioning.md +138 -49
- package/plugins/pbr/references/reading-verification.md +4 -4
- package/plugins/pbr/references/tdd.md +263 -0
- package/plugins/pbr/references/ui-brand.md +449 -0
- package/plugins/pbr/references/verification-overrides.md +39 -0
- package/plugins/pbr/references/verification-patterns.md +529 -113
- package/plugins/pbr/scripts/architecture-guard.js +59 -0
- package/plugins/pbr/scripts/audit-checks/behavioral-compliance.js +2098 -0
- package/plugins/pbr/scripts/audit-checks/error-analysis.js +989 -0
- package/plugins/pbr/scripts/audit-checks/feature-verification.js +723 -0
- package/plugins/pbr/scripts/audit-checks/index.js +433 -0
- package/plugins/pbr/scripts/audit-checks/infrastructure.js +816 -0
- package/plugins/pbr/scripts/audit-checks/quality-metrics.js +452 -0
- package/plugins/pbr/scripts/audit-checks/session-quality.js +980 -0
- package/plugins/pbr/scripts/audit-checks/si-agent-hook-config-checks.js +396 -0
- package/plugins/pbr/scripts/audit-checks/si-cross-cutting-checks.js +272 -0
- package/plugins/pbr/scripts/audit-checks/si-skill-checks.js +424 -0
- package/plugins/pbr/scripts/audit-checks/workflow-compliance.js +1175 -0
- package/plugins/pbr/scripts/audit-dimensions.js +556 -0
- package/plugins/pbr/scripts/auto-continue.js +192 -31
- package/plugins/pbr/scripts/block-skill-self-read.js +124 -0
- package/plugins/pbr/scripts/check-agent-state-write.js +63 -0
- package/plugins/pbr/scripts/check-config-change.js +155 -0
- package/plugins/pbr/scripts/check-cross-plugin-sync.js +93 -0
- package/plugins/pbr/scripts/check-dangerous-commands.js +18 -5
- package/plugins/pbr/scripts/check-direct-state-write.js +37 -0
- package/plugins/pbr/scripts/check-phase-boundary.js +3 -8
- package/plugins/pbr/scripts/check-plan-format.js +135 -278
- package/plugins/pbr/scripts/check-read-first.js +345 -0
- package/plugins/pbr/scripts/check-roadmap-sync.js +182 -21
- package/plugins/pbr/scripts/check-skill-workflow.js +24 -27
- package/plugins/pbr/scripts/check-state-sync.js +339 -215
- package/plugins/pbr/scripts/check-subagent-output.js +281 -275
- package/plugins/pbr/scripts/check-summary-gate.js +5 -15
- package/plugins/pbr/scripts/config-schema.json +1134 -95
- package/plugins/pbr/scripts/context-bridge.js +425 -0
- package/plugins/pbr/scripts/context-budget-check.js +169 -14
- package/plugins/pbr/scripts/context-quality.js +271 -0
- package/plugins/pbr/scripts/enforce-context-budget.js +138 -0
- package/plugins/pbr/scripts/enforce-pbr-workflow.js +277 -0
- package/plugins/pbr/scripts/event-handler.js +127 -87
- package/plugins/pbr/scripts/event-logger.js +58 -25
- package/plugins/pbr/scripts/feedback-loop.js +155 -0
- package/plugins/pbr/scripts/graph-update.js +422 -0
- package/plugins/pbr/scripts/hook-logger.js +69 -35
- package/plugins/pbr/scripts/hook-server-client.js +361 -0
- package/plugins/pbr/scripts/hook-server.js +658 -0
- package/plugins/pbr/scripts/hooks-schema.json +13 -5
- package/plugins/pbr/scripts/instructions-loaded.js +173 -0
- package/plugins/pbr/scripts/intent-router.cjs +147 -0
- package/plugins/pbr/scripts/intercept-plan-mode.js +52 -18
- package/plugins/pbr/scripts/lib/alternatives.js +203 -0
- package/plugins/pbr/scripts/lib/audit.js +65 -0
- package/plugins/pbr/scripts/lib/auto-cleanup.js +221 -0
- package/plugins/pbr/scripts/lib/auto-verify.js +103 -0
- package/plugins/pbr/scripts/lib/build.js +719 -0
- package/plugins/pbr/scripts/lib/ci-fix-loop.js +228 -0
- package/plugins/pbr/scripts/lib/commands.js +483 -0
- package/plugins/pbr/scripts/lib/compound.js +216 -0
- package/plugins/pbr/scripts/lib/config.js +1308 -0
- package/plugins/pbr/scripts/lib/context.js +254 -0
- package/plugins/pbr/scripts/lib/contextual-help.js +183 -0
- package/plugins/pbr/scripts/lib/convention-detector.js +413 -0
- package/plugins/pbr/scripts/lib/core.js +1569 -0
- package/plugins/pbr/scripts/lib/dashboard-launch.js +364 -0
- package/plugins/pbr/scripts/lib/data-hygiene.js +179 -0
- package/plugins/pbr/scripts/lib/decision-extraction.js +183 -0
- package/plugins/pbr/scripts/lib/decisions.js +194 -0
- package/plugins/pbr/scripts/lib/dependency-break.js +147 -0
- package/plugins/pbr/scripts/lib/format-validators.js +1025 -0
- package/plugins/pbr/scripts/lib/frontmatter.js +302 -0
- package/plugins/pbr/scripts/lib/gates/advisories.js +129 -0
- package/plugins/pbr/scripts/lib/gates/build-dependency.js +115 -0
- package/plugins/pbr/scripts/lib/gates/build-executor.js +104 -0
- package/plugins/pbr/scripts/lib/gates/doc-existence.js +46 -0
- package/plugins/pbr/scripts/lib/gates/helpers.js +93 -0
- package/plugins/pbr/scripts/lib/gates/inline-execution.js +185 -0
- package/plugins/pbr/scripts/lib/gates/milestone-complete.js +136 -0
- package/plugins/pbr/scripts/lib/gates/milestone-summary.js +119 -0
- package/plugins/pbr/scripts/lib/gates/multi-phase-loader.js +147 -0
- package/plugins/pbr/scripts/lib/gates/plan-executor.js +36 -0
- package/plugins/pbr/scripts/lib/gates/plan-validation.js +114 -0
- package/plugins/pbr/scripts/lib/gates/quick-executor.js +76 -0
- package/plugins/pbr/scripts/lib/gates/review-planner.js +61 -0
- package/plugins/pbr/scripts/lib/gates/review-verifier.js +69 -0
- package/plugins/pbr/scripts/lib/gates/rich-agent-context.js +137 -0
- package/plugins/pbr/scripts/lib/gates/user-confirmation.js +93 -0
- package/plugins/pbr/scripts/lib/graph-cli.js +89 -0
- package/plugins/pbr/scripts/lib/graph.js +553 -0
- package/plugins/pbr/scripts/lib/health-checks.js +107 -0
- package/plugins/pbr/scripts/lib/health-phase06.js +120 -0
- package/plugins/pbr/scripts/lib/health.js +132 -0
- package/plugins/pbr/scripts/lib/help.js +100 -0
- package/plugins/pbr/scripts/lib/history.js +150 -0
- package/plugins/pbr/scripts/lib/impact-analysis.js +319 -0
- package/plugins/pbr/scripts/lib/incidents.js +190 -0
- package/plugins/pbr/scripts/lib/init.js +643 -0
- package/plugins/pbr/scripts/lib/insights-parser.js +320 -0
- package/plugins/pbr/scripts/lib/intel.js +653 -0
- package/plugins/pbr/scripts/lib/learnings.js +511 -0
- package/plugins/pbr/scripts/lib/migrate.js +298 -0
- package/plugins/pbr/scripts/lib/milestone.js +306 -0
- package/plugins/pbr/scripts/lib/negative-knowledge.js +194 -0
- package/plugins/pbr/scripts/lib/notification-throttle.js +141 -0
- package/plugins/pbr/scripts/lib/onboarding-generator.js +288 -0
- package/plugins/pbr/scripts/lib/parse-args.js +134 -0
- package/plugins/pbr/scripts/lib/pattern-routing.js +55 -0
- package/plugins/pbr/scripts/lib/patterns.js +272 -0
- package/plugins/pbr/scripts/lib/perf.js +190 -0
- package/plugins/pbr/scripts/lib/phase.js +1025 -0
- package/plugins/pbr/scripts/lib/pid-lock.js +154 -0
- package/plugins/pbr/scripts/lib/post-hoc.js +160 -0
- package/plugins/pbr/scripts/lib/pre-commit-checks.js +220 -0
- package/plugins/pbr/scripts/lib/pre-research.js +126 -0
- package/plugins/pbr/scripts/lib/preview.js +174 -0
- package/plugins/pbr/scripts/lib/progress-visualization.js +296 -0
- package/plugins/pbr/scripts/lib/quick-init.js +131 -0
- package/plugins/pbr/scripts/lib/reference.js +236 -0
- package/plugins/pbr/scripts/lib/requirements.js +153 -0
- package/plugins/pbr/scripts/lib/resolve-root.js +66 -0
- package/plugins/pbr/scripts/lib/reverse-spec.js +259 -0
- package/plugins/pbr/scripts/lib/roadmap.js +1089 -0
- package/plugins/pbr/scripts/lib/security-scan.js +200 -0
- package/plugins/pbr/scripts/lib/session-briefing.js +895 -0
- package/plugins/pbr/scripts/lib/skill-section.js +99 -0
- package/plugins/pbr/scripts/lib/smart-next-task.js +198 -0
- package/plugins/pbr/scripts/lib/snapshot-manager.js +232 -0
- package/plugins/pbr/scripts/lib/spec-diff.js +209 -0
- package/plugins/pbr/scripts/lib/spec-engine.js +189 -0
- package/plugins/pbr/scripts/lib/spot-check.js +539 -0
- package/plugins/pbr/scripts/lib/state-queue.js +171 -0
- package/plugins/pbr/scripts/lib/state.js +1082 -0
- package/plugins/pbr/scripts/lib/status-render.js +511 -0
- package/plugins/pbr/scripts/lib/step-verify.js +149 -0
- package/plugins/pbr/scripts/lib/subagent-validators.js +1059 -0
- package/plugins/pbr/scripts/lib/suggest-next.js +435 -0
- package/plugins/pbr/scripts/lib/tech-debt-scanner.js +116 -0
- package/plugins/pbr/scripts/lib/templates.js +362 -0
- package/plugins/pbr/scripts/lib/test-selection.js +163 -0
- package/plugins/pbr/scripts/lib/todo.js +300 -0
- package/plugins/pbr/scripts/lib/verify.js +1483 -0
- package/plugins/pbr/scripts/log-notification.js +131 -0
- package/plugins/pbr/scripts/log-subagent.js +203 -18
- package/plugins/pbr/scripts/log-tool-failure.js +60 -8
- package/plugins/pbr/scripts/milestone-learnings.js +519 -0
- package/plugins/pbr/scripts/package.json +1 -1
- package/plugins/pbr/scripts/pbr-tools.js +1754 -1171
- package/plugins/pbr/scripts/post-bash-triage.js +96 -0
- package/plugins/pbr/scripts/post-compact.js +135 -0
- package/plugins/pbr/scripts/post-hoc.js +237 -0
- package/plugins/pbr/scripts/post-write-dispatch.js +201 -31
- package/plugins/pbr/scripts/post-write-quality.js +4 -3
- package/plugins/pbr/scripts/pre-bash-dispatch.js +147 -51
- package/plugins/pbr/scripts/pre-skill-dispatch.js +114 -0
- package/plugins/pbr/scripts/pre-task-dispatch.js +269 -0
- package/plugins/pbr/scripts/pre-write-dispatch.js +170 -73
- package/plugins/pbr/scripts/progress-tracker.js +122 -310
- package/plugins/pbr/scripts/prompt-guard.js +114 -0
- package/plugins/pbr/scripts/prompt-routing.js +209 -0
- package/plugins/pbr/scripts/quick-status.js +179 -0
- package/plugins/pbr/scripts/record-incident.js +37 -0
- package/plugins/pbr/scripts/risk-classifier.cjs +123 -0
- package/plugins/pbr/scripts/run-hook.js +62 -10
- package/plugins/pbr/scripts/session-cleanup.js +428 -29
- package/plugins/pbr/scripts/session-tracker.js +124 -0
- package/plugins/pbr/scripts/status-line.js +593 -32
- package/plugins/pbr/scripts/suggest-compact.js +201 -13
- package/plugins/pbr/scripts/sync-context-to-claude.js +100 -0
- package/plugins/pbr/scripts/task-completed.js +165 -4
- package/plugins/pbr/scripts/test/config.test.js +126 -0
- package/plugins/pbr/scripts/test/cross-platform.test.js +131 -0
- package/plugins/pbr/scripts/test/fixtures/config.json +20 -0
- package/plugins/pbr/scripts/test/fixtures/plan.md +54 -0
- package/plugins/pbr/scripts/test/fixtures/project.md +30 -0
- package/plugins/pbr/scripts/test/fixtures/roadmap.md +55 -0
- package/plugins/pbr/scripts/test/fixtures/state.md +60 -0
- package/plugins/pbr/scripts/test/fixtures/summary.md +35 -0
- package/plugins/pbr/scripts/test/fixtures.test.js +184 -0
- package/plugins/pbr/scripts/test/phase.test.js +142 -0
- package/plugins/pbr/scripts/test/roadmap.test.js +96 -0
- package/plugins/pbr/scripts/test/state.test.js +155 -0
- package/plugins/pbr/scripts/track-context-budget.js +368 -99
- package/plugins/pbr/scripts/track-user-gates.js +88 -0
- package/plugins/pbr/scripts/trust-tracker.js +193 -0
- package/plugins/pbr/scripts/validate-commit.js +41 -26
- package/plugins/pbr/scripts/validate-skill-args.js +87 -15
- package/plugins/pbr/scripts/validate-task.js +83 -627
- package/plugins/pbr/scripts/worktree-create.js +144 -0
- package/plugins/pbr/scripts/worktree-remove.js +147 -0
- package/plugins/pbr/skills/audit/SKILL.md +195 -24
- package/plugins/pbr/skills/audit-fix/SKILL.md +326 -0
- package/plugins/pbr/skills/autonomous/SKILL.md +545 -0
- package/plugins/pbr/skills/backlog/SKILL.md +56 -0
- package/plugins/pbr/skills/begin/SKILL.md +508 -153
- package/plugins/pbr/skills/begin/templates/STATE.md.tmpl +1 -2
- package/plugins/pbr/skills/begin/templates/config.json.tmpl +411 -36
- package/plugins/pbr/skills/begin/templates/researcher-prompt.md.tmpl +28 -0
- package/plugins/pbr/skills/begin/templates/roadmap-prompt.md.tmpl +28 -3
- package/plugins/pbr/skills/begin/templates/synthesis-prompt.md.tmpl +33 -5
- package/plugins/pbr/skills/build/SKILL.md +1040 -354
- package/plugins/pbr/skills/build/templates/continuation-prompt.md.tmpl +26 -0
- package/plugins/pbr/skills/build/templates/executor-prompt.md.tmpl +77 -0
- package/plugins/pbr/skills/build/templates/inline-verifier-prompt.md.tmpl +33 -0
- package/plugins/pbr/skills/config/SKILL.md +112 -9
- package/plugins/pbr/skills/continue/SKILL.md +113 -33
- package/plugins/pbr/skills/dashboard/SKILL.md +21 -9
- package/plugins/pbr/skills/debug/SKILL.md +70 -12
- package/plugins/pbr/skills/debug/templates/continuation-prompt.md.tmpl +12 -1
- package/plugins/pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +12 -5
- package/plugins/pbr/skills/discuss/SKILL.md +206 -25
- package/plugins/pbr/skills/discuss/templates/CONTEXT.md.tmpl +21 -1
- package/plugins/pbr/skills/do/SKILL.md +119 -24
- package/plugins/pbr/skills/explore/SKILL.md +95 -20
- package/plugins/pbr/skills/fast/SKILL.md +94 -0
- package/plugins/pbr/skills/forensics/SKILL.md +144 -0
- package/plugins/pbr/skills/health/SKILL.md +35 -117
- package/plugins/pbr/skills/help/SKILL.md +84 -101
- package/plugins/pbr/skills/import/SKILL.md +332 -13
- package/plugins/pbr/skills/intel/SKILL.md +131 -0
- package/plugins/pbr/skills/list-phase-assumptions/SKILL.md +231 -0
- package/plugins/pbr/skills/milestone/SKILL.md +421 -263
- package/plugins/pbr/skills/milestone/templates/audit-output.md.tmpl +76 -0
- package/plugins/pbr/skills/milestone/templates/complete-output.md.tmpl +32 -0
- package/plugins/pbr/skills/milestone/templates/edge-cases.md +54 -0
- package/plugins/pbr/skills/milestone/templates/gaps-output.md.tmpl +25 -0
- package/plugins/pbr/skills/milestone/templates/integration-checker-prompt.md.tmpl +25 -0
- package/plugins/pbr/skills/milestone/templates/new-output.md.tmpl +29 -0
- package/plugins/pbr/skills/milestone-summary/SKILL.md +86 -0
- package/plugins/pbr/skills/note/SKILL.md +20 -4
- package/plugins/pbr/skills/pause/SKILL.md +54 -14
- package/plugins/pbr/skills/pause/templates/continue-here.md.tmpl +33 -52
- package/plugins/pbr/skills/plan/SKILL.md +526 -280
- package/plugins/pbr/skills/plan/templates/checker-prompt.md.tmpl +5 -2
- package/plugins/pbr/skills/plan/templates/completion-output.md.tmpl +27 -0
- package/plugins/pbr/skills/plan/templates/planner-prompt.md.tmpl +27 -1
- package/plugins/pbr/skills/plan/templates/revision-prompt.md.tmpl +21 -5
- package/plugins/pbr/skills/profile/SKILL.md +185 -0
- package/plugins/pbr/skills/profile-user/SKILL.md +227 -0
- package/plugins/pbr/skills/quick/SKILL.md +435 -100
- package/plugins/pbr/skills/release/SKILL.md +206 -0
- package/plugins/pbr/skills/resume/SKILL.md +170 -46
- package/plugins/pbr/skills/review/SKILL.md +217 -164
- package/plugins/pbr/skills/review/templates/verifier-prompt.md.tmpl +7 -0
- package/plugins/pbr/skills/scan/SKILL.md +152 -106
- package/plugins/pbr/skills/scan/templates/mapper-prompt.md.tmpl +5 -56
- package/plugins/pbr/skills/seed/SKILL.md +87 -0
- package/plugins/pbr/skills/session-report/SKILL.md +130 -0
- package/plugins/pbr/skills/setup/SKILL.md +150 -202
- package/plugins/pbr/skills/shared/agent-context-enrichment.md +21 -0
- package/plugins/pbr/skills/shared/agent-type-resolution.md +32 -0
- package/plugins/pbr/skills/shared/commit-planning-docs.md +8 -0
- package/plugins/pbr/skills/shared/context-budget.md +66 -1
- package/plugins/pbr/skills/shared/context-loader-task.md +18 -11
- package/plugins/pbr/skills/shared/digest-select.md +2 -2
- package/plugins/pbr/skills/shared/domain-probes.md +1 -1
- package/plugins/pbr/skills/shared/error-reporting.md +38 -60
- package/plugins/pbr/skills/shared/gate-prompts.md +4 -2
- package/plugins/pbr/skills/shared/memory-capture.md +48 -0
- package/plugins/pbr/skills/shared/phase-argument-parsing.md +4 -4
- package/plugins/pbr/skills/shared/revision-loop.md +24 -6
- package/plugins/pbr/skills/shared/state-update.md +49 -56
- package/plugins/pbr/skills/shared/universal-anti-patterns.md +27 -4
- package/plugins/pbr/skills/ship/SKILL.md +155 -0
- package/plugins/pbr/skills/stats/SKILL.md +80 -0
- package/plugins/pbr/skills/status/SKILL.md +185 -119
- package/plugins/pbr/skills/test/SKILL.md +254 -0
- package/plugins/pbr/skills/thread/SKILL.md +73 -0
- package/plugins/pbr/skills/todo/SKILL.md +28 -72
- package/plugins/pbr/skills/ui-phase/SKILL.md +180 -0
- package/plugins/pbr/skills/ui-review/SKILL.md +206 -0
- package/plugins/pbr/skills/undo/SKILL.md +221 -0
- package/plugins/pbr/skills/validate-phase/SKILL.md +362 -0
- package/plugins/pbr/templates/CONTEXT.md.tmpl +45 -20
- package/plugins/pbr/templates/DISCOVERY.md.tmpl +29 -0
- package/plugins/pbr/templates/DISCUSSION-LOG.md.tmpl +49 -0
- package/plugins/pbr/templates/HANDOFF.json.tmpl +30 -0
- package/plugins/pbr/templates/INTEGRATION-REPORT.md.tmpl +18 -2
- package/plugins/pbr/templates/MILESTONE-AUDIT.md.tmpl +44 -0
- package/plugins/pbr/templates/PROJECT.md.tmpl +126 -0
- package/plugins/pbr/templates/REQUIREMENTS.md.tmpl +96 -0
- package/plugins/pbr/templates/RETROSPECTIVE.md.tmpl +43 -0
- package/plugins/pbr/templates/ROADMAP.md.tmpl +108 -14
- package/plugins/pbr/templates/SUMMARY-complex.md.tmpl +133 -0
- package/plugins/pbr/templates/SUMMARY-minimal.md.tmpl +55 -0
- package/plugins/pbr/templates/SUMMARY.md.tmpl +21 -0
- package/plugins/pbr/templates/UAT.md.tmpl +94 -0
- package/plugins/pbr/templates/UI-SPEC.md.tmpl +144 -0
- package/plugins/pbr/templates/VALIDATION.md.tmpl +94 -0
- package/plugins/pbr/templates/VERIFICATION-DETAIL.md.tmpl +49 -13
- package/plugins/pbr/templates/project-CONTEXT.md.tmpl +59 -0
- package/plugins/pbr/templates/research-outputs/ARCHITECTURE.md.tmpl +91 -0
- package/plugins/pbr/templates/research-outputs/FEATURES.md.tmpl +64 -0
- package/plugins/pbr/templates/research-outputs/PITFALLS.md.tmpl +50 -0
- package/plugins/pbr/templates/research-outputs/STACK.md.tmpl +63 -0
- package/plugins/pbr/templates/research-outputs/SUMMARY.md.tmpl +98 -0
- package/scripts/build-hooks.js +61 -0
- package/scripts/check-ci.js +100 -0
- package/scripts/clean-changelog.js +364 -0
- package/scripts/generate-derivatives.js +581 -0
- package/scripts/posttest.js +93 -0
- package/scripts/release.js +262 -0
- package/scripts/run-tests.cjs +29 -0
- package/scripts/test-wrapper.js +43 -0
- package/dashboard/bin/cli.js +0 -25
- package/dashboard/public/css/layout.css +0 -704
- package/dashboard/public/css/status-colors.css +0 -98
- package/dashboard/public/css/tokens.css +0 -59
- package/dashboard/public/js/htmx-title.js +0 -5
- package/dashboard/public/js/sidebar-toggle.js +0 -34
- package/dashboard/public/js/sse-client.js +0 -100
- package/dashboard/public/js/theme-toggle.js +0 -46
- package/dashboard/src/app.js +0 -91
- package/dashboard/src/middleware/current-phase.js +0 -24
- package/dashboard/src/middleware/errorHandler.js +0 -52
- package/dashboard/src/middleware/notFoundHandler.js +0 -9
- package/dashboard/src/repositories/planning.repository.js +0 -130
- package/dashboard/src/routes/events.routes.js +0 -45
- package/dashboard/src/routes/index.routes.js +0 -35
- package/dashboard/src/routes/pages.routes.js +0 -426
- package/dashboard/src/server.js +0 -42
- package/dashboard/src/services/analytics.service.js +0 -141
- package/dashboard/src/services/dashboard.service.js +0 -309
- package/dashboard/src/services/milestone.service.js +0 -222
- package/dashboard/src/services/notes.service.js +0 -50
- package/dashboard/src/services/phase.service.js +0 -232
- package/dashboard/src/services/project.service.js +0 -57
- package/dashboard/src/services/roadmap.service.js +0 -258
- package/dashboard/src/services/sse.service.js +0 -58
- package/dashboard/src/services/todo.service.js +0 -272
- package/dashboard/src/services/watcher.service.js +0 -48
- package/dashboard/src/utils/cache.js +0 -55
- package/dashboard/src/views/analytics.ejs +0 -5
- package/dashboard/src/views/coming-soon.ejs +0 -11
- package/dashboard/src/views/dependencies.ejs +0 -5
- package/dashboard/src/views/error.ejs +0 -20
- package/dashboard/src/views/index.ejs +0 -5
- package/dashboard/src/views/milestone-detail.ejs +0 -5
- package/dashboard/src/views/milestones.ejs +0 -5
- package/dashboard/src/views/notes.ejs +0 -5
- package/dashboard/src/views/partials/analytics-content.ejs +0 -90
- package/dashboard/src/views/partials/breadcrumbs.ejs +0 -14
- package/dashboard/src/views/partials/dashboard-content.ejs +0 -84
- package/dashboard/src/views/partials/dependencies-content.ejs +0 -48
- package/dashboard/src/views/partials/empty-state.ejs +0 -7
- package/dashboard/src/views/partials/footer.ejs +0 -3
- package/dashboard/src/views/partials/head.ejs +0 -30
- package/dashboard/src/views/partials/header.ejs +0 -21
- package/dashboard/src/views/partials/layout-bottom.ejs +0 -43
- package/dashboard/src/views/partials/layout-top.ejs +0 -16
- package/dashboard/src/views/partials/milestone-detail-content.ejs +0 -20
- package/dashboard/src/views/partials/milestones-content.ejs +0 -88
- package/dashboard/src/views/partials/notes-content.ejs +0 -23
- package/dashboard/src/views/partials/phase-content.ejs +0 -193
- package/dashboard/src/views/partials/phase-doc-content.ejs +0 -38
- package/dashboard/src/views/partials/phases-content.ejs +0 -124
- package/dashboard/src/views/partials/roadmap-content.ejs +0 -180
- package/dashboard/src/views/partials/sidebar.ejs +0 -99
- package/dashboard/src/views/partials/todo-create-content.ejs +0 -54
- package/dashboard/src/views/partials/todo-detail-content.ejs +0 -42
- package/dashboard/src/views/partials/todos-content.ejs +0 -97
- package/dashboard/src/views/phase-detail.ejs +0 -5
- package/dashboard/src/views/phase-doc.ejs +0 -5
- package/dashboard/src/views/phases.ejs +0 -5
- package/dashboard/src/views/roadmap.ejs +0 -5
- package/dashboard/src/views/todo-create.ejs +0 -5
- package/dashboard/src/views/todo-detail.ejs +0 -5
- package/dashboard/src/views/todos.ejs +0 -5
- package/plugins/copilot-pbr/CHANGELOG.md +0 -19
- package/plugins/copilot-pbr/README.md +0 -139
- package/plugins/copilot-pbr/agents/audit.agent.md +0 -113
- package/plugins/copilot-pbr/agents/codebase-mapper.agent.md +0 -151
- package/plugins/copilot-pbr/agents/debugger.agent.md +0 -182
- package/plugins/copilot-pbr/agents/executor.agent.md +0 -267
- package/plugins/copilot-pbr/agents/general.agent.md +0 -88
- package/plugins/copilot-pbr/agents/integration-checker.agent.md +0 -119
- package/plugins/copilot-pbr/agents/plan-checker.agent.md +0 -208
- package/plugins/copilot-pbr/agents/planner.agent.md +0 -238
- package/plugins/copilot-pbr/agents/researcher.agent.md +0 -186
- package/plugins/copilot-pbr/agents/synthesizer.agent.md +0 -126
- package/plugins/copilot-pbr/agents/verifier.agent.md +0 -228
- package/plugins/copilot-pbr/hooks/hooks.json +0 -156
- package/plugins/copilot-pbr/plugin.json +0 -30
- package/plugins/copilot-pbr/references/agent-anti-patterns.md +0 -25
- package/plugins/copilot-pbr/references/agent-contracts.md +0 -297
- package/plugins/copilot-pbr/references/agent-interactions.md +0 -135
- package/plugins/copilot-pbr/references/agent-teams.md +0 -55
- package/plugins/copilot-pbr/references/checkpoints.md +0 -158
- package/plugins/copilot-pbr/references/common-bug-patterns.md +0 -14
- package/plugins/copilot-pbr/references/config-reference.md +0 -442
- package/plugins/copilot-pbr/references/continuation-format.md +0 -213
- package/plugins/copilot-pbr/references/deviation-rules.md +0 -113
- package/plugins/copilot-pbr/references/git-integration.md +0 -227
- package/plugins/copilot-pbr/references/integration-patterns.md +0 -118
- package/plugins/copilot-pbr/references/model-profiles.md +0 -100
- package/plugins/copilot-pbr/references/model-selection.md +0 -32
- package/plugins/copilot-pbr/references/pbr-rules.md +0 -195
- package/plugins/copilot-pbr/references/pbr-tools-cli.md +0 -285
- package/plugins/copilot-pbr/references/plan-authoring.md +0 -182
- package/plugins/copilot-pbr/references/plan-format.md +0 -288
- package/plugins/copilot-pbr/references/planning-config.md +0 -214
- package/plugins/copilot-pbr/references/questioning.md +0 -215
- package/plugins/copilot-pbr/references/reading-verification.md +0 -128
- package/plugins/copilot-pbr/references/stub-patterns.md +0 -161
- package/plugins/copilot-pbr/references/subagent-coordination.md +0 -120
- package/plugins/copilot-pbr/references/ui-formatting.md +0 -444
- package/plugins/copilot-pbr/references/verification-patterns.md +0 -199
- package/plugins/copilot-pbr/references/wave-execution.md +0 -96
- package/plugins/copilot-pbr/rules/pbr-workflow.mdc +0 -48
- package/plugins/copilot-pbr/setup.ps1 +0 -93
- package/plugins/copilot-pbr/setup.sh +0 -93
- package/plugins/copilot-pbr/skills/audit/SKILL.md +0 -330
- package/plugins/copilot-pbr/skills/begin/SKILL.md +0 -589
- package/plugins/copilot-pbr/skills/begin/templates/PROJECT.md.tmpl +0 -34
- package/plugins/copilot-pbr/skills/begin/templates/REQUIREMENTS.md.tmpl +0 -19
- package/plugins/copilot-pbr/skills/begin/templates/STATE.md.tmpl +0 -50
- package/plugins/copilot-pbr/skills/begin/templates/config.json.tmpl +0 -64
- package/plugins/copilot-pbr/skills/begin/templates/researcher-prompt.md.tmpl +0 -20
- package/plugins/copilot-pbr/skills/begin/templates/roadmap-prompt.md.tmpl +0 -31
- package/plugins/copilot-pbr/skills/begin/templates/synthesis-prompt.md.tmpl +0 -17
- package/plugins/copilot-pbr/skills/build/SKILL.md +0 -960
- package/plugins/copilot-pbr/skills/config/SKILL.md +0 -250
- package/plugins/copilot-pbr/skills/continue/SKILL.md +0 -159
- package/plugins/copilot-pbr/skills/dashboard/SKILL.md +0 -43
- package/plugins/copilot-pbr/skills/debug/SKILL.md +0 -508
- package/plugins/copilot-pbr/skills/debug/templates/continuation-prompt.md.tmpl +0 -17
- package/plugins/copilot-pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +0 -28
- package/plugins/copilot-pbr/skills/discuss/SKILL.md +0 -353
- package/plugins/copilot-pbr/skills/discuss/templates/CONTEXT.md.tmpl +0 -62
- package/plugins/copilot-pbr/skills/discuss/templates/decision-categories.md +0 -10
- package/plugins/copilot-pbr/skills/do/SKILL.md +0 -66
- package/plugins/copilot-pbr/skills/explore/SKILL.md +0 -373
- package/plugins/copilot-pbr/skills/health/SKILL.md +0 -283
- package/plugins/copilot-pbr/skills/health/templates/check-pattern.md.tmpl +0 -31
- package/plugins/copilot-pbr/skills/health/templates/output-format.md.tmpl +0 -64
- package/plugins/copilot-pbr/skills/help/SKILL.md +0 -170
- package/plugins/copilot-pbr/skills/import/SKILL.md +0 -502
- package/plugins/copilot-pbr/skills/milestone/SKILL.md +0 -745
- package/plugins/copilot-pbr/skills/milestone/templates/audit-report.md.tmpl +0 -49
- package/plugins/copilot-pbr/skills/milestone/templates/stats-file.md.tmpl +0 -31
- package/plugins/copilot-pbr/skills/note/SKILL.md +0 -213
- package/plugins/copilot-pbr/skills/pause/SKILL.md +0 -247
- package/plugins/copilot-pbr/skills/pause/templates/continue-here.md.tmpl +0 -72
- package/plugins/copilot-pbr/skills/plan/SKILL.md +0 -662
- package/plugins/copilot-pbr/skills/plan/templates/checker-prompt.md.tmpl +0 -22
- package/plugins/copilot-pbr/skills/plan/templates/gap-closure-prompt.md.tmpl +0 -33
- package/plugins/copilot-pbr/skills/plan/templates/planner-prompt.md.tmpl +0 -39
- package/plugins/copilot-pbr/skills/plan/templates/researcher-prompt.md.tmpl +0 -20
- package/plugins/copilot-pbr/skills/plan/templates/revision-prompt.md.tmpl +0 -24
- package/plugins/copilot-pbr/skills/quick/SKILL.md +0 -376
- package/plugins/copilot-pbr/skills/resume/SKILL.md +0 -399
- package/plugins/copilot-pbr/skills/review/SKILL.md +0 -653
- package/plugins/copilot-pbr/skills/review/templates/debugger-prompt.md.tmpl +0 -61
- package/plugins/copilot-pbr/skills/review/templates/gap-planner-prompt.md.tmpl +0 -41
- package/plugins/copilot-pbr/skills/review/templates/verifier-prompt.md.tmpl +0 -116
- package/plugins/copilot-pbr/skills/scan/SKILL.md +0 -299
- package/plugins/copilot-pbr/skills/scan/templates/mapper-prompt.md.tmpl +0 -202
- package/plugins/copilot-pbr/skills/setup/SKILL.md +0 -296
- package/plugins/copilot-pbr/skills/shared/commit-planning-docs.md +0 -36
- package/plugins/copilot-pbr/skills/shared/config-loading.md +0 -103
- package/plugins/copilot-pbr/skills/shared/context-budget.md +0 -41
- package/plugins/copilot-pbr/skills/shared/context-loader-task.md +0 -87
- package/plugins/copilot-pbr/skills/shared/digest-select.md +0 -80
- package/plugins/copilot-pbr/skills/shared/domain-probes.md +0 -126
- package/plugins/copilot-pbr/skills/shared/error-reporting.md +0 -81
- package/plugins/copilot-pbr/skills/shared/gate-prompts.md +0 -389
- package/plugins/copilot-pbr/skills/shared/phase-argument-parsing.md +0 -46
- package/plugins/copilot-pbr/skills/shared/progress-display.md +0 -53
- package/plugins/copilot-pbr/skills/shared/revision-loop.md +0 -82
- package/plugins/copilot-pbr/skills/shared/state-loading.md +0 -63
- package/plugins/copilot-pbr/skills/shared/state-update.md +0 -162
- package/plugins/copilot-pbr/skills/shared/universal-anti-patterns.md +0 -38
- package/plugins/copilot-pbr/skills/status/SKILL.md +0 -362
- package/plugins/copilot-pbr/skills/statusline/SKILL.md +0 -149
- package/plugins/copilot-pbr/skills/todo/SKILL.md +0 -279
- package/plugins/copilot-pbr/templates/CONTEXT.md.tmpl +0 -53
- package/plugins/copilot-pbr/templates/INTEGRATION-REPORT.md.tmpl +0 -152
- package/plugins/copilot-pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -98
- package/plugins/copilot-pbr/templates/ROADMAP.md.tmpl +0 -41
- package/plugins/copilot-pbr/templates/SUMMARY.md.tmpl +0 -82
- package/plugins/copilot-pbr/templates/VERIFICATION-DETAIL.md.tmpl +0 -117
- package/plugins/copilot-pbr/templates/codebase/ARCHITECTURE.md.tmpl +0 -98
- package/plugins/copilot-pbr/templates/codebase/CONCERNS.md.tmpl +0 -93
- package/plugins/copilot-pbr/templates/codebase/CONVENTIONS.md.tmpl +0 -104
- package/plugins/copilot-pbr/templates/codebase/INTEGRATIONS.md.tmpl +0 -78
- package/plugins/copilot-pbr/templates/codebase/STACK.md.tmpl +0 -78
- package/plugins/copilot-pbr/templates/codebase/STRUCTURE.md.tmpl +0 -80
- package/plugins/copilot-pbr/templates/codebase/TESTING.md.tmpl +0 -107
- package/plugins/copilot-pbr/templates/continue-here.md.tmpl +0 -74
- package/plugins/copilot-pbr/templates/prompt-partials/phase-project-context.md.tmpl +0 -38
- package/plugins/copilot-pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
- package/plugins/copilot-pbr/templates/research/STACK.md.tmpl +0 -71
- package/plugins/copilot-pbr/templates/research/SUMMARY.md.tmpl +0 -112
- package/plugins/copilot-pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
- package/plugins/copilot-pbr/templates/research-outputs/project-research.md.tmpl +0 -99
- package/plugins/copilot-pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
- package/plugins/cursor-pbr/.cursor-plugin/plugin.json +0 -32
- package/plugins/cursor-pbr/CHANGELOG.md +0 -15
- package/plugins/cursor-pbr/README.md +0 -123
- package/plugins/cursor-pbr/agents/audit.md +0 -178
- package/plugins/cursor-pbr/agents/codebase-mapper.md +0 -150
- package/plugins/cursor-pbr/agents/debugger.md +0 -181
- package/plugins/cursor-pbr/agents/executor.md +0 -266
- package/plugins/cursor-pbr/agents/general.md +0 -87
- package/plugins/cursor-pbr/agents/integration-checker.md +0 -118
- package/plugins/cursor-pbr/agents/plan-checker.md +0 -207
- package/plugins/cursor-pbr/agents/planner.md +0 -237
- package/plugins/cursor-pbr/agents/researcher.md +0 -185
- package/plugins/cursor-pbr/agents/synthesizer.md +0 -125
- package/plugins/cursor-pbr/agents/verifier.md +0 -227
- package/plugins/cursor-pbr/assets/.gitkeep +0 -0
- package/plugins/cursor-pbr/assets/logo.svg +0 -21
- package/plugins/cursor-pbr/hooks/hooks.json +0 -213
- package/plugins/cursor-pbr/references/agent-anti-patterns.md +0 -25
- package/plugins/cursor-pbr/references/agent-contracts.md +0 -297
- package/plugins/cursor-pbr/references/agent-interactions.md +0 -135
- package/plugins/cursor-pbr/references/agent-teams.md +0 -55
- package/plugins/cursor-pbr/references/checkpoints.md +0 -158
- package/plugins/cursor-pbr/references/common-bug-patterns.md +0 -14
- package/plugins/cursor-pbr/references/config-reference.md +0 -442
- package/plugins/cursor-pbr/references/continuation-format.md +0 -213
- package/plugins/cursor-pbr/references/deviation-rules.md +0 -113
- package/plugins/cursor-pbr/references/git-integration.md +0 -227
- package/plugins/cursor-pbr/references/integration-patterns.md +0 -118
- package/plugins/cursor-pbr/references/model-profiles.md +0 -100
- package/plugins/cursor-pbr/references/model-selection.md +0 -32
- package/plugins/cursor-pbr/references/pbr-rules.md +0 -195
- package/plugins/cursor-pbr/references/pbr-tools-cli.md +0 -285
- package/plugins/cursor-pbr/references/plan-authoring.md +0 -182
- package/plugins/cursor-pbr/references/plan-format.md +0 -288
- package/plugins/cursor-pbr/references/planning-config.md +0 -214
- package/plugins/cursor-pbr/references/questioning.md +0 -215
- package/plugins/cursor-pbr/references/reading-verification.md +0 -128
- package/plugins/cursor-pbr/references/stub-patterns.md +0 -161
- package/plugins/cursor-pbr/references/subagent-coordination.md +0 -120
- package/plugins/cursor-pbr/references/ui-formatting.md +0 -444
- package/plugins/cursor-pbr/references/verification-patterns.md +0 -199
- package/plugins/cursor-pbr/references/wave-execution.md +0 -96
- package/plugins/cursor-pbr/rules/pbr-workflow.mdc +0 -48
- package/plugins/cursor-pbr/setup.ps1 +0 -78
- package/plugins/cursor-pbr/setup.sh +0 -83
- package/plugins/cursor-pbr/skills/audit/SKILL.md +0 -331
- package/plugins/cursor-pbr/skills/begin/SKILL.md +0 -589
- package/plugins/cursor-pbr/skills/begin/templates/PROJECT.md.tmpl +0 -34
- package/plugins/cursor-pbr/skills/begin/templates/REQUIREMENTS.md.tmpl +0 -19
- package/plugins/cursor-pbr/skills/begin/templates/STATE.md.tmpl +0 -50
- package/plugins/cursor-pbr/skills/begin/templates/config.json.tmpl +0 -64
- package/plugins/cursor-pbr/skills/begin/templates/researcher-prompt.md.tmpl +0 -20
- package/plugins/cursor-pbr/skills/begin/templates/roadmap-prompt.md.tmpl +0 -31
- package/plugins/cursor-pbr/skills/begin/templates/synthesis-prompt.md.tmpl +0 -17
- package/plugins/cursor-pbr/skills/build/SKILL.md +0 -961
- package/plugins/cursor-pbr/skills/config/SKILL.md +0 -252
- package/plugins/cursor-pbr/skills/continue/SKILL.md +0 -159
- package/plugins/cursor-pbr/skills/dashboard/SKILL.md +0 -44
- package/plugins/cursor-pbr/skills/debug/SKILL.md +0 -512
- package/plugins/cursor-pbr/skills/debug/templates/continuation-prompt.md.tmpl +0 -17
- package/plugins/cursor-pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +0 -28
- package/plugins/cursor-pbr/skills/discuss/SKILL.md +0 -354
- package/plugins/cursor-pbr/skills/discuss/templates/CONTEXT.md.tmpl +0 -62
- package/plugins/cursor-pbr/skills/discuss/templates/decision-categories.md +0 -10
- package/plugins/cursor-pbr/skills/do/SKILL.md +0 -67
- package/plugins/cursor-pbr/skills/explore/SKILL.md +0 -376
- package/plugins/cursor-pbr/skills/health/SKILL.md +0 -283
- package/plugins/cursor-pbr/skills/health/templates/check-pattern.md.tmpl +0 -31
- package/plugins/cursor-pbr/skills/health/templates/output-format.md.tmpl +0 -64
- package/plugins/cursor-pbr/skills/help/SKILL.md +0 -170
- package/plugins/cursor-pbr/skills/import/SKILL.md +0 -505
- package/plugins/cursor-pbr/skills/milestone/SKILL.md +0 -746
- package/plugins/cursor-pbr/skills/milestone/templates/audit-report.md.tmpl +0 -49
- package/plugins/cursor-pbr/skills/milestone/templates/stats-file.md.tmpl +0 -31
- package/plugins/cursor-pbr/skills/note/SKILL.md +0 -214
- package/plugins/cursor-pbr/skills/pause/SKILL.md +0 -248
- package/plugins/cursor-pbr/skills/pause/templates/continue-here.md.tmpl +0 -72
- package/plugins/cursor-pbr/skills/plan/SKILL.md +0 -663
- package/plugins/cursor-pbr/skills/plan/templates/checker-prompt.md.tmpl +0 -22
- package/plugins/cursor-pbr/skills/plan/templates/gap-closure-prompt.md.tmpl +0 -33
- package/plugins/cursor-pbr/skills/plan/templates/planner-prompt.md.tmpl +0 -39
- package/plugins/cursor-pbr/skills/plan/templates/researcher-prompt.md.tmpl +0 -20
- package/plugins/cursor-pbr/skills/plan/templates/revision-prompt.md.tmpl +0 -24
- package/plugins/cursor-pbr/skills/quick/SKILL.md +0 -376
- package/plugins/cursor-pbr/skills/resume/SKILL.md +0 -399
- package/plugins/cursor-pbr/skills/review/SKILL.md +0 -654
- package/plugins/cursor-pbr/skills/review/templates/debugger-prompt.md.tmpl +0 -61
- package/plugins/cursor-pbr/skills/review/templates/gap-planner-prompt.md.tmpl +0 -41
- package/plugins/cursor-pbr/skills/review/templates/verifier-prompt.md.tmpl +0 -116
- package/plugins/cursor-pbr/skills/scan/SKILL.md +0 -300
- package/plugins/cursor-pbr/skills/scan/templates/mapper-prompt.md.tmpl +0 -202
- package/plugins/cursor-pbr/skills/setup/SKILL.md +0 -296
- package/plugins/cursor-pbr/skills/shared/commit-planning-docs.md +0 -36
- package/plugins/cursor-pbr/skills/shared/config-loading.md +0 -103
- package/plugins/cursor-pbr/skills/shared/context-budget.md +0 -41
- package/plugins/cursor-pbr/skills/shared/context-loader-task.md +0 -87
- package/plugins/cursor-pbr/skills/shared/digest-select.md +0 -80
- package/plugins/cursor-pbr/skills/shared/domain-probes.md +0 -126
- package/plugins/cursor-pbr/skills/shared/error-reporting.md +0 -81
- package/plugins/cursor-pbr/skills/shared/gate-prompts.md +0 -389
- package/plugins/cursor-pbr/skills/shared/phase-argument-parsing.md +0 -46
- package/plugins/cursor-pbr/skills/shared/progress-display.md +0 -53
- package/plugins/cursor-pbr/skills/shared/revision-loop.md +0 -82
- package/plugins/cursor-pbr/skills/shared/state-loading.md +0 -63
- package/plugins/cursor-pbr/skills/shared/state-update.md +0 -162
- package/plugins/cursor-pbr/skills/shared/universal-anti-patterns.md +0 -38
- package/plugins/cursor-pbr/skills/status/SKILL.md +0 -362
- package/plugins/cursor-pbr/skills/statusline/SKILL.md +0 -150
- package/plugins/cursor-pbr/skills/todo/SKILL.md +0 -280
- package/plugins/cursor-pbr/templates/CONTEXT.md.tmpl +0 -53
- package/plugins/cursor-pbr/templates/INTEGRATION-REPORT.md.tmpl +0 -152
- package/plugins/cursor-pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -98
- package/plugins/cursor-pbr/templates/ROADMAP.md.tmpl +0 -41
- package/plugins/cursor-pbr/templates/SUMMARY.md.tmpl +0 -82
- package/plugins/cursor-pbr/templates/VERIFICATION-DETAIL.md.tmpl +0 -117
- package/plugins/cursor-pbr/templates/codebase/ARCHITECTURE.md.tmpl +0 -98
- package/plugins/cursor-pbr/templates/codebase/CONCERNS.md.tmpl +0 -93
- package/plugins/cursor-pbr/templates/codebase/CONVENTIONS.md.tmpl +0 -104
- package/plugins/cursor-pbr/templates/codebase/INTEGRATIONS.md.tmpl +0 -78
- package/plugins/cursor-pbr/templates/codebase/STACK.md.tmpl +0 -78
- package/plugins/cursor-pbr/templates/codebase/STRUCTURE.md.tmpl +0 -80
- package/plugins/cursor-pbr/templates/codebase/TESTING.md.tmpl +0 -107
- package/plugins/cursor-pbr/templates/continue-here.md.tmpl +0 -74
- package/plugins/cursor-pbr/templates/prompt-partials/phase-project-context.md.tmpl +0 -38
- package/plugins/cursor-pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
- package/plugins/cursor-pbr/templates/research/STACK.md.tmpl +0 -71
- package/plugins/cursor-pbr/templates/research/SUMMARY.md.tmpl +0 -112
- package/plugins/cursor-pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
- package/plugins/cursor-pbr/templates/research-outputs/project-research.md.tmpl +0 -99
- package/plugins/cursor-pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
- package/plugins/pbr/references/agent-interactions.md +0 -134
- package/plugins/pbr/references/pbr-rules.md +0 -194
- package/plugins/pbr/references/pbr-tools-cli.md +0 -285
- package/plugins/pbr/references/planning-config.md +0 -213
- package/plugins/pbr/references/subagent-coordination.md +0 -119
- package/plugins/pbr/references/ui-formatting.md +0 -444
- package/plugins/pbr/scripts/validate-plugin-structure.js +0 -183
- package/plugins/pbr/skills/milestone/templates/audit-report.md.tmpl +0 -48
- package/plugins/pbr/skills/shared/progress-display.md +0 -53
- package/plugins/pbr/skills/shared/state-loading.md +0 -62
- package/plugins/pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -97
- package/plugins/pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
- package/plugins/pbr/templates/research/STACK.md.tmpl +0 -71
- package/plugins/pbr/templates/research/SUMMARY.md.tmpl +0 -112
- package/plugins/pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
- package/plugins/pbr/templates/research-outputs/project-research.md.tmpl +0 -99
- package/plugins/pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
- /package/plugins/pbr/references/{agent-anti-patterns.md → archive/agent-anti-patterns.md} +0 -0
|
@@ -0,0 +1,980 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Session Quality & UX Check Module
|
|
5
|
+
*
|
|
6
|
+
* Implements SQ-01 through SQ-03 session quality dimensions for the PBR audit system.
|
|
7
|
+
* Each check returns a structured result: { dimension, status, message, evidence }.
|
|
8
|
+
*
|
|
9
|
+
* Checks:
|
|
10
|
+
* SQ-01: Session start quality (progress-tracker briefing injection)
|
|
11
|
+
* SQ-02: Briefing freshness (STATE.md staleness and size)
|
|
12
|
+
* SQ-03: Session duration/cost analysis (duration and tool call volume)
|
|
13
|
+
*
|
|
14
|
+
* Shared helpers:
|
|
15
|
+
* readJsonlFiles(logsDir, prefix) — reads all {prefix}-*.jsonl files
|
|
16
|
+
* readHookLogs(logsDir) — reads hook logs
|
|
17
|
+
* readEventLogs(logsDir) — reads event logs
|
|
18
|
+
* getLogsDir(planningDir) — resolves logs directory path
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const fs = require('fs');
|
|
22
|
+
const path = require('path');
|
|
23
|
+
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Result helper
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Build a structured check result.
|
|
30
|
+
* @param {string} dimCode - Dimension code (e.g. "SQ-01")
|
|
31
|
+
* @param {'pass'|'warn'|'fail'|'info'} status
|
|
32
|
+
* @param {string} message
|
|
33
|
+
* @param {string[]} [evidence]
|
|
34
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
35
|
+
*/
|
|
36
|
+
function result(dimCode, status, message, evidence) {
|
|
37
|
+
return {
|
|
38
|
+
dimension: dimCode,
|
|
39
|
+
status,
|
|
40
|
+
message,
|
|
41
|
+
evidence: evidence || [],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Shared JSONL helpers
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Return the logs directory path for a planning directory.
|
|
51
|
+
* @param {string} planningDir
|
|
52
|
+
* @returns {string}
|
|
53
|
+
*/
|
|
54
|
+
function getLogsDir(planningDir) {
|
|
55
|
+
return path.join(planningDir, 'logs');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Read all {prefix}-*.jsonl files in logsDir, parse each line as JSON.
|
|
60
|
+
* Returns a flat array of parsed entries. Skips unparseable lines.
|
|
61
|
+
* Returns empty array if directory is missing.
|
|
62
|
+
* @param {string} logsDir
|
|
63
|
+
* @param {string} prefix
|
|
64
|
+
* @returns {object[]}
|
|
65
|
+
*/
|
|
66
|
+
function readJsonlFiles(logsDir, prefix) {
|
|
67
|
+
if (!fs.existsSync(logsDir)) return [];
|
|
68
|
+
|
|
69
|
+
const entries = [];
|
|
70
|
+
let files;
|
|
71
|
+
try {
|
|
72
|
+
files = fs.readdirSync(logsDir).filter(f => f.startsWith(prefix + '-') && f.endsWith('.jsonl'));
|
|
73
|
+
} catch (_e) {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
for (const file of files) {
|
|
78
|
+
try {
|
|
79
|
+
const content = fs.readFileSync(path.join(logsDir, file), 'utf8');
|
|
80
|
+
const lines = content.split('\n');
|
|
81
|
+
for (const line of lines) {
|
|
82
|
+
const trimmed = line.trim();
|
|
83
|
+
if (!trimmed) continue;
|
|
84
|
+
try {
|
|
85
|
+
entries.push(JSON.parse(trimmed));
|
|
86
|
+
} catch (_e) {
|
|
87
|
+
// Skip unparseable lines
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} catch (_e) {
|
|
91
|
+
// Skip unreadable files
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return entries;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Read all hook log entries from logsDir.
|
|
100
|
+
* @param {string} logsDir
|
|
101
|
+
* @returns {object[]}
|
|
102
|
+
*/
|
|
103
|
+
function readHookLogs(logsDir) {
|
|
104
|
+
return readJsonlFiles(logsDir, 'hooks');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Read all event log entries from logsDir.
|
|
109
|
+
* @param {string} logsDir
|
|
110
|
+
* @returns {object[]}
|
|
111
|
+
*/
|
|
112
|
+
function readEventLogs(logsDir) {
|
|
113
|
+
return readJsonlFiles(logsDir, 'events');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
// SQ-01: Session Start Quality
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Check whether progress-tracker injected a session-start briefing.
|
|
122
|
+
* Examines hook logs for progress-tracker SessionStart entries and
|
|
123
|
+
* event logs for workflow/session-start entries.
|
|
124
|
+
*
|
|
125
|
+
* @param {string} planningDir - Path to .planning directory
|
|
126
|
+
* @param {object} _config - Audit config (unused for this check)
|
|
127
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
128
|
+
*/
|
|
129
|
+
function checkSessionStartQuality(planningDir, _config) {
|
|
130
|
+
const logsDir = getLogsDir(planningDir);
|
|
131
|
+
const hookLogs = readHookLogs(logsDir);
|
|
132
|
+
const eventLogs = readEventLogs(logsDir);
|
|
133
|
+
|
|
134
|
+
// Find progress-tracker SessionStart entries in hook logs
|
|
135
|
+
const hookStarts = hookLogs.filter(
|
|
136
|
+
e => e.hook === 'progress-tracker' && e.event === 'SessionStart'
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
// Find session-start entries in event logs
|
|
140
|
+
const eventStarts = eventLogs.filter(
|
|
141
|
+
e => e.cat === 'workflow' && e.event === 'session-start'
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const allStarts = [...hookStarts, ...eventStarts];
|
|
145
|
+
|
|
146
|
+
if (allStarts.length === 0) {
|
|
147
|
+
return result('SQ-01', 'warn', 'No session start events found in logs', [
|
|
148
|
+
'No session start events found in logs',
|
|
149
|
+
]);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Check how many sessions had briefing injection
|
|
153
|
+
// Hook logs: decision === 'injected' or presence of output/additionalContext
|
|
154
|
+
// Event logs: details might contain hasState or injected fields
|
|
155
|
+
let injectedCount = 0;
|
|
156
|
+
let totalCount = allStarts.length;
|
|
157
|
+
const evidence = [];
|
|
158
|
+
|
|
159
|
+
for (const entry of hookStarts) {
|
|
160
|
+
const injected = entry.decision === 'injected' || entry.decision === 'inject' ||
|
|
161
|
+
(entry.detail && typeof entry.detail === 'string' && entry.detail.includes('inject'));
|
|
162
|
+
const hasState = entry.hasState !== undefined ? entry.hasState : 'unknown';
|
|
163
|
+
if (injected) injectedCount++;
|
|
164
|
+
evidence.push(`Session start: briefing ${injected ? 'injected' : 'not injected'} (hasState: ${hasState})`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
for (const entry of eventStarts) {
|
|
168
|
+
const injected = entry.injected === true || entry.hasState === true;
|
|
169
|
+
if (injected) injectedCount++;
|
|
170
|
+
evidence.push(`Session start event: briefing ${injected ? 'injected' : 'not detected'} (ts: ${entry.ts || 'unknown'})`);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
let status;
|
|
174
|
+
let message;
|
|
175
|
+
if (injectedCount === totalCount) {
|
|
176
|
+
status = 'pass';
|
|
177
|
+
message = `All ${totalCount} sessions had briefing injection`;
|
|
178
|
+
} else if (injectedCount > 0) {
|
|
179
|
+
status = 'warn';
|
|
180
|
+
message = `${injectedCount}/${totalCount} sessions had briefing injection`;
|
|
181
|
+
} else {
|
|
182
|
+
status = 'fail';
|
|
183
|
+
message = `No sessions had briefing injection (${totalCount} sessions checked)`;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return result('SQ-01', status, message, evidence);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// ---------------------------------------------------------------------------
|
|
190
|
+
// SQ-02: Briefing Freshness
|
|
191
|
+
// ---------------------------------------------------------------------------
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Measure STATE.md staleness and size relative to the most recent session start.
|
|
195
|
+
* Fresh = STATE.md modified within 1 hour of session start. Bloated = over 5000 chars.
|
|
196
|
+
*
|
|
197
|
+
* @param {string} planningDir - Path to .planning directory
|
|
198
|
+
* @param {object} _config - Audit config (unused for this check)
|
|
199
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
200
|
+
*/
|
|
201
|
+
function checkBriefingFreshness(planningDir, _config) {
|
|
202
|
+
const stateFile = path.join(planningDir, 'STATE.md');
|
|
203
|
+
|
|
204
|
+
// Check STATE.md existence
|
|
205
|
+
if (!fs.existsSync(stateFile)) {
|
|
206
|
+
return result('SQ-02', 'info', 'No STATE.md found', ['STATE.md does not exist']);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
let stateMtime;
|
|
210
|
+
let stateContent;
|
|
211
|
+
try {
|
|
212
|
+
const stat = fs.statSync(stateFile);
|
|
213
|
+
stateMtime = stat.mtime;
|
|
214
|
+
stateContent = fs.readFileSync(stateFile, 'utf8');
|
|
215
|
+
} catch (_e) {
|
|
216
|
+
return result('SQ-02', 'warn', 'Could not read STATE.md', ['Error reading STATE.md']);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const stateSize = stateContent.length;
|
|
220
|
+
const evidence = [];
|
|
221
|
+
|
|
222
|
+
// Find most recent session-start from event logs
|
|
223
|
+
const logsDir = getLogsDir(planningDir);
|
|
224
|
+
const eventLogs = readEventLogs(logsDir);
|
|
225
|
+
const sessionStarts = eventLogs
|
|
226
|
+
.filter(e => e.cat === 'workflow' && e.event === 'session-start' && e.ts)
|
|
227
|
+
.sort((a, b) => new Date(b.ts).getTime() - new Date(a.ts).getTime());
|
|
228
|
+
|
|
229
|
+
if (sessionStarts.length === 0) {
|
|
230
|
+
// No session data — report size only
|
|
231
|
+
const sizeAssessment = stateSize > 5000 ? 'bloated' : 'reasonable';
|
|
232
|
+
evidence.push(`STATE.md: ${stateSize} chars (${sizeAssessment}), no session data to compare staleness`);
|
|
233
|
+
if (stateSize > 5000) {
|
|
234
|
+
return result('SQ-02', 'warn', `STATE.md is bloated (${stateSize} chars) — no session timing data`, evidence);
|
|
235
|
+
}
|
|
236
|
+
return result('SQ-02', 'info', 'No session data to measure staleness', evidence);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Compare most recent session start to STATE.md mtime
|
|
240
|
+
const latestStart = new Date(sessionStarts[0].ts);
|
|
241
|
+
const stalenessMs = latestStart.getTime() - stateMtime.getTime();
|
|
242
|
+
const stalenessMin = Math.round(stalenessMs / 60000);
|
|
243
|
+
const isStale = stalenessMs > 3600000; // >1 hour
|
|
244
|
+
const isBloated = stateSize > 5000;
|
|
245
|
+
|
|
246
|
+
const ageStr = stalenessMs >= 0
|
|
247
|
+
? `${stalenessMin}min before session start`
|
|
248
|
+
: `${Math.abs(stalenessMin)}min after session start`;
|
|
249
|
+
|
|
250
|
+
evidence.push(`STATE.md: ${stateSize} chars, last modified ${ageStr}`);
|
|
251
|
+
evidence.push(`Size assessment: ${isBloated ? 'bloated (>5000 chars)' : 'reasonable'}`);
|
|
252
|
+
evidence.push(`Freshness: ${isStale ? 'stale (>1h)' : 'fresh'}`);
|
|
253
|
+
|
|
254
|
+
let status;
|
|
255
|
+
let message;
|
|
256
|
+
if (!isStale && !isBloated) {
|
|
257
|
+
status = 'pass';
|
|
258
|
+
message = `STATE.md is fresh and ${stateSize} chars`;
|
|
259
|
+
} else {
|
|
260
|
+
status = 'warn';
|
|
261
|
+
const issues = [];
|
|
262
|
+
if (isStale) issues.push(`stale (${ageStr})`);
|
|
263
|
+
if (isBloated) issues.push(`bloated (${stateSize} chars)`);
|
|
264
|
+
message = `STATE.md: ${issues.join(', ')}`;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return result('SQ-02', status, message, evidence);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// ---------------------------------------------------------------------------
|
|
271
|
+
// SQ-03: Session Duration & Cost Analysis
|
|
272
|
+
// ---------------------------------------------------------------------------
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Measure session durations and tool call volumes. Flags sessions exceeding
|
|
276
|
+
* the configured duration threshold.
|
|
277
|
+
*
|
|
278
|
+
* @param {string} planningDir - Path to .planning directory
|
|
279
|
+
* @param {object} config - Audit config (uses config.audit.thresholds.session_duration_warn_ms)
|
|
280
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
281
|
+
*/
|
|
282
|
+
function checkSessionDurationCost(planningDir, config) {
|
|
283
|
+
const logsDir = getLogsDir(planningDir);
|
|
284
|
+
const eventLogs = readEventLogs(logsDir);
|
|
285
|
+
|
|
286
|
+
// Get duration threshold from config (default 1 hour)
|
|
287
|
+
const thresholds = (config && config.audit && config.audit.thresholds) || {};
|
|
288
|
+
const session_duration_warn_ms = thresholds.session_duration_warn_ms || 3600000;
|
|
289
|
+
|
|
290
|
+
// Find all session-start events
|
|
291
|
+
const sessionStarts = eventLogs
|
|
292
|
+
.filter(e => e.cat === 'workflow' && e.event === 'session-start' && e.ts)
|
|
293
|
+
.sort((a, b) => new Date(a.ts).getTime() - new Date(b.ts).getTime());
|
|
294
|
+
|
|
295
|
+
if (sessionStarts.length === 0) {
|
|
296
|
+
return result('SQ-03', 'info', 'No session data', ['No session-start events found in logs']);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Find session-end events
|
|
300
|
+
const sessionEnds = eventLogs
|
|
301
|
+
.filter(e => e.cat === 'workflow' && (e.event === 'session-end' || e.event === 'session-stop') && e.ts)
|
|
302
|
+
.sort((a, b) => new Date(a.ts).getTime() - new Date(b.ts).getTime());
|
|
303
|
+
|
|
304
|
+
// Count all tool-use events for cost proxy
|
|
305
|
+
const toolUseEvents = eventLogs.filter(
|
|
306
|
+
e => e.cat === 'tool' || e.event === 'tool-use' || e.event === 'PostToolUse'
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
// Also check hook logs for tool-use events as a supplementary source
|
|
310
|
+
const hookLogs = readHookLogs(logsDir);
|
|
311
|
+
const hookToolEvents = hookLogs.filter(e => e.event === 'PostToolUse' || e.event === 'PreToolUse');
|
|
312
|
+
|
|
313
|
+
const evidence = [];
|
|
314
|
+
let anyExceeded = false;
|
|
315
|
+
|
|
316
|
+
for (let i = 0; i < sessionStarts.length; i++) {
|
|
317
|
+
const startTs = new Date(sessionStarts[i].ts).getTime();
|
|
318
|
+
const startDate = new Date(sessionStarts[i].ts).toISOString().slice(0, 16);
|
|
319
|
+
|
|
320
|
+
// Find the matching end: next session-end after this start but before next start
|
|
321
|
+
const nextStartTs = i + 1 < sessionStarts.length
|
|
322
|
+
? new Date(sessionStarts[i + 1].ts).getTime()
|
|
323
|
+
: Infinity;
|
|
324
|
+
|
|
325
|
+
const matchingEnd = sessionEnds.find(e => {
|
|
326
|
+
const endTs = new Date(e.ts).getTime();
|
|
327
|
+
return endTs > startTs && endTs <= nextStartTs;
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
let endTs;
|
|
331
|
+
if (matchingEnd) {
|
|
332
|
+
endTs = new Date(matchingEnd.ts).getTime();
|
|
333
|
+
} else {
|
|
334
|
+
// Use last event before next session start as approximate end
|
|
335
|
+
const eventsInRange = eventLogs
|
|
336
|
+
.filter(e => e.ts && new Date(e.ts).getTime() > startTs && new Date(e.ts).getTime() < nextStartTs)
|
|
337
|
+
.map(e => new Date(e.ts).getTime());
|
|
338
|
+
endTs = eventsInRange.length > 0 ? Math.max(...eventsInRange) : startTs;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const durationMs = endTs - startTs;
|
|
342
|
+
const durationMin = Math.round(durationMs / 60000);
|
|
343
|
+
|
|
344
|
+
// Count tool calls within this session's time range
|
|
345
|
+
const sessionToolCalls = toolUseEvents.filter(e => {
|
|
346
|
+
if (!e.ts) return false;
|
|
347
|
+
const t = new Date(e.ts).getTime();
|
|
348
|
+
return t >= startTs && t < nextStartTs;
|
|
349
|
+
}).length;
|
|
350
|
+
|
|
351
|
+
const sessionHookCalls = hookToolEvents.filter(e => {
|
|
352
|
+
if (!e.ts) return false;
|
|
353
|
+
const t = new Date(e.ts).getTime();
|
|
354
|
+
return t >= startTs && t < nextStartTs;
|
|
355
|
+
}).length;
|
|
356
|
+
|
|
357
|
+
const totalCalls = sessionToolCalls + sessionHookCalls;
|
|
358
|
+
|
|
359
|
+
if (durationMs > session_duration_warn_ms) {
|
|
360
|
+
anyExceeded = true;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
evidence.push(`Session ${startDate}: ${durationMin}min, ${totalCalls} tool calls`);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
let status;
|
|
367
|
+
let message;
|
|
368
|
+
if (anyExceeded) {
|
|
369
|
+
status = 'warn';
|
|
370
|
+
message = `${sessionStarts.length} session(s) analyzed — some exceeded ${Math.round(session_duration_warn_ms / 60000)}min threshold`;
|
|
371
|
+
} else {
|
|
372
|
+
status = 'pass';
|
|
373
|
+
message = `${sessionStarts.length} session(s) analyzed — all within duration threshold`;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return result('SQ-03', status, message, evidence);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// ---------------------------------------------------------------------------
|
|
380
|
+
// SQ-04: Skill Routing Accuracy
|
|
381
|
+
// ---------------------------------------------------------------------------
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Evaluate whether /pbr:do routing events matched user intent.
|
|
385
|
+
* Scans hook logs for check-skill-workflow entries (blocks = misroutes)
|
|
386
|
+
* and event logs for skill-workflow-block events.
|
|
387
|
+
*
|
|
388
|
+
* @param {string} planningDir - Path to .planning directory
|
|
389
|
+
* @param {object} _config - Audit config (unused for this check)
|
|
390
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
391
|
+
*/
|
|
392
|
+
function checkSkillRoutingAccuracy(planningDir, _config) {
|
|
393
|
+
const logsDir = getLogsDir(planningDir);
|
|
394
|
+
const hookLogs = readHookLogs(logsDir);
|
|
395
|
+
const eventLogs = readEventLogs(logsDir);
|
|
396
|
+
|
|
397
|
+
// Find skill-workflow hook entries (routing enforcement events)
|
|
398
|
+
const skillWorkflowHooks = hookLogs.filter(
|
|
399
|
+
e => e.hook === 'check-skill-workflow'
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
// Find skill-workflow-block events in event logs
|
|
403
|
+
const routingBlocks = eventLogs.filter(
|
|
404
|
+
e => e.cat === 'workflow' && e.event === 'skill-workflow-block'
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
// Find /pbr:do usage — event log entries mentioning "do" skill or routing
|
|
408
|
+
const doSkillEvents = eventLogs.filter(
|
|
409
|
+
e => (e.skill === 'do' || e.event === 'natural-language-routing' ||
|
|
410
|
+
(e.detail && typeof e.detail === 'string' && e.detail.includes('pbr:do')))
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
const evidence = [];
|
|
414
|
+
|
|
415
|
+
// Count routing events
|
|
416
|
+
let blocked = 0;
|
|
417
|
+
let successful = 0;
|
|
418
|
+
|
|
419
|
+
for (const entry of skillWorkflowHooks) {
|
|
420
|
+
if (entry.decision === 'block') {
|
|
421
|
+
blocked++;
|
|
422
|
+
const detail = entry.file || entry.skill || 'unknown';
|
|
423
|
+
evidence.push(`Routing block: skill=${entry.skill || 'unknown'}, file=${detail}`);
|
|
424
|
+
} else {
|
|
425
|
+
successful++;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Count event-log blocks
|
|
430
|
+
for (const entry of routingBlocks) {
|
|
431
|
+
blocked++;
|
|
432
|
+
evidence.push(`Workflow block event: ${entry.detail || entry.reason || 'no detail'}`);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Count /pbr:do events as successful routes (unless already counted as blocks)
|
|
436
|
+
for (const entry of doSkillEvents) {
|
|
437
|
+
successful++;
|
|
438
|
+
evidence.push(`/pbr:do routing: ${entry.detail || entry.event || 'routed'}`);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const total = successful + blocked;
|
|
442
|
+
|
|
443
|
+
if (total === 0) {
|
|
444
|
+
return result('SQ-04', 'info', 'No skill routing events found in logs', [
|
|
445
|
+
'No routing events detected in hook or event logs',
|
|
446
|
+
]);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
evidence.unshift(`Skill routing: ${successful}/${total} successful, ${blocked} blocked`);
|
|
450
|
+
|
|
451
|
+
let status;
|
|
452
|
+
if (blocked === 0 || (successful / total) > 0.9) {
|
|
453
|
+
status = 'pass';
|
|
454
|
+
} else {
|
|
455
|
+
status = 'warn';
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const message = `Skill routing: ${successful}/${total} successful, ${blocked} blocked`;
|
|
459
|
+
return result('SQ-04', status, message, evidence);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// ---------------------------------------------------------------------------
|
|
463
|
+
// SQ-05: Memory Update Tracking
|
|
464
|
+
// ---------------------------------------------------------------------------
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Detect auto-memory save events (writes to MEMORY.md, agent-memory/, notes/).
|
|
468
|
+
* Scans event logs and hook logs for write events targeting memory-related paths.
|
|
469
|
+
*
|
|
470
|
+
* @param {string} planningDir - Path to .planning directory
|
|
471
|
+
* @param {object} _config - Audit config (unused for this check)
|
|
472
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
473
|
+
*/
|
|
474
|
+
function checkMemoryUpdateTracking(planningDir, _config) {
|
|
475
|
+
const logsDir = getLogsDir(planningDir);
|
|
476
|
+
const hookLogs = readHookLogs(logsDir);
|
|
477
|
+
const eventLogs = readEventLogs(logsDir);
|
|
478
|
+
|
|
479
|
+
const evidence = [];
|
|
480
|
+
const memoryPaths = [];
|
|
481
|
+
|
|
482
|
+
// Scan hook logs for writes to memory-related paths
|
|
483
|
+
const memoryPatterns = ['MEMORY.md', 'agent-memory', '.claude/memory', '.claude/notes'];
|
|
484
|
+
for (const entry of hookLogs) {
|
|
485
|
+
const filePath = entry.file || entry.path || '';
|
|
486
|
+
if (memoryPatterns.some(p => filePath.includes(p))) {
|
|
487
|
+
memoryPaths.push(filePath);
|
|
488
|
+
evidence.push(`Hook log: memory write to ${path.basename(filePath)}`);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Scan event logs for memory-related writes
|
|
493
|
+
for (const entry of eventLogs) {
|
|
494
|
+
const filePath = entry.file || entry.path || entry.detail || '';
|
|
495
|
+
if (typeof filePath === 'string' && memoryPatterns.some(p => filePath.includes(p))) {
|
|
496
|
+
memoryPaths.push(filePath);
|
|
497
|
+
evidence.push(`Event log: memory activity at ${path.basename(filePath)}`);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Check for recent notes in .planning/notes/
|
|
502
|
+
const notesDir = path.join(planningDir, 'notes');
|
|
503
|
+
if (fs.existsSync(notesDir)) {
|
|
504
|
+
try {
|
|
505
|
+
const noteFiles = fs.readdirSync(notesDir).filter(f => f.endsWith('.md'));
|
|
506
|
+
const now = Date.now();
|
|
507
|
+
const recentThreshold = 24 * 60 * 60 * 1000; // 24 hours
|
|
508
|
+
for (const noteFile of noteFiles) {
|
|
509
|
+
try {
|
|
510
|
+
const stat = fs.statSync(path.join(notesDir, noteFile));
|
|
511
|
+
if (now - stat.mtime.getTime() < recentThreshold) {
|
|
512
|
+
memoryPaths.push(noteFile);
|
|
513
|
+
evidence.push(`Recent note: ${noteFile}`);
|
|
514
|
+
}
|
|
515
|
+
} catch (_e) {
|
|
516
|
+
// Skip unreadable note files
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
} catch (_e) {
|
|
520
|
+
// Skip unreadable notes directory
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
const count = memoryPaths.length;
|
|
525
|
+
evidence.unshift(`Memory updates: ${count} saves detected`);
|
|
526
|
+
|
|
527
|
+
let status;
|
|
528
|
+
let message;
|
|
529
|
+
if (count > 0) {
|
|
530
|
+
status = 'pass';
|
|
531
|
+
message = `${count} memory update(s) detected during session`;
|
|
532
|
+
} else {
|
|
533
|
+
status = 'info';
|
|
534
|
+
message = 'No memory updates detected (session may not have had new learnings)';
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
return result('SQ-05', status, message, evidence);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// ---------------------------------------------------------------------------
|
|
541
|
+
// SQ-06: Convention Detection Monitoring
|
|
542
|
+
// ---------------------------------------------------------------------------
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Check whether the convention_memory feature is active and capturing conventions.
|
|
546
|
+
* Examines config, conventions storage, and log entries for convention-detector activity.
|
|
547
|
+
*
|
|
548
|
+
* @param {string} planningDir - Path to .planning directory
|
|
549
|
+
* @param {object} config - Audit config (uses config.features.convention_memory)
|
|
550
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
551
|
+
*/
|
|
552
|
+
function checkConventionDetectionMonitoring(planningDir, config) {
|
|
553
|
+
const features = (config && config.features) || {};
|
|
554
|
+
const conventionMemoryEnabled = features.convention_memory === true;
|
|
555
|
+
|
|
556
|
+
if (!conventionMemoryEnabled) {
|
|
557
|
+
return result('SQ-06', 'info', 'convention_memory feature disabled', [
|
|
558
|
+
'config.features.convention_memory is not enabled',
|
|
559
|
+
]);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
const evidence = [];
|
|
563
|
+
|
|
564
|
+
// Check if conventions storage exists
|
|
565
|
+
const conventionsJson = path.join(planningDir, 'conventions.json');
|
|
566
|
+
const conventionsDir = path.join(planningDir, 'conventions');
|
|
567
|
+
let conventionsCount = 0;
|
|
568
|
+
|
|
569
|
+
if (fs.existsSync(conventionsJson)) {
|
|
570
|
+
try {
|
|
571
|
+
const content = fs.readFileSync(conventionsJson, 'utf8');
|
|
572
|
+
const parsed = JSON.parse(content);
|
|
573
|
+
if (Array.isArray(parsed)) {
|
|
574
|
+
conventionsCount = parsed.length;
|
|
575
|
+
} else if (typeof parsed === 'object' && parsed !== null) {
|
|
576
|
+
conventionsCount = Object.keys(parsed).length;
|
|
577
|
+
}
|
|
578
|
+
evidence.push(`conventions.json: ${conventionsCount} entries`);
|
|
579
|
+
} catch (_e) {
|
|
580
|
+
evidence.push('conventions.json: exists but could not be parsed');
|
|
581
|
+
}
|
|
582
|
+
} else if (fs.existsSync(conventionsDir)) {
|
|
583
|
+
try {
|
|
584
|
+
const files = fs.readdirSync(conventionsDir);
|
|
585
|
+
conventionsCount = files.length;
|
|
586
|
+
evidence.push(`conventions/: ${conventionsCount} files`);
|
|
587
|
+
} catch (_e) {
|
|
588
|
+
evidence.push('conventions/: exists but could not be read');
|
|
589
|
+
}
|
|
590
|
+
} else {
|
|
591
|
+
evidence.push('No conventions.json or conventions/ directory found');
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// Check logs for convention-detector activity
|
|
595
|
+
const logsDir = getLogsDir(planningDir);
|
|
596
|
+
const hookLogs = readHookLogs(logsDir);
|
|
597
|
+
const eventLogs = readEventLogs(logsDir);
|
|
598
|
+
|
|
599
|
+
const conventionHookEntries = hookLogs.filter(
|
|
600
|
+
e => e.hook === 'convention-detector' || (e.detail && typeof e.detail === 'string' && e.detail.includes('convention'))
|
|
601
|
+
);
|
|
602
|
+
const conventionEventEntries = eventLogs.filter(
|
|
603
|
+
e => (e.event && typeof e.event === 'string' && e.event.includes('convention')) ||
|
|
604
|
+
(e.detail && typeof e.detail === 'string' && e.detail.includes('convention'))
|
|
605
|
+
);
|
|
606
|
+
|
|
607
|
+
const logActivity = conventionHookEntries.length + conventionEventEntries.length;
|
|
608
|
+
evidence.push(`Convention detector activity: ${logActivity} log entries`);
|
|
609
|
+
|
|
610
|
+
let status;
|
|
611
|
+
let message;
|
|
612
|
+
if (conventionsCount > 0) {
|
|
613
|
+
status = 'pass';
|
|
614
|
+
message = `Convention detection active: ${conventionsCount} conventions captured`;
|
|
615
|
+
} else if (logActivity > 0) {
|
|
616
|
+
status = 'pass';
|
|
617
|
+
message = `Convention detector ran (${logActivity} log entries) but no conventions captured yet`;
|
|
618
|
+
} else {
|
|
619
|
+
status = 'warn';
|
|
620
|
+
message = 'convention_memory enabled but no conventions captured and no detector activity';
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
return result('SQ-06', status, message, evidence);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// ---------------------------------------------------------------------------
|
|
627
|
+
// SQ-07: User Frustration Signals
|
|
628
|
+
// ---------------------------------------------------------------------------
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Scan session JSONL for user messages containing frustration keywords.
|
|
632
|
+
* Counts frustration signals vs total user messages.
|
|
633
|
+
* Pass if <10% frustration rate, warn if 10-25%, fail if >25%.
|
|
634
|
+
*
|
|
635
|
+
* @param {string} planningDir - Path to .planning directory
|
|
636
|
+
* @param {object} _config - Audit config (unused for this check)
|
|
637
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
638
|
+
*/
|
|
639
|
+
function checkUserFrustrationSignals(planningDir, _config) {
|
|
640
|
+
const logsDir = getLogsDir(planningDir);
|
|
641
|
+
const eventLogs = readEventLogs(logsDir);
|
|
642
|
+
const hookLogs = readHookLogs(logsDir);
|
|
643
|
+
const allEntries = [...eventLogs, ...hookLogs];
|
|
644
|
+
|
|
645
|
+
// Find user messages from event logs
|
|
646
|
+
const userMessages = allEntries.filter(e =>
|
|
647
|
+
e.role === 'user' ||
|
|
648
|
+
e.cat === 'user' ||
|
|
649
|
+
e.event === 'user-message' ||
|
|
650
|
+
e.event === 'UserPromptSubmit' ||
|
|
651
|
+
(e.details && e.details.role === 'user')
|
|
652
|
+
);
|
|
653
|
+
|
|
654
|
+
if (userMessages.length === 0) {
|
|
655
|
+
return result('SQ-07', 'info', 'No user messages found in logs', [
|
|
656
|
+
'No user message events detected in session logs',
|
|
657
|
+
]);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// Frustration keywords and patterns
|
|
661
|
+
const frustrationPatterns = [
|
|
662
|
+
/\bno\b(?:\s*,|\s*\.|\s*!|\s+that|n't)/i,
|
|
663
|
+
/\bstop\b/i,
|
|
664
|
+
/\bwrong\b/i,
|
|
665
|
+
/\bthat's not\b/i,
|
|
666
|
+
/\bundo\b/i,
|
|
667
|
+
/\brevert\b/i,
|
|
668
|
+
/\bdon't\b/i,
|
|
669
|
+
/\bshouldn't\b/i,
|
|
670
|
+
/\bwhy did you\b/i,
|
|
671
|
+
/\bthat broke\b/i,
|
|
672
|
+
/\btry again\b/i,
|
|
673
|
+
/\bnot what I\b/i,
|
|
674
|
+
];
|
|
675
|
+
|
|
676
|
+
let frustrationCount = 0;
|
|
677
|
+
const evidence = [];
|
|
678
|
+
|
|
679
|
+
for (const entry of userMessages) {
|
|
680
|
+
const content = entry.content || entry.message || entry.text ||
|
|
681
|
+
(entry.details && (entry.details.content || entry.details.message)) || '';
|
|
682
|
+
const contentStr = typeof content === 'string' ? content : JSON.stringify(content);
|
|
683
|
+
|
|
684
|
+
if (contentStr.length < 2) continue;
|
|
685
|
+
|
|
686
|
+
const hasFrustration = frustrationPatterns.some(p => p.test(contentStr));
|
|
687
|
+
if (hasFrustration) {
|
|
688
|
+
frustrationCount++;
|
|
689
|
+
if (evidence.length < 3) {
|
|
690
|
+
const snippet = contentStr.substring(0, 80).replace(/\n/g, ' ');
|
|
691
|
+
evidence.push(`Frustration signal: "${snippet}..."`);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
const total = userMessages.length;
|
|
697
|
+
const rate = total > 0 ? Math.round((frustrationCount / total) * 100) : 0;
|
|
698
|
+
evidence.unshift(`${frustrationCount}/${total} user messages contain frustration signals (${rate}%)`);
|
|
699
|
+
|
|
700
|
+
let status;
|
|
701
|
+
if (rate < 10) {
|
|
702
|
+
status = 'pass';
|
|
703
|
+
} else if (rate <= 25) {
|
|
704
|
+
status = 'warn';
|
|
705
|
+
} else {
|
|
706
|
+
status = 'fail';
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
return result('SQ-07', status, `Frustration rate: ${rate}% (${frustrationCount}/${total} messages)`, evidence);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// ---------------------------------------------------------------------------
|
|
713
|
+
// SQ-08: Satisfaction Signals
|
|
714
|
+
// ---------------------------------------------------------------------------
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Scan session JSONL for positive signals vs negative signals.
|
|
718
|
+
* Pass if positive/negative ratio >2:1, warn if 1:1-2:1, fail if <1:1.
|
|
719
|
+
*
|
|
720
|
+
* @param {string} planningDir - Path to .planning directory
|
|
721
|
+
* @param {object} _config - Audit config (unused for this check)
|
|
722
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
723
|
+
*/
|
|
724
|
+
function checkSatisfactionSignals(planningDir, _config) {
|
|
725
|
+
const logsDir = getLogsDir(planningDir);
|
|
726
|
+
const eventLogs = readEventLogs(logsDir);
|
|
727
|
+
const hookLogs = readHookLogs(logsDir);
|
|
728
|
+
const allEntries = [...eventLogs, ...hookLogs];
|
|
729
|
+
|
|
730
|
+
const userMessages = allEntries.filter(e =>
|
|
731
|
+
e.role === 'user' ||
|
|
732
|
+
e.cat === 'user' ||
|
|
733
|
+
e.event === 'user-message' ||
|
|
734
|
+
e.event === 'UserPromptSubmit' ||
|
|
735
|
+
(e.details && e.details.role === 'user')
|
|
736
|
+
);
|
|
737
|
+
|
|
738
|
+
if (userMessages.length === 0) {
|
|
739
|
+
return result('SQ-08', 'info', 'No user messages found in logs', [
|
|
740
|
+
'No user message events detected in session logs',
|
|
741
|
+
]);
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
const positivePatterns = [
|
|
745
|
+
/\bperfect\b/i,
|
|
746
|
+
/\bgreat\b/i,
|
|
747
|
+
/\bexactly\b/i,
|
|
748
|
+
/\byes\b/i,
|
|
749
|
+
/\bthanks?\b/i,
|
|
750
|
+
/\bthank you\b/i,
|
|
751
|
+
/\bawesome\b/i,
|
|
752
|
+
/\blooks good\b/i,
|
|
753
|
+
/\bnice\b/i,
|
|
754
|
+
/\bcorrect\b/i,
|
|
755
|
+
/\bgood job\b/i,
|
|
756
|
+
/\bwell done\b/i,
|
|
757
|
+
];
|
|
758
|
+
|
|
759
|
+
const negativePatterns = [
|
|
760
|
+
/\bno\b(?:\s*[,\.!]|\s+that)/i,
|
|
761
|
+
/\bwrong\b/i,
|
|
762
|
+
/\bstop\b/i,
|
|
763
|
+
/\bundo\b/i,
|
|
764
|
+
/\bbroke\b/i,
|
|
765
|
+
/\bfailed\b/i,
|
|
766
|
+
/\bnot right\b/i,
|
|
767
|
+
/\bnot what\b/i,
|
|
768
|
+
/\btry again\b/i,
|
|
769
|
+
];
|
|
770
|
+
|
|
771
|
+
let positiveCount = 0;
|
|
772
|
+
let negativeCount = 0;
|
|
773
|
+
|
|
774
|
+
for (const entry of userMessages) {
|
|
775
|
+
const content = entry.content || entry.message || entry.text ||
|
|
776
|
+
(entry.details && (entry.details.content || entry.details.message)) || '';
|
|
777
|
+
const contentStr = typeof content === 'string' ? content : JSON.stringify(content);
|
|
778
|
+
if (contentStr.length < 2) continue;
|
|
779
|
+
|
|
780
|
+
if (positivePatterns.some(p => p.test(contentStr))) positiveCount++;
|
|
781
|
+
if (negativePatterns.some(p => p.test(contentStr))) negativeCount++;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
const evidence = [
|
|
785
|
+
`Positive signals: ${positiveCount}, Negative signals: ${negativeCount}`,
|
|
786
|
+
];
|
|
787
|
+
|
|
788
|
+
let status;
|
|
789
|
+
let ratioStr;
|
|
790
|
+
if (negativeCount === 0) {
|
|
791
|
+
status = 'pass';
|
|
792
|
+
ratioStr = positiveCount > 0 ? `${positiveCount}:0 (all positive)` : 'no signals detected';
|
|
793
|
+
} else {
|
|
794
|
+
const ratio = positiveCount / negativeCount;
|
|
795
|
+
ratioStr = `${positiveCount}:${negativeCount} (${ratio.toFixed(1)}:1)`;
|
|
796
|
+
if (ratio > 2) {
|
|
797
|
+
status = 'pass';
|
|
798
|
+
} else if (ratio >= 1) {
|
|
799
|
+
status = 'warn';
|
|
800
|
+
} else {
|
|
801
|
+
status = 'fail';
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
return result('SQ-08', status, `Satisfaction ratio: ${ratioStr}`, evidence);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// ---------------------------------------------------------------------------
|
|
809
|
+
// SQ-09: Skill Escalation Patterns
|
|
810
|
+
// ---------------------------------------------------------------------------
|
|
811
|
+
|
|
812
|
+
/**
|
|
813
|
+
* Detect skill transitions that indicate task was harder than expected.
|
|
814
|
+
* E.g., quick -> debug, quick -> plan. Informational only (not pass/fail).
|
|
815
|
+
*
|
|
816
|
+
* @param {string} planningDir - Path to .planning directory
|
|
817
|
+
* @param {object} _config - Audit config (unused for this check)
|
|
818
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
819
|
+
*/
|
|
820
|
+
function checkSkillEscalationPatterns(planningDir, _config) {
|
|
821
|
+
const logsDir = getLogsDir(planningDir);
|
|
822
|
+
const eventLogs = readEventLogs(logsDir);
|
|
823
|
+
const hookLogs = readHookLogs(logsDir);
|
|
824
|
+
const allEntries = [...eventLogs, ...hookLogs].sort((a, b) => {
|
|
825
|
+
const ta = a.ts || a.timestamp || '';
|
|
826
|
+
const tb = b.ts || b.timestamp || '';
|
|
827
|
+
return ta < tb ? -1 : ta > tb ? 1 : 0;
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
// Escalation transitions: lightweight skill followed by heavier skill
|
|
831
|
+
const ESCALATION_PAIRS = {
|
|
832
|
+
'quick': ['debug', 'plan', 'build'],
|
|
833
|
+
'do': ['debug', 'plan', 'build'],
|
|
834
|
+
'scan': ['debug', 'plan'],
|
|
835
|
+
'test': ['debug'],
|
|
836
|
+
};
|
|
837
|
+
|
|
838
|
+
// Extract skill invocations in order
|
|
839
|
+
const skillInvocations = [];
|
|
840
|
+
for (const entry of allEntries) {
|
|
841
|
+
const skill = entry.skill ||
|
|
842
|
+
(entry.event && entry.event.startsWith('pbr:') ? entry.event.replace('pbr:', '').split('-')[0] : null) ||
|
|
843
|
+
(entry.cat === 'skill' ? entry.event : null) ||
|
|
844
|
+
(entry.details && entry.details.skill) || null;
|
|
845
|
+
|
|
846
|
+
if (skill) {
|
|
847
|
+
skillInvocations.push({
|
|
848
|
+
skill,
|
|
849
|
+
ts: entry.ts || entry.timestamp || '',
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
if (skillInvocations.length < 2) {
|
|
855
|
+
return result('SQ-09', 'info', 'Fewer than 2 skill invocations — no transitions to analyze', [
|
|
856
|
+
`Found ${skillInvocations.length} skill invocation(s)`,
|
|
857
|
+
]);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
const escalations = [];
|
|
861
|
+
for (let i = 0; i < skillInvocations.length - 1; i++) {
|
|
862
|
+
const from = skillInvocations[i].skill;
|
|
863
|
+
const to = skillInvocations[i + 1].skill;
|
|
864
|
+
if (ESCALATION_PAIRS[from] && ESCALATION_PAIRS[from].includes(to)) {
|
|
865
|
+
escalations.push(`${from} -> ${to}`);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
const evidence = [
|
|
870
|
+
`${skillInvocations.length} skill invocations, ${escalations.length} escalation(s) detected`,
|
|
871
|
+
];
|
|
872
|
+
|
|
873
|
+
if (escalations.length > 0) {
|
|
874
|
+
const unique = [...new Set(escalations)];
|
|
875
|
+
for (const esc of unique.slice(0, 5)) {
|
|
876
|
+
evidence.push(`Escalation: ${esc}`);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
return result('SQ-09', 'info',
|
|
881
|
+
`${escalations.length} skill escalation(s) detected across ${skillInvocations.length} invocations`,
|
|
882
|
+
evidence
|
|
883
|
+
);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// ---------------------------------------------------------------------------
|
|
887
|
+
// SQ-10: Notification Quality
|
|
888
|
+
// ---------------------------------------------------------------------------
|
|
889
|
+
|
|
890
|
+
/**
|
|
891
|
+
* Check notification frequency from hook log entries.
|
|
892
|
+
* Pass if <10 per session, warn if 10-30, fail if >30.
|
|
893
|
+
*
|
|
894
|
+
* @param {string} planningDir - Path to .planning directory
|
|
895
|
+
* @param {object} _config - Audit config (unused for this check)
|
|
896
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
897
|
+
*/
|
|
898
|
+
function checkNotificationQuality(planningDir, _config) {
|
|
899
|
+
const logsDir = getLogsDir(planningDir);
|
|
900
|
+
const hookLogs = readHookLogs(logsDir);
|
|
901
|
+
const eventLogs = readEventLogs(logsDir);
|
|
902
|
+
|
|
903
|
+
// Find notification entries from hook logs and event logs
|
|
904
|
+
const notifications = [];
|
|
905
|
+
|
|
906
|
+
for (const entry of hookLogs) {
|
|
907
|
+
if (entry.event === 'Notification' ||
|
|
908
|
+
entry.hook === 'log-notification' ||
|
|
909
|
+
(entry.details && entry.details.type === 'notification')) {
|
|
910
|
+
notifications.push({
|
|
911
|
+
hook: entry.hook || 'unknown',
|
|
912
|
+
ts: entry.ts || entry.timestamp || '',
|
|
913
|
+
message: (entry.details && entry.details.message) || '',
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
for (const entry of eventLogs) {
|
|
919
|
+
if (entry.event === 'notification' ||
|
|
920
|
+
entry.cat === 'notification' ||
|
|
921
|
+
(entry.details && entry.details.type === 'notification')) {
|
|
922
|
+
notifications.push({
|
|
923
|
+
source: 'event',
|
|
924
|
+
ts: entry.ts || entry.timestamp || '',
|
|
925
|
+
message: entry.message || (entry.details && entry.details.message) || '',
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
const count = notifications.length;
|
|
931
|
+
const evidence = [`${count} notification(s) found in session logs`];
|
|
932
|
+
|
|
933
|
+
// Show a sample of notification sources if many
|
|
934
|
+
if (count > 0) {
|
|
935
|
+
const hookCounts = {};
|
|
936
|
+
for (const n of notifications) {
|
|
937
|
+
const src = n.hook || n.source || 'unknown';
|
|
938
|
+
hookCounts[src] = (hookCounts[src] || 0) + 1;
|
|
939
|
+
}
|
|
940
|
+
const breakdown = Object.entries(hookCounts)
|
|
941
|
+
.sort((a, b) => b[1] - a[1])
|
|
942
|
+
.slice(0, 5)
|
|
943
|
+
.map(([src, cnt]) => `${src}: ${cnt}`)
|
|
944
|
+
.join(', ');
|
|
945
|
+
evidence.push(`Sources: ${breakdown}`);
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
let status;
|
|
949
|
+
if (count < 10) {
|
|
950
|
+
status = 'pass';
|
|
951
|
+
} else if (count <= 30) {
|
|
952
|
+
status = 'warn';
|
|
953
|
+
} else {
|
|
954
|
+
status = 'fail';
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
return result('SQ-10', status, `${count} notification(s) in session (threshold: <10 pass, 10-30 warn, >30 fail)`, evidence);
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
// ---------------------------------------------------------------------------
|
|
961
|
+
// Exports
|
|
962
|
+
// ---------------------------------------------------------------------------
|
|
963
|
+
|
|
964
|
+
module.exports = {
|
|
965
|
+
checkSessionStartQuality,
|
|
966
|
+
checkBriefingFreshness,
|
|
967
|
+
checkSessionDurationCost,
|
|
968
|
+
checkSkillRoutingAccuracy,
|
|
969
|
+
checkMemoryUpdateTracking,
|
|
970
|
+
checkConventionDetectionMonitoring,
|
|
971
|
+
checkUserFrustrationSignals,
|
|
972
|
+
checkSatisfactionSignals,
|
|
973
|
+
checkSkillEscalationPatterns,
|
|
974
|
+
checkNotificationQuality,
|
|
975
|
+
// Shared helpers exported for reuse by other SQ checks and tests
|
|
976
|
+
readJsonlFiles,
|
|
977
|
+
readHookLogs,
|
|
978
|
+
readEventLogs,
|
|
979
|
+
getLogsDir,
|
|
980
|
+
};
|