@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 @@
|
|
|
1
|
+
{"version":3,"file":"useDecisions-D-G2Ft5T.js","sources":["../../src/hooks/decisions-derive.ts","../../src/hooks/useDecisions.ts"],"sourcesContent":["/**\n * decisions-derive — 治理 · 决策列表/详情 (Phase 3a, decision 29688066) 纯派生层。\n *\n * 项目前端单测跑在 environment:'node'(无 jsdom / RTL,见 workplace-data.test.ts\n * 注解),故所有「端点响应 → 视图模型」的计算都抽进本纯函数模块,页面组件只渲染\n * 派生结果。这里逐函数锁端点对接口径(**已 curl 真实 payload 对字段**):\n *\n * GET /api/decisions[?status=&limit=] → 决策行**裸数组**(DecisionRow[])\n * GET /api/decisions/:id → DecisionRow + related_spawns[] +\n * spawn_count + related_changelogs[]\n *\n * 真实端点形状(curl 自查,2026-06-12)—— 关键事实:\n * - 列表/详情都用同一 DecisionRow 结构(详情多挂 related_* 三字段)。\n * - intent 摘要字段名是 `trigger_prompt`(非 spec 写的 intent_summary)。\n * - options_json / risks_json / open_questions_json 是**字符串化 JSON**,\n * 端点 NOT 解析(DecisionsOperations 注释明示),由本层 JSON.parse。\n * - options_json 元素形状:{name, what[], pros[], cons[], probability,\n * reversibility, rejected_reason}。**无 `rec` 布尔**——推荐项靠把每个\n * option 的 name/key 与 `recommendation` 文本匹配推断(见 markRecommended)。\n * - open_questions_json = string[];risks_json 可能 null 或 string[]。\n * - **端点不返回**:triage(可逆/影响/路径)、next_steps、structured spawns、\n * precedent(outcome-weighted 被引决策)、markdown 正文。仅有\n * `decision_doc_path`(决策文档路径,不含正文)。故详情正文 = 结构化字段\n * (context=trigger_prompt / options / recommendation / risks / questions),\n * 原型的 Triage / Next Steps / precedent 三块按「缺字段降级」处理(见下)。\n * - related_spawns = routing_events(关联 spawn 真值,端点已 join decision_id)。\n * - related_changelogs = 关联 changelog 文件相对路径数组(端点扫 docs/implementation)。\n *\n * 降级口径(重要,勿「规整」/硬塞):\n * - Triage 横条:端点无结构化 triage → 用 outcome/status/kind/source +\n * 选项数 + spawn 数组装一条「概要统计条」,不伪造可逆性/影响/路径文案。\n * - precedent(outcome-weighted 被引决策):端点不返回 → 详情右栏标注\n * 「端点未返回被引先例」空态,不 mock。\n * - Next Steps:端点不返回 → 不渲染该块(避免伪造)。\n * - 关联任务:决策行无 task_id 字段;session_id 有但非 task。降级为空态。\n */\n\n// ─── endpoint response shapes(严格按 curl 真实字段名)────────────────────────\n\nexport type DecisionStatus =\n | 'advisory'\n | 'pending'\n | 'resolved'\n | 'bypassed'\n | 'expired'\n | string\n\nexport type DecisionOutcome = 'success' | 'failed' | 'partial' | null\nexport type DecisionKind = 'decision' | 'spec' | string\n\n/** 单行(列表与详情共用此基底)。仅声明 UI 用到的字段,其余端点字段忽略。 */\nexport interface DecisionRow {\n id: string\n session_id: string\n project_path: string\n trigger_prompt: string\n suggested_agent: string | null\n kind: DecisionKind\n status: DecisionStatus\n options_json: string | null\n recommendation: string | null\n risks_json: string | null\n open_questions_json: string | null\n decision_doc_path: string | null\n recommended_agents: string | null\n recommended_skills: string | null\n approval_token: string | null\n spec_source: string | null\n outcome: DecisionOutcome\n approved_at: string | null\n approved_by: string | null\n bypass_flag?: 0 | 1\n created_at: string\n expires_at?: string\n resolved_at: string | null\n}\n\nexport interface RelatedSpawn {\n id: number\n routed_to_name: string | null\n ts: number\n obeyed: number | null\n}\n\n/** GET /api/decisions/:id = DecisionRow + 这三个挂载字段。 */\nexport interface DecisionDetailResp extends DecisionRow {\n related_spawns?: RelatedSpawn[]\n spawn_count?: number\n related_changelogs?: string[]\n}\n\n/** options_json 元素的原始(字符串化 JSON 解出后)形状。 */\nexport interface RawOption {\n name?: string\n what?: string[] | string\n pros?: string[]\n cons?: string[]\n probability?: string\n reversibility?: string\n rejected_reason?: string | null\n}\n\n// ─── view models ─────────────────────────────────────────────────────────────\n\n/** 列表行视图模型。 */\nexport interface DecisionListRow {\n id: string\n /** intent 摘要 = trigger_prompt。 */\n intent: string\n kind: DecisionKind\n status: DecisionStatus\n outcome: DecisionOutcome\n /** source:spec 行用 spec_source,decision 行用 suggested_agent 兜底。 */\n source: string\n /** 排序/显示用时间戳(created_at ISO TEXT)。 */\n createdAt: string\n /** resolved/approved 与否(控制「批准」动作可见性)。 */\n canApprove: boolean\n}\n\nexport interface DecisionOption {\n /** 选项键:从 name 抽 \"Option A\"/\"A\"/\"0.5\" 等,无则用序号。 */\n key: string\n /** 选项标题(去掉 \"Option X:\" 前缀后的主体;无前缀则用整 name)。 */\n title: string\n what: string[]\n pros: string[]\n cons: string[]\n probability: string\n reversibility: string\n /** 端点无 rec 布尔 → 由 markRecommended 按 recommendation 文本匹配推断。 */\n recommended: boolean\n /** rejected_reason 非空 = 该选项被否决。 */\n rejectedReason: string | null\n}\n\nexport interface DecisionDetailView {\n id: string\n intent: string\n kind: DecisionKind\n status: DecisionStatus\n outcome: DecisionOutcome\n source: string\n suggestedAgent: string | null\n createdAt: string\n resolvedAt: string | null\n approvedBy: string | null\n docPath: string | null\n recommendedAgents: string[]\n recommendedSkills: string[]\n /** Context 背景 = trigger_prompt 全文。 */\n context: string\n options: DecisionOption[]\n recommendation: string | null\n risks: string[]\n openQuestions: string[]\n relatedSpawns: RelatedSpawn[]\n spawnCount: number\n relatedChangelogs: string[]\n canApprove: boolean\n /**\n * advisory / 直接记录决策标识:daemon mint 但主线程 bypass 了 decision-maker\n * (skip decision),决策本就没产出 options/recommendation/open_questions/risks。\n * 详情页据此**不渲染**那几张空的结构化卡,改为一张正向说明卡 + 仅展示有内容的\n * 部分(Context / 概要 / outcome / related_changelogs)。判定见 isAdvisoryDecision。\n */\n isAdvisory: boolean\n}\n\n/**\n * advisory / lightweight 决策判定:无 options 且无 recommendation 且无\n * open_questions 且无 risks → 视为 advisory/bypass 决策(decision-maker 未跑,\n * 本就无结构化内容),而非「详情页坏了」。结构化决策(走了 decision-maker)至少\n * 有 options 或 recommendation 之一,不会命中此判定。\n */\nexport function isAdvisoryDecision(v: {\n options: DecisionOption[]\n recommendation: string | null\n openQuestions: string[]\n risks: string[]\n}): boolean {\n const recText = (v.recommendation ?? '').trim()\n return (\n v.options.length === 0 &&\n recText === '' &&\n v.openQuestions.length === 0 &&\n v.risks.length === 0\n )\n}\n\n// ─── helpers ─────────────────────────────────────────────────────────────────\n\n/** 安全 JSON.parse:失败/空 → fallback。 */\nexport function safeParse<T>(raw: string | null | undefined, fallback: T): T {\n if (!raw || typeof raw !== 'string') return fallback\n try {\n const v = JSON.parse(raw)\n return (v ?? fallback) as T\n } catch {\n return fallback\n }\n}\n\n/** 归一为字符串数组(容忍 string | string[] | null)。 */\nexport function toStringArray(v: unknown): string[] {\n if (Array.isArray(v)) return v.filter((x) => typeof x === 'string' && x.trim() !== '') as string[]\n if (typeof v === 'string' && v.trim() !== '') return [v]\n return []\n}\n\n/** 逗号分隔 → 去空 trim 数组(recommended_agents/skills)。 */\nexport function splitCsv(v: string | null | undefined): string[] {\n if (!v) return []\n return v\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s !== '')\n}\n\n/**\n * 从 option.name 抽 key + title。\n * \"Option A: 全量重构(...)\" → key='A', title='全量重构(...)'\n * \"Option 0.5: Reframe(...)\" → key='0.5', title='Reframe(...)'\n * 无 \"Option X:\" 前缀 → key=序号(idx+1), title=整 name。\n */\nexport function deriveOptionKeyTitle(name: string | undefined, idx: number): { key: string; title: string } {\n const raw = (name ?? '').trim()\n if (!raw) return { key: String(idx + 1), title: `选项 ${idx + 1}` }\n const m = raw.match(/^Option\\s+([A-Za-z0-9.]+)\\s*[::]\\s*(.+)$/i)\n if (m) return { key: m[1], title: m[2].trim() }\n return { key: String(idx + 1), title: raw }\n}\n\n/**\n * 端点无 `rec` 布尔。推荐项推断:recommendation 文本里出现该选项的 key\n * (如 \"Option B\" / \"B —\" / 行首 \"B:\")即判为推荐。匹配「Option <key>」或\n * 「<key>」作为独立 token(避免 \"A\" 误命中单词内字母)。多命中取第一个。\n */\nexport function findRecommendedKey(\n recommendation: string | null | undefined,\n optionKeys: string[],\n): string | null {\n const text = recommendation ?? ''\n if (!text) return null\n for (const key of optionKeys) {\n const esc = key.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n // \"Option B\" 显式形式(最可靠)\n if (new RegExp(`Option\\\\s+${esc}\\\\b`, 'i').test(text)) return key\n // 行首/独立 \"B —\" / \"B:\" / \"B:\" 形式\n if (new RegExp(`(^|[\\\\s((])${esc}\\\\s*[—::-]`, 'm').test(text)) return key\n }\n return null\n}\n\nconst STATUS_LABEL: Record<string, string> = {\n advisory: '已记录',\n pending: '待批准',\n resolved: '已批准',\n bypassed: '已绕过',\n expired: '已过期',\n}\n\nexport function statusLabel(status: string): string {\n return STATUS_LABEL[status] ?? status\n}\n\nexport function statusColor(status: string): string {\n switch (status) {\n case 'pending':\n return 'orange'\n case 'resolved':\n return 'green'\n case 'advisory':\n return 'arcoblue'\n case 'bypassed':\n return 'gray'\n case 'expired':\n return 'gray'\n default:\n return 'gray'\n }\n}\n\nconst OUTCOME_LABEL: Record<string, string> = {\n success: '成功',\n partial: '部分',\n failed: '失败',\n}\n\nexport function outcomeLabel(outcome: DecisionOutcome): string {\n if (!outcome) return '待回填'\n return OUTCOME_LABEL[outcome] ?? outcome\n}\n\nexport function outcomeColor(outcome: DecisionOutcome): string {\n switch (outcome) {\n case 'success':\n return 'green'\n case 'partial':\n return 'gold'\n case 'failed':\n return 'red'\n default:\n return 'gray'\n }\n}\n\nexport function kindLabel(kind: DecisionKind): string {\n if (kind === 'decision') return 'decision'\n if (kind === 'spec') return 'spec'\n return kind\n}\n\n/** source 解析:spec 行优先 spec_source,否则 suggested_agent,否则 kind。 */\nexport function deriveSource(row: { kind: DecisionKind; spec_source: string | null; suggested_agent: string | null }): string {\n if (row.spec_source) return row.spec_source\n if (row.suggested_agent) return row.suggested_agent\n return row.kind === 'spec' ? 'planner' : 'decision'\n}\n\n/** 「仍可批准」= advisory|pending(OPEN_DECISION_STATUSES 口径)。 */\nexport function isApprovable(status: string): boolean {\n return status === 'advisory' || status === 'pending'\n}\n\n// ─── list assembly ───────────────────────────────────────────────────────────\n\n/**\n * 把列表端点裸数组装配成列表视图行。按 created_at 倒序(最新在前);端点已按\n * created DESC 返回,这里再 stable 排一次防御。\n */\nexport function buildDecisionListRows(rows: DecisionRow[] | undefined): DecisionListRow[] {\n if (!Array.isArray(rows)) return []\n const out = rows.map((r): DecisionListRow => ({\n id: r.id,\n intent: r.trigger_prompt || '(无摘要)',\n kind: r.kind,\n status: r.status,\n outcome: r.outcome ?? null,\n source: deriveSource(r),\n createdAt: r.created_at,\n canApprove: isApprovable(r.status),\n }))\n out.sort((a, b) => (a.createdAt < b.createdAt ? 1 : a.createdAt > b.createdAt ? -1 : 0))\n return out\n}\n\n// ─── detail assembly ─────────────────────────────────────────────────────────\n\n/** 把 raw options 数组 + recommendation 文本 → 结构化选项卡(含推荐高亮)。 */\nexport function buildOptions(\n rawOptions: RawOption[],\n recommendation: string | null,\n): DecisionOption[] {\n const prelim = rawOptions.map((o, idx) => {\n const { key, title } = deriveOptionKeyTitle(o.name, idx)\n return {\n key,\n title,\n what: toStringArray(o.what),\n pros: toStringArray(o.pros),\n cons: toStringArray(o.cons),\n probability: o.probability?.trim() || '—',\n reversibility: o.reversibility?.trim() || '—',\n rejectedReason: o.rejected_reason ?? null,\n }\n })\n const recKey = findRecommendedKey(recommendation, prelim.map((o) => o.key))\n return prelim.map((o) => ({ ...o, recommended: o.key === recKey }))\n}\n\n/** 装配详情视图(端点返回为空 → null,让页面走错误/空态)。 */\nexport function buildDecisionDetailView(\n resp: DecisionDetailResp | undefined,\n): DecisionDetailView | null {\n if (!resp || !resp.id) return null\n const rawOptions = safeParse<RawOption[]>(resp.options_json, [])\n const risks = toStringArray(safeParse<unknown>(resp.risks_json, []))\n const openQuestions = toStringArray(safeParse<unknown>(resp.open_questions_json, []))\n const options = buildOptions(Array.isArray(rawOptions) ? rawOptions : [], resp.recommendation)\n const recommendation = resp.recommendation ?? null\n\n return {\n id: resp.id,\n intent: resp.trigger_prompt || '(无摘要)',\n kind: resp.kind,\n status: resp.status,\n outcome: resp.outcome ?? null,\n source: deriveSource(resp),\n suggestedAgent: resp.suggested_agent ?? null,\n createdAt: resp.created_at,\n resolvedAt: resp.resolved_at ?? null,\n approvedBy: resp.approved_by ?? null,\n docPath: resp.decision_doc_path ?? null,\n recommendedAgents: splitCsv(resp.recommended_agents),\n recommendedSkills: splitCsv(resp.recommended_skills),\n context: resp.trigger_prompt || '',\n options,\n recommendation,\n risks,\n openQuestions,\n relatedSpawns: Array.isArray(resp.related_spawns) ? resp.related_spawns : [],\n spawnCount: typeof resp.spawn_count === 'number' ? resp.spawn_count : (resp.related_spawns?.length ?? 0),\n relatedChangelogs: Array.isArray(resp.related_changelogs) ? resp.related_changelogs : [],\n canApprove: isApprovable(resp.status),\n isAdvisory: isAdvisoryDecision({ options, recommendation, openQuestions, risks }),\n }\n}\n\n/** ISO-TEXT created_at → 紧凑 \"MM-DD HH:mm\"。 */\nexport function fmtCreated(iso: string | null | undefined): string {\n if (!iso) return '—'\n // 端点形如 \"2026-06-12 03:31:03\" 或 ISO \"2026-06-12T03:31:03\"\n const s = iso.replace('T', ' ')\n const m = s.match(/^\\d{4}-(\\d{2}-\\d{2})[ ](\\d{2}:\\d{2})/)\n if (m) return `${m[1]} ${m[2]}`\n return s.slice(0, 16)\n}\n","/**\n * useDecisions / useDecisionDetail — 治理 · 决策列表 + 详情 (Phase 3a, decision 29688066)\n * 取数 hook。\n *\n * 接真实端点,零新后端(curl 已验形状):\n * GET /api/decisions?limit=200 → 决策行裸数组(DecisionRow[])\n * GET /api/decisions/:id → DecisionRow + related_spawns +\n * spawn_count + related_changelogs\n *\n * 决策端点**不吃 window 参数**(列表是全量 + status 过滤,非时间窗聚合),故本 hook\n * 不挂 useTimeWindow——与 KB/Skill 等窗口驱动页不同(端点真实形状决定,勿硬塞 window)。\n * 取数后交 decisions-derive.ts 纯函数装配视图,页面只渲染派生结果。\n */\nimport { useQuery } from '@tanstack/react-query'\n\nimport {\n buildDecisionListRows,\n buildDecisionDetailView,\n type DecisionRow,\n type DecisionDetailResp,\n type DecisionListRow,\n type DecisionDetailView,\n} from './decisions-derive'\n\nasync function fetchJson<T>(url: string): Promise<T> {\n const r = await fetch(url)\n if (!r.ok) throw new Error(`${url} → ${r.status}`)\n return r.json() as Promise<T>\n}\n\nconst LIST_LIMIT = 200\n\nconst fetchList = () => fetchJson<DecisionRow[]>(`/api/decisions?limit=${LIST_LIMIT}`)\nconst fetchDetail = (id: string) =>\n fetchJson<DecisionDetailResp>(`/api/decisions/${encodeURIComponent(id)}`)\n\nexport interface DecisionsListResult {\n rows: DecisionListRow[]\n loading: boolean\n isError: boolean\n error: Error | null\n refetch: () => void\n}\n\n/** 决策列表取数 + 装配。 */\nexport function useDecisions(): DecisionsListResult {\n const listQ = useQuery({\n queryKey: ['decisions-list'],\n queryFn: fetchList,\n refetchInterval: 60_000,\n refetchIntervalInBackground: false,\n })\n\n return {\n rows: buildDecisionListRows(listQ.data),\n loading: listQ.isLoading,\n isError: listQ.isError,\n error: (listQ.error as Error) ?? null,\n refetch: () => {\n void listQ.refetch()\n },\n }\n}\n\nexport interface DecisionDetailResult {\n view: DecisionDetailView | null\n loading: boolean\n isError: boolean\n error: Error | null\n refetch: () => void\n}\n\n/** 单决策详情取数 + 装配。 */\nexport function useDecisionDetail(id: string | undefined): DecisionDetailResult {\n const detailQ = useQuery({\n queryKey: ['decision-detail', id],\n queryFn: () => fetchDetail(id!),\n enabled: !!id,\n refetchInterval: 30_000,\n })\n\n const view = id ? buildDecisionDetailView(detailQ.data) : null\n\n return {\n view,\n loading: detailQ.isLoading,\n isError: detailQ.isError,\n error: (detailQ.error as Error) ?? null,\n refetch: () => {\n void detailQ.refetch()\n },\n }\n}\n"],"names":["isAdvisoryDecision","v","recText","safeParse","raw","fallback","toStringArray","x","splitCsv","s","deriveOptionKeyTitle","name","idx","m","findRecommendedKey","recommendation","optionKeys","text","key","esc","STATUS_LABEL","statusLabel","status","statusColor","OUTCOME_LABEL","outcomeLabel","outcome","outcomeColor","kindLabel","kind","deriveSource","row","isApprovable","buildDecisionListRows","rows","out","r","a","b","buildOptions","rawOptions","prelim","o","title","_a","_b","recKey","buildDecisionDetailView","resp","risks","openQuestions","options","fmtCreated","iso","fetchJson","url","LIST_LIMIT","fetchList","fetchDetail","id","useDecisions","listQ","useQuery","useDecisionDetail","detailQ"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{u as d}from"./query-CgCOpYWf.js";const g={"obra-superpowers":"obra/superpowers","anthropics-skills":"anthropics/skills","affaan-m-ecc":"affaan-m/ECC","multica-karpathy":"multica/karpathy"},_=new Set(["multica-karpathy"]);function k(e){if(!e||typeof e!="string")return null;const i=e.trim();return!i||i==="unknown"?null:i.slice(0,7)}function f(e){if(!e||typeof e!="string")return null;const i=e.match(/github\.com[/:]([^/]+\/[^/]+?)(?:\.git)?\/?$/);return i?i[1]:e.replace(/\.git$/,"")||null}function $(e){if(!e)return"—";const i=new Date(e);if(Number.isNaN(i.getTime()))return"—";const n=t=>String(t).padStart(2,"0");return`${i.getFullYear()}-${n(i.getMonth()+1)}-${n(i.getDate())} ${n(i.getHours())}:${n(i.getMinutes())}`}function F(e){return e==="distilled"?{label:"蒸馏",color:"green",icon:"check"}:e==="skipped"?{label:"跳过",color:"gray",icon:"minus"}:{label:"锚点拒",color:"red",icon:"close"}}const w=[{key:"d1",label:"D1 多语言通用"},{key:"d2",label:"D2 工具链中立"},{key:"d3",label:"D3 流程独立"},{key:"d4",label:"D4 可移植"},{key:"d5",label:"D5 知识浓度"}];function L(e){return e==null||!Number.isFinite(e)?"—":`${e.toFixed(1)} / 5`}function v(e,i){const n=(e==null?void 0:e.state)??(i==null?void 0:i.state)??null,t=((i==null?void 0:i.distilledFiles)??[]).map(l=>({id:l.id,decision:"distilled",score:Number.isFinite(l.itScore)?l.itScore:null,upstreamRepo:null,upstreamCommit:null})),s=((n==null?void 0:n.skipped)??[]).map(l=>({id:l,decision:"skipped",score:null,upstreamRepo:null,upstreamCommit:null})),a=((n==null?void 0:n.rejected)??[]).map(l=>({id:l,decision:"rejected",score:null,upstreamRepo:null,upstreamCommit:null}));t.sort((l,u)=>{const y=l.score??-1,h=u.score??-1;return h!==y?h-y:l.id.localeCompare(u.id)}),s.sort((l,u)=>l.id.localeCompare(u.id)),a.sort((l,u)=>l.id.localeCompare(u.id));const p=[...t,...s,...a],c=(n==null?void 0:n.upstreamCommits)??{},r=(Object.keys(c).length>0?Object.keys(c):Object.keys(g)).map(l=>({key:l,label:g[l]??l,commit:k(c[l]),isSkipSource:_.has(l)}));return{rows:p,upstreams:r,cacheReady:!!(e!=null&&e.stateFileExists)||!!n,phase:(n==null?void 0:n.phase)??"idle",lastRunAt:(n==null?void 0:n.lastRunAt)??null,distilledCount:t.length,skippedCount:s.length,rejectedCount:a.length}}function D(e){return{repo:f(e.upstream)??e.upstream,url:e.upstream,license:e.license??null,commit:k(e.commit),paths:e.paths??[]}}function S(e){return w.map(({key:i,label:n})=>({key:i,label:n,value:typeof(e==null?void 0:e[i])=="number"?e[i]:0}))}function C(e,i,n){const t=(n==null?void 0:n.state)??null,s=e.replace(/^distilled-/,""),a=((t==null?void 0:t.skipped)??[]).includes(e)||((t==null?void 0:t.skipped)??[]).includes(s),p=((t==null?void 0:t.rejected)??[]).includes(e)||((t==null?void 0:t.rejected)??[]).includes(s),c=!!i&&(!!i.frontmatter||!!i.distilledMarkdown);let o;if(c)o="distilled";else if(p)o="rejected";else if(a)o="skipped";else if(i)o="distilled";else return null;const r=(i==null?void 0:i.frontmatter)??{},l=typeof r.it_universal_score=="number"?r.it_universal_score:null;return{id:e,name:r.name??e,version:r.version??null,description:r.description??null,decision:o,score:l,dims:S(r.it_universal_dims),rationale:r.it_universal_rationale??null,distilledBy:r.distilled_by??null,distilledAt:r.distilled_at??null,spawnAgent:typeof r.spawn_agent=="string"?r.spawn_agent:null,attributions:(r.distilled_from??[]).map(D),body:(i==null?void 0:i.distilledMarkdown)??"",frontmatter:r,upstreams:(i==null?void 0:i.upstreams)??[]}}function q(e){const i=[],n=(t,s)=>{s!=null&&i.push(`${t}: ${typeof s=="string"?s:JSON.stringify(s)}`)};return n("name",e.name),n("version",e.version),n("description",e.description),e.keywords&&e.keywords.length&&n("keywords",e.keywords),n("it_universal_score",e.it_universal_score),e.it_universal_dims&&n("it_universal_dims",e.it_universal_dims),n("distilled_by",e.distilled_by),n("distilled_at",e.distilled_at),i.join(`
|
|
2
|
+
`)}async function m(e){const i=await fetch(e);if(!i.ok)throw new Error(`${e} → ${i.status}`);return i.json()}const b=()=>m("/api/skills/distill/status"),R=()=>m("/api/skills/distill/review"),j=e=>m(`/api/skills/distill/review/${encodeURIComponent(e)}/diff`);function A(){const e=d({queryKey:["distill-status"],queryFn:b,refetchInterval:6e4,refetchIntervalInBackground:!1}),i=d({queryKey:["distill-review"],queryFn:R,staleTime:6e4}),n=v(e.data,i.data),t=e.isError&&i.isError;return{view:n,loading:e.isLoading||i.isLoading,isError:t,error:e.error??i.error??null,refetch:()=>{e.refetch(),i.refetch()}}}function M(e){const i=d({queryKey:["distill-diff",e],queryFn:()=>j(e),enabled:!!e,staleTime:3e5,retry:!1}),n=d({queryKey:["distill-status"],queryFn:b,staleTime:6e4}),t=e?C(e,i.data,n.data):null,s=!!e&&i.isError&&t===null;return{view:t,loading:i.isLoading||n.isLoading,isError:s,error:i.error??null,refetch:()=>{i.refetch(),n.refetch()}}}export{$ as a,M as b,q as c,F as d,L as f,A as u};
|
|
3
|
+
//# sourceMappingURL=useDistill-21dZkXlT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDistill-21dZkXlT.js","sources":["../../src/hooks/distill-derive.ts","../../src/hooks/useDistill.ts"],"sourcesContent":["/**\n * distill-derive — 蒸馏列表/详情 (Phase 2e, decision 29688066) 纯派生层。\n *\n * 项目前端单测跑在 environment:'node'(无 jsdom / RTL,见 workplace-data.test.ts\n * 注解),故所有「端点响应 → 视图模型」的计算都抽进本纯函数模块,页面组件只渲染\n * 派生结果。逐函数锁端点对接口径(字段名严格按服务端真实 curl payload,避免\n * Phase 2b 的「派生层读了服务端从不产出的字段」血泪坑):\n *\n * GET /api/skills/distill/status\n * → { stateFileExists, state, isBusy, currentRunId, lastRunId,\n * claudeCliAvailable, claudeCliPath, stubs[] }\n * state = { phase, cacheRoot, upstreamCommits{repo→commit},\n * completed[], skipped[], rejected[], lastRunAt, updatedAt,\n * pending[] }\n * GET /api/skills/distill/review\n * → { distilledFiles[{id,path,itScore,realDistillation}], pending[], state }\n * GET /api/skills/distill/review/:topicId/diff\n * → { topicId, filePath, distilledMarkdown, frontmatter{...}, upstreams[] }\n * frontmatter = { name, version, description, keywords[], rubric_version,\n * distilled_from[{upstream,license,commit,paths[]}],\n * distilled_at, distilled_by, it_universal_score(0-5),\n * it_universal_dims{d1..d5 各 0/0.5/1},\n * it_universal_rationale } ← spawn_agent 实测缺省(降级)\n * upstreams = [{ upstream, path, content|null }]\n *\n * 口径说明(重要,勿\"规整\"):\n * - 列表「决定」三态:\n * distilled = review.distilledFiles 有该 id(itScore≥3 蒸馏成 SKILL)\n * skipped = state.skipped[] 含该 topic(<3 分跳过,不出 distilled 文件)\n * rejected = state.rejected[] 含该 topic(body 含项目锚点 → ProjectAnchorRejection)\n * - it_universal_score 实测 0-5(一位小数,如 4.5);缺省 0。\n * - 5 维 d1..d5 各 0/0.5/1,合计 = it_universal_score(理论上限 5)。\n * - 上游源状态条:3 repo(obra-superpowers / anthropics-skills / affaan-m-ecc)\n * + multica-karpathy(skip);commit 来自 state.upstreamCommits(\"unknown\" 常见)。\n */\n\n// ─── endpoint response shapes (严格按真实 curl payload) ─────────────────────────\n\n/** GET /api/skills/distill/status 的 state 块(skills-distill-state.json)。 */\nexport interface DistillState {\n phase: 'idle' | 'running' | 'done' | 'error' | string\n cacheRoot?: string\n upstreamCommits?: Record<string, string>\n completed?: string[]\n skipped?: string[]\n rejected?: string[]\n lastRunAt?: string | null\n updatedAt?: string | null\n pending?: string[]\n}\n\n/** GET /api/skills/distill/status 的 stub 描述(spec 0930 stub 检测)。 */\nexport interface DistillStub {\n outputId?: string\n topicId?: string\n reason?: string\n bodyChars?: number\n}\n\n/** GET /api/skills/distill/status 完整响应。 */\nexport interface DistillStatusResp {\n stateFileExists?: boolean\n state?: DistillState | null\n isBusy?: boolean\n currentRunId?: string | null\n lastRunId?: string | null\n claudeCliAvailable?: boolean\n claudeCliPath?: string | null\n stubs?: DistillStub[]\n}\n\n/** GET /api/skills/distill/review 单条 distilled 文件。 */\nexport interface DistilledFile {\n id: string\n path: string\n itScore: number\n realDistillation: boolean\n}\n\n/** GET /api/skills/distill/review 完整响应。 */\nexport interface DistillReviewResp {\n distilledFiles?: DistilledFile[]\n pending?: unknown[]\n state?: DistillState | null\n}\n\n/** GET /api/skills/distill/review/:topicId/diff 的 distilled_from 单条。 */\nexport interface DistilledFromSource {\n upstream: string\n license?: string\n commit?: string\n paths?: string[]\n}\n\n/** 5 维评分块(各 0/0.5/1)。 */\nexport interface ItUniversalDims {\n d1?: number\n d2?: number\n d3?: number\n d4?: number\n d5?: number\n}\n\n/** GET /api/skills/distill/review/:topicId/diff 的 frontmatter。 */\nexport interface DistillFrontmatter {\n name?: string\n version?: string\n description?: string\n keywords?: string[]\n rubric_version?: number\n distilled_from?: DistilledFromSource[]\n distilled_at?: string\n distilled_by?: string\n it_universal_score?: number\n it_universal_dims?: ItUniversalDims\n it_universal_rationale?: string\n /** 实测缺省(部分早期文件没写);降级处理。 */\n spawn_agent?: string\n [k: string]: unknown\n}\n\n/** GET /api/skills/distill/review/:topicId/diff 的 upstream 内容单条。 */\nexport interface DistillUpstream {\n upstream: string\n path: string\n content: string | null\n}\n\n/** GET /api/skills/distill/review/:topicId/diff 完整响应。 */\nexport interface DistillDiffResp {\n topicId?: string\n filePath?: string\n distilledMarkdown?: string\n frontmatter?: DistillFrontmatter\n upstreams?: DistillUpstream[]\n}\n\n// ─── view models ─────────────────────────────────────────────────────────────\n\nexport type DistillDecision = 'distilled' | 'skipped' | 'rejected'\n\n/** 列表行(已蒸馏 / 跳过 / 锚点拒 统一行模型)。 */\nexport interface DistillRow {\n /** 列表 rowKey + 详情路由参数(distilled-xxx 或 topic 名)。 */\n id: string\n /** 三态决定。 */\n decision: DistillDecision\n /** it_universal_score(0-5,一位小数);skip/rejected 端点不出分 → null。 */\n score: number | null\n /** 主上游 repo 短名(distilled_from[0] 截短);列表只有 review 时为 null。 */\n upstreamRepo: string | null\n /** 主上游 commit 短哈希(≤7 位);unknown → null。 */\n upstreamCommit: string | null\n}\n\n/** 上游源状态条单条。 */\nexport interface UpstreamSourceStatus {\n key: string\n label: string\n /** 短哈希;unknown / 缺省 → null。 */\n commit: string | null\n /** karpathy 是 skip 源,UI 标注。 */\n isSkipSource: boolean\n}\n\nexport interface DistillListView {\n rows: DistillRow[]\n /** 上游源状态条(3 蒸馏源 + 1 skip 源)。 */\n upstreams: UpstreamSourceStatus[]\n cacheReady: boolean\n phase: string\n lastRunAt: string | null\n /** 三态计数(页头汇总)。 */\n distilledCount: number\n skippedCount: number\n rejectedCount: number\n}\n\n// ─── formatting helpers ──────────────────────────────────────────────────────\n\n/** 上游源 key → 中文/英文展示名(3 蒸馏源 + 1 skip 源)。 */\nconst UPSTREAM_LABELS: Record<string, string> = {\n 'obra-superpowers': 'obra/superpowers',\n 'anthropics-skills': 'anthropics/skills',\n 'affaan-m-ecc': 'affaan-m/ECC',\n 'multica-karpathy': 'multica/karpathy',\n}\n\nconst SKIP_SOURCE_KEYS = new Set(['multica-karpathy'])\n\n/** \"unknown\" / 空 / 非字符串 → null;否则截短到 7 位短哈希。 */\nexport function shortCommit(commit: string | null | undefined): string | null {\n if (!commit || typeof commit !== 'string') return null\n const c = commit.trim()\n if (!c || c === 'unknown') return null\n return c.slice(0, 7)\n}\n\n/**\n * distilled_from 第一条 upstream URL → 短 repo 名(owner/repo)。\n * 例:https://github.com/obra/superpowers.git → obra/superpowers。\n */\nexport function shortRepo(upstreamUrl: string | null | undefined): string | null {\n if (!upstreamUrl || typeof upstreamUrl !== 'string') return null\n const m = upstreamUrl.match(/github\\.com[/:]([^/]+\\/[^/]+?)(?:\\.git)?\\/?$/)\n if (m) return m[1]\n // 已是短名(如映射表里的值)直接返回\n return upstreamUrl.replace(/\\.git$/, '') || null\n}\n\n/** ISO ts → \"YYYY-MM-DD HH:mm\";缺省 → \"—\"。 */\nexport function formatIso(ts: string | null | undefined): string {\n if (!ts) return '—'\n const d = new Date(ts)\n if (Number.isNaN(d.getTime())) return '—'\n const pad = (n: number) => String(n).padStart(2, '0')\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`\n}\n\n/** decision → 中文标签 + Arco Tag color。 */\nexport function decisionMeta(\n d: DistillDecision,\n): { label: string; color: string; icon: 'check' | 'minus' | 'close' } {\n if (d === 'distilled') return { label: '蒸馏', color: 'green', icon: 'check' }\n if (d === 'skipped') return { label: '跳过', color: 'gray', icon: 'minus' }\n return { label: '锚点拒', color: 'red', icon: 'close' }\n}\n\n/** 5 维 key → 中文维度名(D1 多语言通用 … D5 知识浓度)。 */\nexport const DIM_LABELS: Array<{ key: keyof ItUniversalDims; label: string }> = [\n { key: 'd1', label: 'D1 多语言通用' },\n { key: 'd2', label: 'D2 工具链中立' },\n { key: 'd3', label: 'D3 流程独立' },\n { key: 'd4', label: 'D4 可移植' },\n { key: 'd5', label: 'D5 知识浓度' },\n]\n\n/** score(0-5) → \"N.N / 5\";null → \"—\"。 */\nexport function formatScore(score: number | null | undefined): string {\n if (score === null || score === undefined || !Number.isFinite(score)) return '—'\n return `${score.toFixed(1)} / 5`\n}\n\n// ─── list assembly ───────────────────────────────────────────────────────────\n\n/**\n * 装配蒸馏列表视图。以 review.distilledFiles 为「已蒸馏」主源(含 itScore),\n * 以 status.state.skipped / rejected 为另两态。上游源状态条来自\n * state.upstreamCommits(3 蒸馏源 + karpathy skip 源)。\n *\n * 列表层只有 review(无逐文件 frontmatter),故 upstreamRepo/Commit 在列表\n * 留 null(详情页才有 distilled_from);UI 列表「上游源」列改用顶部状态条统一展示。\n */\nexport function buildDistillListView(\n status: DistillStatusResp | undefined,\n review: DistillReviewResp | undefined,\n): DistillListView {\n const state = status?.state ?? review?.state ?? null\n\n const distilledRows: DistillRow[] = (review?.distilledFiles ?? []).map((f) => ({\n id: f.id,\n decision: 'distilled' as const,\n score: Number.isFinite(f.itScore) ? f.itScore : null,\n upstreamRepo: null,\n upstreamCommit: null,\n }))\n\n const skippedRows: DistillRow[] = (state?.skipped ?? []).map((t) => ({\n id: t,\n decision: 'skipped' as const,\n score: null,\n upstreamRepo: null,\n upstreamCommit: null,\n }))\n\n const rejectedRows: DistillRow[] = (state?.rejected ?? []).map((t) => ({\n id: t,\n decision: 'rejected' as const,\n score: null,\n upstreamRepo: null,\n upstreamCommit: null,\n }))\n\n // 排序:已蒸馏(按分降序)→ 跳过 → 锚点拒;同态内按 id 升序稳定。\n distilledRows.sort((a, b) => {\n const as = a.score ?? -1\n const bs = b.score ?? -1\n if (bs !== as) return bs - as\n return a.id.localeCompare(b.id)\n })\n skippedRows.sort((a, b) => a.id.localeCompare(b.id))\n rejectedRows.sort((a, b) => a.id.localeCompare(b.id))\n\n const rows = [...distilledRows, ...skippedRows, ...rejectedRows]\n\n // 上游源状态条:以 upstreamCommits key 为序;缺则用已知 4 源兜底。\n const commits = state?.upstreamCommits ?? {}\n const keys = Object.keys(commits).length > 0\n ? Object.keys(commits)\n : Object.keys(UPSTREAM_LABELS)\n const upstreams: UpstreamSourceStatus[] = keys.map((key) => ({\n key,\n label: UPSTREAM_LABELS[key] ?? key,\n commit: shortCommit(commits[key]),\n isSkipSource: SKIP_SOURCE_KEYS.has(key),\n }))\n\n return {\n rows,\n upstreams,\n cacheReady: !!status?.stateFileExists || !!state,\n phase: state?.phase ?? 'idle',\n lastRunAt: state?.lastRunAt ?? null,\n distilledCount: distilledRows.length,\n skippedCount: skippedRows.length,\n rejectedCount: rejectedRows.length,\n }\n}\n\n// ─── detail assembly ─────────────────────────────────────────────────────────\n\nexport interface DimBar {\n key: string\n label: string\n /** 0 / 0.5 / 1。 */\n value: number\n}\n\nexport interface UpstreamAttribution {\n /** 短 repo 名(owner/repo)。 */\n repo: string\n /** 完整 URL(用于 title / 链接)。 */\n url: string\n license: string | null\n commit: string | null\n paths: string[]\n}\n\nexport interface DistillDetailView {\n /** 路由参数(distilled-xxx 或 topic)。 */\n id: string\n /** frontmatter.name(封装 SKILL 名);缺省回退 id。 */\n name: string\n version: string | null\n description: string | null\n decision: DistillDecision\n score: number | null\n /** 5 维评分条。 */\n dims: DimBar[]\n rationale: string | null\n distilledBy: string | null\n distilledAt: string | null\n /** 实测缺省(spawn_agent 字段)。 */\n spawnAgent: string | null\n /** 上游归属(distilled_from 解析)。 */\n attributions: UpstreamAttribution[]\n /** SKILL 封装预览正文(distilledMarkdown)。 */\n body: string\n /** frontmatter 原文(用于「封装预览」frontmatter 块)。 */\n frontmatter: DistillFrontmatter\n /** 上游原文内容(review/diff 端点返回;可能为 null)。 */\n upstreams: DistillUpstream[]\n}\n\n/** distilled_from 单条 → 归属视图。 */\nexport function deriveAttribution(src: DistilledFromSource): UpstreamAttribution {\n return {\n repo: shortRepo(src.upstream) ?? src.upstream,\n url: src.upstream,\n license: src.license ?? null,\n commit: shortCommit(src.commit),\n paths: src.paths ?? [],\n }\n}\n\n/** frontmatter.it_universal_dims → 5 维评分条(缺维度补 0)。 */\nexport function deriveDims(dims: ItUniversalDims | undefined): DimBar[] {\n return DIM_LABELS.map(({ key, label }) => ({\n key,\n label,\n value: typeof dims?.[key] === 'number' ? (dims[key] as number) : 0,\n }))\n}\n\n/**\n * 装配蒸馏详情视图。主源是 review/diff 端点(含 frontmatter + distilledMarkdown +\n * upstreams)。decision 三态由 status.state(skipped/rejected 含该 topic)+ diff 是否\n * 存在共同判定:diff 端点只对「已蒸馏」文件存在,故拿到 diff → distilled;否则查\n * state.skipped / rejected。\n */\nexport function buildDistillDetailView(\n id: string,\n diff: DistillDiffResp | undefined,\n status: DistillStatusResp | undefined,\n): DistillDetailView | null {\n const state = status?.state ?? null\n // 归一化:剥 distilled- 前缀用于在 skipped/rejected(topic 名)里匹配。\n const bareTopic = id.replace(/^distilled-/, '')\n const inSkipped =\n (state?.skipped ?? []).includes(id) || (state?.skipped ?? []).includes(bareTopic)\n const inRejected =\n (state?.rejected ?? []).includes(id) || (state?.rejected ?? []).includes(bareTopic)\n\n const hasDiff = !!diff && (!!diff.frontmatter || !!diff.distilledMarkdown)\n\n let decision: DistillDecision\n if (hasDiff) decision = 'distilled'\n else if (inRejected) decision = 'rejected'\n else if (inSkipped) decision = 'skipped'\n else if (!diff) return null // 既无 diff 也不在 skip/reject → 无法渲染\n else decision = 'distilled'\n\n const fm = diff?.frontmatter ?? {}\n const score =\n typeof fm.it_universal_score === 'number' ? fm.it_universal_score : null\n\n return {\n id,\n name: fm.name ?? id,\n version: fm.version ?? null,\n description: fm.description ?? null,\n decision,\n score,\n dims: deriveDims(fm.it_universal_dims),\n rationale: fm.it_universal_rationale ?? null,\n distilledBy: fm.distilled_by ?? null,\n distilledAt: fm.distilled_at ?? null,\n spawnAgent: typeof fm.spawn_agent === 'string' ? fm.spawn_agent : null,\n attributions: (fm.distilled_from ?? []).map(deriveAttribution),\n body: diff?.distilledMarkdown ?? '',\n frontmatter: fm,\n upstreams: diff?.upstreams ?? [],\n }\n}\n\n/**\n * 把 frontmatter 还原成 YAML-ish 预览文本(封装预览的 frontmatter 块用)。\n * 非完整 YAML 序列化,只是给详情页「SKILL 封装预览」展示用的可读形式。\n */\nexport function frontmatterPreview(fm: DistillFrontmatter): string {\n const lines: string[] = []\n const push = (k: string, v: unknown) => {\n if (v === undefined || v === null) return\n lines.push(`${k}: ${typeof v === 'string' ? v : JSON.stringify(v)}`)\n }\n push('name', fm.name)\n push('version', fm.version)\n push('description', fm.description)\n if (fm.keywords && fm.keywords.length) push('keywords', fm.keywords)\n push('it_universal_score', fm.it_universal_score)\n if (fm.it_universal_dims) push('it_universal_dims', fm.it_universal_dims)\n push('distilled_by', fm.distilled_by)\n push('distilled_at', fm.distilled_at)\n return lines.join('\\n')\n}\n","/**\n * useDistill / useDistillDetail — 蒸馏列表 + 详情 (Phase 2e, decision 29688066) 取数 hook。\n *\n * 蒸馏是 Web-UI 专属只读视图(端点在 src/web/routes/skills-distill.ts,全部本地回环)。\n * 本轮只接只读端点(列表 + 详情静态部分),执行向导 `/ai/distill/run` 不在本轮:\n * GET /api/skills/distill/status → state(三态 + 上游 commit)\n * GET /api/skills/distill/review → distilledFiles[](含 itScore)\n * GET /api/skills/distill/review/:topicId/diff → 单文件 frontmatter + body + upstreams(仅详情)\n *\n * 蒸馏不随时间窗变化(state 文件快照),故不接 useTimeWindow。取数后交给\n * distill-derive.ts 纯函数装配视图模型;页面组件只渲染派生结果。\n */\nimport { useQuery } from '@tanstack/react-query'\n\nimport {\n buildDistillListView,\n buildDistillDetailView,\n type DistillStatusResp,\n type DistillReviewResp,\n type DistillDiffResp,\n type DistillListView,\n type DistillDetailView,\n} from './distill-derive'\n\nasync function fetchJson<T>(url: string): Promise<T> {\n const r = await fetch(url)\n if (!r.ok) throw new Error(`${url} → ${r.status}`)\n return r.json() as Promise<T>\n}\n\nconst fetchStatus = () =>\n fetchJson<DistillStatusResp>('/api/skills/distill/status')\nconst fetchReview = () =>\n fetchJson<DistillReviewResp>('/api/skills/distill/review')\nconst fetchDiff = (topicId: string) =>\n fetchJson<DistillDiffResp>(\n `/api/skills/distill/review/${encodeURIComponent(topicId)}/diff`,\n )\n\nexport interface DistillListResult {\n view: DistillListView\n loading: boolean\n isError: boolean\n error: Error | null\n refetch: () => void\n}\n\n/** 蒸馏列表取数 + 装配(status state + review distilledFiles)。 */\nexport function useDistill(): DistillListResult {\n const statusQ = useQuery({\n queryKey: ['distill-status'],\n queryFn: fetchStatus,\n refetchInterval: 60_000,\n refetchIntervalInBackground: false,\n })\n const reviewQ = useQuery({\n queryKey: ['distill-review'],\n queryFn: fetchReview,\n staleTime: 60_000,\n })\n\n const view = buildDistillListView(statusQ.data, reviewQ.data)\n\n // review 是 itScore 主源,status 是三态/上游条主源;任一失败都降级而非整页崩。\n const isError = statusQ.isError && reviewQ.isError\n return {\n view,\n loading: statusQ.isLoading || reviewQ.isLoading,\n isError,\n error: (statusQ.error as Error) ?? (reviewQ.error as Error) ?? null,\n refetch: () => {\n void statusQ.refetch()\n void reviewQ.refetch()\n },\n }\n}\n\nexport interface DistillDetailResult {\n view: DistillDetailView | null\n loading: boolean\n isError: boolean\n error: Error | null\n refetch: () => void\n}\n\n/** 蒸馏详情取数 + 装配(diff 端点 frontmatter + body + upstreams;status 定三态)。 */\nexport function useDistillDetail(topicId: string | undefined): DistillDetailResult {\n const diffQ = useQuery({\n queryKey: ['distill-diff', topicId],\n queryFn: () => fetchDiff(topicId!),\n enabled: !!topicId,\n staleTime: 5 * 60_000,\n // skip/rejected topic 无 distilled 文件 → diff 端点 404;不让它把整页打成 error,\n // 由 status.state 兜出 skip/rejected 形状。\n retry: false,\n })\n const statusQ = useQuery({\n queryKey: ['distill-status'],\n queryFn: fetchStatus,\n staleTime: 60_000,\n })\n\n const view = topicId\n ? buildDistillDetailView(topicId, diffQ.data, statusQ.data)\n : null\n\n // diff 404 但 status 已加载且能判定 skip/rejected → 不算 error(view 非 null)。\n const isError = !!topicId && diffQ.isError && view === null\n return {\n view,\n loading: diffQ.isLoading || statusQ.isLoading,\n isError,\n error: (diffQ.error as Error) ?? null,\n refetch: () => {\n void diffQ.refetch()\n void statusQ.refetch()\n },\n }\n}\n"],"names":["UPSTREAM_LABELS","SKIP_SOURCE_KEYS","shortCommit","commit","c","shortRepo","upstreamUrl","m","formatIso","ts","d","pad","n","decisionMeta","DIM_LABELS","formatScore","score","buildDistillListView","status","review","state","distilledRows","f","skippedRows","t","rejectedRows","a","b","as","bs","rows","commits","upstreams","key","deriveAttribution","src","deriveDims","dims","label","buildDistillDetailView","id","diff","bareTopic","inSkipped","inRejected","hasDiff","decision","fm","frontmatterPreview","lines","push","k","v","fetchJson","url","r","fetchStatus","fetchReview","fetchDiff","topicId","useDistill","statusQ","useQuery","reviewQ","view","isError","useDistillDetail","diffQ"],"mappings":"wCAqLA,MAAMA,EAA0C,CAC9C,mBAAoB,mBACpB,oBAAqB,oBACrB,eAAgB,eAChB,mBAAoB,kBACtB,EAEMC,EAAmB,IAAI,IAAI,CAAC,kBAAkB,CAAC,EAG9C,SAASC,EAAYC,EAAkD,CAC5E,GAAI,CAACA,GAAU,OAAOA,GAAW,SAAU,OAAO,KAClD,MAAMC,EAAID,EAAO,KAAA,EACjB,MAAI,CAACC,GAAKA,IAAM,UAAkB,KAC3BA,EAAE,MAAM,EAAG,CAAC,CACrB,CAMO,SAASC,EAAUC,EAAuD,CAC/E,GAAI,CAACA,GAAe,OAAOA,GAAgB,SAAU,OAAO,KAC5D,MAAMC,EAAID,EAAY,MAAM,8CAA8C,EAC1E,OAAIC,EAAUA,EAAE,CAAC,EAEVD,EAAY,QAAQ,SAAU,EAAE,GAAK,IAC9C,CAGO,SAASE,EAAUC,EAAuC,CAC/D,GAAI,CAACA,EAAI,MAAO,IAChB,MAAMC,EAAI,IAAI,KAAKD,CAAE,EACrB,GAAI,OAAO,MAAMC,EAAE,QAAA,CAAS,EAAG,MAAO,IACtC,MAAMC,EAAOC,GAAc,OAAOA,CAAC,EAAE,SAAS,EAAG,GAAG,EACpD,MAAO,GAAGF,EAAE,YAAA,CAAa,IAAIC,EAAID,EAAE,SAAA,EAAa,CAAC,CAAC,IAAIC,EAAID,EAAE,QAAA,CAAS,CAAC,IAAIC,EAAID,EAAE,SAAA,CAAU,CAAC,IAAIC,EAAID,EAAE,WAAA,CAAY,CAAC,EACpH,CAGO,SAASG,EACdH,EACqE,CACrE,OAAIA,IAAM,YAAoB,CAAE,MAAO,KAAM,MAAO,QAAS,KAAM,OAAA,EAC/DA,IAAM,UAAkB,CAAE,MAAO,KAAM,MAAO,OAAQ,KAAM,OAAA,EACzD,CAAE,MAAO,MAAO,MAAO,MAAO,KAAM,OAAA,CAC7C,CAGO,MAAMI,EAAmE,CAC9E,CAAE,IAAK,KAAM,MAAO,UAAA,EACpB,CAAE,IAAK,KAAM,MAAO,UAAA,EACpB,CAAE,IAAK,KAAM,MAAO,SAAA,EACpB,CAAE,IAAK,KAAM,MAAO,QAAA,EACpB,CAAE,IAAK,KAAM,MAAO,SAAA,CACtB,EAGO,SAASC,EAAYC,EAA0C,CACpE,OAAIA,GAAU,MAA+B,CAAC,OAAO,SAASA,CAAK,EAAU,IACtE,GAAGA,EAAM,QAAQ,CAAC,CAAC,MAC5B,CAYO,SAASC,EACdC,EACAC,EACiB,CACjB,MAAMC,GAAQF,GAAA,YAAAA,EAAQ,SAASC,GAAA,YAAAA,EAAQ,QAAS,KAE1CE,IAA+BF,GAAA,YAAAA,EAAQ,iBAAkB,CAAA,GAAI,IAAKG,IAAO,CAC7E,GAAIA,EAAE,GACN,SAAU,YACV,MAAO,OAAO,SAASA,EAAE,OAAO,EAAIA,EAAE,QAAU,KAChD,aAAc,KACd,eAAgB,IAAA,EAChB,EAEIC,IAA6BH,GAAA,YAAAA,EAAO,UAAW,CAAA,GAAI,IAAKI,IAAO,CACnE,GAAIA,EACJ,SAAU,UACV,MAAO,KACP,aAAc,KACd,eAAgB,IAAA,EAChB,EAEIC,IAA8BL,GAAA,YAAAA,EAAO,WAAY,CAAA,GAAI,IAAKI,IAAO,CACrE,GAAIA,EACJ,SAAU,WACV,MAAO,KACP,aAAc,KACd,eAAgB,IAAA,EAChB,EAGFH,EAAc,KAAK,CAACK,EAAGC,IAAM,CAC3B,MAAMC,EAAKF,EAAE,OAAS,GAChBG,EAAKF,EAAE,OAAS,GACtB,OAAIE,IAAOD,EAAWC,EAAKD,EACpBF,EAAE,GAAG,cAAcC,EAAE,EAAE,CAChC,CAAC,EACDJ,EAAY,KAAK,CAACG,EAAGC,IAAMD,EAAE,GAAG,cAAcC,EAAE,EAAE,CAAC,EACnDF,EAAa,KAAK,CAACC,EAAGC,IAAMD,EAAE,GAAG,cAAcC,EAAE,EAAE,CAAC,EAEpD,MAAMG,EAAO,CAAC,GAAGT,EAAe,GAAGE,EAAa,GAAGE,CAAY,EAGzDM,GAAUX,GAAA,YAAAA,EAAO,kBAAmB,CAAA,EAIpCY,GAHO,OAAO,KAAKD,CAAO,EAAE,OAAS,EACvC,OAAO,KAAKA,CAAO,EACnB,OAAO,KAAK/B,CAAe,GACgB,IAAKiC,IAAS,CAC3D,IAAAA,EACA,MAAOjC,EAAgBiC,CAAG,GAAKA,EAC/B,OAAQ/B,EAAY6B,EAAQE,CAAG,CAAC,EAChC,aAAchC,EAAiB,IAAIgC,CAAG,CAAA,EACtC,EAEF,MAAO,CACL,KAAAH,EACA,UAAAE,EACA,WAAY,CAAC,EAACd,GAAA,MAAAA,EAAQ,kBAAmB,CAAC,CAACE,EAC3C,OAAOA,GAAA,YAAAA,EAAO,QAAS,OACvB,WAAWA,GAAA,YAAAA,EAAO,YAAa,KAC/B,eAAgBC,EAAc,OAC9B,aAAcE,EAAY,OAC1B,cAAeE,EAAa,MAAA,CAEhC,CAgDO,SAASS,EAAkBC,EAA+C,CAC/E,MAAO,CACL,KAAM9B,EAAU8B,EAAI,QAAQ,GAAKA,EAAI,SACrC,IAAKA,EAAI,SACT,QAASA,EAAI,SAAW,KACxB,OAAQjC,EAAYiC,EAAI,MAAM,EAC9B,MAAOA,EAAI,OAAS,CAAA,CAAC,CAEzB,CAGO,SAASC,EAAWC,EAA6C,CACtE,OAAOvB,EAAW,IAAI,CAAC,CAAE,IAAAmB,EAAK,MAAAK,MAAa,CACzC,IAAAL,EACA,MAAAK,EACA,MAAO,OAAOD,GAAA,YAAAA,EAAOJ,KAAS,SAAYI,EAAKJ,CAAG,EAAe,CAAA,EACjE,CACJ,CAQO,SAASM,EACdC,EACAC,EACAvB,EAC0B,CAC1B,MAAME,GAAQF,GAAA,YAAAA,EAAQ,QAAS,KAEzBwB,EAAYF,EAAG,QAAQ,cAAe,EAAE,EACxCG,IACHvB,GAAA,YAAAA,EAAO,UAAW,CAAA,GAAI,SAASoB,CAAE,KAAMpB,GAAA,YAAAA,EAAO,UAAW,CAAA,GAAI,SAASsB,CAAS,EAC5EE,IACHxB,GAAA,YAAAA,EAAO,WAAY,CAAA,GAAI,SAASoB,CAAE,KAAMpB,GAAA,YAAAA,EAAO,WAAY,CAAA,GAAI,SAASsB,CAAS,EAE9EG,EAAU,CAAC,CAACJ,IAAS,CAAC,CAACA,EAAK,aAAe,CAAC,CAACA,EAAK,mBAExD,IAAIK,EACJ,GAAID,EAASC,EAAW,oBACfF,EAAYE,EAAW,mBACvBH,EAAWG,EAAW,kBACrBL,EACLK,EAAW,gBADA,QAAO,KAGvB,MAAMC,GAAKN,GAAA,YAAAA,EAAM,cAAe,CAAA,EAC1BzB,EACJ,OAAO+B,EAAG,oBAAuB,SAAWA,EAAG,mBAAqB,KAEtE,MAAO,CACL,GAAAP,EACA,KAAMO,EAAG,MAAQP,EACjB,QAASO,EAAG,SAAW,KACvB,YAAaA,EAAG,aAAe,KAC/B,SAAAD,EACA,MAAA9B,EACA,KAAMoB,EAAWW,EAAG,iBAAiB,EACrC,UAAWA,EAAG,wBAA0B,KACxC,YAAaA,EAAG,cAAgB,KAChC,YAAaA,EAAG,cAAgB,KAChC,WAAY,OAAOA,EAAG,aAAgB,SAAWA,EAAG,YAAc,KAClE,cAAeA,EAAG,gBAAkB,CAAA,GAAI,IAAIb,CAAiB,EAC7D,MAAMO,GAAA,YAAAA,EAAM,oBAAqB,GACjC,YAAaM,EACb,WAAWN,GAAA,YAAAA,EAAM,YAAa,CAAA,CAAC,CAEnC,CAMO,SAASO,EAAmBD,EAAgC,CACjE,MAAME,EAAkB,CAAA,EAClBC,EAAO,CAACC,EAAWC,IAAe,CACfA,GAAM,MAC7BH,EAAM,KAAK,GAAGE,CAAC,KAAK,OAAOC,GAAM,SAAWA,EAAI,KAAK,UAAUA,CAAC,CAAC,EAAE,CACrE,EACA,OAAAF,EAAK,OAAQH,EAAG,IAAI,EACpBG,EAAK,UAAWH,EAAG,OAAO,EAC1BG,EAAK,cAAeH,EAAG,WAAW,EAC9BA,EAAG,UAAYA,EAAG,SAAS,QAAQG,EAAK,WAAYH,EAAG,QAAQ,EACnEG,EAAK,qBAAsBH,EAAG,kBAAkB,EAC5CA,EAAG,mBAAmBG,EAAK,oBAAqBH,EAAG,iBAAiB,EACxEG,EAAK,eAAgBH,EAAG,YAAY,EACpCG,EAAK,eAAgBH,EAAG,YAAY,EAC7BE,EAAM,KAAK;AAAA,CAAI,CACxB,CC9aA,eAAeI,EAAaC,EAAyB,CACnD,MAAMC,EAAI,MAAM,MAAMD,CAAG,EACzB,GAAI,CAACC,EAAE,GAAI,MAAM,IAAI,MAAM,GAAGD,CAAG,MAAMC,EAAE,MAAM,EAAE,EACjD,OAAOA,EAAE,KAAA,CACX,CAEA,MAAMC,EAAc,IAClBH,EAA6B,4BAA4B,EACrDI,EAAc,IAClBJ,EAA6B,4BAA4B,EACrDK,EAAaC,GACjBN,EACE,8BAA8B,mBAAmBM,CAAO,CAAC,OAC3D,EAWK,SAASC,GAAgC,CAC9C,MAAMC,EAAUC,EAAS,CACvB,SAAU,CAAC,gBAAgB,EAC3B,QAASN,EACT,gBAAiB,IACjB,4BAA6B,EAAA,CAC9B,EACKO,EAAUD,EAAS,CACvB,SAAU,CAAC,gBAAgB,EAC3B,QAASL,EACT,UAAW,GAAA,CACZ,EAEKO,EAAO/C,EAAqB4C,EAAQ,KAAME,EAAQ,IAAI,EAGtDE,EAAUJ,EAAQ,SAAWE,EAAQ,QAC3C,MAAO,CACL,KAAAC,EACA,QAASH,EAAQ,WAAaE,EAAQ,UACtC,QAAAE,EACA,MAAQJ,EAAQ,OAAoBE,EAAQ,OAAmB,KAC/D,QAAS,IAAM,CACRF,EAAQ,QAAA,EACRE,EAAQ,QAAA,CACf,CAAA,CAEJ,CAWO,SAASG,EAAiBP,EAAkD,CACjF,MAAMQ,EAAQL,EAAS,CACrB,SAAU,CAAC,eAAgBH,CAAO,EAClC,QAAS,IAAMD,EAAUC,CAAQ,EACjC,QAAS,CAAC,CAACA,EACX,UAAW,IAGX,MAAO,EAAA,CACR,EACKE,EAAUC,EAAS,CACvB,SAAU,CAAC,gBAAgB,EAC3B,QAASN,EACT,UAAW,GAAA,CACZ,EAEKQ,EAAOL,EACTpB,EAAuBoB,EAASQ,EAAM,KAAMN,EAAQ,IAAI,EACxD,KAGEI,EAAU,CAAC,CAACN,GAAWQ,EAAM,SAAWH,IAAS,KACvD,MAAO,CACL,KAAAA,EACA,QAASG,EAAM,WAAaN,EAAQ,UACpC,QAAAI,EACA,MAAQE,EAAM,OAAmB,KACjC,QAAS,IAAM,CACRA,EAAM,QAAA,EACNN,EAAQ,QAAA,CACf,CAAA,CAEJ"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{u as s}from"./query-CgCOpYWf.js";import{a as o,A as c,r as a,l as u,k as n}from"./index-DileOOE4.js";function j(){const{project:e}=o(),{data:r}=s({queryKey:n(),queryFn:u,staleTime:3e4}),t=(r==null?void 0:r.current)??"";return{project:a(e,t),isAllProjects:e===c,selection:e,daemonCurrent:t}}export{j as u};
|
|
2
|
+
//# sourceMappingURL=useEffectiveProject-DQiyX54y.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useEffectiveProject-DQiyX54y.js","sources":["../../src/hooks/useEffectiveProject.ts"],"sourcesContent":["/**\n * useEffectiveProject — shared resolver for the global project selection\n * (decision dd79010a, building on decision 39839e30).\n *\n * Every per-project AI-resource hook (useKbHits / useSkillStats / useAgentStats\n * / useAgentHealth) needs the same three things the Workplace / TasksHub pages\n * already inline:\n * 1. the raw selection from `useProject()` (ProjectContext / localStorage),\n * 2. the daemon-current project (from `/api/knowledge/projects`), and\n * 3. `resolveEffectiveProject(selection, current)` → the actual `?project=`\n * value the backend filter receives.\n *\n * Centralising it here avoids re-deriving the same `kbProjects` query + resolve\n * logic in four hooks (and keeps the all-projects / default-scoped semantics\n * from drifting). Returns the effective path to append plus the `isAllProjects`\n * flag the global-vs-project hint banner reads.\n */\nimport { useQuery } from '@tanstack/react-query'\n\nimport { useProject } from '../lib/project'\nimport { resolveEffectiveProject } from '../lib/project-resolve'\nimport { kbProjectsKey, ALL_PROJECTS } from '../utils/kbProject'\nimport { listKbProjects } from '../utils/kbApi'\n\nexport interface EffectiveProject {\n /**\n * The value to pass to `appendProject(url, project)`. '' = no filter (the\n * explicit 全部项目 view OR an empty daemon-current fallback).\n */\n project: string\n /** True when the user explicitly chose the all-projects view. */\n isAllProjects: boolean\n /** The raw stored selection ('' = default scoped-to-current). */\n selection: string\n /** The daemon-current project path ('' until the projects query resolves). */\n daemonCurrent: string\n}\n\n/** Resolve the effective `?project=` filter for the current global selection. */\nexport function useEffectiveProject(): EffectiveProject {\n const { project: selection } = useProject()\n const { data: kbProjects } = useQuery({\n queryKey: kbProjectsKey(),\n queryFn: listKbProjects,\n staleTime: 30_000,\n })\n const daemonCurrent = kbProjects?.current ?? ''\n return {\n project: resolveEffectiveProject(selection, daemonCurrent),\n isAllProjects: selection === ALL_PROJECTS,\n selection,\n daemonCurrent,\n }\n}\n"],"names":["useEffectiveProject","selection","useProject","kbProjects","useQuery","kbProjectsKey","listKbProjects","daemonCurrent","resolveEffectiveProject","ALL_PROJECTS"],"mappings":"4GAuCO,SAASA,GAAwC,CACtD,KAAM,CAAE,QAASC,CAAA,EAAcC,EAAA,EACzB,CAAE,KAAMC,CAAA,EAAeC,EAAS,CACpC,SAAUC,EAAA,EACV,QAASC,EACT,UAAW,GAAA,CACZ,EACKC,GAAgBJ,GAAA,YAAAA,EAAY,UAAW,GAC7C,MAAO,CACL,QAASK,EAAwBP,EAAWM,CAAa,EACzD,cAAeN,IAAcQ,EAC7B,UAAAR,EACA,cAAAM,CAAA,CAEJ"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{u as f}from"./query-CgCOpYWf.js";import{u as h}from"./index-DileOOE4.js";const m=200,g=25;async function $(e,t=m,r=g){const i=[];let s=0,n=0,o=!1;for(;;){const a=await e(s);n+=1;const u=Array.isArray(a==null?void 0:a.items)?a.items:[];for(const d of u)d.outcome==="failed"&&i.push(d);if(u.length===0||(a==null?void 0:a.has_more)!==!0)break;if(n>=r){o=!0;break}s+=u.length||t}return{failed:i,truncated:o,pagesScanned:n}}function E(e){const t=(e||"").match(/^(\w+)\s+blocked by\s+([A-Za-z0-9_.-]+)/i);return t?{action:t[1],rule:t[2]}:{action:null,rule:null}}function v(e){return e?/-hard$/.test(e)||/skip-decision/.test(e)?"high":/grep|search|find/.test(e)?"low":"mid":"mid"}function w(e){return e==="failed"?"high":"mid"}function k(){return"high"}const I={high:"高",mid:"中",low:"低"};function R(e){return I[e]??e}function M(e){return e==="high"?"red":e==="mid"?"orange":"gray"}const A={intercept:"拦截",violation:"违规",failure:"失败",drift:"漂移"};function Q(e){return A[e]??e}function U(e){switch(e){case"intercept":return"red";case"violation":return"orange";case"failure":return"red";case"drift":return"gold";default:return"gray"}}function b(e){return(e||"").toLowerCase().replace(/[^a-z0-9一-龥]+/g,"-").replace(/^-+|-+$/g,"")||"x"}function c(e){if(!e)return 0;const t=Date.parse(e);return Number.isFinite(t)?Math.floor(t/1e3):0}function V(e){if(!e)return"—";const t=e.replace("T"," "),r=t.match(/^\d{4}-(\d{2}-\d{2})[ ](\d{2}:\d{2})/);return r?`${r[1]} ${r[2]}`:t.slice(0,16)}function p(e,t){return t==="failure"?"复盘失败任务的执行链路;疑难全链路故障走 harness-debug-full(会解压 gzip event、核 DB 列类型)。已记 issue 待重做。":e?/-multi-file-hard$/.test(e)?"改用 Task tool spawn subagent_type='coder' 或 'safety-net-implementer',把后续改动委托给 sub-agent;主线程只协调与汇总。如确认需继续,可在命令末尾加 skip decision 走 bypass。":/grep|search|find/.test(e)?"spawn Explore agent(subagent_type='Explore')承接跨文件查找;单文件已知路径用 Read 工具。":/git-log-diff/.test(e)?"二选一:1) spawn Explore agent 做跨文件查找;2) 若确为元任务(commit / staged 核对),git diff 带 `-- <file>` 限定路径。":/skip-decision/.test(e)?"任何 substantive Edit/Write 前必须先 spawn decision-maker(不依赖 daemon hint 是否触发);或末尾加 skip decision bypass。":`回顾规则 ${e} 的拦截意图;按 CLAUDE.md 委托协议改走对应 agent,或确为例外时 bypass。`:"回顾 CLAUDE.md「DECISION HINT 协议契约」四步链路;纯确认 / 元任务 / 单文件已知路径 Read 除外,或末尾加 skip decision bypass。"}function y(e,t,r){if(r==="failure")return"verify-agent verdict FAIL:实施结果未通过验证门(commit 前硬门)。失败根因见任务详情的执行链路与 outcome_reason。";const i=t||"该动作";return e?/-multi-file-hard$/.test(e)?`${i} 在单 session 内触及过多文件(硬阈值 3)。CLAUDE.md「自检 #1」要求跨多文件实施必须 spawn agent,主线程不直接批量改。`:/git-log-diff/.test(e)?"git log / git diff 未带 `-- <file>` 限定,多半是探索性查询。主线程是纯编排者,跨文件查代码应委托 Explore。":/grep|search|find/.test(e)?"主线程禁止 Bash grep/find 查代码(应走 Explore)。skill 不替代 agent。":`${i} 命中规则 ${e}(deny/warn 拦截)。端点未返回该规则的命中阈值,规则名见下方概要。`:`${i} 触发了治理信号(来源 user_keyword / routing 未遵从)。端点未返回结构化规则阈值,规则名见下方概要。`}function L(e){const{action:t,rule:r}=E(e.summary),i=e.signal==="tool_intercept",s=i?"intercept":"violation",n=r||e.detectedKeyword||(i?"(未知规则)":"(治理信号)"),o=e.signal==="user_keyword"?"mid":v(r);return{id:`viol-${e.signal}-${c(e.timestamp)}`,type:s,severity:o,title:e.summary||(i?"工具拦截":"合规违规"),rule:n,action:t||(i?"工具":e.expectedAgent?"spawn":"—"),source:"violations",time:e.timestamp,session:null,what:e.summary||"(端点未返回命令原文,仅摘要)",why:y(r,t,s),hint:p(r,s),relatedTaskId:null}}function _(e){const t=e.outcome_reason||e.first_prompt||e.title||"(无摘要)";return{id:`fail-${e.id}`,type:"failure",severity:w(e.outcome),title:`任务失败 · ${e.title||"(无标题)"}`,rule:"verify-agent FAIL",action:"verify",source:"tasks",time:e.end_time||e.start_time,session:e.session_id||null,what:`任务「${e.title||"(无标题)"}」outcome=${e.outcome??"—"}。${t}`,why:y("verify-agent FAIL","verify","failure"),hint:p("verify-agent FAIL","failure"),relatedTaskId:e.id}}function F(e,t){return{id:`drift-${b(e.rule)}`,type:"drift",severity:k(),title:`漂移 · ${e.rule}`,rule:e.rule,action:"drift",source:"drift",time:t||"",session:null,what:`实测 ${e.actual}(期望 ${e.expected})`,why:`合规漂移:${e.rule} 实测「${e.actual}」未达声明「${e.expected}」。CLAUDE.md 声明行为与事件流实测出现偏离。`,hint:"核对该规则的声明阈值与实际运行数据,定位漂移来源(采纳率 / 委托率 / 记录连续性等),必要时调整阈值或补齐链路。",relatedTaskId:null}}function T(e,t,r){var s;const i=[];if(e&&Array.isArray(e.violations))for(const n of e.violations)i.push(L(n));if(t&&Array.isArray(t.items))for(const n of t.items)n.outcome==="failed"&&i.push(_(n));if(r&&Array.isArray(r.checks)){const n=((s=r.period)==null?void 0:s.since)??null;for(const o of r.checks)o.status==="fail"&&i.push(F(o,n))}return i.sort((n,o)=>{const a=c(n.time),u=c(o.time);return a!==u?u-a:n.id<o.id?1:n.id>o.id?-1:0}),i}function z(e){const t=[],r=[];for(const i of e)i.type==="drift"?r.push(i):t.push(i);return{primary:t,drift:r}}function N(e,t){return t?e.find(r=>r.id===t)??null:null}function P(e,t){return t.type==="intercept"||t.type==="violation"?e.filter(r=>(r.type==="intercept"||r.type==="violation")&&r.rule===t.rule).length:e.filter(r=>r.type===t.type).length}function W(e){const t={total:e.length,intercept:0,violation:0,failure:0,drift:0};for(const r of e)t[r.type]+=1;return t}async function l(e){const t=await fetch(e);if(!t.ok)throw new Error(`${e} → ${t.status}`);return t.json()}function D(e){return Math.min(e,30)}const S=100,x=e=>l(`/api/violations?days=${D(e)}&limit=${S}`),C=e=>$(t=>l(`/api/tasks?window=${e}&limit=${m}&offset=${t}`)),q=e=>l(`/api/drift/report?days=${e}`);function G(){const{window:e}=h(),t=f({queryKey:["issues-violations",e],queryFn:()=>x(e),refetchInterval:6e4,refetchIntervalInBackground:!1}),r=f({queryKey:["issues-failed-tasks",e],queryFn:()=>C(e),staleTime:6e4}),i=f({queryKey:["issues-drift",e],queryFn:()=>q(e),staleTime:6e4,retry:1}),s=r.isError?void 0:r.data,n=s?{items:s.failed}:void 0;return{issues:T(t.isError?void 0:t.data,n,i.isError?void 0:i.data),violationsError:t.isError,tasksError:r.isError,driftError:i.isError,tasksTruncated:(s==null?void 0:s.truncated)??!1,loading:t.isLoading||r.isLoading,isError:t.isError&&r.isError&&i.isError,error:t.error??r.error??null,refetch:()=>{t.refetch(),r.refetch(),i.refetch()}}}export{U as a,W as b,R as c,M as d,N as e,V as f,P as g,z as s,Q as t,G as u};
|
|
2
|
+
//# sourceMappingURL=useIssuesFeed-CFiyQkAL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useIssuesFeed-CFiyQkAL.js","sources":["../../src/hooks/issues-derive.ts","../../src/hooks/useIssuesFeed.ts"],"sourcesContent":["/**\n * issues-derive — 治理 · 问题(治理)列表/详情 (Phase 3b, decision 29688066) 纯派生层。\n *\n * 项目前端单测跑在 environment:'node'(无 jsdom / RTL),故所有「端点响应 → 视图\n * 模型」的计算都抽进本纯函数模块,页面组件只渲染派生结果。本 Phase 重点是**前端\n * merge 三源、归一成统一 Issue 形状 + 稳定 id**(做成纯函数好单测)。\n *\n * ── 三源真实形状(已 curl 真实 payload 对字段,2026-06-12)─────────────────────\n *\n * 1. 违规拦截 GET /api/violations?days=&limit=&offset=\n * → { generatedAt, windowDays, limit, offset, count, total_in_window,\n * total_by_signal_in_window:{routing_disobeyed,user_keyword,tool_intercept},\n * violations:[{ timestamp, summary, signal, detectedKeyword, expectedAgent,\n * relativeTime }] }\n * 关键事实:toApi() **只暴露** timestamp/summary/signal/detectedKeyword/\n * expectedAgent/relativeTime —— **不返回** rule_id / tool_name / severity /\n * note(hint) / command 原文。规则名只能从 summary 解析(形如\n * \"Bash blocked by bash-grep-multi-file\" / \"Edit blocked by edit-multi-file-hard\")。\n * 被拦命令原文 / hint **端点未返回 → 降级**(详情 ① 用 summary 兜底、③ 用\n * 规则启发文案)。\n *\n * 2. 失败任务 GET /api/tasks?limit=(**注意:端点不认 ?status= 过滤**,只认\n * limit/offset/project/from/to/search/session/window/include_kinds)\n * → { items:[{ id, session_id, title, start_time, end_time, status,\n * event_count, project_path, first_prompt, outcome, outcome_reason,\n * commit_count, ... }], total, has_more }\n * failure 源 = items 里 outcome==='failed' 的行(前端 filter,端点无 status 过滤)。\n *\n * 3. drift GET /api/drift/report?days=\n * → { generatedAt, period:{days,since}, checks:[{ rule, expected, actual,\n * status:'pass'|'fail' }], overallScore }\n * drift 源 = checks 里 status==='fail' 的行(漂移项)。**端点存在**(curl 确认)。\n *\n * ── 归一(统一 Issue 形状 + 稳定 id)─────────────────────────────────────────\n * 三源各映射成 Issue,id 带源前缀保证跨源唯一 + 稳定(同一条多次拉取 id 不变):\n * - 违规拦截:id = `viol-<signal>-<epochSec>`(signal+秒级时间戳,足够区分一窗内的条)\n * - 失败任务:id = `fail-<taskId>`(任务 id 天然稳定唯一)\n * - drift :id = `drift-<slug(rule)>`(规则名 slug,一份报告内规则名唯一)\n */\n\n// ─── endpoint response shapes(严格按 curl 真实字段名)────────────────────────\n\nexport type ViolationSignal = 'routing_disobeyed' | 'user_keyword' | 'tool_intercept'\n\n/** /api/violations 的 violations[] 元素(toApi 暴露的全部字段)。 */\nexport interface ApiViolation {\n timestamp: string\n summary: string\n signal: ViolationSignal | string\n detectedKeyword: string | null\n expectedAgent: string | null\n relativeTime: string\n}\n\nexport interface ViolationsResp {\n generatedAt?: string\n windowDays?: number\n total_in_window?: number\n total_by_signal_in_window?: {\n routing_disobeyed: number\n user_keyword: number\n tool_intercept: number\n }\n violations?: ApiViolation[]\n}\n\n/** /api/tasks 的 items[] 元素(仅声明本页用到的字段)。 */\nexport interface ApiTask {\n id: string\n session_id: string\n title: string\n start_time: string\n end_time: string | null\n status: string\n project_path: string\n first_prompt?: string | null\n outcome: string | null\n outcome_reason: string | null\n event_count?: number\n commit_count?: number\n}\n\nexport interface TasksResp {\n items?: ApiTask[]\n total?: number\n has_more?: boolean\n}\n\n/** /api/drift/report 的 checks[] 元素。 */\nexport interface DriftCheck {\n rule: string\n expected: string\n actual: string\n status: 'pass' | 'fail' | string\n}\n\nexport interface DriftResp {\n generatedAt?: string\n period?: { days: number; since: string }\n checks?: DriftCheck[]\n overallScore?: number\n}\n\n// ─── failed-tasks pagination drain(offset 分页拉全当前窗 + 安全上限)──────────\n\n/**\n * /api/tasks 真实分页(已 curl + 核 src/web/routes/tasks.ts 2026-06-12 确认):\n * - 参数名为 `offset`(非 cursor/page),`limit` 被 zod clamp 到 max 200;\n * - 排序新→旧;返回 { items, total, has_more },\n * has_more = offset + items.length < total;\n * - 端点不认 ?status= 过滤 → 失败任务只能前端 filter outcome==='failed'。\n *\n * 因此「只拉一页 limit=200 再 filter」会在窗口内任务数 > 200 时**静默丢掉**第 200\n * 名之后的失败任务(live 30d 窗口 total 已 >400)。本函数按 offset 分页 drain 当前\n * 窗的全部 items 直到 has_more===false,再 filter 失败;命中安全上限则置 truncated\n * 标志(诚实降级,UI 明示「可能少报」),不假装拉全。\n */\nexport const TASKS_PAGE_SIZE = 200 // 端点 limit 上限(zod clamp max 200)\nexport const TASKS_MAX_PAGES = 25 // 安全上限:最多 25 页 = 5000 条 / 窗,防极端窗口拉爆\n\nexport interface DrainFailedResult {\n /** 拉全(或到安全上限为止)后 filter outcome==='failed' 的任务行。 */\n failed: ApiTask[]\n /** 命中安全上限提前停止(窗口内任务数超出扫描范围)→ 失败列表可能少报。 */\n truncated: boolean\n /** 实际扫描过的页数(诊断用)。 */\n pagesScanned: number\n}\n\n/**\n * 分页 drain 当前时间窗的失败任务(纯逻辑,fetch 由调用方注入便于单测)。\n *\n * @param fetchPage 给定 offset 拉一页 → Promise<TasksResp>(调用方绑定 window/limit)。\n * @param pageSize 每页条数(默认 TASKS_PAGE_SIZE,即端点上限 200)。\n * @param maxPages 安全上限页数(默认 TASKS_MAX_PAGES)。命中即停并置 truncated。\n *\n * 终止条件:has_more===false(拉全) 或 达到 maxPages(truncated) 或 某页空 items。\n */\nexport async function drainFailedTasks(\n fetchPage: (offset: number) => Promise<TasksResp>,\n pageSize: number = TASKS_PAGE_SIZE,\n maxPages: number = TASKS_MAX_PAGES,\n): Promise<DrainFailedResult> {\n const failed: ApiTask[] = []\n let offset = 0\n let pagesScanned = 0\n let truncated = false\n\n for (;;) {\n const resp = await fetchPage(offset)\n pagesScanned += 1\n const items = Array.isArray(resp?.items) ? resp.items : []\n for (const t of items) {\n if (t.outcome === 'failed') failed.push(t)\n }\n // 空页 / 端点已无更多 → 拉全,正常结束\n if (items.length === 0 || resp?.has_more !== true) break\n // 命中安全上限 → 诚实降级(仍有更多但停止扫描),标 truncated\n if (pagesScanned >= maxPages) {\n truncated = true\n break\n }\n offset += items.length || pageSize\n }\n\n return { failed, truncated, pagesScanned }\n}\n\n// ─── unified view model ───────────────────────────────────────────────────────\n\nexport type IssueType = 'intercept' | 'violation' | 'failure' | 'drift'\nexport type IssueSeverity = 'high' | 'mid' | 'low'\n\n/** 统一 Issue 形状(三源归一)。 */\nexport interface Issue {\n /** 稳定且跨源唯一的 id(带 viol-/fail-/drift- 前缀)。 */\n id: string\n type: IssueType\n severity: IssueSeverity\n /** 列表展示标题(规则名拦截语 / 任务标题 / 漂移规则名)。 */\n title: string\n /** 规则名(拦截/违规:解析自 summary;漂移:drift check.rule;失败:'verify-agent FAIL' 兜底)。 */\n rule: string\n /** 触发动作(Bash/Edit/Write/...;失败=verify;漂移=drift)。 */\n action: string\n /** 来源端点标签(violations / tasks / drift)。 */\n source: 'violations' | 'tasks' | 'drift'\n /** 排序/显示用 ISO 时间戳(漂移用报告 since 兜底)。 */\n time: string\n /** session id(拦截/失败有;漂移无 → null)。 */\n session: string | null\n /** ① 发生了什么:被拦命令原文 / 失败摘要 / 漂移 actual——端点缺命令原文则用 summary 兜底。 */\n what: string\n /** ② 为什么:规则说明 + 命中阈值(端点无结构化 → 启发式文案 / 漂移 expected)。 */\n why: string\n /** ③ 建议怎么做:hint(端点未返回 → 规则启发文案 / 漂移空降级)。 */\n hint: string\n /** 关联任务 id(失败源天然有;其余 null)。 */\n relatedTaskId: string | null\n}\n\n// ─── helpers ─────────────────────────────────────────────────────────────────\n\n/**\n * 从 violation.summary 解析「动作 + 规则名」。\n * 真实形如 \"Bash blocked by bash-grep-multi-file\" / \"Edit blocked by edit-multi-file-hard\"\n * / \"Write blocked by write-multi-file-hard\"。无 \"blocked by\" 形态(user_keyword 信号)\n * → action 用空、rule 用 detectedKeyword 兜底(在 buildIssueFromViolation 处理)。\n */\nexport function parseInterceptSummary(summary: string): { action: string | null; rule: string | null } {\n const m = (summary || '').match(/^(\\w+)\\s+blocked by\\s+([A-Za-z0-9_.-]+)/i)\n if (m) return { action: m[1], rule: m[2] }\n return { action: null, rule: null }\n}\n\n/**\n * 规则名 → 严重度。deny 类硬拦(*-hard / skip-decision-maker)= high;\n * 其余拦截 = mid;user_keyword 信号(无规则)= mid;探索性 grep/git = low 兜底\n * 由调用方按 signal 决定。这里只按规则名启发。\n */\nexport function severityForRule(rule: string | null): IssueSeverity {\n if (!rule) return 'mid'\n if (/-hard$/.test(rule) || /skip-decision/.test(rule)) return 'high'\n if (/grep|search|find/.test(rule)) return 'low'\n return 'mid'\n}\n\n/** 失败任务 outcome → 严重度(failed=high;其余兜底 mid)。 */\nexport function severityForFailure(outcome: string | null): IssueSeverity {\n return outcome === 'failed' ? 'high' : 'mid'\n}\n\n/** drift check → 严重度:fail 一律 high(漂移即偏离声明)。 */\nexport function severityForDrift(): IssueSeverity {\n return 'high'\n}\n\nconst SEV_LABEL: Record<IssueSeverity, string> = { high: '高', mid: '中', low: '低' }\nexport function severityLabel(s: IssueSeverity): string {\n return SEV_LABEL[s] ?? s\n}\nexport function severityColor(s: IssueSeverity): string {\n return s === 'high' ? 'red' : s === 'mid' ? 'orange' : 'gray'\n}\n\nconst TYPE_LABEL: Record<IssueType, string> = {\n intercept: '拦截',\n violation: '违规',\n failure: '失败',\n drift: '漂移',\n}\nexport function typeLabel(t: IssueType): string {\n return TYPE_LABEL[t] ?? t\n}\nexport function typeColor(t: IssueType): string {\n switch (t) {\n case 'intercept':\n return 'red'\n case 'violation':\n return 'orange'\n case 'failure':\n return 'red'\n case 'drift':\n return 'gold'\n default:\n return 'gray'\n }\n}\n\n/** 规则名 → slug(drift id 用,去非字母数字、转小写)。 */\nexport function slugify(s: string): string {\n return (s || '')\n .toLowerCase()\n .replace(/[^a-z0-9一-龥]+/g, '-')\n .replace(/^-+|-+$/g, '')\n || 'x'\n}\n\n/** ISO/epoch → 秒级整数(稳定 id 用,避免毫秒抖动)。 */\nfunction epochSec(iso: string | null | undefined): number {\n if (!iso) return 0\n const t = Date.parse(iso)\n return Number.isFinite(t) ? Math.floor(t / 1000) : 0\n}\n\n/** ISO-TEXT → 紧凑 \"MM-DD HH:mm\"(与 decisions/kb 派生一致口径)。 */\nexport function fmtTime(iso: string | null | undefined): string {\n if (!iso) return '—'\n const s = iso.replace('T', ' ')\n const m = s.match(/^\\d{4}-(\\d{2}-\\d{2})[ ](\\d{2}:\\d{2})/)\n if (m) return `${m[1]} ${m[2]}`\n return s.slice(0, 16)\n}\n\n// ─── per-source builders ──────────────────────────────────────────────────────\n\n/** 规则启发式 hint(端点不返回 hint,按规则名给可操作建议;未知规则 → 通用降级文案)。 */\nfunction heuristicHint(rule: string | null, type: IssueType): string {\n if (type === 'failure') {\n return '复盘失败任务的执行链路;疑难全链路故障走 harness-debug-full(会解压 gzip event、核 DB 列类型)。已记 issue 待重做。'\n }\n if (!rule) {\n return '回顾 CLAUDE.md「DECISION HINT 协议契约」四步链路;纯确认 / 元任务 / 单文件已知路径 Read 除外,或末尾加 skip decision bypass。'\n }\n if (/-multi-file-hard$/.test(rule)) {\n return \"改用 Task tool spawn subagent_type='coder' 或 'safety-net-implementer',把后续改动委托给 sub-agent;主线程只协调与汇总。如确认需继续,可在命令末尾加 skip decision 走 bypass。\"\n }\n if (/grep|search|find/.test(rule)) {\n return \"spawn Explore agent(subagent_type='Explore')承接跨文件查找;单文件已知路径用 Read 工具。\"\n }\n if (/git-log-diff/.test(rule)) {\n return '二选一:1) spawn Explore agent 做跨文件查找;2) 若确为元任务(commit / staged 核对),git diff 带 `-- <file>` 限定路径。'\n }\n if (/skip-decision/.test(rule)) {\n return '任何 substantive Edit/Write 前必须先 spawn decision-maker(不依赖 daemon hint 是否触发);或末尾加 skip decision bypass。'\n }\n return `回顾规则 ${rule} 的拦截意图;按 CLAUDE.md 委托协议改走对应 agent,或确为例外时 bypass。`\n}\n\n/** 规则启发式 why(端点无结构化阈值,summary 已含规则名;这里给规则用途解释)。 */\nfunction heuristicWhy(rule: string | null, action: string | null, type: IssueType): string {\n if (type === 'failure') {\n return 'verify-agent verdict FAIL:实施结果未通过验证门(commit 前硬门)。失败根因见任务详情的执行链路与 outcome_reason。'\n }\n const act = action || '该动作'\n if (!rule) {\n return `${act} 触发了治理信号(来源 user_keyword / routing 未遵从)。端点未返回结构化规则阈值,规则名见下方概要。`\n }\n if (/-multi-file-hard$/.test(rule)) {\n return `${act} 在单 session 内触及过多文件(硬阈值 3)。CLAUDE.md「自检 #1」要求跨多文件实施必须 spawn agent,主线程不直接批量改。`\n }\n if (/git-log-diff/.test(rule)) {\n return 'git log / git diff 未带 `-- <file>` 限定,多半是探索性查询。主线程是纯编排者,跨文件查代码应委托 Explore。'\n }\n if (/grep|search|find/.test(rule)) {\n return '主线程禁止 Bash grep/find 查代码(应走 Explore)。skill 不替代 agent。'\n }\n return `${act} 命中规则 ${rule}(deny/warn 拦截)。端点未返回该规则的命中阈值,规则名见下方概要。`\n}\n\n/**\n * 单条 violation → Issue。intercept(tool_intercept 信号) vs violation(其它信号)\n * 由 signal 区分。规则名解析自 summary;command 原文端点未返回 → what 用 summary。\n */\nexport function buildIssueFromViolation(v: ApiViolation): Issue {\n const { action, rule } = parseInterceptSummary(v.summary)\n const isIntercept = v.signal === 'tool_intercept'\n const type: IssueType = isIntercept ? 'intercept' : 'violation'\n const effRule = rule || v.detectedKeyword || (isIntercept ? '(未知规则)' : '(治理信号)')\n // signal=user_keyword 探索性 → low;否则按规则名启发\n const severity: IssueSeverity =\n v.signal === 'user_keyword' ? 'mid' : severityForRule(rule)\n return {\n id: `viol-${v.signal}-${epochSec(v.timestamp)}`,\n type,\n severity,\n title: v.summary || (isIntercept ? '工具拦截' : '合规违规'),\n rule: effRule,\n action: action || (isIntercept ? '工具' : v.expectedAgent ? 'spawn' : '—'),\n source: 'violations',\n time: v.timestamp,\n session: null, // 端点未返回 session_id → 降级 null\n // ① 端点未返回被拦命令原文 → 用 summary 兜底(标注为摘要而非原文)\n what: v.summary || '(端点未返回命令原文,仅摘要)',\n why: heuristicWhy(rule, action, type),\n hint: heuristicHint(rule, type),\n relatedTaskId: null,\n }\n}\n\n/** 单条失败任务 → Issue。 */\nexport function buildIssueFromTask(t: ApiTask): Issue {\n const summary = t.outcome_reason || t.first_prompt || t.title || '(无摘要)'\n return {\n id: `fail-${t.id}`,\n type: 'failure',\n severity: severityForFailure(t.outcome),\n title: `任务失败 · ${t.title || '(无标题)'}`,\n rule: 'verify-agent FAIL',\n action: 'verify',\n source: 'tasks',\n time: t.end_time || t.start_time,\n session: t.session_id || null,\n what: `任务「${t.title || '(无标题)'}」outcome=${t.outcome ?? '—'}。${summary}`,\n why: heuristicWhy('verify-agent FAIL', 'verify', 'failure'),\n hint: heuristicHint('verify-agent FAIL', 'failure'),\n relatedTaskId: t.id,\n }\n}\n\n/** 单条 drift fail check → Issue(report 的 since 作时间兜底)。 */\nexport function buildIssueFromDrift(c: DriftCheck, since: string | null): Issue {\n return {\n id: `drift-${slugify(c.rule)}`,\n type: 'drift',\n severity: severityForDrift(),\n title: `漂移 · ${c.rule}`,\n rule: c.rule,\n action: 'drift',\n source: 'drift',\n time: since || '',\n session: null,\n what: `实测 ${c.actual}(期望 ${c.expected})`,\n why: `合规漂移:${c.rule} 实测「${c.actual}」未达声明「${c.expected}」。CLAUDE.md 声明行为与事件流实测出现偏离。`,\n hint: '核对该规则的声明阈值与实际运行数据,定位漂移来源(采纳率 / 委托率 / 记录连续性等),必要时调整阈值或补齐链路。',\n relatedTaskId: null,\n }\n}\n\n// ─── merge / assembly ─────────────────────────────────────────────────────────\n\n/**\n * 三源 merge → 统一 Issue 列表(按时间倒序)。任一源缺失(undefined)安全跳过。\n * - violations:全部 violations 行\n * - tasks:仅 outcome==='failed' 的 items(端点无 status 过滤 → 前端 filter)\n * - drift:仅 status==='fail' 的 checks(漂移项)\n */\nexport function buildIssueList(\n violations: ViolationsResp | undefined,\n tasks: TasksResp | undefined,\n drift: DriftResp | undefined,\n): Issue[] {\n const out: Issue[] = []\n\n if (violations && Array.isArray(violations.violations)) {\n for (const v of violations.violations) out.push(buildIssueFromViolation(v))\n }\n\n if (tasks && Array.isArray(tasks.items)) {\n for (const t of tasks.items) {\n if (t.outcome === 'failed') out.push(buildIssueFromTask(t))\n }\n }\n\n if (drift && Array.isArray(drift.checks)) {\n const since = drift.period?.since ?? null\n for (const c of drift.checks) {\n if (c.status === 'fail') out.push(buildIssueFromDrift(c, since))\n }\n }\n\n // 稳定排序:时间倒序(最新在前);漂移无精确时间用 since,排在同时间段。\n out.sort((a, b) => {\n const ta = epochSec(a.time)\n const tb = epochSec(b.time)\n if (ta !== tb) return tb - ta\n return a.id < b.id ? 1 : a.id > b.id ? -1 : 0\n })\n return out\n}\n\n/** 拆分 merge 后列表为「拦截/违规/失败」(一表)与「漂移」(卡片)两组,供两 Tab。 */\nexport function splitIssues(issues: Issue[]): { primary: Issue[]; drift: Issue[] } {\n const primary: Issue[] = []\n const drift: Issue[] = []\n for (const i of issues) {\n if (i.type === 'drift') drift.push(i)\n else primary.push(i)\n }\n return { primary, drift }\n}\n\n/** 单条 id → Issue(详情页按稳定 id 在 merge 列表里定位)。 */\nexport function findIssueById(issues: Issue[], id: string | undefined): Issue | null {\n if (!id) return null\n return issues.find((i) => i.id === id) ?? null\n}\n\n/**\n * 同类近 7 天计数:拦截/违规按相同 rule 计数,失败/漂移按相同 type 计数。\n * 输入为同源拉到的全量(窗口由调用层时间窗决定),这里只做纯计数。\n */\nexport function countSimilar(issues: Issue[], target: Issue): number {\n if (target.type === 'intercept' || target.type === 'violation') {\n return issues.filter(\n (i) => (i.type === 'intercept' || i.type === 'violation') && i.rule === target.rule,\n ).length\n }\n return issues.filter((i) => i.type === target.type).length\n}\n\n/** 列表/KPI 概览计数(各类型条数 + 总数)。 */\nexport interface IssueCounts {\n total: number\n intercept: number\n violation: number\n failure: number\n drift: number\n}\n\nexport function buildIssueCounts(issues: Issue[]): IssueCounts {\n const c: IssueCounts = { total: issues.length, intercept: 0, violation: 0, failure: 0, drift: 0 }\n for (const i of issues) c[i.type] += 1\n return c\n}\n","/**\n * useIssuesFeed — 治理 · 问题(治理)列表 + 详情 (Phase 3b, decision 29688066) 取数 hook。\n *\n * 前端 merge 三源、零新后端(已 curl 真实形状,见 issues-derive.ts 顶注):\n * GET /api/violations?days=&limit= → 违规/拦截(windowDays 受 1..30 校验)\n * GET /api/tasks?limit=&window= → 失败任务(前端 filter outcome==='failed',\n * 端点不认 ?status= 过滤)\n * GET /api/drift/report?days= → 漂移(status==='fail' 的 checks)\n *\n * 全局时间窗 `useTimeWindow()` 驱动 queryKey(Risk R7:切换 7d/30d/90d 自动重拉)。\n * 注意端点 days 校验差异:violations clamp [1,30]、drift clamp [1,90]、tasks window\n * 任意。全局窗值域 7/30/90 → violations 在 90d 时 clamp 到 30(端点上限),故 days\n * 入参对 violations 取 min(win, 30)(不硬塞超界值,按端点真实约束)。\n *\n * 取数后交 issues-derive.ts 纯函数 merge/归一,页面只渲染派生结果。详情页复用同一\n * merge 列表按稳定 id 定位(findIssueById),不再额外请求单条端点(零新后端)。\n */\nimport { useQuery } from '@tanstack/react-query'\n\nimport { useTimeWindow } from '../lib/time-window'\nimport {\n buildIssueList,\n drainFailedTasks,\n TASKS_PAGE_SIZE,\n type ViolationsResp,\n type TasksResp,\n type DrainFailedResult,\n type DriftResp,\n type Issue,\n} from './issues-derive'\n\nasync function fetchJson<T>(url: string): Promise<T> {\n const r = await fetch(url)\n if (!r.ok) throw new Error(`${url} → ${r.status}`)\n return r.json() as Promise<T>\n}\n\n/** violations 端点 days 上限 30 → clamp 全局窗。 */\nfunction violDays(win: number): number {\n return Math.min(win, 30)\n}\n\nconst VIOL_LIMIT = 100 // 端点 limit 上限 100(ViolationsPage paginator 既有口径)\n\nconst fetchViolations = (win: number) =>\n fetchJson<ViolationsResp>(`/api/violations?days=${violDays(win)}&limit=${VIOL_LIMIT}`)\n/**\n * 失败任务:/api/tasks 端点不认 ?status= 过滤、limit 被 clamp 到 max 200、排序新→旧、\n * 返回 { items, total, has_more }。单页只能盖 200 条 → 窗口内 total>200 时第 200 名\n * 之后的失败任务会被静默丢掉(live 30d 窗口 total 已 >400)。故按 offset 分页 **drain\n * 拉全当前窗** 直到 has_more===false,再 filter outcome==='failed';命中安全上限\n * (TASKS_MAX_PAGES)则置 truncated 标志、UI 明示「可能少报」(诚实降级,不夸大不漏)。\n */\nconst fetchFailedTasksDrained = (win: number): Promise<DrainFailedResult> =>\n drainFailedTasks((offset) =>\n fetchJson<TasksResp>(`/api/tasks?window=${win}&limit=${TASKS_PAGE_SIZE}&offset=${offset}`),\n )\nconst fetchDrift = (win: number) =>\n fetchJson<DriftResp>(`/api/drift/report?days=${win}`)\n\nexport interface IssuesFeedResult {\n issues: Issue[]\n /** 各源单独的成功/失败标记(drift 源缺失时只降级该源,不让整页报错)。 */\n violationsError: boolean\n tasksError: boolean\n driftError: boolean\n /** 失败任务源命中扫描安全上限 → 列表可能少报(诚实降级标志)。 */\n tasksTruncated: boolean\n loading: boolean\n /** 全部源都失败才算整页错误。 */\n isError: boolean\n error: Error | null\n refetch: () => void\n}\n\n/**\n * 三源并行取数 + merge(受全局时间窗驱动)。\n * 单源失败不阻塞其余源——drift 源若不存在/报错,仅降级丢掉漂移项,前两源照常 merge。\n */\nexport function useIssuesFeed(): IssuesFeedResult {\n const { window: win } = useTimeWindow()\n\n const violQ = useQuery({\n queryKey: ['issues-violations', win],\n queryFn: () => fetchViolations(win),\n refetchInterval: 60_000,\n refetchIntervalInBackground: false,\n })\n const taskQ = useQuery({\n queryKey: ['issues-failed-tasks', win],\n queryFn: () => fetchFailedTasksDrained(win),\n staleTime: 60_000,\n })\n const driftQ = useQuery({\n queryKey: ['issues-drift', win],\n queryFn: () => fetchDrift(win),\n staleTime: 60_000,\n // drift 报告偶发不可用时不无限重试刷屏,降级即可。\n retry: 1,\n })\n\n // taskQ.data 是 drain 结果(已 filter 失败);包成 TasksResp 形喂 buildIssueList\n // (后者再 filter 一次无害,行已是 outcome==='failed')。\n const drained = taskQ.isError ? undefined : taskQ.data\n const tasksResp: TasksResp | undefined = drained ? { items: drained.failed } : undefined\n\n const issues = buildIssueList(\n violQ.isError ? undefined : violQ.data,\n tasksResp,\n driftQ.isError ? undefined : driftQ.data,\n )\n\n return {\n issues,\n violationsError: violQ.isError,\n tasksError: taskQ.isError,\n driftError: driftQ.isError,\n tasksTruncated: drained?.truncated ?? false,\n loading: violQ.isLoading || taskQ.isLoading,\n isError: violQ.isError && taskQ.isError && driftQ.isError,\n error: (violQ.error as Error) ?? (taskQ.error as Error) ?? null,\n refetch: () => {\n void violQ.refetch()\n void taskQ.refetch()\n void driftQ.refetch()\n },\n }\n}\n"],"names":["TASKS_PAGE_SIZE","TASKS_MAX_PAGES","drainFailedTasks","fetchPage","pageSize","maxPages","failed","offset","pagesScanned","truncated","resp","items","t","parseInterceptSummary","summary","m","severityForRule","rule","severityForFailure","outcome","severityForDrift","SEV_LABEL","severityLabel","s","severityColor","TYPE_LABEL","typeLabel","typeColor","slugify","epochSec","iso","fmtTime","heuristicHint","type","heuristicWhy","action","act","buildIssueFromViolation","v","isIntercept","effRule","severity","buildIssueFromTask","buildIssueFromDrift","c","since","buildIssueList","violations","tasks","drift","out","_a","a","b","ta","tb","splitIssues","issues","primary","findIssueById","id","i","countSimilar","target","buildIssueCounts","fetchJson","url","r","violDays","win","VIOL_LIMIT","fetchViolations","fetchFailedTasksDrained","fetchDrift","useIssuesFeed","useTimeWindow","violQ","useQuery","taskQ","driftQ","drained","tasksResp"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{u as c}from"./query-CgCOpYWf.js";import{u as g,b as l}from"./index-DileOOE4.js";import{u as m}from"./useEffectiveProject-DQiyX54y.js";function j(e){return e==="cli"?"agent-pull":e==="daemon-probe"||e==="legacy"||e==="injection"||!e?"injection":"other"}function h(e){const t={agentPull:0,injection:0,other:0};for(const n of e??[]){const o=j(n.source);o==="agent-pull"?t.agentPull+=n.count:o==="injection"?t.injection+=n.count:t.other+=n.count}return t}function k(e){return e.agentPull===0&&e.injection===0?"none":e.agentPull>0&&e.injection>0?e.agentPull===e.injection?"mixed":e.agentPull>e.injection?"agent-pull":"injection":e.agentPull>0?"agent-pull":"injection"}function b(e){return e?typeof e.kb_hit_rate=="number"&&Number.isFinite(e.kb_hit_rate)?e.kb_hit_rate>1?e.kb_hit_rate/100:e.kb_hit_rate:typeof e.kb_inject_count=="number"&&typeof e.eligible_prompts=="number"&&e.eligible_prompts>0?e.kb_inject_count/e.eligible_prompts:null:null}function Q(e){return e===null||!Number.isFinite(e)?"—":`${Math.round(e*100)}%`}const p={"agent-pull":"agent-pull",injection:"injection",mixed:"混合",none:"无"};function S(e){return p[e]}function v(e,t,n){if(!e||!e.kb_built)return{built:!1,rows:[],totalPages:0,totalHits:0,adoptionRate:null,dominantSource:"none",sourceBreakdown:{agentPull:0,injection:0,other:0}};const o=(t==null?void 0:t.pages)??{},r=h(n==null?void 0:n.source_distribution),u=k(r),a=(e.pages??[]).map(i=>({name:i.name,title:i.title,kind:i.kind,hits:o[i.name]??0,refs:i.refs_count,audit_status:i.audit_status,source:(o[i.name]??0)>0?r.agentPull>0?"mixed":"injection":u,generated_at:i.generated_at}));a.sort((i,s)=>s.hits!==i.hits?s.hits-i.hits:i.name.localeCompare(s.name));const d=a.reduce((i,s)=>i+s.hits,0);return{built:!0,rows:a,totalPages:a.length,totalHits:d,adoptionRate:b(e.kb_hit_rate),dominantSource:u,sourceBreakdown:r}}function P(e){if(!e)return 0;const t=(e.match(/[一-鿿-ヿ]/g)||[]).length,n=(e.replace(/[一-鿿-ヿ]/g," ").match(/[A-Za-z0-9_]+/g)||[]).length;return t+n}function q(e,t=20){return((e==null?void 0:e.recent)??[]).slice(0,t).map(n=>({agent:n.agent_id||"系统注入",reason:n.reason||(n.workflow?`${n.workflow}${n.phase?`/${n.phase}`:""}`:"—"),source:"agent-pull",ts:n.ts}))}function K(e,t,n,o,r){if(!t)return null;const u=(n==null?void 0:n.pages)??{},a=h(r==null?void 0:r.source_distribution);return{name:t.name||e,title:t.title||e,kind:t.kind||"module",content:t.content??"",wordCount:P(t.content),refs:Array.isArray(t.refs)?t.refs.length:0,auditStatus:t.audit_status||"ok",generatedAt:t.generated_at,hits:u[e]??0,adoptionRate:b(o==null?void 0:o.kb_hit_rate),dominantSource:k(a),pulls:q(r)}}function A(e){return e==="cross"?"跨模块":e==="module"?"模块文档":e}async function f(e){const t=await fetch(e);if(!t.ok)throw new Error(`${e} → ${t.status}`);return t.json()}const _=(e,t)=>f(l(`/api/knowledge/list?window=${e}`,t)),w=(e,t)=>f(l(`/api/insights/kb-cited-pages?window=${e}`,t)),y=(e,t)=>f(l(`/api/insights/agent-kb-pulls?window=${e}`,t)),$=(e,t)=>f(l(`/api/knowledge/page/${encodeURIComponent(e)}`,t));function R(){const{window:e}=g(),{project:t,isAllProjects:n}=m(),o=c({queryKey:["kb-list",e,t],queryFn:()=>_(e,t),refetchInterval:6e4,refetchIntervalInBackground:!1}),r=c({queryKey:["kb-cited",e,t],queryFn:()=>w(e,t),staleTime:6e4}),u=c({queryKey:["kb-pulls",e,t],queryFn:()=>y(e,t),staleTime:6e4});return{view:v(o.data,r.data,u.data),loading:o.isLoading,isError:o.isError,error:o.error??null,project:t,isAllProjects:n,refetch:()=>{o.refetch(),r.refetch(),u.refetch()}}}function T(e){const{window:t}=g(),{project:n}=m(),o=c({queryKey:["kb-page",e,n],queryFn:()=>$(e,n),enabled:!!e,refetchInterval:3e4}),r=c({queryKey:["kb-cited",t,n],queryFn:()=>w(t,n),staleTime:6e4}),u=c({queryKey:["kb-list",t,n],queryFn:()=>_(t,n),staleTime:6e4}),a=c({queryKey:["kb-pulls",t,n],queryFn:()=>y(t,n),staleTime:6e4});return{view:e?K(e,o.data,r.data,u.data,a.data):null,loading:o.isLoading,isError:o.isError,error:o.error??null,refetch:()=>{o.refetch(),r.refetch(),u.refetch(),a.refetch()}}}export{T as a,Q as f,A as k,S as s,R as u};
|
|
2
|
+
//# sourceMappingURL=useKbHits-xKXWgqh9.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useKbHits-xKXWgqh9.js","sources":["../../src/hooks/kb-derive.ts","../../src/hooks/useKbHits.ts"],"sourcesContent":["/**\n * kb-derive — KB 命中列表/详情 (Phase 2b, decision 29688066) 纯派生层。\n *\n * 项目前端单测跑在 environment:'node'(无 jsdom / RTL,见 workplace-data.test.ts\n * 注解),故所有「端点响应 → 视图模型」的计算都抽进本纯函数模块,页面组件只渲染\n * 派生结果。这里逐函数锁端点对接口径:\n *\n * GET /api/knowledge/list → pages 目录(name/title/kind/refs_count/...)\n * GET /api/insights/kb-cited-pages → page_name → cited_count(注入命中口径,\n * injections WHERE source_handler=...:kb,\n * ISO-TEXT 窗口,无 adopted_at 门)\n * GET /api/insights/agent-kb-pulls → agent 主动 cli pull(by_workflow / recent\n * 逐条 verbatim / source_distribution)\n * GET /api/knowledge/page/:name → 详情正文(content/refs/...,详情页用)\n *\n * 命中口径说明(重要,勿\"规整\"):\n * - 列表「命中次数」= kb-cited-pages 的注入命中计数(push 路径)。这是唯一\n * per-page 命中真值;agent-kb-pulls.recent 只有 query/reason 没有 page_name,\n * 无法可靠 join 回单页,故 per-page 不混入 cli-pull 计数。\n * - 「主要来源」= 该页是否有 agent-pull 活动 vs 纯 injection——用全局\n * source_distribution 推断主导来源(降级:无 per-page 来源拆分时取全局占比)。\n * - 「采纳率」per-page 不可得(list.kb_hit_rate 是聚合 effective 命中率),\n * 列表展示聚合采纳率,详情展示同一聚合值并标注口径。\n */\n\n// ─── endpoint response shapes ────────────────────────────────────────────────\n\nexport interface KbListPage {\n name: string\n title: string\n kind: 'module' | 'cross' | string\n refs_count: number\n audit_status: 'ok' | 'stale' | 'error' | string\n generated_at?: string\n ai_model?: string\n}\n\n/**\n * Aggregate effective-adoption payload as emitted by GET /api/knowledge/list\n * (server: computeKbHitRate, src/web/routes/knowledge.ts:241-248). The server\n * already computes `kb_hit_rate` as a clamped 0..1 ratio; the raw count +\n * denominator are also sent so the client can fall back if needed.\n */\nexport interface KbHitRate {\n /** effective hit-rate numerator: KB injection events in window. */\n kb_inject_count?: number\n /** effective hit-rate denominator: skill-worthy eligible prompts. */\n eligible_prompts?: number\n /** all prompts in window (raw_hit_rate denominator). */\n total_prompts?: number\n /** kb_inject_count / eligible_prompts, server-computed 0..1 ratio. */\n kb_hit_rate?: number\n /** kb_inject_count / total_prompts, server-computed 0..1 ratio. */\n raw_hit_rate?: number\n window_days?: number\n}\n\nexport interface KbListResp {\n kb_built: boolean\n pages?: KbListPage[]\n stats?: {\n total: number\n by_kind?: { module: number; cross: number }\n by_audit_status?: { ok: number; stale: number; error: number }\n }\n kb_hit_rate?: KbHitRate\n generated_at?: string\n}\n\nexport interface KbCitedPagesResp {\n generated_at?: string\n project?: string | null\n window_days?: number\n /** page_name → cited (injection) count. */\n pages: Record<string, number>\n}\n\nexport interface AgentKbPull {\n ts: number\n query: string\n reason: string | null\n workflow: string | null\n phase: string | null\n result_count: number\n agent_id: string | null\n}\n\nexport interface AgentKbPullsResp {\n window_days?: number\n by_workflow?: Array<{ workflow: string; count: number }>\n recent?: AgentKbPull[]\n source_distribution?: Array<{ source: string; count: number }>\n total_cli_pulls?: number\n}\n\nexport interface KbPageDetailResp {\n name: string\n title?: string\n content: string\n refs?: unknown[]\n kind?: string\n audit_status?: string\n generated_at?: string\n ai_model?: string\n}\n\n// ─── view models ─────────────────────────────────────────────────────────────\n\nexport type KbSource = 'agent-pull' | 'injection' | 'mixed' | 'none'\n\nexport interface KbHitRow {\n name: string\n title: string\n kind: string\n /** injection-path cited count (kb-cited-pages). */\n hits: number\n refs: number\n audit_status: string\n /** dominant source for the whole window (degraded: global, not per-page). */\n source: KbSource\n generated_at?: string\n}\n\nexport interface KbListView {\n built: boolean\n rows: KbHitRow[]\n totalPages: number\n totalHits: number\n /** aggregate effective adoption rate as a 0..1 ratio, or null when unknown. */\n adoptionRate: number | null\n /** dominant window-wide source from source_distribution. */\n dominantSource: KbSource\n sourceBreakdown: { agentPull: number; injection: number; other: number }\n}\n\n// ─── source helpers ──────────────────────────────────────────────────────────\n\n/**\n * Classify a raw kb_query_log `source` token into the UI's three buckets.\n * cli → agent-pull (deliberate agent/operator pull); daemon-probe / legacy /\n * '' → injection (push path). Anything else is bucketed as \"other\".\n */\nexport function classifySource(raw: string | null | undefined): 'agent-pull' | 'injection' | 'other' {\n if (raw === 'cli') return 'agent-pull'\n if (raw === 'daemon-probe' || raw === 'legacy' || raw === 'injection' || !raw) return 'injection'\n return 'other'\n}\n\n/** Roll a source_distribution array into agent-pull / injection / other counts. */\nexport function deriveSourceBreakdown(\n dist: Array<{ source: string; count: number }> | undefined,\n): { agentPull: number; injection: number; other: number } {\n const out = { agentPull: 0, injection: 0, other: 0 }\n for (const d of dist ?? []) {\n const bucket = classifySource(d.source)\n if (bucket === 'agent-pull') out.agentPull += d.count\n else if (bucket === 'injection') out.injection += d.count\n else out.other += d.count\n }\n return out\n}\n\n/** Pick the dominant source given a breakdown. Ties / all-zero → 'none'. */\nexport function dominantSourceOf(b: {\n agentPull: number\n injection: number\n other: number\n}): KbSource {\n if (b.agentPull === 0 && b.injection === 0) return 'none'\n if (b.agentPull > 0 && b.injection > 0) {\n // both present → label by the larger; equal → mixed.\n if (b.agentPull === b.injection) return 'mixed'\n return b.agentPull > b.injection ? 'agent-pull' : 'injection'\n }\n return b.agentPull > 0 ? 'agent-pull' : 'injection'\n}\n\n// ─── adoption rate ───────────────────────────────────────────────────────────\n\n/**\n * Pull the aggregate effective adoption rate out of list.kb_hit_rate as a 0..1\n * ratio. Prefers the server-computed `kb_hit_rate`; else derives\n * kb_inject_count / eligible_prompts; else null.\n */\nexport function deriveAdoptionRate(hr: KbHitRate | undefined): number | null {\n if (!hr) return null\n if (typeof hr.kb_hit_rate === 'number' && Number.isFinite(hr.kb_hit_rate)) {\n // tolerate either a 0..1 ratio or a 0..100 percentage from the server.\n return hr.kb_hit_rate > 1 ? hr.kb_hit_rate / 100 : hr.kb_hit_rate\n }\n if (\n typeof hr.kb_inject_count === 'number' &&\n typeof hr.eligible_prompts === 'number' &&\n hr.eligible_prompts > 0\n ) {\n return hr.kb_inject_count / hr.eligible_prompts\n }\n return null\n}\n\n/** Format a 0..1 ratio as a \"NN%\" string, or \"—\" when null. */\nexport function formatPct(ratio: number | null): string {\n if (ratio === null || !Number.isFinite(ratio)) return '—'\n return `${Math.round(ratio * 100)}%`\n}\n\n// ─── list assembly ───────────────────────────────────────────────────────────\n\nconst SOURCE_LABEL: Record<KbSource, string> = {\n 'agent-pull': 'agent-pull',\n injection: 'injection',\n mixed: '混合',\n none: '无',\n}\n\nexport function sourceLabel(s: KbSource): string {\n return SOURCE_LABEL[s]\n}\n\n/**\n * Assemble the KB-hits list view from the three list-feed endpoints. Rows are\n * sorted by hits desc (prototype口径), then by name asc for stable ordering.\n */\nexport function buildKbListView(\n list: KbListResp | undefined,\n cited: KbCitedPagesResp | undefined,\n pulls: AgentKbPullsResp | undefined,\n): KbListView {\n if (!list || !list.kb_built) {\n return {\n built: false,\n rows: [],\n totalPages: 0,\n totalHits: 0,\n adoptionRate: null,\n dominantSource: 'none',\n sourceBreakdown: { agentPull: 0, injection: 0, other: 0 },\n }\n }\n\n const citedMap = cited?.pages ?? {}\n const breakdown = deriveSourceBreakdown(pulls?.source_distribution)\n const dominant = dominantSourceOf(breakdown)\n\n const rows: KbHitRow[] = (list.pages ?? []).map((p) => ({\n name: p.name,\n title: p.title,\n kind: p.kind,\n hits: citedMap[p.name] ?? 0,\n refs: p.refs_count,\n audit_status: p.audit_status,\n // per-page source is not derivable from the feeds; degrade to: if this page\n // has any injection hits AND the window has agent-pull activity → mixed;\n // pure-injection hits → injection; no hits → fall back to window dominant.\n source:\n (citedMap[p.name] ?? 0) > 0\n ? breakdown.agentPull > 0\n ? 'mixed'\n : 'injection'\n : dominant,\n generated_at: p.generated_at,\n }))\n\n rows.sort((a, b) => {\n if (b.hits !== a.hits) return b.hits - a.hits\n return a.name.localeCompare(b.name)\n })\n\n const totalHits = rows.reduce((s, r) => s + r.hits, 0)\n\n return {\n built: true,\n rows,\n totalPages: rows.length,\n totalHits,\n adoptionRate: deriveAdoptionRate(list.kb_hit_rate),\n dominantSource: dominant,\n sourceBreakdown: breakdown,\n }\n}\n\n// ─── detail assembly ─────────────────────────────────────────────────────────\n\nexport interface KbPullRow {\n agent: string\n reason: string\n source: 'agent-pull' | 'injection' | 'other'\n ts: number\n}\n\nexport interface KbDetailView {\n name: string\n title: string\n kind: string\n /** truncated-friendly markdown body for preview. */\n content: string\n wordCount: number\n refs: number\n auditStatus: string\n generatedAt?: string\n hits: number\n adoptionRate: number | null\n dominantSource: KbSource\n /** deliberate agent pulls in window (global feed; agent/reason/source/ts). */\n pulls: KbPullRow[]\n}\n\n/** Rough word count for a markdown body (CJK-aware: count CJK chars + ws words). */\nexport function countWords(body: string | undefined): number {\n if (!body) return 0\n const cjk = (body.match(/[一-鿿-ヿ]/g) || []).length\n const ascii = (body.replace(/[一-鿿-ヿ]/g, ' ').match(/[A-Za-z0-9_]+/g) || []).length\n return cjk + ascii\n}\n\n/** Map the global agent-pull recent feed into detail \"who pulled it\" rows. */\nexport function derivePullRows(pulls: AgentKbPullsResp | undefined, limit = 20): KbPullRow[] {\n return (pulls?.recent ?? []).slice(0, limit).map((p) => ({\n agent: p.agent_id || '系统注入',\n reason: p.reason || (p.workflow ? `${p.workflow}${p.phase ? `/${p.phase}` : ''}` : '—'),\n source: 'agent-pull',\n ts: p.ts,\n }))\n}\n\n/**\n * Assemble the KB detail view from the page-content endpoint + the window feeds.\n * `pageName` is the route param; hits/adoption come from the same list-feed\n * sources used by the list page so the two stay consistent.\n */\nexport function buildKbDetailView(\n pageName: string,\n page: KbPageDetailResp | undefined,\n cited: KbCitedPagesResp | undefined,\n list: KbListResp | undefined,\n pulls: AgentKbPullsResp | undefined,\n): KbDetailView | null {\n if (!page) return null\n const citedMap = cited?.pages ?? {}\n const breakdown = deriveSourceBreakdown(pulls?.source_distribution)\n return {\n name: page.name || pageName,\n title: page.title || pageName,\n kind: page.kind || 'module',\n content: page.content ?? '',\n wordCount: countWords(page.content),\n refs: Array.isArray(page.refs) ? page.refs.length : 0,\n auditStatus: page.audit_status || 'ok',\n generatedAt: page.generated_at,\n hits: citedMap[pageName] ?? 0,\n adoptionRate: deriveAdoptionRate(list?.kb_hit_rate),\n dominantSource: dominantSourceOf(breakdown),\n pulls: derivePullRows(pulls),\n }\n}\n\n// ─── kind label (shared by list + detail) ────────────────────────────────────\n\nexport function kindLabel(kind: string): string {\n if (kind === 'cross') return '跨模块'\n if (kind === 'module') return '模块文档'\n return kind\n}\n","/**\n * useKbHits / useKbDetail — KB 命中列表 + 详情 (Phase 2b, decision 29688066) 取数 hook。\n *\n * 全局时间窗 `useTimeWindow()` 驱动 queryKey(Risk R7:切换 7d/30d/90d 自动重拉)。\n * 接真实端点,零新后端:\n * GET /api/knowledge/list?window= → KB 页目录 + 聚合命中率\n * GET /api/insights/kb-cited-pages?window= → page_name → 注入命中计数\n * GET /api/insights/agent-kb-pulls?window= → agent 主动 cli pull(recent / 来源分布)\n * GET /api/knowledge/page/:name → 详情正文(仅详情页拉)\n *\n * 取数后交给 kb-derive.ts 纯函数装配视图模型;页面组件只渲染派生结果。\n * kb-cited-pages / agent-kb-pulls 的 window 受端点 1..90 校验约束,与全局窗\n * (7/30/90)天然兼容,无需 clamp。\n */\nimport { useQuery } from '@tanstack/react-query'\n\nimport { useTimeWindow } from '../lib/time-window'\nimport { useEffectiveProject } from './useEffectiveProject'\nimport { appendProject } from '../utils/kbProject'\nimport {\n buildKbListView,\n buildKbDetailView,\n type KbListResp,\n type KbCitedPagesResp,\n type AgentKbPullsResp,\n type KbPageDetailResp,\n type KbListView,\n type KbDetailView,\n} from './kb-derive'\n\nasync function fetchJson<T>(url: string): Promise<T> {\n const r = await fetch(url)\n if (!r.ok) throw new Error(`${url} → ${r.status}`)\n return r.json() as Promise<T>\n}\n\n// decision dd79010a: append `?project=` so the global selector切到对应项目的\n// KB 内容(list → resolveProjectRoot 切 `.forge-knowledge/` 目录;cited/pulls\n// 读 req.query.project)。project='' → 不带参(全部项目 / daemon 当前)。\nconst fetchList = (win: number, project: string) =>\n fetchJson<KbListResp>(appendProject(`/api/knowledge/list?window=${win}`, project))\nconst fetchCited = (win: number, project: string) =>\n fetchJson<KbCitedPagesResp>(appendProject(`/api/insights/kb-cited-pages?window=${win}`, project))\nconst fetchPulls = (win: number, project: string) =>\n fetchJson<AgentKbPullsResp>(appendProject(`/api/insights/agent-kb-pulls?window=${win}`, project))\nconst fetchPage = (name: string, project: string) =>\n fetchJson<KbPageDetailResp>(appendProject(`/api/knowledge/page/${encodeURIComponent(name)}`, project))\n\nexport interface KbHitsResult {\n view: KbListView\n loading: boolean\n isError: boolean\n error: Error | null\n /** Effective project filter applied ('' = all projects). decision dd79010a. */\n project: string\n /** True when the explicit all-projects view is selected. */\n isAllProjects: boolean\n refetch: () => void\n}\n\n/** KB 命中列表取数 + 装配(受全局时间窗 + 全局项目筛选驱动)。 */\nexport function useKbHits(): KbHitsResult {\n const { window: win } = useTimeWindow()\n const { project, isAllProjects } = useEffectiveProject()\n\n const listQ = useQuery({\n queryKey: ['kb-list', win, project],\n queryFn: () => fetchList(win, project),\n refetchInterval: 60_000,\n refetchIntervalInBackground: false,\n })\n const citedQ = useQuery({\n queryKey: ['kb-cited', win, project],\n queryFn: () => fetchCited(win, project),\n staleTime: 60_000,\n })\n const pullsQ = useQuery({\n queryKey: ['kb-pulls', win, project],\n queryFn: () => fetchPulls(win, project),\n staleTime: 60_000,\n })\n\n const view = buildKbListView(listQ.data, citedQ.data, pullsQ.data)\n\n return {\n view,\n loading: listQ.isLoading,\n isError: listQ.isError,\n error: (listQ.error as Error) ?? null,\n project,\n isAllProjects,\n refetch: () => {\n void listQ.refetch()\n void citedQ.refetch()\n void pullsQ.refetch()\n },\n }\n}\n\nexport interface KbDetailResult {\n view: KbDetailView | null\n loading: boolean\n isError: boolean\n error: Error | null\n refetch: () => void\n}\n\n/** KB 详情取数 + 装配(页正文 + 同窗命中/采纳/pull 上下文,受全局项目筛选驱动)。 */\nexport function useKbDetail(name: string | undefined): KbDetailResult {\n const { window: win } = useTimeWindow()\n const { project } = useEffectiveProject()\n\n const pageQ = useQuery({\n queryKey: ['kb-page', name, project],\n queryFn: () => fetchPage(name!, project),\n enabled: !!name,\n refetchInterval: 30_000,\n })\n const citedQ = useQuery({\n queryKey: ['kb-cited', win, project],\n queryFn: () => fetchCited(win, project),\n staleTime: 60_000,\n })\n const listQ = useQuery({\n queryKey: ['kb-list', win, project],\n queryFn: () => fetchList(win, project),\n staleTime: 60_000,\n })\n const pullsQ = useQuery({\n queryKey: ['kb-pulls', win, project],\n queryFn: () => fetchPulls(win, project),\n staleTime: 60_000,\n })\n\n const view = name\n ? buildKbDetailView(name, pageQ.data, citedQ.data, listQ.data, pullsQ.data)\n : null\n\n return {\n view,\n loading: pageQ.isLoading,\n isError: pageQ.isError,\n error: (pageQ.error as Error) ?? null,\n refetch: () => {\n void pageQ.refetch()\n void citedQ.refetch()\n void listQ.refetch()\n void pullsQ.refetch()\n },\n }\n}\n"],"names":["classifySource","raw","deriveSourceBreakdown","dist","out","d","bucket","dominantSourceOf","b","deriveAdoptionRate","hr","formatPct","ratio","SOURCE_LABEL","sourceLabel","s","buildKbListView","list","cited","pulls","citedMap","breakdown","dominant","rows","p","a","totalHits","r","countWords","body","cjk","ascii","derivePullRows","limit","buildKbDetailView","pageName","page","kindLabel","kind","fetchJson","url","fetchList","win","project","appendProject","fetchCited","fetchPulls","fetchPage","name","useKbHits","useTimeWindow","isAllProjects","useEffectiveProject","listQ","useQuery","citedQ","pullsQ","useKbDetail","pageQ"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{u}from"./query-CgCOpYWf.js";import{u as y,b}from"./index-DileOOE4.js";import{u as m}from"./useEffectiveProject-DQiyX54y.js";function _(e,n){return!n||n<=0?null:e/n}function K(e){return e===null||!Number.isFinite(e)?"—":`${Math.round(e*100)}%`}function L(e){if(e===null||!Number.isFinite(e))return 0;const n=e*5;return Math.round(n*2)/2}function P(e){if(!e||!Number.isFinite(e))return"—";const n=new Date(e),o=l=>String(l).padStart(2,"0");return`${o(n.getMonth()+1)}-${o(n.getDate())} ${o(n.getHours())}:${o(n.getMinutes())}`}function x(e){return e==="cli"?"CLI 主动":e==="dynamic"?"MCP 动态":e==="static"?"关键词匹配":e==="slash_command"?"斜杠命令":e}function B(e){return e==="helped"?{label:"helped",color:"green"}:e==="partial"?{label:"partial",color:"orange"}:e==="not-actionable"?{label:"not-actionable",color:"red"}:{label:"未评分",color:"gray"}}function v(e,n){const o=_(e.helped,e.total_rated);return{id:e.skill_id,description:n,calls:e.total,invoked:e.invoked,genuine:e.genuine??e.invoked,injected:e.injected,helped:e.helped,partial:e.partial,notActionable:e.not_actionable,totalRated:e.total_rated,pending:e.pending,actionableRate:o,caller:e.top_agent||e.top_workflow||null,lastTs:e.last_ts,isUnused:e.total<=0}}function q(e,n){return{id:e,description:n,calls:0,invoked:0,genuine:0,injected:0,helped:0,partial:0,notActionable:0,totalRated:0,pending:0,actionableRate:null,caller:null,lastTs:0,isUnused:!0}}function T(e,n){const o=new Map;for(const i of(e==null?void 0:e.skills)??[])o.set(i.id,i.description||"");const l=new Map;for(const i of(n==null?void 0:n.invocations)??[])l.set(i.skill_id,i);const t=[],s=new Set;for(const i of(e==null?void 0:e.skills)??[]){if(s.has(i.id))continue;s.add(i.id);const r=l.get(i.id);t.push(r?v(r,i.description||""):q(i.id,i.description||""))}for(const i of(n==null?void 0:n.invocations)??[])s.has(i.skill_id)||(s.add(i.skill_id),t.push(v(i,o.get(i.skill_id)??"")));return t.sort((i,r)=>{if(r.calls!==i.calls)return r.calls-i.calls;const c=i.actionableRate??-1,a=r.actionableRate??-1;return a!==c?a-c:i.id.localeCompare(r.id)}),{rows:t,totalSkills:t.length,totalInvoked:typeof(n==null?void 0:n.genuineInvoke)=="number"?n.genuineInvoke:t.reduce((i,r)=>i+r.genuine,0),totalCalls:t.reduce((i,r)=>i+r.calls,0),totalRated:t.reduce((i,r)=>i+r.totalRated,0),totalHelped:t.reduce((i,r)=>i+r.helped,0),unusedSkills:t.reduce((i,r)=>i+(r.isUnused?1:0),0)}}function D(e,n){return n==="invoked"?e.filter(o=>!o.isUnused):n==="unused"?e.filter(o=>o.isUnused):e}function I(e){const n=e.reason||(e.workflow?`${e.workflow}${e.phase?`/${e.phase}`:""}`:"—");return{id:e.id,agent:e.agent_id||"系统/CLI",invocationType:e.invocation_type,reason:n,workflow:e.workflow,phase:e.phase,usefulness:e.usefulness??null,usefulnessNote:e.usefulness_note??null,ts:e.timestamp,sessionId:e.session_id}}function C(e){const n=(e==null?void 0:e.helped)??0,o=(e==null?void 0:e.partial)??0,l=(e==null?void 0:e.not_actionable)??0,t=(e==null?void 0:e.total_rated)??0,s=(e==null?void 0:e.pending)??0;return{helped:n,partial:o,notActionable:l,totalRated:t,pending:s,actionableRate:_(n,t)}}function F(e,n,o,l,t){var r;if(!n&&!o)return null;const s=C(n==null?void 0:n.usefulness),i=((n==null?void 0:n.records)??[]).map(I);return{id:e,description:(l==null?void 0:l.description)??"",content:t!=null&&t.exists?t.body??"":"",contentExists:!!(t!=null&&t.exists),calls:(o==null?void 0:o.total)??i.length,invoked:(o==null?void 0:o.invoked)??0,injected:(o==null?void 0:o.injected)??0,caller:o&&(o.top_agent||o.top_workflow)||null,lastTs:(o==null?void 0:o.last_ts)??((r=i[0])==null?void 0:r.ts)??0,breakdown:s,records:i}}async function d(e){const n=await fetch(e);if(!n.ok)throw new Error(`${e} → ${n.status}`);return n.json()}const $=()=>d("/api/skills"),j=(e,n)=>d(b(`/api/skill-stats/invocations?days=${e}`,n)),M=(e,n,o)=>d(b(`/api/skill-stats/invocations/${encodeURIComponent(e)}?days=${n}`,o)),E=e=>d(`/api/skills/${encodeURIComponent(e)}/content`);function N(){const{window:e}=y(),{project:n,isAllProjects:o}=m(),l=u({queryKey:["skill-catalog"],queryFn:$,staleTime:5*6e4}),t=u({queryKey:["skill-stats",e,n],queryFn:()=>j(e,n),refetchInterval:6e4,refetchIntervalInBackground:!1});return{view:T(l.data,t.data),loading:t.isLoading,isError:t.isError,error:t.error??null,project:n,isAllProjects:o,refetch:()=>{l.refetch(),t.refetch()}}}function H(e){var p,k,h,w;const{window:n}=y(),{project:o,isAllProjects:l}=m(),t=u({queryKey:["skill-records",e,n,o],queryFn:()=>M(e,n,o),enabled:!!e,refetchInterval:6e4}),s=u({queryKey:["skill-stats",n,o],queryFn:()=>j(n,o),staleTime:6e4}),i=u({queryKey:["skill-catalog"],queryFn:$,staleTime:5*6e4}),r=u({queryKey:["skill-content",e],queryFn:()=>E(e),enabled:!!e,staleTime:5*6e4,retry:!1}),c=e?(k=(p=s.data)==null?void 0:p.invocations)==null?void 0:k.find(f=>f.skill_id===e):void 0,a=e?(w=(h=i.data)==null?void 0:h.skills)==null?void 0:w.find(f=>f.id===e):void 0;return{view:e?F(e,t.data,c,a,r.data):null,loading:t.isLoading,isError:t.isError,error:t.error??null,project:o,isAllProjects:l,refetch:()=>{t.refetch(),s.refetch(),i.refetch(),r.refetch()}}}export{P as a,K as b,H as c,B as d,D as f,x as i,L as r,N as u};
|
|
2
|
+
//# sourceMappingURL=useSkillStats-B5hbIwdf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSkillStats-B5hbIwdf.js","sources":["../../src/hooks/skill-derive.ts","../../src/hooks/useSkillStats.ts"],"sourcesContent":["/**\n * skill-derive — Skill 调用列表/详情 (Phase 2c, decision 29688066) 纯派生层。\n *\n * 项目前端单测跑在 environment:'node'(无 jsdom / RTL,见 workplace-data.test.ts\n * 注解),故所有「端点响应 → 视图模型」的计算都抽进本纯函数模块,页面组件只渲染\n * 派生结果。这里逐函数锁端点对接口径(字段名严格按服务端真实 curl payload,避免\n * Phase 2b 的「派生层读了服务端从不产出的字段」血泪坑):\n *\n * GET /api/skills → distilled-* skill 目录(id/description/...)\n * GET /api/skill-stats/invocations?days= → 每 skill 调用数 + 真调用拆分 +\n * usefulness 聚合(helped/partial/\n * not_actionable/total_rated/pending/\n * actionable_rate)+ top_workflow /\n * top_agent / last_ts(列表用)\n * GET /api/skill-stats/invocations/:id?days=→ 单 skill 详情:usefulness 聚合 +\n * records[](agent_id / invocation_type /\n * reason / workflow / phase / usefulness /\n * usefulness_note / timestamp …)\n * GET /api/skills/:id/content → 方法论正文(body / frontmatter / exists …)\n *\n * 口径说明(重要,勿\"规整\"):\n * - 「调用次数」= invocations[].total(skill_invocations 全行计数,含注入+真调用)。\n * 真调用拆分 invoked / injected 也带出,详情页注明口径。\n * - 「有用性 ★」= actionable_rate = helped / total_rated(STRICT helped-only,\n * decision d24cd3a2 Q3)。total_rated=0(全 pending)时 rate=0,UI 标「未评分」。\n * - 「主要调用方」= 实测 agent_id 列恒为空(全是 cli pull),故降级为 top_workflow\n * (reason 解析出的 <workflow>,列恒有值),有 agent 时优先 top_agent。\n * - 「最近调用」= last_ts(毫秒 epoch,INTEGER 列;注意非 ISO TEXT)。\n */\n\n// ─── endpoint response shapes (严格按真实 curl payload) ─────────────────────────\n\n/** GET /api/skills 单条(src/web/routes/skills.ts:23-31)。 */\nexport interface SkillCatalogItem {\n name: string\n id: string\n description: string\n keywords: string[]\n path: string\n isBuiltin: boolean\n source: 'builtin' | 'user' | string\n}\n\nexport interface SkillCatalogResp {\n skills?: SkillCatalogItem[]\n}\n\n/**\n * GET /api/skill-stats/invocations 单条(src/web/routes/skill-stats.ts,Phase 2c 富化)。\n * 字段名与服务端 res.json 完全一致——helped/partial/not_actionable 用下划线\n * (aggregateSkillUsefulness SQL 列名),actionable_rate 是 0..1(helped/total_rated)。\n */\nexport interface SkillInvocationStat {\n skill_id: string\n total: number\n success: number\n failed: number\n injected: number\n invoked: number\n /**\n * decision 76be4e4a: genuine agent invokes for this skill\n * (`invocation_type='cli' AND recorded_at_inject IS NULL`). Authoritative\n * 「真实调用」口径——excludes dynamic keyword-matcher rows that `invoked` counts.\n */\n genuine?: number\n helped: number\n partial: number\n not_actionable: number\n total_rated: number\n pending: number\n actionable_rate: number\n top_workflow: string | null\n top_agent: string | null\n /** 毫秒 epoch;0 表示窗口内无调用记录。 */\n last_ts: number\n}\n\nexport interface SkillInvocationsResp {\n days?: number\n total?: number\n injected?: number\n /** events.tool_name path (MCP/Skill 工具);decision 76be4e4a 起降为次要参考。 */\n realCalls?: number\n /**\n * decision 76be4e4a: 权威「Skill 调用」口径——genuine agent invokes\n * (`invocation_type='cli' AND recorded_at_inject IS NULL`)。工作台 KPI 与\n * Skill 专页头部主数字都读它(不是 realCalls=2,也不是含 keyword-matcher 的\n * invoked 和 ≈166)。\n */\n genuineInvoke?: number\n invocations?: SkillInvocationStat[]\n}\n\n/** GET /api/skill-stats/invocations/:id 的 usefulness 聚合块(可能为 null)。 */\nexport interface SkillUsefulnessAgg {\n skill_id: string\n total_rated: number\n helped: number\n partial: number\n not_actionable: number\n pending: number\n actionable_rate: number\n}\n\n/** GET /api/skill-stats/invocations/:id 的单条调用记录。 */\nexport interface SkillRecord {\n id: string\n agent_id: string | null\n invocation_type: 'static' | 'dynamic' | 'slash_command' | 'cli' | string\n reason: string | null\n workflow: string | null\n phase: string | null\n usefulness: 'helped' | 'partial' | 'not-actionable' | null\n usefulness_note: string | null\n success: number\n timestamp: number\n session_id: string\n}\n\nexport interface SkillRecordsResp {\n skill_id: string\n days?: number\n usefulness: SkillUsefulnessAgg | null\n records?: SkillRecord[]\n}\n\n/** GET /api/skills/:id/content(src/web/routes/skill-content.ts)。 */\nexport interface SkillContentResp {\n id: string\n source: 'official' | 'distilled' | 'missing' | string\n exists: boolean\n path: string | null\n bytes: number\n body: string\n frontmatter: Record<string, unknown>\n}\n\n// ─── view models ─────────────────────────────────────────────────────────────\n\nexport interface SkillRow {\n id: string\n description: string\n /** 全行调用数(含注入)。 */\n calls: number\n /** 含 keyword-matcher 的非注入数(recorded_at_inject IS NULL);次要口径。 */\n invoked: number\n /**\n * decision 76be4e4a: genuine agent invoke(cli + 非注入)——权威「真实调用」口径。\n */\n genuine: number\n injected: number\n helped: number\n partial: number\n notActionable: number\n totalRated: number\n pending: number\n /** helped / total_rated,0..1;total_rated=0 时为 null(未评分)。 */\n actionableRate: number | null\n /** 主要调用方(top_agent 优先,降级 top_workflow)。 */\n caller: string | null\n /** 最近调用毫秒 epoch;0 → 无。 */\n lastTs: number\n /**\n * decision 568a8c53 Q2: catalog 全量主键源后,从未被调用的「死库存」skill\n * 也进列表(zero-fill)。true = calls===0 且无任何调用记录 → UI 标「未使用」徽标。\n */\n isUnused: boolean\n}\n\n/** decision 568a8c53 Q2: 列表三态筛选。 */\nexport type SkillUsageFilter = 'all' | 'invoked' | 'unused'\n\nexport interface SkillListView {\n rows: SkillRow[]\n totalSkills: number\n /**\n * 权威「真实调用」口径(decision 76be4e4a)——Σ per-row genuine\n * (`invocation_type='cli' AND recorded_at_inject IS NULL`,真 agent 主动\n * pull),与工作台 KPI skillCallCount 同口径(≈140 全项目 / 106 本项目)。专页\n * 头部主数字用它,消除「工作台 2、这里 166」的困惑。\n *\n * 注意:旧实现(decision 2d6d59b0)这里 Σ invoked,把 dynamic keyword-matcher\n * 历史 auto-match 也算进真实调用,导致虚高(≈166)——76be4e4a 改回 genuine。\n */\n totalInvoked: number\n /** 全行口径(含注入推送 + keyword-matcher 历史匹配);专页降为次要小字。 */\n totalCalls: number\n totalRated: number\n totalHelped: number\n /**\n * decision 568a8c53 Q2: 从未被调用的「死库存」skill 数(isUnused=true 行数)。\n * 页头展示「N 个未使用」让死重一眼可见。\n */\n unusedSkills: number\n}\n\n// ─── formatting helpers ──────────────────────────────────────────────────────\n\n/** helped / total_rated → 0..1,未评分(total_rated=0)→ null。 */\nexport function deriveActionableRate(helped: number, totalRated: number): number | null {\n if (!totalRated || totalRated <= 0) return null\n return helped / totalRated\n}\n\n/** 0..1 ratio → \"NN%\";null → \"—\"。 */\nexport function formatPct(ratio: number | null): string {\n if (ratio === null || !Number.isFinite(ratio)) return '—'\n return `${Math.round(ratio * 100)}%`\n}\n\n/**\n * 有用性星级(0-5 ★,半星粒度):actionable_rate * 5,四舍五入到 0.5。\n * 未评分(rate=null)→ 0 且 UI 另标「未评分」。\n */\nexport function ratingStars(rate: number | null): number {\n if (rate === null || !Number.isFinite(rate)) return 0\n const raw = rate * 5\n return Math.round(raw * 2) / 2\n}\n\n/** 毫秒 epoch → \"MM-DD HH:mm\";0/非法 → \"—\"。 */\nexport function formatTs(ts: number | null | undefined): string {\n if (!ts || !Number.isFinite(ts)) return '—'\n const d = new Date(ts)\n const pad = (n: number) => String(n).padStart(2, '0')\n return `${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`\n}\n\n/** invocation_type → 中文标签。 */\nexport function invocationTypeLabel(t: string): string {\n if (t === 'cli') return 'CLI 主动'\n if (t === 'dynamic') return 'MCP 动态'\n if (t === 'static') return '关键词匹配'\n if (t === 'slash_command') return '斜杠命令'\n return t\n}\n\n/** usefulness rating → 中文标签 + 语义色(Arco Tag color token)。 */\nexport function usefulnessMeta(\n u: SkillRecord['usefulness'],\n): { label: string; color: string } {\n if (u === 'helped') return { label: 'helped', color: 'green' }\n if (u === 'partial') return { label: 'partial', color: 'orange' }\n if (u === 'not-actionable') return { label: 'not-actionable', color: 'red' }\n return { label: '未评分', color: 'gray' }\n}\n\n// ─── list assembly ───────────────────────────────────────────────────────────\n\n/** 把单条 invocation stat 映射成列表行(join 后的 description / isUnused 由调用方填)。 */\nfunction statToRow(\n s: SkillInvocationStat,\n description: string,\n): SkillRow {\n const rate = deriveActionableRate(s.helped, s.total_rated)\n return {\n id: s.skill_id,\n description,\n calls: s.total,\n invoked: s.invoked,\n // decision 76be4e4a: genuine = cli + 非注入;后端未给(旧响应)时降级到\n // invoked 以保持向后兼容。\n genuine: s.genuine ?? s.invoked,\n injected: s.injected,\n helped: s.helped,\n partial: s.partial,\n notActionable: s.not_actionable,\n totalRated: s.total_rated,\n pending: s.pending,\n actionableRate: rate,\n caller: s.top_agent || s.top_workflow || null,\n lastTs: s.last_ts,\n // calls===0(窗口内零调用记录)即「未使用」死库存。\n isUnused: s.total <= 0,\n }\n}\n\n/** 给 catalog 里从未出现在 invocations 的 skill 造一行 zero-fill「未使用」行。 */\nfunction unusedRow(id: string, description: string): SkillRow {\n return {\n id,\n description,\n calls: 0,\n invoked: 0,\n genuine: 0,\n injected: 0,\n helped: 0,\n partial: 0,\n notActionable: 0,\n totalRated: 0,\n pending: 0,\n actionableRate: null,\n caller: null,\n lastTs: 0,\n isUnused: true,\n }\n}\n\n/**\n * 装配 Skill 调用列表视图。\n *\n * decision 568a8c53 Q2: 主键源从 `invocations` 换成**全量 catalog 左 join\n * skill_invocations**——catalog(/api/skills,25 条)里每个 skill 都出现,从未被\n * 调用的 zero-fill(calls=0、isUnused=true,UI 标「未使用」徽标)。这样「死库存」\n * skill(~14 个从未调用)不再被静默丢弃,完整库存一眼可见(参照先例 76be4e4a /\n * 2d6d59b0 的左 join zero-fill 做法)。\n *\n * 若调用记录里有 catalog 之外的 skill_id(如历史/测试残留),也一并展示——不静默\n * 丢真实数据,向后兼容旧行为。按调用数(total)降序,次按 actionable_rate 降序、\n * skill_id 升序稳定排序(未使用行 calls=0 自然沉底)。\n */\nexport function buildSkillListView(\n catalog: SkillCatalogResp | undefined,\n stats: SkillInvocationsResp | undefined,\n): SkillListView {\n const descById = new Map<string, string>()\n for (const s of catalog?.skills ?? []) {\n descById.set(s.id, s.description || '')\n }\n\n const statById = new Map<string, SkillInvocationStat>()\n for (const s of stats?.invocations ?? []) {\n statById.set(s.skill_id, s)\n }\n\n const rows: SkillRow[] = []\n const seen = new Set<string>()\n\n // 主键源:全量 catalog(左 join invocations,未命中 zero-fill「未使用」)。\n for (const c of catalog?.skills ?? []) {\n if (seen.has(c.id)) continue\n seen.add(c.id)\n const stat = statById.get(c.id)\n rows.push(\n stat ? statToRow(stat, c.description || '') : unusedRow(c.id, c.description || ''),\n )\n }\n\n // catalog 之外但有真实调用记录的 skill(历史/测试残留)也一并展示,不丢数据。\n for (const s of stats?.invocations ?? []) {\n if (seen.has(s.skill_id)) continue\n seen.add(s.skill_id)\n rows.push(statToRow(s, descById.get(s.skill_id) ?? ''))\n }\n\n rows.sort((a, b) => {\n if (b.calls !== a.calls) return b.calls - a.calls\n const ar = a.actionableRate ?? -1\n const br = b.actionableRate ?? -1\n if (br !== ar) return br - ar\n return a.id.localeCompare(b.id)\n })\n\n return {\n rows,\n totalSkills: rows.length,\n // decision 76be4e4a: prefer the backend's authoritative genuineInvoke\n // headline; fall back to Σ per-row genuine when an older response omits it.\n totalInvoked:\n typeof stats?.genuineInvoke === 'number'\n ? stats.genuineInvoke\n : rows.reduce((s, r) => s + r.genuine, 0),\n totalCalls: rows.reduce((s, r) => s + r.calls, 0),\n totalRated: rows.reduce((s, r) => s + r.totalRated, 0),\n totalHelped: rows.reduce((s, r) => s + r.helped, 0),\n unusedSkills: rows.reduce((s, r) => s + (r.isUnused ? 1 : 0), 0),\n }\n}\n\n/**\n * decision 568a8c53 Q2: 列表三态筛选——全部 / 仅调用过 / 仅未使用。\n * - 'all' → 不过滤\n * - 'invoked' → 只留有调用记录的(!isUnused)\n * - 'unused' → 只留从未调用的死库存(isUnused)\n */\nexport function filterSkillRows(rows: SkillRow[], filter: SkillUsageFilter): SkillRow[] {\n if (filter === 'invoked') return rows.filter((r) => !r.isUnused)\n if (filter === 'unused') return rows.filter((r) => r.isUnused)\n return rows\n}\n\n// ─── detail assembly ─────────────────────────────────────────────────────────\n\nexport interface SkillRecordRow {\n id: string\n agent: string\n invocationType: string\n reason: string\n workflow: string | null\n phase: string | null\n usefulness: SkillRecord['usefulness']\n usefulnessNote: string | null\n ts: number\n sessionId: string\n}\n\nexport interface UsefulnessBreakdown {\n helped: number\n partial: number\n notActionable: number\n totalRated: number\n pending: number\n actionableRate: number | null\n}\n\nexport interface SkillDetailView {\n id: string\n description: string\n /** 方法论正文(content endpoint body;缺则空串,UI 降级)。 */\n content: string\n contentExists: boolean\n calls: number\n invoked: number\n injected: number\n caller: string | null\n lastTs: number\n breakdown: UsefulnessBreakdown\n records: SkillRecordRow[]\n}\n\n/** 把单条 record 映射成详情列表行(agent 缺 → 系统;reason 缺 → workflow/phase)。 */\nexport function deriveRecordRow(r: SkillRecord): SkillRecordRow {\n const reason =\n r.reason ||\n (r.workflow ? `${r.workflow}${r.phase ? `/${r.phase}` : ''}` : '—')\n return {\n id: r.id,\n agent: r.agent_id || '系统/CLI',\n invocationType: r.invocation_type,\n reason,\n workflow: r.workflow,\n phase: r.phase,\n usefulness: r.usefulness ?? null,\n usefulnessNote: r.usefulness_note ?? null,\n ts: r.timestamp,\n sessionId: r.session_id,\n }\n}\n\n/** 从 usefulness 聚合块(详情端点)+ records 兜底装配分布。 */\nexport function deriveBreakdown(\n agg: SkillUsefulnessAgg | null | undefined,\n): UsefulnessBreakdown {\n const helped = agg?.helped ?? 0\n const partial = agg?.partial ?? 0\n const notActionable = agg?.not_actionable ?? 0\n const totalRated = agg?.total_rated ?? 0\n const pending = agg?.pending ?? 0\n return {\n helped,\n partial,\n notActionable,\n totalRated,\n pending,\n actionableRate: deriveActionableRate(helped, totalRated),\n }\n}\n\n/**\n * 装配 Skill 详情视图。records 端点是单 skill 真值源;list stat(同窗)补\n * calls/invoked/caller/lastTs 概要(records 端点不重复 aggregate 这些);content\n * 端点给方法论正文(不存在则降级空串)。\n */\nexport function buildSkillDetailView(\n skillId: string,\n recordsResp: SkillRecordsResp | undefined,\n listStat: SkillInvocationStat | undefined,\n catalogItem: SkillCatalogItem | undefined,\n content: SkillContentResp | undefined,\n): SkillDetailView | null {\n if (!recordsResp && !listStat) return null\n const breakdown = deriveBreakdown(recordsResp?.usefulness)\n const records = (recordsResp?.records ?? []).map(deriveRecordRow)\n return {\n id: skillId,\n description: catalogItem?.description ?? '',\n content: content?.exists ? content.body ?? '' : '',\n contentExists: !!content?.exists,\n calls: listStat?.total ?? records.length,\n invoked: listStat?.invoked ?? 0,\n injected: listStat?.injected ?? 0,\n caller: listStat ? listStat.top_agent || listStat.top_workflow || null : null,\n lastTs: listStat?.last_ts ?? (records[0]?.ts ?? 0),\n breakdown,\n records,\n }\n}\n","/**\n * useSkillStats / useSkillDetail — Skill 调用列表 + 详情 (Phase 2c, decision 29688066) 取数 hook。\n *\n * 全局时间窗 `useTimeWindow()` 驱动 queryKey(Risk R7:切换 7d/30d/90d 自动重拉)。\n * 接真实端点,后端仅 Phase 2c 富化的 skill-stats(无新表):\n * GET /api/skills → distilled-* skill 目录(description join)\n * GET /api/skill-stats/invocations?days= → 每 skill 调用 + usefulness + caller + 最近\n * GET /api/skill-stats/invocations/:id?days= → 单 skill records + usefulness(仅详情页)\n * GET /api/skills/:id/content → 方法论正文(仅详情页)\n *\n * 取数后交给 skill-derive.ts 纯函数装配视图模型;页面组件只渲染派生结果。\n * skill-stats 用 `days` 参数(非 KB 的 `window`),全局窗值 7/30/90 直接透传。\n */\nimport { useQuery } from '@tanstack/react-query'\n\nimport { useTimeWindow } from '../lib/time-window'\nimport { useEffectiveProject } from './useEffectiveProject'\nimport { appendProject } from '../utils/kbProject'\nimport {\n buildSkillListView,\n buildSkillDetailView,\n type SkillCatalogResp,\n type SkillInvocationsResp,\n type SkillRecordsResp,\n type SkillContentResp,\n type SkillListView,\n type SkillDetailView,\n} from './skill-derive'\n\nasync function fetchJson<T>(url: string): Promise<T> {\n const r = await fetch(url)\n if (!r.ok) throw new Error(`${url} → ${r.status}`)\n return r.json() as Promise<T>\n}\n\n// catalog + content 是全局定义(一套库),不带 project;只有 usage 维度\n// (invocations / records / usefulness)按项目过滤(decision dd79010a)。\nconst fetchCatalog = () => fetchJson<SkillCatalogResp>('/api/skills')\nconst fetchStats = (days: number, project: string) =>\n fetchJson<SkillInvocationsResp>(\n appendProject(`/api/skill-stats/invocations?days=${days}`, project),\n )\nconst fetchRecords = (id: string, days: number, project: string) =>\n fetchJson<SkillRecordsResp>(\n appendProject(\n `/api/skill-stats/invocations/${encodeURIComponent(id)}?days=${days}`,\n project,\n ),\n )\nconst fetchContent = (id: string) =>\n fetchJson<SkillContentResp>(`/api/skills/${encodeURIComponent(id)}/content`)\n\nexport interface SkillStatsResult {\n view: SkillListView\n loading: boolean\n isError: boolean\n error: Error | null\n /** Effective project filter applied to usage ('' = all). decision dd79010a. */\n project: string\n /** True when the explicit all-projects view is selected. */\n isAllProjects: boolean\n refetch: () => void\n}\n\n/** Skill 调用列表取数 + 装配(catalog 全局 · usage 受全局项目筛选驱动)。 */\nexport function useSkillStats(): SkillStatsResult {\n const { window: win } = useTimeWindow()\n const { project, isAllProjects } = useEffectiveProject()\n\n const catalogQ = useQuery({\n queryKey: ['skill-catalog'],\n queryFn: fetchCatalog,\n staleTime: 5 * 60_000,\n })\n const statsQ = useQuery({\n queryKey: ['skill-stats', win, project],\n queryFn: () => fetchStats(win, project),\n refetchInterval: 60_000,\n refetchIntervalInBackground: false,\n })\n\n const view = buildSkillListView(catalogQ.data, statsQ.data)\n\n return {\n view,\n loading: statsQ.isLoading,\n isError: statsQ.isError,\n error: (statsQ.error as Error) ?? null,\n project,\n isAllProjects,\n refetch: () => {\n void catalogQ.refetch()\n void statsQ.refetch()\n },\n }\n}\n\nexport interface SkillDetailResult {\n view: SkillDetailView | null\n loading: boolean\n isError: boolean\n error: Error | null\n /** Effective project filter applied to usage ('' = all). decision dd79010a. */\n project: string\n /** True when the explicit all-projects view is selected. */\n isAllProjects: boolean\n refetch: () => void\n}\n\n/** Skill 详情取数 + 装配(records/usage 按项目 + list stat 概要 + 全局正文)。 */\nexport function useSkillDetail(id: string | undefined): SkillDetailResult {\n const { window: win } = useTimeWindow()\n const { project, isAllProjects } = useEffectiveProject()\n\n const recordsQ = useQuery({\n queryKey: ['skill-records', id, win, project],\n queryFn: () => fetchRecords(id!, win, project),\n enabled: !!id,\n refetchInterval: 60_000,\n })\n const statsQ = useQuery({\n queryKey: ['skill-stats', win, project],\n queryFn: () => fetchStats(win, project),\n staleTime: 60_000,\n })\n const catalogQ = useQuery({\n queryKey: ['skill-catalog'],\n queryFn: fetchCatalog,\n staleTime: 5 * 60_000,\n })\n const contentQ = useQuery({\n queryKey: ['skill-content', id],\n queryFn: () => fetchContent(id!),\n enabled: !!id,\n staleTime: 5 * 60_000,\n // content endpoint may 400/403 (local-only / bad id) — tolerate without\n // failing the whole detail page; the body simply degrades to empty.\n retry: false,\n })\n\n const listStat = id\n ? statsQ.data?.invocations?.find((s) => s.skill_id === id)\n : undefined\n const catalogItem = id\n ? catalogQ.data?.skills?.find((s) => s.id === id)\n : undefined\n\n const view = id\n ? buildSkillDetailView(id, recordsQ.data, listStat, catalogItem, contentQ.data)\n : null\n\n return {\n view,\n loading: recordsQ.isLoading,\n isError: recordsQ.isError,\n error: (recordsQ.error as Error) ?? null,\n project,\n isAllProjects,\n refetch: () => {\n void recordsQ.refetch()\n void statsQ.refetch()\n void catalogQ.refetch()\n void contentQ.refetch()\n },\n }\n}\n"],"names":["deriveActionableRate","helped","totalRated","formatPct","ratio","ratingStars","rate","raw","formatTs","ts","d","pad","n","invocationTypeLabel","t","usefulnessMeta","u","statToRow","s","description","unusedRow","id","buildSkillListView","catalog","stats","descById","statById","rows","seen","c","stat","a","b","ar","br","filterSkillRows","filter","r","deriveRecordRow","reason","deriveBreakdown","agg","partial","notActionable","pending","buildSkillDetailView","skillId","recordsResp","listStat","catalogItem","content","breakdown","records","_a","fetchJson","url","fetchCatalog","fetchStats","days","project","appendProject","fetchRecords","fetchContent","useSkillStats","win","useTimeWindow","isAllProjects","useEffectiveProject","catalogQ","useQuery","statsQ","useSkillDetail","recordsQ","contentQ","_b","_d","_c"],"mappings":"mIAuMO,SAASA,EAAqBC,EAAgBC,EAAmC,CACtF,MAAI,CAACA,GAAcA,GAAc,EAAU,KACpCD,EAASC,CAClB,CAGO,SAASC,EAAUC,EAA8B,CACtD,OAAIA,IAAU,MAAQ,CAAC,OAAO,SAASA,CAAK,EAAU,IAC/C,GAAG,KAAK,MAAMA,EAAQ,GAAG,CAAC,GACnC,CAMO,SAASC,EAAYC,EAA6B,CACvD,GAAIA,IAAS,MAAQ,CAAC,OAAO,SAASA,CAAI,EAAG,MAAO,GACpD,MAAMC,EAAMD,EAAO,EACnB,OAAO,KAAK,MAAMC,EAAM,CAAC,EAAI,CAC/B,CAGO,SAASC,EAASC,EAAuC,CAC9D,GAAI,CAACA,GAAM,CAAC,OAAO,SAASA,CAAE,EAAG,MAAO,IACxC,MAAMC,EAAI,IAAI,KAAKD,CAAE,EACfE,EAAOC,GAAc,OAAOA,CAAC,EAAE,SAAS,EAAG,GAAG,EACpD,MAAO,GAAGD,EAAID,EAAE,SAAA,EAAa,CAAC,CAAC,IAAIC,EAAID,EAAE,QAAA,CAAS,CAAC,IAAIC,EAAID,EAAE,UAAU,CAAC,IAAIC,EAAID,EAAE,WAAA,CAAY,CAAC,EACjG,CAGO,SAASG,EAAoBC,EAAmB,CACrD,OAAIA,IAAM,MAAc,SACpBA,IAAM,UAAkB,SACxBA,IAAM,SAAiB,QACvBA,IAAM,gBAAwB,OAC3BA,CACT,CAGO,SAASC,EACdC,EACkC,CAClC,OAAIA,IAAM,SAAiB,CAAE,MAAO,SAAU,MAAO,OAAA,EACjDA,IAAM,UAAkB,CAAE,MAAO,UAAW,MAAO,QAAA,EACnDA,IAAM,iBAAyB,CAAE,MAAO,iBAAkB,MAAO,KAAA,EAC9D,CAAE,MAAO,MAAO,MAAO,MAAA,CAChC,CAKA,SAASC,EACPC,EACAC,EACU,CACV,MAAMb,EAAON,EAAqBkB,EAAE,OAAQA,EAAE,WAAW,EACzD,MAAO,CACL,GAAIA,EAAE,SACN,YAAAC,EACA,MAAOD,EAAE,MACT,QAASA,EAAE,QAGX,QAASA,EAAE,SAAWA,EAAE,QACxB,SAAUA,EAAE,SACZ,OAAQA,EAAE,OACV,QAASA,EAAE,QACX,cAAeA,EAAE,eACjB,WAAYA,EAAE,YACd,QAASA,EAAE,QACX,eAAgBZ,EAChB,OAAQY,EAAE,WAAaA,EAAE,cAAgB,KACzC,OAAQA,EAAE,QAEV,SAAUA,EAAE,OAAS,CAAA,CAEzB,CAGA,SAASE,EAAUC,EAAYF,EAA+B,CAC5D,MAAO,CACL,GAAAE,EACA,YAAAF,EACA,MAAO,EACP,QAAS,EACT,QAAS,EACT,SAAU,EACV,OAAQ,EACR,QAAS,EACT,cAAe,EACf,WAAY,EACZ,QAAS,EACT,eAAgB,KAChB,OAAQ,KACR,OAAQ,EACR,SAAU,EAAA,CAEd,CAeO,SAASG,EACdC,EACAC,EACe,CACf,MAAMC,MAAe,IACrB,UAAWP,KAAKK,GAAA,YAAAA,EAAS,SAAU,CAAA,EACjCE,EAAS,IAAIP,EAAE,GAAIA,EAAE,aAAe,EAAE,EAGxC,MAAMQ,MAAe,IACrB,UAAWR,KAAKM,GAAA,YAAAA,EAAO,cAAe,CAAA,EACpCE,EAAS,IAAIR,EAAE,SAAUA,CAAC,EAG5B,MAAMS,EAAmB,CAAA,EACnBC,MAAW,IAGjB,UAAWC,KAAKN,GAAA,YAAAA,EAAS,SAAU,CAAA,EAAI,CACrC,GAAIK,EAAK,IAAIC,EAAE,EAAE,EAAG,SACpBD,EAAK,IAAIC,EAAE,EAAE,EACb,MAAMC,EAAOJ,EAAS,IAAIG,EAAE,EAAE,EAC9BF,EAAK,KACHG,EAAOb,EAAUa,EAAMD,EAAE,aAAe,EAAE,EAAIT,EAAUS,EAAE,GAAIA,EAAE,aAAe,EAAE,CAAA,CAErF,CAGA,UAAWX,KAAKM,GAAA,YAAAA,EAAO,cAAe,CAAA,EAChCI,EAAK,IAAIV,EAAE,QAAQ,IACvBU,EAAK,IAAIV,EAAE,QAAQ,EACnBS,EAAK,KAAKV,EAAUC,EAAGO,EAAS,IAAIP,EAAE,QAAQ,GAAK,EAAE,CAAC,GAGxD,OAAAS,EAAK,KAAK,CAACI,EAAGC,IAAM,CAClB,GAAIA,EAAE,QAAUD,EAAE,MAAO,OAAOC,EAAE,MAAQD,EAAE,MAC5C,MAAME,EAAKF,EAAE,gBAAkB,GACzBG,EAAKF,EAAE,gBAAkB,GAC/B,OAAIE,IAAOD,EAAWC,EAAKD,EACpBF,EAAE,GAAG,cAAcC,EAAE,EAAE,CAChC,CAAC,EAEM,CACL,KAAAL,EACA,YAAaA,EAAK,OAGlB,aACE,OAAOH,GAAA,YAAAA,EAAO,gBAAkB,SAC5BA,EAAM,cACNG,EAAK,OAAO,CAACT,EAAG,IAAMA,EAAI,EAAE,QAAS,CAAC,EAC5C,WAAYS,EAAK,OAAO,CAACT,EAAG,IAAMA,EAAI,EAAE,MAAO,CAAC,EAChD,WAAYS,EAAK,OAAO,CAACT,EAAG,IAAMA,EAAI,EAAE,WAAY,CAAC,EACrD,YAAaS,EAAK,OAAO,CAACT,EAAG,IAAMA,EAAI,EAAE,OAAQ,CAAC,EAClD,aAAcS,EAAK,OAAO,CAACT,EAAG,IAAMA,GAAK,EAAE,SAAW,EAAI,GAAI,CAAC,CAAA,CAEnE,CAQO,SAASiB,EAAgBR,EAAkBS,EAAsC,CACtF,OAAIA,IAAW,UAAkBT,EAAK,OAAQU,GAAM,CAACA,EAAE,QAAQ,EAC3DD,IAAW,SAAiBT,EAAK,OAAQU,GAAMA,EAAE,QAAQ,EACtDV,CACT,CA0CO,SAASW,EAAgBD,EAAgC,CAC9D,MAAME,EACJF,EAAE,SACDA,EAAE,SAAW,GAAGA,EAAE,QAAQ,GAAGA,EAAE,MAAQ,IAAIA,EAAE,KAAK,GAAK,EAAE,GAAK,KACjE,MAAO,CACL,GAAIA,EAAE,GACN,MAAOA,EAAE,UAAY,SACrB,eAAgBA,EAAE,gBAClB,OAAAE,EACA,SAAUF,EAAE,SACZ,MAAOA,EAAE,MACT,WAAYA,EAAE,YAAc,KAC5B,eAAgBA,EAAE,iBAAmB,KACrC,GAAIA,EAAE,UACN,UAAWA,EAAE,UAAA,CAEjB,CAGO,SAASG,EACdC,EACqB,CACrB,MAAMxC,GAASwC,GAAA,YAAAA,EAAK,SAAU,EACxBC,GAAUD,GAAA,YAAAA,EAAK,UAAW,EAC1BE,GAAgBF,GAAA,YAAAA,EAAK,iBAAkB,EACvCvC,GAAauC,GAAA,YAAAA,EAAK,cAAe,EACjCG,GAAUH,GAAA,YAAAA,EAAK,UAAW,EAChC,MAAO,CACL,OAAAxC,EACA,QAAAyC,EACA,cAAAC,EACA,WAAAzC,EACA,QAAA0C,EACA,eAAgB5C,EAAqBC,EAAQC,CAAU,CAAA,CAE3D,CAOO,SAAS2C,EACdC,EACAC,EACAC,EACAC,EACAC,EACwB,OACxB,GAAI,CAACH,GAAe,CAACC,EAAU,OAAO,KACtC,MAAMG,EAAYX,EAAgBO,GAAA,YAAAA,EAAa,UAAU,EACnDK,IAAWL,GAAA,YAAAA,EAAa,UAAW,CAAA,GAAI,IAAIT,CAAe,EAChE,MAAO,CACL,GAAIQ,EACJ,aAAaG,GAAA,YAAAA,EAAa,cAAe,GACzC,QAASC,GAAA,MAAAA,EAAS,OAASA,EAAQ,MAAQ,GAAK,GAChD,cAAe,CAAC,EAACA,GAAA,MAAAA,EAAS,QAC1B,OAAOF,GAAA,YAAAA,EAAU,QAASI,EAAQ,OAClC,SAASJ,GAAA,YAAAA,EAAU,UAAW,EAC9B,UAAUA,GAAA,YAAAA,EAAU,WAAY,EAChC,OAAQA,IAAWA,EAAS,WAAaA,EAAS,eAAgB,KAClE,QAAQA,GAAA,YAAAA,EAAU,YAAYK,EAAAD,EAAQ,CAAC,IAAT,YAAAC,EAAY,KAAM,EAChD,UAAAF,EACA,QAAAC,CAAA,CAEJ,CCzcA,eAAeE,EAAaC,EAAyB,CACnD,MAAMlB,EAAI,MAAM,MAAMkB,CAAG,EACzB,GAAI,CAAClB,EAAE,GAAI,MAAM,IAAI,MAAM,GAAGkB,CAAG,MAAMlB,EAAE,MAAM,EAAE,EACjD,OAAOA,EAAE,KAAA,CACX,CAIA,MAAMmB,EAAe,IAAMF,EAA4B,aAAa,EAC9DG,EAAa,CAACC,EAAcC,IAChCL,EACEM,EAAc,qCAAqCF,CAAI,GAAIC,CAAO,CACpE,EACIE,EAAe,CAACxC,EAAYqC,EAAcC,IAC9CL,EACEM,EACE,gCAAgC,mBAAmBvC,CAAE,CAAC,SAASqC,CAAI,GACnEC,CAAA,CAEJ,EACIG,EAAgBzC,GACpBiC,EAA4B,eAAe,mBAAmBjC,CAAE,CAAC,UAAU,EAetE,SAAS0C,GAAkC,CAChD,KAAM,CAAE,OAAQC,CAAA,EAAQC,EAAA,EAClB,CAAE,QAAAN,EAAS,cAAAO,CAAA,EAAkBC,EAAA,EAE7BC,EAAWC,EAAS,CACxB,SAAU,CAAC,eAAe,EAC1B,QAASb,EACT,UAAW,EAAI,GAAA,CAChB,EACKc,EAASD,EAAS,CACtB,SAAU,CAAC,cAAeL,EAAKL,CAAO,EACtC,QAAS,IAAMF,EAAWO,EAAKL,CAAO,EACtC,gBAAiB,IACjB,4BAA6B,EAAA,CAC9B,EAID,MAAO,CACL,KAHWrC,EAAmB8C,EAAS,KAAME,EAAO,IAAI,EAIxD,QAASA,EAAO,UAChB,QAASA,EAAO,QAChB,MAAQA,EAAO,OAAmB,KAClC,QAAAX,EACA,cAAAO,EACA,QAAS,IAAM,CACRE,EAAS,QAAA,EACTE,EAAO,QAAA,CACd,CAAA,CAEJ,CAeO,SAASC,EAAelD,EAA2C,aACxE,KAAM,CAAE,OAAQ2C,CAAA,EAAQC,EAAA,EAClB,CAAE,QAAAN,EAAS,cAAAO,CAAA,EAAkBC,EAAA,EAE7BK,EAAWH,EAAS,CACxB,SAAU,CAAC,gBAAiBhD,EAAI2C,EAAKL,CAAO,EAC5C,QAAS,IAAME,EAAaxC,EAAK2C,EAAKL,CAAO,EAC7C,QAAS,CAAC,CAACtC,EACX,gBAAiB,GAAA,CAClB,EACKiD,EAASD,EAAS,CACtB,SAAU,CAAC,cAAeL,EAAKL,CAAO,EACtC,QAAS,IAAMF,EAAWO,EAAKL,CAAO,EACtC,UAAW,GAAA,CACZ,EACKS,EAAWC,EAAS,CACxB,SAAU,CAAC,eAAe,EAC1B,QAASb,EACT,UAAW,EAAI,GAAA,CAChB,EACKiB,EAAWJ,EAAS,CACxB,SAAU,CAAC,gBAAiBhD,CAAE,EAC9B,QAAS,IAAMyC,EAAazC,CAAG,EAC/B,QAAS,CAAC,CAACA,EACX,UAAW,EAAI,IAGf,MAAO,EAAA,CACR,EAEK2B,EAAW3B,GACbqD,GAAArB,EAAAiB,EAAO,OAAP,YAAAjB,EAAa,cAAb,YAAAqB,EAA0B,KAAMxD,GAAMA,EAAE,WAAaG,GACrD,OACE4B,EAAc5B,GAChBsD,GAAAC,EAAAR,EAAS,OAAT,YAAAQ,EAAe,SAAf,YAAAD,EAAuB,KAAMzD,GAAMA,EAAE,KAAOG,GAC5C,OAMJ,MAAO,CACL,KALWA,EACTwB,EAAqBxB,EAAImD,EAAS,KAAMxB,EAAUC,EAAawB,EAAS,IAAI,EAC5E,KAIF,QAASD,EAAS,UAClB,QAASA,EAAS,QAClB,MAAQA,EAAS,OAAmB,KACpC,QAAAb,EACA,cAAAO,EACA,QAAS,IAAM,CACRM,EAAS,QAAA,EACTF,EAAO,QAAA,EACPF,EAAS,QAAA,EACTK,EAAS,QAAA,CAChB,CAAA,CAEJ"}
|