@winspan/claude-forge 8.54.4 → 9.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DEVELOPMENT.md +723 -46
- package/README.md +166 -21
- package/dist/catalogs/agents.json +67 -0
- package/dist/catalogs/skills.json +306 -0
- package/dist/claudemd/claudemd-generator.d.ts +45 -45
- package/dist/claudemd/claudemd-generator.d.ts.map +1 -1
- package/dist/claudemd/claudemd-generator.js +128 -449
- package/dist/claudemd/claudemd-generator.js.map +1 -1
- package/dist/claudemd/index.d.ts +14 -4
- package/dist/claudemd/index.d.ts.map +1 -1
- package/dist/claudemd/index.js +15 -4
- package/dist/claudemd/index.js.map +1 -1
- package/dist/claudemd/resume-manager.d.ts.map +1 -1
- package/dist/claudemd/resume-manager.js +37 -9
- package/dist/claudemd/resume-manager.js.map +1 -1
- package/dist/claudemd/templates/swarm-protocol.md +35 -186
- package/dist/claudemd/violations-manager.d.ts +40 -0
- package/dist/claudemd/violations-manager.d.ts.map +1 -0
- package/dist/claudemd/violations-manager.js +106 -0
- package/dist/claudemd/violations-manager.js.map +1 -0
- package/dist/cli/commands/admin.d.ts +15 -0
- package/dist/cli/commands/admin.d.ts.map +1 -0
- package/dist/cli/commands/admin.js +177 -0
- package/dist/cli/commands/admin.js.map +1 -0
- package/dist/cli/commands/agent.d.ts +169 -0
- package/dist/cli/commands/agent.d.ts.map +1 -0
- package/dist/cli/commands/agent.js +690 -0
- package/dist/cli/commands/agent.js.map +1 -0
- package/dist/cli/commands/agents.d.ts +18 -0
- package/dist/cli/commands/agents.d.ts.map +1 -0
- package/dist/cli/commands/agents.js +160 -0
- package/dist/cli/commands/agents.js.map +1 -0
- package/dist/cli/commands/bypass.d.ts +18 -0
- package/dist/cli/commands/bypass.d.ts.map +1 -0
- package/dist/cli/commands/bypass.js +87 -0
- package/dist/cli/commands/bypass.js.map +1 -0
- package/dist/cli/commands/claudemd.d.ts +60 -0
- package/dist/cli/commands/claudemd.d.ts.map +1 -1
- package/dist/cli/commands/claudemd.js +174 -37
- package/dist/cli/commands/claudemd.js.map +1 -1
- package/dist/cli/commands/codegraph.d.ts +17 -0
- package/dist/cli/commands/codegraph.d.ts.map +1 -0
- package/dist/cli/commands/codegraph.js +263 -0
- package/dist/cli/commands/codegraph.js.map +1 -0
- package/dist/cli/commands/config.d.ts.map +1 -1
- package/dist/cli/commands/config.js +94 -1
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/daemon.d.ts +39 -0
- package/dist/cli/commands/daemon.d.ts.map +1 -1
- package/dist/cli/commands/daemon.js +167 -20
- package/dist/cli/commands/daemon.js.map +1 -1
- package/dist/cli/commands/decisions.d.ts +129 -0
- package/dist/cli/commands/decisions.d.ts.map +1 -0
- package/dist/cli/commands/decisions.js +706 -0
- package/dist/cli/commands/decisions.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +29 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +124 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/entropy.d.ts +35 -0
- package/dist/cli/commands/entropy.d.ts.map +1 -0
- package/dist/cli/commands/entropy.js +121 -0
- package/dist/cli/commands/entropy.js.map +1 -0
- package/dist/cli/commands/executions.d.ts +1 -0
- package/dist/cli/commands/executions.d.ts.map +1 -1
- package/dist/cli/commands/executions.js +12 -2
- package/dist/cli/commands/executions.js.map +1 -1
- package/dist/cli/commands/fix.d.ts +31 -0
- package/dist/cli/commands/fix.d.ts.map +1 -0
- package/dist/cli/commands/fix.js +108 -0
- package/dist/cli/commands/fix.js.map +1 -0
- package/dist/cli/commands/governance.d.ts +21 -0
- package/dist/cli/commands/governance.d.ts.map +1 -0
- package/dist/cli/commands/governance.js +60 -0
- package/dist/cli/commands/governance.js.map +1 -0
- package/dist/cli/commands/init.d.ts +27 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +158 -146
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/insights-goal-check.d.ts +54 -0
- package/dist/cli/commands/insights-goal-check.d.ts.map +1 -0
- package/dist/cli/commands/insights-goal-check.js +318 -0
- package/dist/cli/commands/insights-goal-check.js.map +1 -0
- package/dist/cli/commands/insights.d.ts +15 -0
- package/dist/cli/commands/insights.d.ts.map +1 -0
- package/dist/cli/commands/insights.js +127 -0
- package/dist/cli/commands/insights.js.map +1 -0
- package/dist/cli/commands/knowledge.d.ts +117 -0
- package/dist/cli/commands/knowledge.d.ts.map +1 -0
- package/dist/cli/commands/knowledge.js +1070 -0
- package/dist/cli/commands/knowledge.js.map +1 -0
- package/dist/cli/commands/loop.d.ts +95 -0
- package/dist/cli/commands/loop.d.ts.map +1 -0
- package/dist/cli/commands/loop.js +408 -0
- package/dist/cli/commands/loop.js.map +1 -0
- package/dist/cli/commands/maintenance.d.ts +33 -0
- package/dist/cli/commands/maintenance.d.ts.map +1 -0
- package/dist/cli/commands/maintenance.js +75 -0
- package/dist/cli/commands/maintenance.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +22 -11
- package/dist/cli/commands/mcp.d.ts.map +1 -1
- package/dist/cli/commands/mcp.js +93 -5
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/menu.d.ts.map +1 -1
- package/dist/cli/commands/menu.js +10 -184
- package/dist/cli/commands/menu.js.map +1 -1
- package/dist/cli/commands/project.d.ts +98 -0
- package/dist/cli/commands/project.d.ts.map +1 -0
- package/dist/cli/commands/project.js +382 -0
- package/dist/cli/commands/project.js.map +1 -0
- package/dist/cli/commands/skills.d.ts +131 -0
- package/dist/cli/commands/skills.d.ts.map +1 -1
- package/dist/cli/commands/skills.js +404 -118
- package/dist/cli/commands/skills.js.map +1 -1
- package/dist/cli/commands/spec.d.ts +40 -0
- package/dist/cli/commands/spec.d.ts.map +1 -0
- package/dist/cli/commands/spec.js +49 -0
- package/dist/cli/commands/spec.js.map +1 -0
- package/dist/cli/commands/stats.d.ts.map +1 -1
- package/dist/cli/commands/stats.js +11 -3
- package/dist/cli/commands/stats.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +17 -2
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/trace.d.ts.map +1 -1
- package/dist/cli/commands/trace.js +4 -9
- package/dist/cli/commands/trace.js.map +1 -1
- package/dist/cli/commands/violations.d.ts +14 -0
- package/dist/cli/commands/violations.d.ts.map +1 -0
- package/dist/cli/commands/violations.js +43 -0
- package/dist/cli/commands/violations.js.map +1 -0
- package/dist/cli/index.js +34 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init/hook-manager.d.ts +1 -1
- package/dist/cli/init/hook-manager.d.ts.map +1 -1
- package/dist/cli/init/hook-manager.js +6 -0
- package/dist/cli/init/hook-manager.js.map +1 -1
- package/dist/cli/utils/resolve-session.d.ts +32 -0
- package/dist/cli/utils/resolve-session.d.ts.map +1 -0
- package/dist/cli/utils/resolve-session.js +39 -0
- package/dist/cli/utils/resolve-session.js.map +1 -0
- package/dist/core/config.d.ts +4 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +11 -23
- package/dist/core/config.js.map +1 -1
- package/dist/core/constants.d.ts +51 -13
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/core/constants.js +63 -13
- package/dist/core/constants.js.map +1 -1
- package/dist/core/diagnostics/checks.d.ts +151 -0
- package/dist/core/diagnostics/checks.d.ts.map +1 -0
- package/dist/core/diagnostics/checks.js +766 -0
- package/dist/core/diagnostics/checks.js.map +1 -0
- package/dist/core/diagnostics/daemon-status.d.ts +77 -0
- package/dist/core/diagnostics/daemon-status.d.ts.map +1 -0
- package/dist/core/diagnostics/daemon-status.js +113 -0
- package/dist/core/diagnostics/daemon-status.js.map +1 -0
- package/dist/core/diagnostics/entropy-checks.d.ts +83 -0
- package/dist/core/diagnostics/entropy-checks.d.ts.map +1 -0
- package/dist/core/diagnostics/entropy-checks.js +400 -0
- package/dist/core/diagnostics/entropy-checks.js.map +1 -0
- package/dist/core/diagnostics/fix-runner.d.ts +54 -0
- package/dist/core/diagnostics/fix-runner.d.ts.map +1 -0
- package/dist/core/diagnostics/fix-runner.js +90 -0
- package/dist/core/diagnostics/fix-runner.js.map +1 -0
- package/dist/core/diagnostics/heartbeat-reader.d.ts +28 -0
- package/dist/core/diagnostics/heartbeat-reader.d.ts.map +1 -0
- package/dist/core/diagnostics/heartbeat-reader.js +50 -0
- package/dist/core/diagnostics/heartbeat-reader.js.map +1 -0
- package/dist/core/diagnostics/knip-runner.d.ts +49 -0
- package/dist/core/diagnostics/knip-runner.d.ts.map +1 -0
- package/dist/core/diagnostics/knip-runner.js +100 -0
- package/dist/core/diagnostics/knip-runner.js.map +1 -0
- package/dist/core/diagnostics/markers.d.ts +96 -0
- package/dist/core/diagnostics/markers.d.ts.map +1 -0
- package/dist/core/diagnostics/markers.js +153 -0
- package/dist/core/diagnostics/markers.js.map +1 -0
- package/dist/core/event-fields.d.ts +27 -0
- package/dist/core/event-fields.d.ts.map +1 -1
- package/dist/core/event-fields.js +43 -0
- package/dist/core/event-fields.js.map +1 -1
- package/dist/core/governance/global-inject.d.ts +90 -0
- package/dist/core/governance/global-inject.d.ts.map +1 -0
- package/dist/core/governance/global-inject.js +184 -0
- package/dist/core/governance/global-inject.js.map +1 -0
- package/dist/core/insights/agent-anchor-guard.d.ts +77 -0
- package/dist/core/insights/agent-anchor-guard.d.ts.map +1 -0
- package/dist/core/insights/agent-anchor-guard.js +119 -0
- package/dist/core/insights/agent-anchor-guard.js.map +1 -0
- package/dist/core/insights/agent-distill-context.d.ts +55 -0
- package/dist/core/insights/agent-distill-context.d.ts.map +1 -0
- package/dist/core/insights/agent-distill-context.js +146 -0
- package/dist/core/insights/agent-distill-context.js.map +1 -0
- package/dist/core/insights/agent-distill-spawn.d.ts +56 -0
- package/dist/core/insights/agent-distill-spawn.d.ts.map +1 -0
- package/dist/core/insights/agent-distill-spawn.js +179 -0
- package/dist/core/insights/agent-distill-spawn.js.map +1 -0
- package/dist/core/insights/agent-drift.d.ts +66 -0
- package/dist/core/insights/agent-drift.d.ts.map +1 -0
- package/dist/core/insights/agent-drift.js +109 -0
- package/dist/core/insights/agent-drift.js.map +1 -0
- package/dist/core/insights/agent-evolution-sources.d.ts +21 -0
- package/dist/core/insights/agent-evolution-sources.d.ts.map +1 -0
- package/dist/core/insights/agent-evolution-sources.js +36 -0
- package/dist/core/insights/agent-evolution-sources.js.map +1 -0
- package/dist/core/insights/agent-health.d.ts +142 -0
- package/dist/core/insights/agent-health.d.ts.map +1 -0
- package/dist/core/insights/agent-health.js +296 -0
- package/dist/core/insights/agent-health.js.map +1 -0
- package/dist/core/insights/agent-patch-apply.d.ts +45 -0
- package/dist/core/insights/agent-patch-apply.d.ts.map +1 -0
- package/dist/core/insights/agent-patch-apply.js +165 -0
- package/dist/core/insights/agent-patch-apply.js.map +1 -0
- package/dist/core/insights/agent-suggest.d.ts +128 -0
- package/dist/core/insights/agent-suggest.d.ts.map +1 -0
- package/dist/core/insights/agent-suggest.js +284 -0
- package/dist/core/insights/agent-suggest.js.map +1 -0
- package/dist/core/insights/coverage-tiers.d.ts +46 -0
- package/dist/core/insights/coverage-tiers.d.ts.map +1 -0
- package/dist/core/insights/coverage-tiers.js +95 -0
- package/dist/core/insights/coverage-tiers.js.map +1 -0
- package/dist/core/insights/experience-extractor.d.ts +60 -0
- package/dist/core/insights/experience-extractor.d.ts.map +1 -0
- package/dist/core/insights/experience-extractor.js +319 -0
- package/dist/core/insights/experience-extractor.js.map +1 -0
- package/dist/core/insights/violation-reporter.d.ts +149 -0
- package/dist/core/insights/violation-reporter.d.ts.map +1 -0
- package/dist/core/insights/violation-reporter.js +391 -0
- package/dist/core/insights/violation-reporter.js.map +1 -0
- package/dist/core/loop/loop-engine.d.ts +140 -0
- package/dist/core/loop/loop-engine.d.ts.map +1 -0
- package/dist/core/loop/loop-engine.js +266 -0
- package/dist/core/loop/loop-engine.js.map +1 -0
- package/dist/core/queue/index.d.ts +16 -3
- package/dist/core/queue/index.d.ts.map +1 -1
- package/dist/core/queue/index.js +16 -4
- package/dist/core/queue/index.js.map +1 -1
- package/dist/core/storage/base.d.ts +317 -0
- package/dist/core/storage/base.d.ts.map +1 -1
- package/dist/core/storage/base.js +1093 -0
- package/dist/core/storage/base.js.map +1 -1
- package/dist/core/storage/codec/tool-input-codec.d.ts +93 -0
- package/dist/core/storage/codec/tool-input-codec.d.ts.map +1 -0
- package/dist/core/storage/codec/tool-input-codec.js +159 -0
- package/dist/core/storage/codec/tool-input-codec.js.map +1 -0
- package/dist/core/storage/codegraph-types.d.ts +79 -0
- package/dist/core/storage/codegraph-types.d.ts.map +1 -0
- package/dist/core/storage/codegraph-types.js +14 -0
- package/dist/core/storage/codegraph-types.js.map +1 -0
- package/dist/core/storage/codegraph.d.ts +186 -0
- package/dist/core/storage/codegraph.d.ts.map +1 -0
- package/dist/core/storage/codegraph.js +452 -0
- package/dist/core/storage/codegraph.js.map +1 -0
- package/dist/core/storage/decisions.d.ts +387 -0
- package/dist/core/storage/decisions.d.ts.map +1 -0
- package/dist/core/storage/decisions.js +534 -0
- package/dist/core/storage/decisions.js.map +1 -0
- package/dist/core/storage/events.d.ts +239 -8
- package/dist/core/storage/events.d.ts.map +1 -1
- package/dist/core/storage/events.js +705 -39
- package/dist/core/storage/events.js.map +1 -1
- package/dist/core/storage/feedback.d.ts +111 -0
- package/dist/core/storage/feedback.d.ts.map +1 -0
- package/dist/core/storage/feedback.js +186 -0
- package/dist/core/storage/feedback.js.map +1 -0
- package/dist/core/storage/forge-config.d.ts +40 -0
- package/dist/core/storage/forge-config.d.ts.map +1 -0
- package/dist/core/storage/forge-config.js +65 -0
- package/dist/core/storage/forge-config.js.map +1 -0
- package/dist/core/storage/injections.d.ts +68 -0
- package/dist/core/storage/injections.d.ts.map +1 -1
- package/dist/core/storage/injections.js +131 -5
- package/dist/core/storage/injections.js.map +1 -1
- package/dist/core/storage/knowledge.d.ts +332 -0
- package/dist/core/storage/knowledge.d.ts.map +1 -0
- package/dist/core/storage/knowledge.js +589 -0
- package/dist/core/storage/knowledge.js.map +1 -0
- package/dist/core/storage/maintenance.d.ts +36 -9
- package/dist/core/storage/maintenance.d.ts.map +1 -1
- package/dist/core/storage/maintenance.js +56 -24
- package/dist/core/storage/maintenance.js.map +1 -1
- package/dist/core/storage/pipeline-rollup.d.ts +111 -0
- package/dist/core/storage/pipeline-rollup.d.ts.map +1 -0
- package/dist/core/storage/pipeline-rollup.js +432 -0
- package/dist/core/storage/pipeline-rollup.js.map +1 -0
- package/dist/core/storage/routing.d.ts +50 -3
- package/dist/core/storage/routing.d.ts.map +1 -1
- package/dist/core/storage/routing.js +131 -10
- package/dist/core/storage/routing.js.map +1 -1
- package/dist/core/storage/rows.d.ts +31 -8
- package/dist/core/storage/rows.d.ts.map +1 -1
- package/dist/core/storage/schema.sql +367 -23
- package/dist/core/storage/sessions.d.ts +136 -0
- package/dist/core/storage/sessions.d.ts.map +1 -1
- package/dist/core/storage/sessions.js +352 -15
- package/dist/core/storage/sessions.js.map +1 -1
- package/dist/core/storage/skills.d.ts +160 -0
- package/dist/core/storage/skills.d.ts.map +1 -1
- package/dist/core/storage/skills.js +368 -7
- package/dist/core/storage/skills.js.map +1 -1
- package/dist/core/storage/sqlite.d.ts +309 -20
- package/dist/core/storage/sqlite.d.ts.map +1 -1
- package/dist/core/storage/sqlite.js +523 -16
- package/dist/core/storage/sqlite.js.map +1 -1
- package/dist/core/storage/tasks.d.ts +744 -2
- package/dist/core/storage/tasks.d.ts.map +1 -1
- package/dist/core/storage/tasks.js +1691 -17
- package/dist/core/storage/tasks.js.map +1 -1
- package/dist/core/storage/tool-intercepts.d.ts +69 -0
- package/dist/core/storage/tool-intercepts.d.ts.map +1 -0
- package/dist/core/storage/tool-intercepts.js +116 -0
- package/dist/core/storage/tool-intercepts.js.map +1 -0
- package/dist/core/types.d.ts +136 -18
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +10 -0
- package/dist/core/types.js.map +1 -1
- package/dist/core/utils/backup.d.ts +81 -0
- package/dist/core/utils/backup.d.ts.map +1 -0
- package/dist/core/utils/backup.js +98 -0
- package/dist/core/utils/backup.js.map +1 -0
- package/dist/core/utils/binary-paths.d.ts +124 -0
- package/dist/core/utils/binary-paths.d.ts.map +1 -0
- package/dist/core/utils/binary-paths.js +218 -0
- package/dist/core/utils/binary-paths.js.map +1 -0
- package/dist/core/utils/bypass-token.d.ts +75 -0
- package/dist/core/utils/bypass-token.d.ts.map +1 -0
- package/dist/core/utils/bypass-token.js +133 -0
- package/dist/core/utils/bypass-token.js.map +1 -0
- package/dist/core/utils/cc-builtin-agents.d.ts +3 -0
- package/dist/core/utils/cc-builtin-agents.d.ts.map +1 -0
- package/dist/core/utils/cc-builtin-agents.js +29 -0
- package/dist/core/utils/cc-builtin-agents.js.map +1 -0
- package/dist/core/utils/claude-cli-resolver.d.ts +26 -0
- package/dist/core/utils/claude-cli-resolver.d.ts.map +1 -0
- package/dist/core/utils/claude-cli-resolver.js +115 -0
- package/dist/core/utils/claude-cli-resolver.js.map +1 -0
- package/dist/core/utils/claude-cli-spawn.d.ts +106 -0
- package/dist/core/utils/claude-cli-spawn.d.ts.map +1 -0
- package/dist/core/utils/claude-cli-spawn.js +219 -0
- package/dist/core/utils/claude-cli-spawn.js.map +1 -0
- package/dist/core/utils/forge-resume-block.d.ts.map +1 -1
- package/dist/core/utils/forge-resume-block.js +3 -2
- package/dist/core/utils/forge-resume-block.js.map +1 -1
- package/dist/core/utils/logger.d.ts +15 -3
- package/dist/core/utils/logger.d.ts.map +1 -1
- package/dist/core/utils/logger.js +20 -2
- package/dist/core/utils/logger.js.map +1 -1
- package/dist/core/utils/noise-prompt.d.ts +97 -0
- package/dist/core/utils/noise-prompt.d.ts.map +1 -0
- package/dist/core/utils/noise-prompt.js +127 -0
- package/dist/core/utils/noise-prompt.js.map +1 -0
- package/dist/core/utils/path.d.ts +0 -4
- package/dist/core/utils/path.d.ts.map +1 -1
- package/dist/core/utils/path.js +0 -7
- package/dist/core/utils/path.js.map +1 -1
- package/dist/core/utils/time.d.ts +67 -0
- package/dist/core/utils/time.d.ts.map +1 -1
- package/dist/core/utils/time.js +147 -0
- package/dist/core/utils/time.js.map +1 -1
- package/dist/daemon/agent-sync.d.ts +24 -0
- package/dist/daemon/agent-sync.d.ts.map +1 -0
- package/dist/daemon/agent-sync.js +114 -0
- package/dist/daemon/agent-sync.js.map +1 -0
- package/dist/daemon/config-store.d.ts +55 -0
- package/dist/daemon/config-store.d.ts.map +1 -0
- package/dist/daemon/config-store.js +146 -0
- package/dist/daemon/config-store.js.map +1 -0
- package/dist/daemon/event-parser.d.ts +22 -0
- package/dist/daemon/event-parser.d.ts.map +1 -1
- package/dist/daemon/event-parser.js +54 -3
- package/dist/daemon/event-parser.js.map +1 -1
- package/dist/daemon/handlers/history-exporter.d.ts.map +1 -1
- package/dist/daemon/handlers/history-exporter.js +9 -8
- package/dist/daemon/handlers/history-exporter.js.map +1 -1
- package/dist/daemon/handlers/post-tool-use.d.ts +66 -4
- package/dist/daemon/handlers/post-tool-use.d.ts.map +1 -1
- package/dist/daemon/handlers/post-tool-use.js +221 -8
- package/dist/daemon/handlers/post-tool-use.js.map +1 -1
- package/dist/daemon/handlers/pre-tool-use.d.ts +181 -0
- package/dist/daemon/handlers/pre-tool-use.d.ts.map +1 -0
- package/dist/daemon/handlers/pre-tool-use.js +618 -0
- package/dist/daemon/handlers/pre-tool-use.js.map +1 -0
- package/dist/daemon/handlers/stop.d.ts +55 -7
- package/dist/daemon/handlers/stop.d.ts.map +1 -1
- package/dist/daemon/handlers/stop.js +245 -8
- package/dist/daemon/handlers/stop.js.map +1 -1
- package/dist/daemon/handlers/user-prompt.d.ts +51 -14
- package/dist/daemon/handlers/user-prompt.d.ts.map +1 -1
- package/dist/daemon/handlers/user-prompt.js +223 -95
- package/dist/daemon/handlers/user-prompt.js.map +1 -1
- package/dist/daemon/handlers/violation-content-backfill.d.ts +76 -0
- package/dist/daemon/handlers/violation-content-backfill.d.ts.map +1 -0
- package/dist/daemon/handlers/violation-content-backfill.js +167 -0
- package/dist/daemon/handlers/violation-content-backfill.js.map +1 -0
- package/dist/daemon/hook-sync.d.ts.map +1 -1
- package/dist/daemon/hook-sync.js +2 -1
- package/dist/daemon/hook-sync.js.map +1 -1
- package/dist/daemon/index.d.ts +19 -0
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +439 -86
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/lifecycle.d.ts +48 -1
- package/dist/daemon/lifecycle.d.ts.map +1 -1
- package/dist/daemon/lifecycle.js +98 -2
- package/dist/daemon/lifecycle.js.map +1 -1
- package/dist/daemon/router.d.ts +4 -1
- package/dist/daemon/router.d.ts.map +1 -1
- package/dist/daemon/router.js +4 -2
- package/dist/daemon/router.js.map +1 -1
- package/dist/daemon/rules/defaults.d.ts +20 -0
- package/dist/daemon/rules/defaults.d.ts.map +1 -0
- package/dist/daemon/rules/defaults.js +779 -0
- package/dist/daemon/rules/defaults.js.map +1 -0
- package/dist/daemon/rules/registry.d.ts +47 -0
- package/dist/daemon/rules/registry.d.ts.map +1 -0
- package/dist/daemon/rules/registry.js +84 -0
- package/dist/daemon/rules/registry.js.map +1 -0
- package/dist/daemon/rules/types.d.ts +176 -0
- package/dist/daemon/rules/types.d.ts.map +1 -0
- package/dist/daemon/rules/types.js +15 -0
- package/dist/daemon/rules/types.js.map +1 -0
- package/dist/daemon/rules/whitelist.d.ts +101 -0
- package/dist/daemon/rules/whitelist.d.ts.map +1 -0
- package/dist/daemon/rules/whitelist.js +210 -0
- package/dist/daemon/rules/whitelist.js.map +1 -0
- package/dist/daemon/rules/workflow-defaults.d.ts +52 -0
- package/dist/daemon/rules/workflow-defaults.d.ts.map +1 -0
- package/dist/daemon/rules/workflow-defaults.js +521 -0
- package/dist/daemon/rules/workflow-defaults.js.map +1 -0
- package/dist/daemon/server.d.ts +11 -1
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +7 -1
- package/dist/daemon/server.js.map +1 -1
- package/dist/daemon/services/codegraph-sync.d.ts +94 -0
- package/dist/daemon/services/codegraph-sync.d.ts.map +1 -0
- package/dist/daemon/services/codegraph-sync.js +159 -0
- package/dist/daemon/services/codegraph-sync.js.map +1 -0
- package/dist/daemon/services/context-injector.d.ts +34 -0
- package/dist/daemon/services/context-injector.d.ts.map +1 -0
- package/dist/daemon/services/context-injector.js +61 -0
- package/dist/daemon/services/context-injector.js.map +1 -0
- package/dist/daemon/services/decision-hint.d.ts +240 -0
- package/dist/daemon/services/decision-hint.d.ts.map +1 -0
- package/dist/daemon/services/decision-hint.js +562 -0
- package/dist/daemon/services/decision-hint.js.map +1 -0
- package/dist/daemon/services/event-ttl-sweep.d.ts +86 -0
- package/dist/daemon/services/event-ttl-sweep.d.ts.map +1 -0
- package/dist/daemon/services/event-ttl-sweep.js +124 -0
- package/dist/daemon/services/event-ttl-sweep.js.map +1 -0
- package/dist/daemon/services/feedback-aggregator.d.ts +167 -0
- package/dist/daemon/services/feedback-aggregator.d.ts.map +1 -0
- package/dist/daemon/services/feedback-aggregator.js +415 -0
- package/dist/daemon/services/feedback-aggregator.js.map +1 -0
- package/dist/daemon/services/heartbeat-writer.d.ts +46 -0
- package/dist/daemon/services/heartbeat-writer.d.ts.map +1 -0
- package/dist/daemon/services/heartbeat-writer.js +82 -0
- package/dist/daemon/services/heartbeat-writer.js.map +1 -0
- package/dist/daemon/services/idle-session-sweeper.d.ts +61 -0
- package/dist/daemon/services/idle-session-sweeper.d.ts.map +1 -0
- package/dist/daemon/services/idle-session-sweeper.js +94 -0
- package/dist/daemon/services/idle-session-sweeper.js.map +1 -0
- package/dist/daemon/services/idle-task-budget.d.ts +50 -0
- package/dist/daemon/services/idle-task-budget.d.ts.map +1 -0
- package/dist/daemon/services/idle-task-budget.js +72 -0
- package/dist/daemon/services/idle-task-budget.js.map +1 -0
- package/dist/daemon/services/intercept-revive.d.ts +60 -0
- package/dist/daemon/services/intercept-revive.d.ts.map +1 -0
- package/dist/daemon/services/intercept-revive.js +86 -0
- package/dist/daemon/services/intercept-revive.js.map +1 -0
- package/dist/daemon/services/intercept-rollback-guard.d.ts +105 -0
- package/dist/daemon/services/intercept-rollback-guard.d.ts.map +1 -0
- package/dist/daemon/services/intercept-rollback-guard.js +152 -0
- package/dist/daemon/services/intercept-rollback-guard.js.map +1 -0
- package/dist/daemon/services/intercept-timeout-sweeper.d.ts +58 -0
- package/dist/daemon/services/intercept-timeout-sweeper.d.ts.map +1 -0
- package/dist/daemon/services/intercept-timeout-sweeper.js +83 -0
- package/dist/daemon/services/intercept-timeout-sweeper.js.map +1 -0
- package/dist/daemon/services/kb-injector.d.ts +57 -0
- package/dist/daemon/services/kb-injector.d.ts.map +1 -0
- package/dist/daemon/services/kb-injector.js +148 -0
- package/dist/daemon/services/kb-injector.js.map +1 -0
- package/dist/daemon/services/kb-rebuild-scheduler.d.ts +95 -0
- package/dist/daemon/services/kb-rebuild-scheduler.d.ts.map +1 -0
- package/dist/daemon/services/kb-rebuild-scheduler.js +149 -0
- package/dist/daemon/services/kb-rebuild-scheduler.js.map +1 -0
- package/dist/daemon/services/loop-hint.d.ts +139 -0
- package/dist/daemon/services/loop-hint.d.ts.map +1 -0
- package/dist/daemon/services/loop-hint.js +272 -0
- package/dist/daemon/services/loop-hint.js.map +1 -0
- package/dist/daemon/services/outcome-classification-service.d.ts +49 -0
- package/dist/daemon/services/outcome-classification-service.d.ts.map +1 -0
- package/dist/daemon/services/outcome-classification-service.js +214 -0
- package/dist/daemon/services/outcome-classification-service.js.map +1 -0
- package/dist/daemon/services/outcome-classifier.d.ts +136 -0
- package/dist/daemon/services/outcome-classifier.d.ts.map +1 -0
- package/dist/daemon/services/outcome-classifier.js +178 -0
- package/dist/daemon/services/outcome-classifier.js.map +1 -0
- package/dist/daemon/services/outcome-nudge.d.ts +107 -0
- package/dist/daemon/services/outcome-nudge.d.ts.map +1 -0
- package/dist/daemon/services/outcome-nudge.js +242 -0
- package/dist/daemon/services/outcome-nudge.js.map +1 -0
- package/dist/daemon/services/spec-approval.d.ts +127 -0
- package/dist/daemon/services/spec-approval.d.ts.map +1 -0
- package/dist/daemon/services/spec-approval.js +216 -0
- package/dist/daemon/services/spec-approval.js.map +1 -0
- package/dist/daemon/services/spec-gate.d.ts +54 -0
- package/dist/daemon/services/spec-gate.d.ts.map +1 -0
- package/dist/daemon/services/spec-gate.js +113 -0
- package/dist/daemon/services/spec-gate.js.map +1 -0
- package/dist/daemon/services/task-boundary-classifier.d.ts +78 -0
- package/dist/daemon/services/task-boundary-classifier.d.ts.map +1 -0
- package/dist/daemon/services/task-boundary-classifier.js +202 -0
- package/dist/daemon/services/task-boundary-classifier.js.map +1 -0
- package/dist/daemon/services/task-segmenter.d.ts +230 -1
- package/dist/daemon/services/task-segmenter.d.ts.map +1 -1
- package/dist/daemon/services/task-segmenter.js +527 -17
- package/dist/daemon/services/task-segmenter.js.map +1 -1
- package/dist/daemon/skill-sync.d.ts +7 -2
- package/dist/daemon/skill-sync.d.ts.map +1 -1
- package/dist/daemon/skill-sync.js +114 -9
- package/dist/daemon/skill-sync.js.map +1 -1
- package/dist/daemon/startup/maintenance-schedulers.d.ts +68 -0
- package/dist/daemon/startup/maintenance-schedulers.d.ts.map +1 -0
- package/dist/daemon/startup/maintenance-schedulers.js +294 -0
- package/dist/daemon/startup/maintenance-schedulers.js.map +1 -0
- package/dist/daemon/templates/agents/agent-retro-distiller.md +106 -0
- package/dist/daemon/templates/agents/claudemd-writer.md +102 -0
- package/dist/daemon/templates/agents/coder.md +262 -0
- package/dist/daemon/templates/agents/decision-maker.md +546 -0
- package/dist/daemon/templates/agents/doc-reviewer.md +118 -0
- package/dist/daemon/templates/agents/harness-debug-full.md +196 -0
- package/dist/daemon/templates/agents/knowledge-builder.md +120 -0
- package/dist/daemon/templates/agents/patch-applier.md +145 -0
- package/dist/daemon/templates/agents/planner.md +217 -0
- package/dist/daemon/templates/agents/safety-net-implementer.md +278 -0
- package/dist/daemon/templates/agents/skill-distiller.md +114 -0
- package/dist/daemon/templates/agents/task-boundary-classifier.md +65 -0
- package/dist/daemon/templates/agents/verify-agent.md +259 -0
- package/dist/daemon/utils/inject-block.d.ts +39 -0
- package/dist/daemon/utils/inject-block.d.ts.map +1 -0
- package/dist/daemon/utils/inject-block.js +25 -0
- package/dist/daemon/utils/inject-block.js.map +1 -0
- package/dist/hooks/hook-lib.sh +8 -0
- package/dist/hooks/notification.sh +19 -8
- package/dist/hooks/post-tool-use.sh +41 -23
- package/dist/hooks/pre-tool-use.sh +54 -23
- package/dist/hooks/session-start.sh +68 -0
- package/dist/hooks/stop.sh +31 -11
- package/dist/hooks/user-prompt-submit.sh +37 -21
- package/dist/knowledge/adapters/go-adapter.d.ts +65 -0
- package/dist/knowledge/adapters/go-adapter.d.ts.map +1 -0
- package/dist/knowledge/adapters/go-adapter.js +294 -0
- package/dist/knowledge/adapters/go-adapter.js.map +1 -0
- package/dist/knowledge/adapters/index.d.ts +41 -0
- package/dist/knowledge/adapters/index.d.ts.map +1 -0
- package/dist/knowledge/adapters/index.js +71 -0
- package/dist/knowledge/adapters/index.js.map +1 -0
- package/dist/knowledge/adapters/java-adapter.d.ts +66 -0
- package/dist/knowledge/adapters/java-adapter.d.ts.map +1 -0
- package/dist/knowledge/adapters/java-adapter.js +260 -0
- package/dist/knowledge/adapters/java-adapter.js.map +1 -0
- package/dist/knowledge/adapters/js-vue-adapter.d.ts +56 -0
- package/dist/knowledge/adapters/js-vue-adapter.d.ts.map +1 -0
- package/dist/knowledge/adapters/js-vue-adapter.js +203 -0
- package/dist/knowledge/adapters/js-vue-adapter.js.map +1 -0
- package/dist/knowledge/adapters/kotlin-adapter.d.ts +55 -0
- package/dist/knowledge/adapters/kotlin-adapter.d.ts.map +1 -0
- package/dist/knowledge/adapters/kotlin-adapter.js +209 -0
- package/dist/knowledge/adapters/kotlin-adapter.js.map +1 -0
- package/dist/knowledge/adapters/monorepo-adapter.d.ts +77 -0
- package/dist/knowledge/adapters/monorepo-adapter.d.ts.map +1 -0
- package/dist/knowledge/adapters/monorepo-adapter.js +170 -0
- package/dist/knowledge/adapters/monorepo-adapter.js.map +1 -0
- package/dist/knowledge/adapters/python-adapter.d.ts +89 -0
- package/dist/knowledge/adapters/python-adapter.d.ts.map +1 -0
- package/dist/knowledge/adapters/python-adapter.js +358 -0
- package/dist/knowledge/adapters/python-adapter.js.map +1 -0
- package/dist/knowledge/adapters/rust-adapter.d.ts +73 -0
- package/dist/knowledge/adapters/rust-adapter.d.ts.map +1 -0
- package/dist/knowledge/adapters/rust-adapter.js +329 -0
- package/dist/knowledge/adapters/rust-adapter.js.map +1 -0
- package/dist/knowledge/adapters/types.d.ts +99 -0
- package/dist/knowledge/adapters/types.d.ts.map +1 -0
- package/dist/knowledge/adapters/types.js +17 -0
- package/dist/knowledge/adapters/types.js.map +1 -0
- package/dist/knowledge/adapters/typescript-adapter.d.ts +57 -0
- package/dist/knowledge/adapters/typescript-adapter.d.ts.map +1 -0
- package/dist/knowledge/adapters/typescript-adapter.js +171 -0
- package/dist/knowledge/adapters/typescript-adapter.js.map +1 -0
- package/dist/knowledge/audit-applier.d.ts +70 -0
- package/dist/knowledge/audit-applier.d.ts.map +1 -0
- package/dist/knowledge/audit-applier.js +251 -0
- package/dist/knowledge/audit-applier.js.map +1 -0
- package/dist/knowledge/builder.d.ts +261 -0
- package/dist/knowledge/builder.d.ts.map +1 -0
- package/dist/knowledge/builder.js +966 -0
- package/dist/knowledge/builder.js.map +1 -0
- package/dist/knowledge/cli-provider.d.ts +151 -0
- package/dist/knowledge/cli-provider.d.ts.map +1 -0
- package/dist/knowledge/cli-provider.js +313 -0
- package/dist/knowledge/cli-provider.js.map +1 -0
- package/dist/knowledge/constants.d.ts +78 -0
- package/dist/knowledge/constants.d.ts.map +1 -0
- package/dist/knowledge/constants.js +98 -0
- package/dist/knowledge/constants.js.map +1 -0
- package/dist/knowledge/cross-module.d.ts +139 -0
- package/dist/knowledge/cross-module.d.ts.map +1 -0
- package/dist/knowledge/cross-module.js +370 -0
- package/dist/knowledge/cross-module.js.map +1 -0
- package/dist/knowledge/git-hooks.d.ts +67 -0
- package/dist/knowledge/git-hooks.d.ts.map +1 -0
- package/dist/knowledge/git-hooks.js +258 -0
- package/dist/knowledge/git-hooks.js.map +1 -0
- package/dist/knowledge/graph/edge-extractor.d.ts +45 -0
- package/dist/knowledge/graph/edge-extractor.d.ts.map +1 -0
- package/dist/knowledge/graph/edge-extractor.js +242 -0
- package/dist/knowledge/graph/edge-extractor.js.map +1 -0
- package/dist/knowledge/graph/impact.d.ts +73 -0
- package/dist/knowledge/graph/impact.d.ts.map +1 -0
- package/dist/knowledge/graph/impact.js +94 -0
- package/dist/knowledge/graph/impact.js.map +1 -0
- package/dist/knowledge/graph/types.d.ts +22 -0
- package/dist/knowledge/graph/types.d.ts.map +1 -0
- package/dist/knowledge/graph/types.js +13 -0
- package/dist/knowledge/graph/types.js.map +1 -0
- package/dist/knowledge/module-hash.d.ts +88 -0
- package/dist/knowledge/module-hash.d.ts.map +1 -0
- package/dist/knowledge/module-hash.js +162 -0
- package/dist/knowledge/module-hash.js.map +1 -0
- package/dist/knowledge/project-detector.d.ts +101 -0
- package/dist/knowledge/project-detector.d.ts.map +1 -0
- package/dist/knowledge/project-detector.js +223 -0
- package/dist/knowledge/project-detector.js.map +1 -0
- package/dist/knowledge/prompt.d.ts +237 -0
- package/dist/knowledge/prompt.d.ts.map +1 -0
- package/dist/knowledge/prompt.js +416 -0
- package/dist/knowledge/prompt.js.map +1 -0
- package/dist/knowledge/query.d.ts +118 -0
- package/dist/knowledge/query.d.ts.map +1 -0
- package/dist/knowledge/query.js +438 -0
- package/dist/knowledge/query.js.map +1 -0
- package/dist/knowledge/repo-map.d.ts +97 -0
- package/dist/knowledge/repo-map.d.ts.map +1 -0
- package/dist/knowledge/repo-map.js +447 -0
- package/dist/knowledge/repo-map.js.map +1 -0
- package/dist/knowledge/tools/index.d.ts +14 -0
- package/dist/knowledge/tools/index.d.ts.map +1 -0
- package/dist/knowledge/tools/index.js +11 -0
- package/dist/knowledge/tools/index.js.map +1 -0
- package/dist/knowledge/tools/knowledge-get-page.d.ts +46 -0
- package/dist/knowledge/tools/knowledge-get-page.d.ts.map +1 -0
- package/dist/knowledge/tools/knowledge-get-page.js +101 -0
- package/dist/knowledge/tools/knowledge-get-page.js.map +1 -0
- package/dist/knowledge/tools/knowledge-query.d.ts +77 -0
- package/dist/knowledge/tools/knowledge-query.d.ts.map +1 -0
- package/dist/knowledge/tools/knowledge-query.js +104 -0
- package/dist/knowledge/tools/knowledge-query.js.map +1 -0
- package/dist/knowledge/tools/repo-map-lookup.d.ts +45 -0
- package/dist/knowledge/tools/repo-map-lookup.d.ts.map +1 -0
- package/dist/knowledge/tools/repo-map-lookup.js +82 -0
- package/dist/knowledge/tools/repo-map-lookup.js.map +1 -0
- package/dist/knowledge/types.d.ts +269 -0
- package/dist/knowledge/types.d.ts.map +1 -0
- package/dist/knowledge/types.js +10 -0
- package/dist/knowledge/types.js.map +1 -0
- package/dist/knowledge/validator.d.ts +90 -0
- package/dist/knowledge/validator.d.ts.map +1 -0
- package/dist/knowledge/validator.js +355 -0
- package/dist/knowledge/validator.js.map +1 -0
- package/dist/mcp/server.d.ts +64 -8
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +448 -12
- package/dist/mcp/server.js.map +1 -1
- package/dist/skills/builtin-skills.d.ts +35 -0
- package/dist/skills/builtin-skills.d.ts.map +1 -0
- package/dist/skills/builtin-skills.js +68 -0
- package/dist/skills/builtin-skills.js.map +1 -0
- package/dist/skills/distill/attribution.d.ts +59 -0
- package/dist/skills/distill/attribution.d.ts.map +1 -0
- package/dist/skills/distill/attribution.js +101 -0
- package/dist/skills/distill/attribution.js.map +1 -0
- package/dist/skills/distill/distiller.d.ts +161 -0
- package/dist/skills/distill/distiller.d.ts.map +1 -0
- package/dist/skills/distill/distiller.js +461 -0
- package/dist/skills/distill/distiller.js.map +1 -0
- package/dist/skills/distill/index.d.ts +223 -0
- package/dist/skills/distill/index.d.ts.map +1 -0
- package/dist/skills/distill/index.js +466 -0
- package/dist/skills/distill/index.js.map +1 -0
- package/dist/skills/distill/project-anchor-guard.d.ts +116 -0
- package/dist/skills/distill/project-anchor-guard.d.ts.map +1 -0
- package/dist/skills/distill/project-anchor-guard.js +334 -0
- package/dist/skills/distill/project-anchor-guard.js.map +1 -0
- package/dist/skills/distill/topic-deduper.d.ts +77 -0
- package/dist/skills/distill/topic-deduper.d.ts.map +1 -0
- package/dist/skills/distill/topic-deduper.js +119 -0
- package/dist/skills/distill/topic-deduper.js.map +1 -0
- package/dist/skills/distill/upstream-fetcher.d.ts +71 -0
- package/dist/skills/distill/upstream-fetcher.d.ts.map +1 -0
- package/dist/skills/distill/upstream-fetcher.js +202 -0
- package/dist/skills/distill/upstream-fetcher.js.map +1 -0
- package/dist/skills/distilled/distilled-api-design.md +495 -0
- package/dist/skills/distilled/distilled-architecture-decision.md +173 -0
- package/dist/skills/distilled/distilled-brainstorming.md +79 -0
- package/dist/skills/distilled/distilled-brand-guidelines.md +86 -0
- package/dist/skills/distilled/distilled-canvas-design.md +128 -0
- package/dist/skills/distilled/distilled-claude-api.md +185 -0
- package/dist/skills/distilled/distilled-creator.md +181 -0
- package/dist/skills/distilled/distilled-db-schema-design.md +245 -0
- package/dist/skills/distilled/distilled-dispatching-parallel-agents.md +136 -0
- package/dist/skills/distilled/distilled-doc-coauthoring.md +144 -0
- package/dist/skills/distilled/distilled-docx.md +231 -0
- package/dist/skills/distilled/distilled-executing-plans.md +148 -0
- package/dist/skills/distilled/distilled-finishing-a-development-branch.md +213 -0
- package/dist/skills/distilled/distilled-frontend-design.md +118 -0
- package/dist/skills/distilled/distilled-harness-engineering.md +242 -0
- package/dist/skills/distilled/distilled-karpathy-guidelines.md +104 -0
- package/dist/skills/distilled/distilled-performance-optimization.md +175 -0
- package/dist/skills/distilled/distilled-receiving-code-review.md +185 -0
- package/dist/skills/distilled/distilled-spec-driven-design.md +193 -0
- package/dist/skills/distilled/distilled-subagent-driven-development.md +124 -0
- package/dist/skills/distilled/distilled-systematic-debugging.md +154 -0
- package/dist/skills/distilled/distilled-test-driven-development.md +432 -0
- package/dist/skills/distilled/distilled-using-superpowers.md +134 -0
- package/dist/skills/distilled/distilled-verification-before-completion.md +213 -0
- package/dist/skills/distilled/distilled-writing-skills.md +175 -0
- package/dist/skills/registry.d.ts +55 -51
- package/dist/skills/registry.d.ts.map +1 -1
- package/dist/skills/registry.js +82 -196
- package/dist/skills/registry.js.map +1 -1
- package/dist/skills/tools/pipeline-suggest.js +14 -14
- package/dist/skills/tools/pipeline-suggest.js.map +1 -1
- package/dist/skills/tools/skill-invoke.d.ts +3 -2
- package/dist/skills/tools/skill-invoke.d.ts.map +1 -1
- package/dist/skills/tools/skill-invoke.js +4 -2
- package/dist/skills/tools/skill-invoke.js.map +1 -1
- package/dist/web/analytics/anti-pattern-detector.d.ts.map +1 -1
- package/dist/web/analytics/anti-pattern-detector.js +6 -1
- package/dist/web/analytics/anti-pattern-detector.js.map +1 -1
- package/dist/web/analytics/drift-detector.d.ts +6 -0
- package/dist/web/analytics/drift-detector.d.ts.map +1 -1
- package/dist/web/analytics/drift-detector.js +15 -8
- package/dist/web/analytics/drift-detector.js.map +1 -1
- package/dist/web/analytics/weekly-report.d.ts +13 -0
- package/dist/web/analytics/weekly-report.d.ts.map +1 -1
- package/dist/web/analytics/weekly-report.js +17 -3
- package/dist/web/analytics/weekly-report.js.map +1 -1
- package/dist/web/routes/_helpers.d.ts +31 -0
- package/dist/web/routes/_helpers.d.ts.map +1 -1
- package/dist/web/routes/_helpers.js +33 -0
- package/dist/web/routes/_helpers.js.map +1 -1
- package/dist/web/routes/agent-content.d.ts +30 -0
- package/dist/web/routes/agent-content.d.ts.map +1 -0
- package/dist/web/routes/agent-content.js +139 -0
- package/dist/web/routes/agent-content.js.map +1 -0
- package/dist/web/routes/agent-distill.d.ts +49 -0
- package/dist/web/routes/agent-distill.d.ts.map +1 -0
- package/dist/web/routes/agent-distill.js +526 -0
- package/dist/web/routes/agent-distill.js.map +1 -0
- package/dist/web/routes/config.d.ts +56 -0
- package/dist/web/routes/config.d.ts.map +1 -0
- package/dist/web/routes/config.js +243 -0
- package/dist/web/routes/config.js.map +1 -0
- package/dist/web/routes/decisions.d.ts +15 -0
- package/dist/web/routes/decisions.d.ts.map +1 -0
- package/dist/web/routes/decisions.js +181 -0
- package/dist/web/routes/decisions.js.map +1 -0
- package/dist/web/routes/diagnostics.d.ts +61 -0
- package/dist/web/routes/diagnostics.d.ts.map +1 -0
- package/dist/web/routes/diagnostics.js +203 -0
- package/dist/web/routes/diagnostics.js.map +1 -0
- package/dist/web/routes/error-handler.d.ts +0 -4
- package/dist/web/routes/error-handler.d.ts.map +1 -1
- package/dist/web/routes/error-handler.js +0 -8
- package/dist/web/routes/error-handler.js.map +1 -1
- package/dist/web/routes/events.d.ts.map +1 -1
- package/dist/web/routes/events.js +26 -1
- package/dist/web/routes/events.js.map +1 -1
- package/dist/web/routes/health.d.ts +33 -0
- package/dist/web/routes/health.d.ts.map +1 -0
- package/dist/web/routes/health.js +37 -0
- package/dist/web/routes/health.js.map +1 -0
- package/dist/web/routes/insights.d.ts +0 -5
- package/dist/web/routes/insights.d.ts.map +1 -1
- package/dist/web/routes/insights.js +0 -0
- package/dist/web/routes/insights.js.map +1 -1
- package/dist/web/routes/knowledge.d.ts +57 -0
- package/dist/web/routes/knowledge.d.ts.map +1 -0
- package/dist/web/routes/knowledge.js +772 -0
- package/dist/web/routes/knowledge.js.map +1 -0
- package/dist/web/routes/patch.d.ts +60 -1
- package/dist/web/routes/patch.d.ts.map +1 -1
- package/dist/web/routes/patch.js +170 -64
- package/dist/web/routes/patch.js.map +1 -1
- package/dist/web/routes/pipeline.d.ts +28 -0
- package/dist/web/routes/pipeline.d.ts.map +1 -0
- package/dist/web/routes/pipeline.js +145 -0
- package/dist/web/routes/pipeline.js.map +1 -0
- package/dist/web/routes/rules.d.ts.map +1 -1
- package/dist/web/routes/rules.js +26 -7
- package/dist/web/routes/rules.js.map +1 -1
- package/dist/web/routes/sessions.d.ts.map +1 -1
- package/dist/web/routes/sessions.js +17 -8
- package/dist/web/routes/sessions.js.map +1 -1
- package/dist/web/routes/skill-content.d.ts +30 -0
- package/dist/web/routes/skill-content.d.ts.map +1 -0
- package/dist/web/routes/skill-content.js +117 -0
- package/dist/web/routes/skill-content.js.map +1 -0
- package/dist/web/routes/skill-stats.d.ts.map +1 -1
- package/dist/web/routes/skill-stats.js +153 -16
- package/dist/web/routes/skill-stats.js.map +1 -1
- package/dist/web/routes/skills-distill.d.ts +29 -0
- package/dist/web/routes/skills-distill.d.ts.map +1 -0
- package/dist/web/routes/skills-distill.js +552 -0
- package/dist/web/routes/skills-distill.js.map +1 -0
- package/dist/web/routes/skills.js +7 -7
- package/dist/web/routes/skills.js.map +1 -1
- package/dist/web/routes/stats.d.ts.map +1 -1
- package/dist/web/routes/stats.js +2 -1
- package/dist/web/routes/stats.js.map +1 -1
- package/dist/web/routes/task-timeline.d.ts +178 -0
- package/dist/web/routes/task-timeline.d.ts.map +1 -0
- package/dist/web/routes/task-timeline.js +530 -0
- package/dist/web/routes/task-timeline.js.map +1 -0
- package/dist/web/routes/tasks.d.ts.map +1 -1
- package/dist/web/routes/tasks.js +377 -8
- package/dist/web/routes/tasks.js.map +1 -1
- package/dist/web/routes/trace.d.ts.map +1 -1
- package/dist/web/routes/trace.js +3 -2
- package/dist/web/routes/trace.js.map +1 -1
- package/dist/web/routes/types.d.ts +0 -4
- package/dist/web/routes/types.d.ts.map +1 -1
- package/dist/web/routes/types.js +1 -1
- package/dist/web/routes/types.js.map +1 -1
- package/dist/web/routes/violations.d.ts +14 -0
- package/dist/web/routes/violations.d.ts.map +1 -0
- package/dist/web/routes/violations.js +112 -0
- package/dist/web/routes/violations.js.map +1 -0
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +99 -19
- package/dist/web/server.js.map +1 -1
- package/dist/web/services/agent-distill-manager.d.ts +122 -0
- package/dist/web/services/agent-distill-manager.d.ts.map +1 -0
- package/dist/web/services/agent-distill-manager.js +397 -0
- package/dist/web/services/agent-distill-manager.js.map +1 -0
- package/dist/web/services/build-manager.d.ts +72 -0
- package/dist/web/services/build-manager.d.ts.map +1 -0
- package/dist/web/services/build-manager.js +189 -0
- package/dist/web/services/build-manager.js.map +1 -0
- package/dist/web/services/distill-manager.d.ts +172 -0
- package/dist/web/services/distill-manager.d.ts.map +1 -0
- package/dist/web/services/distill-manager.js +411 -0
- package/dist/web/services/distill-manager.js.map +1 -0
- package/dist/web/static/assets/AgentDetailPage-DlUeA1sX.js +2 -0
- package/dist/web/static/assets/AgentDetailPage-DlUeA1sX.js.map +1 -0
- package/dist/web/static/assets/AgentDistillRunPage-Cybo4bii.js +3 -0
- package/dist/web/static/assets/AgentDistillRunPage-Cybo4bii.js.map +1 -0
- package/dist/web/static/assets/AgentsPage-Qd9FExLG.js +2 -0
- package/dist/web/static/assets/AgentsPage-Qd9FExLG.js.map +1 -0
- package/dist/web/static/assets/DaemonHealthPage-DTSVqtrI.js +2 -0
- package/dist/web/static/assets/DaemonHealthPage-DTSVqtrI.js.map +1 -0
- package/dist/web/static/assets/DecisionDetailPage-b4BA8dhc.js +2 -0
- package/dist/web/static/assets/DecisionDetailPage-b4BA8dhc.js.map +1 -0
- package/dist/web/static/assets/DecisionsPage-a3NRo_T7.js +2 -0
- package/dist/web/static/assets/DecisionsPage-a3NRo_T7.js.map +1 -0
- package/dist/web/static/assets/DiagnosticsPage-DIVdiIQG.js +2 -0
- package/dist/web/static/assets/DiagnosticsPage-DIVdiIQG.js.map +1 -0
- package/dist/web/static/assets/DistillDetailPage-U6a3l2iP.js +4 -0
- package/dist/web/static/assets/DistillDetailPage-U6a3l2iP.js.map +1 -0
- package/dist/web/static/assets/DistillPage-O7BHtRN8.js +2 -0
- package/dist/web/static/assets/DistillPage-O7BHtRN8.js.map +1 -0
- package/dist/web/static/assets/DistillRunPage-D1JuRWWr.js +2 -0
- package/dist/web/static/assets/DistillRunPage-D1JuRWWr.js.map +1 -0
- package/dist/web/static/assets/GlobalScopeHint-Q3wTJx3F.js +2 -0
- package/dist/web/static/assets/GlobalScopeHint-Q3wTJx3F.js.map +1 -0
- package/dist/web/static/assets/IssueDetailPage-BDfrtk2C.js +2 -0
- package/dist/web/static/assets/IssueDetailPage-BDfrtk2C.js.map +1 -0
- package/dist/web/static/assets/IssuesPage-SKmhlCrw.js +2 -0
- package/dist/web/static/assets/IssuesPage-SKmhlCrw.js.map +1 -0
- package/dist/web/static/assets/KbDetailPage-Yna86Na8.js +2 -0
- package/dist/web/static/assets/KbDetailPage-Yna86Na8.js.map +1 -0
- package/dist/web/static/assets/KbHitsPage-Cljl7H9p.js +2 -0
- package/dist/web/static/assets/KbHitsPage-Cljl7H9p.js.map +1 -0
- package/dist/web/static/assets/MarkdownRenderer-DlDQNihj.js +3 -0
- package/dist/web/static/assets/MarkdownRenderer-DlDQNihj.js.map +1 -0
- package/dist/web/static/assets/NotFound-LMzbP51V.js +2 -0
- package/dist/web/static/assets/NotFound-LMzbP51V.js.map +1 -0
- package/dist/web/static/assets/SettingsPage-DzoK4PKg.js +2 -0
- package/dist/web/static/assets/SettingsPage-DzoK4PKg.js.map +1 -0
- package/dist/web/static/assets/SkillDetailPage-BuBJJ_NX.js +2 -0
- package/dist/web/static/assets/SkillDetailPage-BuBJJ_NX.js.map +1 -0
- package/dist/web/static/assets/SkillsPage-aojkJpBc.js +2 -0
- package/dist/web/static/assets/SkillsPage-aojkJpBc.js.map +1 -0
- package/dist/web/static/assets/TaskDetailPage-1ckxnGhw.js +4 -0
- package/dist/web/static/assets/TaskDetailPage-1ckxnGhw.js.map +1 -0
- package/dist/web/static/assets/TasksHubPage-C2PLh3eg.js +6 -0
- package/dist/web/static/assets/TasksHubPage-C2PLh3eg.js.map +1 -0
- package/dist/web/static/assets/WorkplacePage-DHrp5VxS.js +2 -0
- package/dist/web/static/assets/WorkplacePage-DHrp5VxS.js.map +1 -0
- package/dist/web/static/assets/arco-DFQA6dO_.css +1 -0
- package/dist/web/static/assets/arco-DV6xCLhr.js +14 -0
- package/dist/web/static/assets/arco-DV6xCLhr.js.map +1 -0
- package/dist/web/static/assets/charts-BSV4cyC4.js +37 -0
- package/dist/web/static/assets/charts-BSV4cyC4.js.map +1 -0
- package/dist/web/static/assets/date-fns-sbWH3_uq.js +2 -0
- package/dist/web/static/assets/date-fns-sbWH3_uq.js.map +1 -0
- package/dist/web/static/assets/index-B_v_MKlb.css +1 -0
- package/dist/web/static/assets/index-DileOOE4.js +4 -0
- package/dist/web/static/assets/index-DileOOE4.js.map +1 -0
- package/dist/web/static/assets/lucide-CnlPQoG8.js +72 -0
- package/dist/web/static/assets/lucide-CnlPQoG8.js.map +1 -0
- package/dist/web/static/assets/markdown-CA7ePUts.js +30 -0
- package/dist/web/static/assets/markdown-CA7ePUts.js.map +1 -0
- package/dist/web/static/assets/outcome-BKGy9azt.js +2 -0
- package/dist/web/static/assets/outcome-BKGy9azt.js.map +1 -0
- package/dist/web/static/assets/query-CgCOpYWf.js +2 -0
- package/dist/web/static/assets/{query-C99w429o.js.map → query-CgCOpYWf.js.map} +1 -1
- package/dist/web/static/assets/{react-router-r79dBVy4.js → react-router-Cxmg8RuL.js} +3 -3
- package/dist/web/static/assets/{react-router-r79dBVy4.js.map → react-router-Cxmg8RuL.js.map} +1 -1
- package/dist/web/static/assets/react-vendor-tkvCrao7.js +57 -0
- package/dist/web/static/assets/react-vendor-tkvCrao7.js.map +1 -0
- package/dist/web/static/assets/syntax-highlighter-BDYycNja.js +6 -0
- package/dist/web/static/assets/syntax-highlighter-BDYycNja.js.map +1 -0
- package/dist/web/static/assets/useAgentStats-B-uTgqBd.js +2 -0
- package/dist/web/static/assets/useAgentStats-B-uTgqBd.js.map +1 -0
- package/dist/web/static/assets/useDecisions-D-G2Ft5T.js +2 -0
- package/dist/web/static/assets/useDecisions-D-G2Ft5T.js.map +1 -0
- package/dist/web/static/assets/useDistill-21dZkXlT.js +3 -0
- package/dist/web/static/assets/useDistill-21dZkXlT.js.map +1 -0
- package/dist/web/static/assets/useEffectiveProject-DQiyX54y.js +2 -0
- package/dist/web/static/assets/useEffectiveProject-DQiyX54y.js.map +1 -0
- package/dist/web/static/assets/useIssuesFeed-CFiyQkAL.js +2 -0
- package/dist/web/static/assets/useIssuesFeed-CFiyQkAL.js.map +1 -0
- package/dist/web/static/assets/useKbHits-xKXWgqh9.js +2 -0
- package/dist/web/static/assets/useKbHits-xKXWgqh9.js.map +1 -0
- package/dist/web/static/assets/useSkillStats-B5hbIwdf.js +2 -0
- package/dist/web/static/assets/useSkillStats-B5hbIwdf.js.map +1 -0
- package/dist/web/static/assets/vendor-DS-q4Eyc.js +36 -0
- package/dist/web/static/assets/vendor-DS-q4Eyc.js.map +1 -0
- package/dist/web/static/index.html +12 -8
- package/package.json +18 -5
- package/dist/core/ai/provider.d.ts +0 -63
- package/dist/core/ai/provider.d.ts.map +0 -1
- package/dist/core/ai/provider.js +0 -241
- package/dist/core/ai/provider.js.map +0 -1
- package/dist/core/ai/types.d.ts +0 -43
- package/dist/core/ai/types.d.ts.map +0 -1
- package/dist/core/ai/types.js +0 -5
- package/dist/core/ai/types.js.map +0 -1
- package/dist/core/storage/token-usage.d.ts +0 -36
- package/dist/core/storage/token-usage.d.ts.map +0 -1
- package/dist/core/storage/token-usage.js +0 -59
- package/dist/core/storage/token-usage.js.map +0 -1
- package/dist/core/utils/token-tracker.d.ts +0 -39
- package/dist/core/utils/token-tracker.d.ts.map +0 -1
- package/dist/core/utils/token-tracker.js +0 -69
- package/dist/core/utils/token-tracker.js.map +0 -1
- package/dist/skills/index.d.ts +0 -3
- package/dist/skills/index.d.ts.map +0 -1
- package/dist/skills/index.js +0 -3
- package/dist/skills/index.js.map +0 -1
- package/dist/skills/matcher.d.ts +0 -26
- package/dist/skills/matcher.d.ts.map +0 -1
- package/dist/skills/matcher.js +0 -113
- package/dist/skills/matcher.js.map +0 -1
- package/dist/skills/official/code-simplifier.md +0 -52
- package/dist/skills/official/find-skills.md +0 -142
- package/dist/skills/official/official-api-design.md +0 -30
- package/dist/skills/official/official-architecture-decision.md +0 -41
- package/dist/skills/official/official-bmad.md +0 -118
- package/dist/skills/official/official-db-schema-design.md +0 -34
- package/dist/skills/official/official-debug.md +0 -25
- package/dist/skills/official/official-doc-driven.md +0 -31
- package/dist/skills/official/official-harness-engineering.md +0 -108
- package/dist/skills/official/official-openspec.md +0 -89
- package/dist/skills/official/official-performance-optimization.md +0 -30
- package/dist/skills/official/official-pr-review.md +0 -35
- package/dist/skills/official/official-release-checklist.md +0 -30
- package/dist/skills/official/official-security-hardening.md +0 -32
- package/dist/skills/official/official-spec-driven-design.md +0 -31
- package/dist/skills/official/planning-with-files.md +0 -241
- package/dist/skills/official/ui-ux-pro-max.md +0 -105
- package/dist/skills/official/webapp-testing.md +0 -96
- package/dist/skills/official-skills.d.ts +0 -26
- package/dist/skills/official-skills.d.ts.map +0 -1
- package/dist/skills/official-skills.js +0 -74
- package/dist/skills/official-skills.js.map +0 -1
- package/dist/skills/semantic-matcher.d.ts +0 -60
- package/dist/skills/semantic-matcher.d.ts.map +0 -1
- package/dist/skills/semantic-matcher.js +0 -192
- package/dist/skills/semantic-matcher.js.map +0 -1
- package/dist/skills/upgrade-engine.d.ts +0 -93
- package/dist/skills/upgrade-engine.d.ts.map +0 -1
- package/dist/skills/upgrade-engine.js +0 -447
- package/dist/skills/upgrade-engine.js.map +0 -1
- package/dist/skills/upgrade-prompt.d.ts +0 -20
- package/dist/skills/upgrade-prompt.d.ts.map +0 -1
- package/dist/skills/upgrade-prompt.js +0 -75
- package/dist/skills/upgrade-prompt.js.map +0 -1
- package/dist/web/routes/ai.d.ts +0 -10
- package/dist/web/routes/ai.d.ts.map +0 -1
- package/dist/web/routes/ai.js +0 -186
- package/dist/web/routes/ai.js.map +0 -1
- package/dist/web/routes/token-usage.d.ts +0 -7
- package/dist/web/routes/token-usage.d.ts.map +0 -1
- package/dist/web/routes/token-usage.js +0 -18
- package/dist/web/routes/token-usage.js.map +0 -1
- package/dist/web/ssrf-guard.d.ts +0 -35
- package/dist/web/ssrf-guard.d.ts.map +0 -1
- package/dist/web/ssrf-guard.js +0 -93
- package/dist/web/ssrf-guard.js.map +0 -1
- package/dist/web/static/assets/AIConfig-CdDWzJyO.js +0 -2
- package/dist/web/static/assets/AIConfig-CdDWzJyO.js.map +0 -1
- package/dist/web/static/assets/Dashboard-CoEmmIDt.js +0 -2
- package/dist/web/static/assets/Dashboard-CoEmmIDt.js.map +0 -1
- package/dist/web/static/assets/Drawer-DdRTzlLB.js +0 -2
- package/dist/web/static/assets/Drawer-DdRTzlLB.js.map +0 -1
- package/dist/web/static/assets/Events-DrIq1SUS.js +0 -2
- package/dist/web/static/assets/Events-DrIq1SUS.js.map +0 -1
- package/dist/web/static/assets/Reports-DFBM3MDK.js +0 -2
- package/dist/web/static/assets/Reports-DFBM3MDK.js.map +0 -1
- package/dist/web/static/assets/SearchInput-qCj_jAcf.js +0 -2
- package/dist/web/static/assets/SearchInput-qCj_jAcf.js.map +0 -1
- package/dist/web/static/assets/SessionDetail-CCzwdoT7.js +0 -2
- package/dist/web/static/assets/SessionDetail-CCzwdoT7.js.map +0 -1
- package/dist/web/static/assets/Sessions-FfLYkAw9.js +0 -2
- package/dist/web/static/assets/Sessions-FfLYkAw9.js.map +0 -1
- package/dist/web/static/assets/Skills-C8Gvs3Qa.js +0 -2
- package/dist/web/static/assets/Skills-C8Gvs3Qa.js.map +0 -1
- package/dist/web/static/assets/TaskDetail-BS8pYhaR.js +0 -2
- package/dist/web/static/assets/TaskDetail-BS8pYhaR.js.map +0 -1
- package/dist/web/static/assets/Tasks-CyuhizG8.js +0 -2
- package/dist/web/static/assets/Tasks-CyuhizG8.js.map +0 -1
- package/dist/web/static/assets/charts-CLrM0_uM.js +0 -37
- package/dist/web/static/assets/charts-CLrM0_uM.js.map +0 -1
- package/dist/web/static/assets/date-fns-CZ_bHujz.js +0 -2
- package/dist/web/static/assets/date-fns-CZ_bHujz.js.map +0 -1
- package/dist/web/static/assets/export-L_VBD2p1.js +0 -4
- package/dist/web/static/assets/export-L_VBD2p1.js.map +0 -1
- package/dist/web/static/assets/index-CBX47X8l.js +0 -3
- package/dist/web/static/assets/index-CBX47X8l.js.map +0 -1
- package/dist/web/static/assets/index-DjIoMdoR.css +0 -1
- package/dist/web/static/assets/lucide-Bs_edTLa.js +0 -232
- package/dist/web/static/assets/lucide-Bs_edTLa.js.map +0 -1
- package/dist/web/static/assets/query-C99w429o.js +0 -2
- package/dist/web/static/assets/react-vendor-CSp-GLFF.js +0 -49
- package/dist/web/static/assets/react-vendor-CSp-GLFF.js.map +0 -1
- package/dist/web/static/assets/syntax-highlighter-44FakypI.js +0 -9
- package/dist/web/static/assets/syntax-highlighter-44FakypI.js.map +0 -1
- package/dist/web/static/assets/time-Bxuk0M-C.js +0 -2
- package/dist/web/static/assets/time-Bxuk0M-C.js.map +0 -1
- package/dist/web/static/assets/vendor-CMMjVdZs.js +0 -64
- package/dist/web/static/assets/vendor-CMMjVdZs.js.map +0 -1
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Idle-session sweeper (Phase 9.5 — daemon hardening).
|
|
3
|
+
*
|
|
4
|
+
* Background
|
|
5
|
+
* ----------
|
|
6
|
+
* Outcome classification normally happens in the Stop hook (see
|
|
7
|
+
* `daemon/handlers/stop.ts`). However a session can end up with `outcome IS
|
|
8
|
+
* NULL` forever in pathological scenarios:
|
|
9
|
+
* - Claude Code crashed / was force-killed before Stop fired
|
|
10
|
+
* - Synthetic UserPromptSubmit events injected by tooling that bypass the
|
|
11
|
+
* hook protocol (no matching Stop event)
|
|
12
|
+
* - Daemon was down during Stop and the event got dropped from the queue
|
|
13
|
+
*
|
|
14
|
+
* Those rows then show up in the Web UI as "in progress" forever, polluting
|
|
15
|
+
* KPIs and confusing users. The sweeper closes that loop: once a session's
|
|
16
|
+
* last activity is older than `idleThresholdMs` (default 24h), we run the
|
|
17
|
+
* existing classifier with whatever signals we have on hand (event_count +
|
|
18
|
+
* user_violation_count from the sessions row). Typical outcome is
|
|
19
|
+
* `abandoned/no_work` or `abandoned/too_short` — exactly what we want for
|
|
20
|
+
* UI surface area.
|
|
21
|
+
*
|
|
22
|
+
* Design notes
|
|
23
|
+
* ------------
|
|
24
|
+
* - **Pure I/O wrapper** over `classifyOutcome` — no new heuristic, no new
|
|
25
|
+
* thresholds. Audited behavior stays in one place (outcome-classifier).
|
|
26
|
+
* - **Race-safe**: `updateSessionOutcome` only writes when the row's outcome
|
|
27
|
+
* is still NULL (SQL `WHERE outcome IS NULL`). If a delayed Stop hook
|
|
28
|
+
* beats us to the write, we no-op.
|
|
29
|
+
* - **Defensive cap**: `maxPerSweep` (default 500) prevents runaway processing
|
|
30
|
+
* if the table has a huge backlog after a long daemon outage.
|
|
31
|
+
* - **No git lookup**: the abandoned path doesn't need commit stats. Skipping
|
|
32
|
+
* `collectCommitStats` keeps the sweep fast (no subprocess fork per row).
|
|
33
|
+
*/
|
|
34
|
+
import { logger } from '../../core/utils/logger.js';
|
|
35
|
+
import { classifyOutcome } from './outcome-classifier.js';
|
|
36
|
+
const DEFAULT_IDLE_MS = 24 * 60 * 60 * 1000;
|
|
37
|
+
const DEFAULT_MAX_PER_SWEEP = 500;
|
|
38
|
+
/**
|
|
39
|
+
* Find sessions whose outcome is NULL but whose last-activity timestamp is
|
|
40
|
+
* older than `idleThresholdMs`. For each, run the existing `classifyOutcome`
|
|
41
|
+
* over the data we have (event_count / user_violation_count from the row) and
|
|
42
|
+
* stamp the result. Returns aggregate counters for logging.
|
|
43
|
+
*
|
|
44
|
+
* Idempotent — running twice in a row produces `scanned=0` on the second call
|
|
45
|
+
* because the first sweep set `outcome` to non-NULL.
|
|
46
|
+
*/
|
|
47
|
+
export function sweepIdleSessions(storage, opts = {}) {
|
|
48
|
+
const idleMs = opts.idleThresholdMs ?? DEFAULT_IDLE_MS;
|
|
49
|
+
const maxRows = opts.maxPerSweep ?? DEFAULT_MAX_PER_SWEEP;
|
|
50
|
+
const cutoff = new Date(Date.now() - idleMs).toISOString();
|
|
51
|
+
const idleHours = Math.round(idleMs / (60 * 60 * 1000));
|
|
52
|
+
let candidates = [];
|
|
53
|
+
try {
|
|
54
|
+
candidates = storage.queryIdleUnclassifiedSessions(cutoff, maxRows);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
logger.warn(`[IdleSweeper] query failed: ${err}`);
|
|
58
|
+
return { scanned: 0, swept: 0, skipped: 0, errors: 1 };
|
|
59
|
+
}
|
|
60
|
+
let swept = 0;
|
|
61
|
+
let errors = 0;
|
|
62
|
+
const classifiedAt = new Date().toISOString();
|
|
63
|
+
for (const sess of candidates) {
|
|
64
|
+
try {
|
|
65
|
+
// Build the classifier input from what the sessions row gives us.
|
|
66
|
+
// Missing signals (commit_count, reverted_commits) default to 0 — these
|
|
67
|
+
// idle/abandoned sessions almost never have git work attributed to them
|
|
68
|
+
// and we deliberately skip the subprocess fork.
|
|
69
|
+
const endTime = sess.last_event_time ?? sess.start_time;
|
|
70
|
+
const result = classifyOutcome({
|
|
71
|
+
session_id: sess.session_id,
|
|
72
|
+
start_time: sess.start_time,
|
|
73
|
+
end_time: endTime,
|
|
74
|
+
event_count: sess.event_count ?? 0,
|
|
75
|
+
violation_count: sess.user_violation_count ?? 0,
|
|
76
|
+
commit_count: 0,
|
|
77
|
+
reverted_commits: 0,
|
|
78
|
+
});
|
|
79
|
+
const annotatedReason = `${result.reason} (idle-swept after ${idleHours}h)`;
|
|
80
|
+
storage.updateSessionOutcome(sess.session_id, {
|
|
81
|
+
outcome: result.outcome,
|
|
82
|
+
outcome_reason: annotatedReason,
|
|
83
|
+
classified_at: classifiedAt,
|
|
84
|
+
});
|
|
85
|
+
swept++;
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
logger.warn(`[IdleSweeper] failed for ${sess.session_id}: ${err}`);
|
|
89
|
+
errors++;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return { scanned: candidates.length, swept, skipped: 0, errors };
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=idle-session-sweeper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idle-session-sweeper.js","sourceRoot":"","sources":["../../../src/daemon/services/idle-session-sweeper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAEpD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAoB1D,MAAM,eAAe,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAC5C,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAElC;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAsB,EACtB,OAAqB,EAAE;IAEvB,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,IAAI,eAAe,CAAC;IACvD,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,IAAI,qBAAqB,CAAC;IAC1D,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;IAExD,IAAI,UAAU,GAMT,EAAE,CAAC;IACR,IAAI,CAAC;QACH,UAAU,GAAG,OAAO,CAAC,6BAA6B,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CAAC,+BAA+B,GAAG,EAAE,CAAC,CAAC;QAClD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IACzD,CAAC;IAED,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,MAAM,YAAY,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAE9C,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,kEAAkE;YAClE,wEAAwE;YACxE,wEAAwE;YACxE,gDAAgD;YAChD,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,UAAU,CAAC;YACxD,MAAM,MAAM,GAAG,eAAe,CAAC;gBAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,QAAQ,EAAE,OAAO;gBACjB,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,CAAC;gBAClC,eAAe,EAAE,IAAI,CAAC,oBAAoB,IAAI,CAAC;gBAC/C,YAAY,EAAE,CAAC;gBACf,gBAAgB,EAAE,CAAC;aACpB,CAAC,CAAC;YAEH,MAAM,eAAe,GAAG,GAAG,MAAM,CAAC,MAAM,sBAAsB,SAAS,IAAI,CAAC;YAC5E,OAAO,CAAC,oBAAoB,CAAC,IAAI,CAAC,UAAU,EAAE;gBAC5C,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,cAAc,EAAE,eAAe;gBAC/B,aAAa,EAAE,YAAY;aAC5B,CAAC,CAAC;YACH,KAAK,EAAE,CAAC;QACV,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,4BAA4B,IAAI,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC,CAAC;YACnE,MAAM,EAAE,CAAC;QACX,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;AACnE,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IdleTaskBudget — Stop-time gate for idle-task outcome classification.
|
|
3
|
+
*
|
|
4
|
+
* Background (audit F-medium #3, 2026-05-26):
|
|
5
|
+
* OutcomeClassificationService.classifyIdleTasks spawns one
|
|
6
|
+
* `git log` subprocess per unclassified task, capped internally at
|
|
7
|
+
* `MAX_IDLE_TASKS_PER_RUN = 20`. The calls run *sequentially* (no
|
|
8
|
+
* concurrency primitive), so a backlog of 20 tasks can stack ~20 git I/O
|
|
9
|
+
* round-trips into the Stop fire-and-forget queue. On a busy machine the
|
|
10
|
+
* queue piles up and Stop handling for the *next* session starts behind
|
|
11
|
+
* the previous session's tail.
|
|
12
|
+
*
|
|
13
|
+
* Fix (stop.ts orchestrator scope):
|
|
14
|
+
* Peek the backlog before invoking classifyIdleTasks. When the queue is
|
|
15
|
+
* small (<= IDLE_TASK_CLASSIFY_LIMIT) we run as before so steady-state
|
|
16
|
+
* sessions still get backfill. When the backlog is large we skip the
|
|
17
|
+
* call entirely — degraded UX is acceptable because:
|
|
18
|
+
*
|
|
19
|
+
* 1. The tasks stay in `outcome=NULL` and will be picked up by the next
|
|
20
|
+
* Stop of the same session (when the backlog has presumably been
|
|
21
|
+
* worked off by intervening Stops), and
|
|
22
|
+
* 2. Skipping is preferable to blocking 20 sequential git subprocesses
|
|
23
|
+
* on the fire-and-forget queue when the user just wants to move on.
|
|
24
|
+
*
|
|
25
|
+
* This is the "skip when N > limit" strategy called out in the original
|
|
26
|
+
* review. A true concurrency limiter is the cleaner long-term fix; that
|
|
27
|
+
* change belongs inside `outcome-classification-service.ts` and is out of
|
|
28
|
+
* scope for this audit pass (constraints forbid modifying that file).
|
|
29
|
+
*/
|
|
30
|
+
import type { SQLiteStorage } from '../../core/storage/sqlite.js';
|
|
31
|
+
/**
|
|
32
|
+
* Maximum backlog size we'll attempt to classify on a single Stop. Tuned so
|
|
33
|
+
* the sequential `git log` subprocess fan-out stays bounded (each `git log`
|
|
34
|
+
* is ~100ms; 5x = ~500ms total Stop-tail). When the backlog exceeds this
|
|
35
|
+
* we skip and let a future Stop pick it up.
|
|
36
|
+
*/
|
|
37
|
+
export declare const IDLE_TASK_CLASSIFY_LIMIT = 5;
|
|
38
|
+
/**
|
|
39
|
+
* Decide whether the orchestrator should call
|
|
40
|
+
* `OutcomeClassificationService.classifyIdleTasks` for the given session.
|
|
41
|
+
*
|
|
42
|
+
* Returns true when the backlog is small enough that classification will
|
|
43
|
+
* complete in a bounded time. Returns false when the backlog is too large;
|
|
44
|
+
* the caller skips the call entirely (logged at info level).
|
|
45
|
+
*
|
|
46
|
+
* Failure mode: never throws. On storage error returns false (the safer
|
|
47
|
+
* choice — skip rather than fan out unbounded).
|
|
48
|
+
*/
|
|
49
|
+
export declare function shouldClassifyIdleTasks(storage: SQLiteStorage, sessionId: string): boolean;
|
|
50
|
+
//# sourceMappingURL=idle-task-budget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idle-task-budget.d.ts","sourceRoot":"","sources":["../../../src/daemon/services/idle-task-budget.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAKlE;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,MAAM,GAChB,OAAO,CAqBT"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IdleTaskBudget — Stop-time gate for idle-task outcome classification.
|
|
3
|
+
*
|
|
4
|
+
* Background (audit F-medium #3, 2026-05-26):
|
|
5
|
+
* OutcomeClassificationService.classifyIdleTasks spawns one
|
|
6
|
+
* `git log` subprocess per unclassified task, capped internally at
|
|
7
|
+
* `MAX_IDLE_TASKS_PER_RUN = 20`. The calls run *sequentially* (no
|
|
8
|
+
* concurrency primitive), so a backlog of 20 tasks can stack ~20 git I/O
|
|
9
|
+
* round-trips into the Stop fire-and-forget queue. On a busy machine the
|
|
10
|
+
* queue piles up and Stop handling for the *next* session starts behind
|
|
11
|
+
* the previous session's tail.
|
|
12
|
+
*
|
|
13
|
+
* Fix (stop.ts orchestrator scope):
|
|
14
|
+
* Peek the backlog before invoking classifyIdleTasks. When the queue is
|
|
15
|
+
* small (<= IDLE_TASK_CLASSIFY_LIMIT) we run as before so steady-state
|
|
16
|
+
* sessions still get backfill. When the backlog is large we skip the
|
|
17
|
+
* call entirely — degraded UX is acceptable because:
|
|
18
|
+
*
|
|
19
|
+
* 1. The tasks stay in `outcome=NULL` and will be picked up by the next
|
|
20
|
+
* Stop of the same session (when the backlog has presumably been
|
|
21
|
+
* worked off by intervening Stops), and
|
|
22
|
+
* 2. Skipping is preferable to blocking 20 sequential git subprocesses
|
|
23
|
+
* on the fire-and-forget queue when the user just wants to move on.
|
|
24
|
+
*
|
|
25
|
+
* This is the "skip when N > limit" strategy called out in the original
|
|
26
|
+
* review. A true concurrency limiter is the cleaner long-term fix; that
|
|
27
|
+
* change belongs inside `outcome-classification-service.ts` and is out of
|
|
28
|
+
* scope for this audit pass (constraints forbid modifying that file).
|
|
29
|
+
*/
|
|
30
|
+
import { logger } from '../../core/utils/logger.js';
|
|
31
|
+
import { truncateSessionId } from '../../core/utils/session.js';
|
|
32
|
+
import { formatError } from '../../core/utils/format.js';
|
|
33
|
+
/**
|
|
34
|
+
* Maximum backlog size we'll attempt to classify on a single Stop. Tuned so
|
|
35
|
+
* the sequential `git log` subprocess fan-out stays bounded (each `git log`
|
|
36
|
+
* is ~100ms; 5x = ~500ms total Stop-tail). When the backlog exceeds this
|
|
37
|
+
* we skip and let a future Stop pick it up.
|
|
38
|
+
*/
|
|
39
|
+
export const IDLE_TASK_CLASSIFY_LIMIT = 5;
|
|
40
|
+
/**
|
|
41
|
+
* Decide whether the orchestrator should call
|
|
42
|
+
* `OutcomeClassificationService.classifyIdleTasks` for the given session.
|
|
43
|
+
*
|
|
44
|
+
* Returns true when the backlog is small enough that classification will
|
|
45
|
+
* complete in a bounded time. Returns false when the backlog is too large;
|
|
46
|
+
* the caller skips the call entirely (logged at info level).
|
|
47
|
+
*
|
|
48
|
+
* Failure mode: never throws. On storage error returns false (the safer
|
|
49
|
+
* choice — skip rather than fan out unbounded).
|
|
50
|
+
*/
|
|
51
|
+
export function shouldClassifyIdleTasks(storage, sessionId) {
|
|
52
|
+
try {
|
|
53
|
+
const backlog = storage.queryIdleUnclassifiedTasks(sessionId);
|
|
54
|
+
if (backlog.length === 0) {
|
|
55
|
+
// Nothing to classify; the service would no-op anyway, but
|
|
56
|
+
// short-circuit here so the orchestrator log line is clearer.
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (backlog.length > IDLE_TASK_CLASSIFY_LIMIT) {
|
|
60
|
+
logger.info(`[Stop] Skipping idle-task classification for session ` +
|
|
61
|
+
`${truncateSessionId(sessionId)} — backlog ${backlog.length} > ` +
|
|
62
|
+
`${IDLE_TASK_CLASSIFY_LIMIT} (will retry on next Stop)`);
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
logger.debug(`[Stop] idle-task budget check failed: ${formatError(err)}`);
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=idle-task-budget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idle-task-budget.js","sourceRoot":"","sources":["../../../src/daemon/services/idle-task-budget.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAE1C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,uBAAuB,CACrC,OAAsB,EACtB,SAAiB;IAEjB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,OAAO,CAAC,0BAA0B,CAAC,SAAS,CAAC,CAAC;QAC9D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,2DAA2D;YAC3D,8DAA8D;YAC9D,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,GAAG,wBAAwB,EAAE,CAAC;YAC9C,MAAM,CAAC,IAAI,CACT,uDAAuD;gBACrD,GAAG,iBAAiB,CAAC,SAAS,CAAC,cAAc,OAAO,CAAC,MAAM,KAAK;gBAChE,GAAG,wBAAwB,4BAA4B,CAC1D,CAAC;YACF,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,yCAAyC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC1E,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InterceptRevive — 8-in-1 Phase D (2026-05-27)
|
|
3
|
+
*
|
|
4
|
+
* Closes the loop with `InterceptRollbackGuard`:
|
|
5
|
+
*
|
|
6
|
+
* • `InterceptRollbackGuard` flips `pre_tool_intercept.enabled=false` and
|
|
7
|
+
* writes `auto_disabled_at` + `auto_disabled_session` audit keys when a
|
|
8
|
+
* session triggers ≥3 denies in 60s. Reason: protect the user from a
|
|
9
|
+
* mis-tuned rule cascade.
|
|
10
|
+
*
|
|
11
|
+
* • Without revive: that flag stays `false` forever. The user has to
|
|
12
|
+
* `cf config set pre_tool_intercept.enabled true` by hand. In practice
|
|
13
|
+
* (per the spec's problem statement) the user never remembers.
|
|
14
|
+
*
|
|
15
|
+
* • Revive: on every daemon startup, check if the flag is `false` AND the
|
|
16
|
+
* `auto_disabled_at` audit key is present AND > 24h has passed. If yes,
|
|
17
|
+
* flip the flag back to `true` and delete the audit keys (clean slate
|
|
18
|
+
* for the next rollback to land).
|
|
19
|
+
*
|
|
20
|
+
* • Hysteresis: 24h is the spec default (`hysteresisHours: 24`). Skips the
|
|
21
|
+
* revive when the disable is fresh — gives the user a debugging window
|
|
22
|
+
* to investigate WHY the rollback fired.
|
|
23
|
+
*
|
|
24
|
+
* • User intent preservation: this service ONLY revives auto-disables.
|
|
25
|
+
* If the user manually ran `cf config set pre_tool_intercept.enabled false`,
|
|
26
|
+
* no `auto_disabled_at` key was written (that's set ONLY by
|
|
27
|
+
* `InterceptRollbackGuard.checkAndMaybeRollback`). The revive sees the
|
|
28
|
+
* missing key and does nothing — user wishes respected.
|
|
29
|
+
*
|
|
30
|
+
* Called once from `src/daemon/index.ts` after `seedDefaults()`. All errors
|
|
31
|
+
* are caught and logged at WARN level — revive must never throw and break
|
|
32
|
+
* daemon boot.
|
|
33
|
+
*/
|
|
34
|
+
import type { ConfigStore } from '../config-store.js';
|
|
35
|
+
export declare const DEFAULT_HYSTERESIS_HOURS = 24;
|
|
36
|
+
export interface ReviveOutcome {
|
|
37
|
+
/** True if the flag was flipped back to 'true' on this call. */
|
|
38
|
+
revived: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Human-readable reason recorded in the daemon log on each call. Stays
|
|
41
|
+
* non-null even when `revived === false` so the test suite can lock down
|
|
42
|
+
* the decision path.
|
|
43
|
+
*/
|
|
44
|
+
reason: string;
|
|
45
|
+
}
|
|
46
|
+
export interface ReviveOptions {
|
|
47
|
+
/** Hours that must have elapsed since auto-disable before revive fires. */
|
|
48
|
+
hysteresisHours?: number;
|
|
49
|
+
/** Inject `now` for tests; defaults to `new Date()`. */
|
|
50
|
+
nowProvider?: () => Date;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Decide whether to revive `pre_tool_intercept.enabled=true` after a stale
|
|
54
|
+
* rollback. Pure: takes ConfigStore + options and returns ReviveOutcome.
|
|
55
|
+
*
|
|
56
|
+
* Safe to call repeatedly; subsequent calls after a successful revive are
|
|
57
|
+
* no-ops (the flag is now `true`).
|
|
58
|
+
*/
|
|
59
|
+
export declare function reviveInterceptIfStale(configStore: ConfigStore, opts?: ReviveOptions): ReviveOutcome;
|
|
60
|
+
//# sourceMappingURL=intercept-revive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intercept-revive.d.ts","sourceRoot":"","sources":["../../../src/daemon/services/intercept-revive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAQtD,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAE3C,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,OAAO,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,WAAW,EACxB,IAAI,GAAE,aAAkB,GACvB,aAAa,CA8Cf"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InterceptRevive — 8-in-1 Phase D (2026-05-27)
|
|
3
|
+
*
|
|
4
|
+
* Closes the loop with `InterceptRollbackGuard`:
|
|
5
|
+
*
|
|
6
|
+
* • `InterceptRollbackGuard` flips `pre_tool_intercept.enabled=false` and
|
|
7
|
+
* writes `auto_disabled_at` + `auto_disabled_session` audit keys when a
|
|
8
|
+
* session triggers ≥3 denies in 60s. Reason: protect the user from a
|
|
9
|
+
* mis-tuned rule cascade.
|
|
10
|
+
*
|
|
11
|
+
* • Without revive: that flag stays `false` forever. The user has to
|
|
12
|
+
* `cf config set pre_tool_intercept.enabled true` by hand. In practice
|
|
13
|
+
* (per the spec's problem statement) the user never remembers.
|
|
14
|
+
*
|
|
15
|
+
* • Revive: on every daemon startup, check if the flag is `false` AND the
|
|
16
|
+
* `auto_disabled_at` audit key is present AND > 24h has passed. If yes,
|
|
17
|
+
* flip the flag back to `true` and delete the audit keys (clean slate
|
|
18
|
+
* for the next rollback to land).
|
|
19
|
+
*
|
|
20
|
+
* • Hysteresis: 24h is the spec default (`hysteresisHours: 24`). Skips the
|
|
21
|
+
* revive when the disable is fresh — gives the user a debugging window
|
|
22
|
+
* to investigate WHY the rollback fired.
|
|
23
|
+
*
|
|
24
|
+
* • User intent preservation: this service ONLY revives auto-disables.
|
|
25
|
+
* If the user manually ran `cf config set pre_tool_intercept.enabled false`,
|
|
26
|
+
* no `auto_disabled_at` key was written (that's set ONLY by
|
|
27
|
+
* `InterceptRollbackGuard.checkAndMaybeRollback`). The revive sees the
|
|
28
|
+
* missing key and does nothing — user wishes respected.
|
|
29
|
+
*
|
|
30
|
+
* Called once from `src/daemon/index.ts` after `seedDefaults()`. All errors
|
|
31
|
+
* are caught and logged at WARN level — revive must never throw and break
|
|
32
|
+
* daemon boot.
|
|
33
|
+
*/
|
|
34
|
+
import { ROLLBACK_FLAG_KEY, ROLLBACK_AUTO_DISABLED_AT_KEY, ROLLBACK_AUTO_DISABLED_SESSION_KEY, } from './intercept-rollback-guard.js';
|
|
35
|
+
import { logger } from '../../core/utils/logger.js';
|
|
36
|
+
export const DEFAULT_HYSTERESIS_HOURS = 24;
|
|
37
|
+
/**
|
|
38
|
+
* Decide whether to revive `pre_tool_intercept.enabled=true` after a stale
|
|
39
|
+
* rollback. Pure: takes ConfigStore + options and returns ReviveOutcome.
|
|
40
|
+
*
|
|
41
|
+
* Safe to call repeatedly; subsequent calls after a successful revive are
|
|
42
|
+
* no-ops (the flag is now `true`).
|
|
43
|
+
*/
|
|
44
|
+
export function reviveInterceptIfStale(configStore, opts = {}) {
|
|
45
|
+
const hysteresisHours = opts.hysteresisHours ?? DEFAULT_HYSTERESIS_HOURS;
|
|
46
|
+
const now = (opts.nowProvider ?? (() => new Date()))();
|
|
47
|
+
try {
|
|
48
|
+
const flag = configStore.get(ROLLBACK_FLAG_KEY);
|
|
49
|
+
if (flag === 'true') {
|
|
50
|
+
return { revived: false, reason: 'already enabled' };
|
|
51
|
+
}
|
|
52
|
+
const autoDisabledAt = configStore.get(ROLLBACK_AUTO_DISABLED_AT_KEY);
|
|
53
|
+
if (!autoDisabledAt) {
|
|
54
|
+
// No audit key → user manually disabled, respect their choice.
|
|
55
|
+
return { revived: false, reason: 'no auto_disabled_at — user-disabled, leaving alone' };
|
|
56
|
+
}
|
|
57
|
+
const disabledMs = Date.parse(autoDisabledAt);
|
|
58
|
+
if (!Number.isFinite(disabledMs)) {
|
|
59
|
+
return {
|
|
60
|
+
revived: false,
|
|
61
|
+
reason: `auto_disabled_at not parseable as ISO date: ${autoDisabledAt}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const elapsedHours = (now.getTime() - disabledMs) / (60 * 60 * 1000);
|
|
65
|
+
if (elapsedHours < hysteresisHours) {
|
|
66
|
+
return {
|
|
67
|
+
revived: false,
|
|
68
|
+
reason: `within hysteresis window (${elapsedHours.toFixed(1)}h elapsed, threshold ${hysteresisHours}h)`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// Flip + clean audit keys.
|
|
72
|
+
configStore.set(ROLLBACK_FLAG_KEY, 'true');
|
|
73
|
+
configStore.delete(ROLLBACK_AUTO_DISABLED_AT_KEY);
|
|
74
|
+
configStore.delete(ROLLBACK_AUTO_DISABLED_SESSION_KEY);
|
|
75
|
+
const msg = `Re-enabled after ${hysteresisHours}h hysteresis since auto-disable ` +
|
|
76
|
+
`(elapsed ${elapsedHours.toFixed(1)}h, auto_disabled_at=${autoDisabledAt})`;
|
|
77
|
+
logger.info(`[InterceptRevive] ${msg}`);
|
|
78
|
+
return { revived: true, reason: msg };
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
const reason = `revive aborted (config read/write failed): ${err}`;
|
|
82
|
+
logger.warn(`[InterceptRevive] ${reason}`);
|
|
83
|
+
return { revived: false, reason };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=intercept-revive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intercept-revive.js","sourceRoot":"","sources":["../../../src/daemon/services/intercept-revive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAGH,OAAO,EACL,iBAAiB,EACjB,6BAA6B,EAC7B,kCAAkC,GACnC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAEpD,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAoB3C;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CACpC,WAAwB,EACxB,OAAsB,EAAE;IAExB,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,IAAI,wBAAwB,CAAC;IACzE,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;IAEvD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAChD,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC;QACvD,CAAC;QAED,MAAM,cAAc,GAAG,WAAW,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QACtE,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,+DAA+D;YAC/D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,oDAAoD,EAAE,CAAC;QAC1F,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC9C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YACjC,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,+CAA+C,cAAc,EAAE;aACxE,CAAC;QACJ,CAAC;QAED,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QACrE,IAAI,YAAY,GAAG,eAAe,EAAE,CAAC;YACnC,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,6BAA6B,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,eAAe,IAAI;aACxG,CAAC;QACJ,CAAC;QAED,2BAA2B;QAC3B,WAAW,CAAC,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;QAC3C,WAAW,CAAC,MAAM,CAAC,6BAA6B,CAAC,CAAC;QAClD,WAAW,CAAC,MAAM,CAAC,kCAAkC,CAAC,CAAC;QACvD,MAAM,GAAG,GACP,oBAAoB,eAAe,kCAAkC;YACrE,YAAY,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB,cAAc,GAAG,CAAC;QAC9E,MAAM,CAAC,IAAI,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;QACxC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IACxC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,8CAA8C,GAAG,EAAE,CAAC;QACnE,MAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,EAAE,CAAC,CAAC;QAC3C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IACpC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InterceptRollbackGuard — Phase 2c safety-net #3.
|
|
3
|
+
*
|
|
4
|
+
* Detect "enforcement misfire" by counting how many `deny` rows the same
|
|
5
|
+
* session produced within a sliding window (5min by default). When the deny
|
|
6
|
+
* count crosses `ROLLBACK_DENY_THRESHOLD` AND the window contains at least
|
|
7
|
+
* `ROLLBACK_DISTINCT_RULES_REQUIRED` distinct `rule_id`s, automatically flip
|
|
8
|
+
* `pre_tool_intercept.enabled` back to `'false'` so the user is not stuck.
|
|
9
|
+
*
|
|
10
|
+
* Why SQL instead of in-memory Map (doc-reviewer P0 Sub-3):
|
|
11
|
+
* • daemon restart would wipe an in-memory counter — a flaky session that
|
|
12
|
+
* restarted the daemon mid-sequence would bypass the guard.
|
|
13
|
+
* • `tool_intercepts` already has every deny row with timestamp & session_id
|
|
14
|
+
* — re-using it is single source of truth.
|
|
15
|
+
*
|
|
16
|
+
* The guard is intentionally light:
|
|
17
|
+
* • Single SQL read per PreToolUseHandler deny decision.
|
|
18
|
+
* • Rollback writes 3 forge_config keys + emits an additionalContext blob.
|
|
19
|
+
* • Once rollback fires it does NOT re-arm until the user manually
|
|
20
|
+
* `cf config set pre_tool_intercept.enabled true` — the new ON event
|
|
21
|
+
* starts a fresh window because the SQL count only looks at the last
|
|
22
|
+
* window length.
|
|
23
|
+
*
|
|
24
|
+
* 2026-05-27 (Spec 4) tuning:
|
|
25
|
+
* • Window widened 60s → 5min and threshold lifted 3 → 10. The old
|
|
26
|
+
* "3 denies in 60s" tripped on normal BMAD multi-file edit bursts that
|
|
27
|
+
* legitimately re-hit the same rule.
|
|
28
|
+
* • Added `ROLLBACK_DISTINCT_RULES_REQUIRED=2` — a single rule slamming the
|
|
29
|
+
* counter is "rules working as designed", not misfire; we now require
|
|
30
|
+
* ≥2 distinct rule_ids in the window before rolling back. Multi-rule
|
|
31
|
+
* storms remain a credible "registry-level misfire" signal.
|
|
32
|
+
*/
|
|
33
|
+
import type { SQLiteStorage } from '../../core/storage/sqlite.js';
|
|
34
|
+
import type { ConfigStore } from '../config-store.js';
|
|
35
|
+
/** Sliding window length used by the guard (ms). 5min default (was 60s). */
|
|
36
|
+
export declare const ROLLBACK_WINDOW_MS: number;
|
|
37
|
+
/** Number of denies inside the window that triggers rollback. 10 default (was 3). */
|
|
38
|
+
export declare const ROLLBACK_DENY_THRESHOLD = 10;
|
|
39
|
+
/**
|
|
40
|
+
* Minimum number of distinct rule_ids whose deny rows must appear in the
|
|
41
|
+
* window before rollback can trigger. Single-rule storms (e.g. user
|
|
42
|
+
* legitimately editing many files and tripping `edit-multi-file-hard`
|
|
43
|
+
* repeatedly) are NOT misfire and should not roll back enforcement.
|
|
44
|
+
* Multi-rule storms (≥2 distinct rules denying in 5min) is the real "rule
|
|
45
|
+
* registry misfire" signal we want to catch.
|
|
46
|
+
*/
|
|
47
|
+
export declare const ROLLBACK_DISTINCT_RULES_REQUIRED = 2;
|
|
48
|
+
/** ConfigStore keys written by the guard on rollback. */
|
|
49
|
+
export declare const ROLLBACK_FLAG_KEY = "pre_tool_intercept.enabled";
|
|
50
|
+
export declare const ROLLBACK_AUTO_DISABLED_AT_KEY = "pre_tool_intercept.auto_disabled_at";
|
|
51
|
+
export declare const ROLLBACK_AUTO_DISABLED_SESSION_KEY = "pre_tool_intercept.auto_disabled_session";
|
|
52
|
+
export interface RollbackOutcome {
|
|
53
|
+
/** True when this call flipped the flag OFF (first crossing of threshold). */
|
|
54
|
+
triggered: boolean;
|
|
55
|
+
/** Number of deny rows within the window AFTER this call (incl. the current one). */
|
|
56
|
+
denyCount: number;
|
|
57
|
+
/** Distinct rule_ids contributing to the window — surfaced in the user warning. */
|
|
58
|
+
ruleIds: string[];
|
|
59
|
+
/**
|
|
60
|
+
* Human-facing context string. Non-null only when `triggered === true`;
|
|
61
|
+
* PreToolUseHandler appends this to its HookResponse.additionalContext.
|
|
62
|
+
*/
|
|
63
|
+
additionalContext: string | null;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Service object. Stateless aside from its dependencies — safe to instantiate
|
|
67
|
+
* once in daemon/index.ts and share across all PreToolUse events.
|
|
68
|
+
*/
|
|
69
|
+
export declare class InterceptRollbackGuard {
|
|
70
|
+
private storage;
|
|
71
|
+
private configStore;
|
|
72
|
+
private windowMs;
|
|
73
|
+
private threshold;
|
|
74
|
+
/**
|
|
75
|
+
* Minimum distinct rule_ids the window must contain before rollback
|
|
76
|
+
* fires. Override only in tests; production keeps the constant default.
|
|
77
|
+
*/
|
|
78
|
+
private distinctRulesRequired;
|
|
79
|
+
constructor(storage: SQLiteStorage, configStore: ConfigStore, windowMs?: number, threshold?: number,
|
|
80
|
+
/**
|
|
81
|
+
* Minimum distinct rule_ids the window must contain before rollback
|
|
82
|
+
* fires. Override only in tests; production keeps the constant default.
|
|
83
|
+
*/
|
|
84
|
+
distinctRulesRequired?: number);
|
|
85
|
+
/**
|
|
86
|
+
* Called by PreToolUseHandler right after it persists a deny row. Returns
|
|
87
|
+
* `RollbackOutcome.triggered === true` exactly on the call that first
|
|
88
|
+
* crosses the threshold; subsequent denies in the same window will still
|
|
89
|
+
* return triggered=false because we early-exit when the flag is already
|
|
90
|
+
* disabled.
|
|
91
|
+
*
|
|
92
|
+
* The caller is responsible for surfacing `additionalContext` back to
|
|
93
|
+
* Claude Code. The current event is NOT blocked — letting one extra deny
|
|
94
|
+
* through is preferable to maintaining write-then-rollback transactionality
|
|
95
|
+
* here.
|
|
96
|
+
*
|
|
97
|
+
* Failures are swallowed (logged at warn): the enforcement pipeline must
|
|
98
|
+
* never throw because a rollback guard misfired.
|
|
99
|
+
*/
|
|
100
|
+
checkAndMaybeRollback(args: {
|
|
101
|
+
sessionId: string;
|
|
102
|
+
nowIso: string;
|
|
103
|
+
}): RollbackOutcome;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=intercept-rollback-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intercept-rollback-guard.d.ts","sourceRoot":"","sources":["../../../src/daemon/services/intercept-rollback-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,QAAgB,CAAC;AAChD,qFAAqF;AACrF,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAC1C;;;;;;;GAOG;AACH,eAAO,MAAM,gCAAgC,IAAI,CAAC;AAElD,yDAAyD;AACzD,eAAO,MAAM,iBAAiB,+BAA+B,CAAC;AAC9D,eAAO,MAAM,6BAA6B,wCAAwC,CAAC;AACnF,eAAO,MAAM,kCAAkC,6CAA6C,CAAC;AAE7F,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,SAAS,EAAE,OAAO,CAAC;IACnB,qFAAqF;IACrF,SAAS,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB;;;OAGG;IACH,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED;;;GAGG;AACH,qBAAa,sBAAsB;IAE/B,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,SAAS;IACjB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;gBARrB,OAAO,EAAE,aAAa,EACtB,WAAW,EAAE,WAAW,EACxB,QAAQ,GAAE,MAA2B,EACrC,SAAS,GAAE,MAAgC;IACnD;;;OAGG;IACK,qBAAqB,GAAE,MAAyC;IAG1E;;;;;;;;;;;;;;OAcG;IACH,qBAAqB,CAAC,IAAI,EAAE;QAC1B,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;KAChB,GAAG,eAAe;CAqDpB"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InterceptRollbackGuard — Phase 2c safety-net #3.
|
|
3
|
+
*
|
|
4
|
+
* Detect "enforcement misfire" by counting how many `deny` rows the same
|
|
5
|
+
* session produced within a sliding window (5min by default). When the deny
|
|
6
|
+
* count crosses `ROLLBACK_DENY_THRESHOLD` AND the window contains at least
|
|
7
|
+
* `ROLLBACK_DISTINCT_RULES_REQUIRED` distinct `rule_id`s, automatically flip
|
|
8
|
+
* `pre_tool_intercept.enabled` back to `'false'` so the user is not stuck.
|
|
9
|
+
*
|
|
10
|
+
* Why SQL instead of in-memory Map (doc-reviewer P0 Sub-3):
|
|
11
|
+
* • daemon restart would wipe an in-memory counter — a flaky session that
|
|
12
|
+
* restarted the daemon mid-sequence would bypass the guard.
|
|
13
|
+
* • `tool_intercepts` already has every deny row with timestamp & session_id
|
|
14
|
+
* — re-using it is single source of truth.
|
|
15
|
+
*
|
|
16
|
+
* The guard is intentionally light:
|
|
17
|
+
* • Single SQL read per PreToolUseHandler deny decision.
|
|
18
|
+
* • Rollback writes 3 forge_config keys + emits an additionalContext blob.
|
|
19
|
+
* • Once rollback fires it does NOT re-arm until the user manually
|
|
20
|
+
* `cf config set pre_tool_intercept.enabled true` — the new ON event
|
|
21
|
+
* starts a fresh window because the SQL count only looks at the last
|
|
22
|
+
* window length.
|
|
23
|
+
*
|
|
24
|
+
* 2026-05-27 (Spec 4) tuning:
|
|
25
|
+
* • Window widened 60s → 5min and threshold lifted 3 → 10. The old
|
|
26
|
+
* "3 denies in 60s" tripped on normal BMAD multi-file edit bursts that
|
|
27
|
+
* legitimately re-hit the same rule.
|
|
28
|
+
* • Added `ROLLBACK_DISTINCT_RULES_REQUIRED=2` — a single rule slamming the
|
|
29
|
+
* counter is "rules working as designed", not misfire; we now require
|
|
30
|
+
* ≥2 distinct rule_ids in the window before rolling back. Multi-rule
|
|
31
|
+
* storms remain a credible "registry-level misfire" signal.
|
|
32
|
+
*/
|
|
33
|
+
import { logger } from '../../core/utils/logger.js';
|
|
34
|
+
/** Sliding window length used by the guard (ms). 5min default (was 60s). */
|
|
35
|
+
export const ROLLBACK_WINDOW_MS = 5 * 60 * 1000;
|
|
36
|
+
/** Number of denies inside the window that triggers rollback. 10 default (was 3). */
|
|
37
|
+
export const ROLLBACK_DENY_THRESHOLD = 10;
|
|
38
|
+
/**
|
|
39
|
+
* Minimum number of distinct rule_ids whose deny rows must appear in the
|
|
40
|
+
* window before rollback can trigger. Single-rule storms (e.g. user
|
|
41
|
+
* legitimately editing many files and tripping `edit-multi-file-hard`
|
|
42
|
+
* repeatedly) are NOT misfire and should not roll back enforcement.
|
|
43
|
+
* Multi-rule storms (≥2 distinct rules denying in 5min) is the real "rule
|
|
44
|
+
* registry misfire" signal we want to catch.
|
|
45
|
+
*/
|
|
46
|
+
export const ROLLBACK_DISTINCT_RULES_REQUIRED = 2;
|
|
47
|
+
/** ConfigStore keys written by the guard on rollback. */
|
|
48
|
+
export const ROLLBACK_FLAG_KEY = 'pre_tool_intercept.enabled';
|
|
49
|
+
export const ROLLBACK_AUTO_DISABLED_AT_KEY = 'pre_tool_intercept.auto_disabled_at';
|
|
50
|
+
export const ROLLBACK_AUTO_DISABLED_SESSION_KEY = 'pre_tool_intercept.auto_disabled_session';
|
|
51
|
+
/**
|
|
52
|
+
* Service object. Stateless aside from its dependencies — safe to instantiate
|
|
53
|
+
* once in daemon/index.ts and share across all PreToolUse events.
|
|
54
|
+
*/
|
|
55
|
+
export class InterceptRollbackGuard {
|
|
56
|
+
storage;
|
|
57
|
+
configStore;
|
|
58
|
+
windowMs;
|
|
59
|
+
threshold;
|
|
60
|
+
distinctRulesRequired;
|
|
61
|
+
constructor(storage, configStore, windowMs = ROLLBACK_WINDOW_MS, threshold = ROLLBACK_DENY_THRESHOLD,
|
|
62
|
+
/**
|
|
63
|
+
* Minimum distinct rule_ids the window must contain before rollback
|
|
64
|
+
* fires. Override only in tests; production keeps the constant default.
|
|
65
|
+
*/
|
|
66
|
+
distinctRulesRequired = ROLLBACK_DISTINCT_RULES_REQUIRED) {
|
|
67
|
+
this.storage = storage;
|
|
68
|
+
this.configStore = configStore;
|
|
69
|
+
this.windowMs = windowMs;
|
|
70
|
+
this.threshold = threshold;
|
|
71
|
+
this.distinctRulesRequired = distinctRulesRequired;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Called by PreToolUseHandler right after it persists a deny row. Returns
|
|
75
|
+
* `RollbackOutcome.triggered === true` exactly on the call that first
|
|
76
|
+
* crosses the threshold; subsequent denies in the same window will still
|
|
77
|
+
* return triggered=false because we early-exit when the flag is already
|
|
78
|
+
* disabled.
|
|
79
|
+
*
|
|
80
|
+
* The caller is responsible for surfacing `additionalContext` back to
|
|
81
|
+
* Claude Code. The current event is NOT blocked — letting one extra deny
|
|
82
|
+
* through is preferable to maintaining write-then-rollback transactionality
|
|
83
|
+
* here.
|
|
84
|
+
*
|
|
85
|
+
* Failures are swallowed (logged at warn): the enforcement pipeline must
|
|
86
|
+
* never throw because a rollback guard misfired.
|
|
87
|
+
*/
|
|
88
|
+
checkAndMaybeRollback(args) {
|
|
89
|
+
const empty = { triggered: false, denyCount: 0, ruleIds: [], additionalContext: null };
|
|
90
|
+
try {
|
|
91
|
+
// If the flag is already OFF, nothing to do — caller already saw
|
|
92
|
+
// dry_run behavior on this deny (the deny was persisted but allow=true).
|
|
93
|
+
// The handler still calls us because it's cheaper than reading the flag
|
|
94
|
+
// twice; we short-circuit here instead.
|
|
95
|
+
if (!this.configStore.isEnabled(ROLLBACK_FLAG_KEY))
|
|
96
|
+
return empty;
|
|
97
|
+
const sinceIso = new Date(Date.parse(args.nowIso) - this.windowMs).toISOString();
|
|
98
|
+
const rows = this.storage.queryToolIntercepts({
|
|
99
|
+
session_id: args.sessionId,
|
|
100
|
+
decision: 'deny',
|
|
101
|
+
since: sinceIso,
|
|
102
|
+
limit: Math.max(this.threshold * 2, 10),
|
|
103
|
+
});
|
|
104
|
+
const denyCount = rows.length;
|
|
105
|
+
// Order-insensitive distinct rule list (Set preserves insertion order in JS).
|
|
106
|
+
const ruleIds = Array.from(new Set(rows.map((r) => r.rule_id)));
|
|
107
|
+
if (denyCount < this.threshold) {
|
|
108
|
+
return { triggered: false, denyCount, ruleIds, additionalContext: null };
|
|
109
|
+
}
|
|
110
|
+
// B3 (Spec 4) — single-rule storms are not misfire. Require at least
|
|
111
|
+
// `distinctRulesRequired` rule_ids in the window before flipping.
|
|
112
|
+
if (ruleIds.length < this.distinctRulesRequired) {
|
|
113
|
+
return { triggered: false, denyCount, ruleIds, additionalContext: null };
|
|
114
|
+
}
|
|
115
|
+
// Threshold reached AND multi-rule storm — flip flag OFF and write audit keys.
|
|
116
|
+
try {
|
|
117
|
+
this.configStore.set(ROLLBACK_FLAG_KEY, 'false');
|
|
118
|
+
this.configStore.set(ROLLBACK_AUTO_DISABLED_AT_KEY, args.nowIso);
|
|
119
|
+
this.configStore.set(ROLLBACK_AUTO_DISABLED_SESSION_KEY, args.sessionId);
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
logger.warn(`[InterceptRollbackGuard] config write failed: ${err}`);
|
|
123
|
+
return { triggered: false, denyCount, ruleIds, additionalContext: null };
|
|
124
|
+
}
|
|
125
|
+
const windowMinutes = Math.round(this.windowMs / 60_000);
|
|
126
|
+
const ctx = buildRollbackMessage(denyCount, ruleIds, windowMinutes);
|
|
127
|
+
logger.warn(`[InterceptRollbackGuard] AUTO-DISABLED enforcement for session ${args.sessionId} ` +
|
|
128
|
+
`(${denyCount} denies in ${windowMinutes}min from ${ruleIds.length} distinct rules; ` +
|
|
129
|
+
`rules=${ruleIds.join(',')})`);
|
|
130
|
+
return { triggered: true, denyCount, ruleIds, additionalContext: ctx };
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
logger.warn(`[InterceptRollbackGuard] check failed: ${err}`);
|
|
134
|
+
return empty;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Pretty-printed user-facing context appended on rollback. Kept in module
|
|
140
|
+
* scope so tests can match against the exact phrasing.
|
|
141
|
+
*/
|
|
142
|
+
function buildRollbackMessage(denyCount, ruleIds, windowMinutes) {
|
|
143
|
+
const ruleList = ruleIds.length > 0 ? ruleIds.join(', ') : '(unknown)';
|
|
144
|
+
return [
|
|
145
|
+
'⚠️ [forge enforcement auto-disabled]',
|
|
146
|
+
`${windowMinutes}min 内此 session 触发 ${denyCount} 次 deny,涉及 ${ruleIds.length} 条规则` +
|
|
147
|
+
`(rules: ${ruleList})→ 已自动关闭强制档。`,
|
|
148
|
+
'重新启用:cf config set pre_tool_intercept.enabled true',
|
|
149
|
+
'反馈误杀:cf logs --tail | grep tool_intercepts',
|
|
150
|
+
].join('\n');
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=intercept-rollback-guard.js.map
|