@winspan/claude-forge 9.2.0 → 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 +80 -19
- package/README.md +13 -6
- package/dist/catalogs/agents.json +19 -24
- package/dist/catalogs/skills.json +139 -27
- package/dist/claudemd/templates/swarm-protocol.md +1 -1
- 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/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/decisions.d.ts.map +1 -1
- package/dist/cli/commands/decisions.js +46 -9
- package/dist/cli/commands/decisions.js.map +1 -1
- package/dist/cli/commands/executions.d.ts.map +1 -1
- package/dist/cli/commands/executions.js +2 -1
- package/dist/cli/commands/executions.js.map +1 -1
- package/dist/cli/commands/insights-goal-check.d.ts +5 -1
- package/dist/cli/commands/insights-goal-check.d.ts.map +1 -1
- package/dist/cli/commands/insights-goal-check.js +15 -15
- package/dist/cli/commands/insights-goal-check.js.map +1 -1
- package/dist/cli/commands/knowledge.d.ts +51 -0
- package/dist/cli/commands/knowledge.d.ts.map +1 -1
- package/dist/cli/commands/knowledge.js +202 -29
- package/dist/cli/commands/knowledge.js.map +1 -1
- 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 +23 -0
- package/dist/cli/commands/mcp.d.ts.map +1 -1
- package/dist/cli/commands/mcp.js +82 -0
- package/dist/cli/commands/mcp.js.map +1 -1
- 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 +409 -9
- package/dist/cli/commands/skills.js.map +1 -1
- package/dist/cli/commands/stats.d.ts.map +1 -1
- package/dist/cli/commands/stats.js +9 -2
- package/dist/cli/commands/stats.js.map +1 -1
- package/dist/cli/index.js +8 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/core/constants.d.ts +37 -0
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/core/constants.js +43 -0
- package/dist/core/constants.js.map +1 -1
- package/dist/core/diagnostics/checks.d.ts.map +1 -1
- package/dist/core/diagnostics/checks.js +2 -1
- package/dist/core/diagnostics/checks.js.map +1 -1
- package/dist/core/diagnostics/daemon-status.d.ts +1 -1
- package/dist/core/diagnostics/daemon-status.d.ts.map +1 -1
- package/dist/core/diagnostics/daemon-status.js +1 -1
- package/dist/core/diagnostics/daemon-status.js.map +1 -1
- package/dist/core/diagnostics/entropy-checks.d.ts +3 -2
- package/dist/core/diagnostics/entropy-checks.d.ts.map +1 -1
- package/dist/core/diagnostics/entropy-checks.js +10 -5
- package/dist/core/diagnostics/entropy-checks.js.map +1 -1
- 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/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 +34 -4
- package/dist/core/governance/global-inject.d.ts.map +1 -1
- package/dist/core/governance/global-inject.js +80 -25
- package/dist/core/governance/global-inject.js.map +1 -1
- 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/{daemon/services → core/insights}/experience-extractor.d.ts +0 -7
- package/dist/core/insights/experience-extractor.d.ts.map +1 -0
- package/dist/{daemon/services → core/insights}/experience-extractor.js +5 -9
- package/dist/core/insights/experience-extractor.js.map +1 -0
- package/dist/{daemon/services → core/insights}/violation-reporter.d.ts +20 -1
- package/dist/core/insights/violation-reporter.d.ts.map +1 -0
- package/dist/{daemon/services → core/insights}/violation-reporter.js +56 -4
- 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.map +1 -1
- package/dist/core/queue/index.js +2 -1
- package/dist/core/queue/index.js.map +1 -1
- package/dist/core/storage/base.d.ts +159 -0
- package/dist/core/storage/base.d.ts.map +1 -1
- package/dist/core/storage/base.js +523 -0
- package/dist/core/storage/base.js.map +1 -1
- 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 +30 -5
- package/dist/core/storage/decisions.d.ts.map +1 -1
- package/dist/core/storage/decisions.js +45 -13
- package/dist/core/storage/decisions.js.map +1 -1
- package/dist/core/storage/events.d.ts +127 -0
- package/dist/core/storage/events.d.ts.map +1 -1
- package/dist/core/storage/events.js +318 -3
- package/dist/core/storage/events.js.map +1 -1
- package/dist/core/storage/feedback.d.ts +3 -23
- package/dist/core/storage/feedback.d.ts.map +1 -1
- package/dist/core/storage/feedback.js +37 -38
- package/dist/core/storage/feedback.js.map +1 -1
- package/dist/core/storage/injections.d.ts +40 -0
- package/dist/core/storage/injections.d.ts.map +1 -1
- package/dist/core/storage/injections.js +69 -0
- package/dist/core/storage/injections.js.map +1 -1
- package/dist/core/storage/knowledge.d.ts +226 -0
- package/dist/core/storage/knowledge.d.ts.map +1 -1
- package/dist/core/storage/knowledge.js +391 -4
- package/dist/core/storage/knowledge.js.map +1 -1
- package/dist/core/storage/pipeline-rollup.d.ts +1 -7
- package/dist/core/storage/pipeline-rollup.d.ts.map +1 -1
- package/dist/core/storage/pipeline-rollup.js +18 -57
- package/dist/core/storage/pipeline-rollup.js.map +1 -1
- package/dist/core/storage/routing.d.ts +34 -0
- package/dist/core/storage/routing.d.ts.map +1 -1
- package/dist/core/storage/routing.js +92 -2
- package/dist/core/storage/routing.js.map +1 -1
- package/dist/core/storage/rows.d.ts +5 -25
- package/dist/core/storage/rows.d.ts.map +1 -1
- package/dist/core/storage/schema.sql +92 -27
- package/dist/core/storage/sessions.d.ts.map +1 -1
- package/dist/core/storage/sessions.js +2 -1
- package/dist/core/storage/sessions.js.map +1 -1
- package/dist/core/storage/skills.d.ts +159 -0
- package/dist/core/storage/skills.d.ts.map +1 -1
- package/dist/core/storage/skills.js +350 -4
- package/dist/core/storage/skills.js.map +1 -1
- package/dist/core/storage/sqlite.d.ts +81 -25
- package/dist/core/storage/sqlite.d.ts.map +1 -1
- package/dist/core/storage/sqlite.js +143 -45
- package/dist/core/storage/sqlite.js.map +1 -1
- package/dist/core/storage/tasks.d.ts +270 -0
- package/dist/core/storage/tasks.d.ts.map +1 -1
- package/dist/core/storage/tasks.js +495 -16
- package/dist/core/storage/tasks.js.map +1 -1
- package/dist/core/storage/tool-intercepts.d.ts +1 -1
- package/dist/core/storage/tool-intercepts.js +1 -1
- package/dist/core/types.d.ts +26 -3
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +1 -3
- package/dist/core/types.js.map +1 -1
- package/dist/core/utils/binary-paths.d.ts +32 -0
- package/dist/core/utils/binary-paths.d.ts.map +1 -1
- package/dist/core/utils/binary-paths.js +52 -0
- package/dist/core/utils/binary-paths.js.map +1 -1
- package/dist/core/utils/claude-cli-resolver.d.ts.map +1 -0
- package/dist/{skills/distill → core/utils}/claude-cli-resolver.js +1 -1
- package/dist/core/utils/claude-cli-resolver.js.map +1 -0
- package/dist/core/utils/claude-cli-spawn.d.ts +1 -1
- package/dist/core/utils/claude-cli-spawn.js +2 -2
- package/dist/core/utils/claude-cli-spawn.js.map +1 -1
- package/dist/core/utils/noise-prompt.d.ts +1 -1
- package/dist/core/utils/noise-prompt.js +1 -1
- package/dist/core/utils/time.d.ts +26 -0
- package/dist/core/utils/time.d.ts.map +1 -1
- package/dist/core/utils/time.js +33 -0
- package/dist/core/utils/time.js.map +1 -1
- package/dist/daemon/config-store.d.ts.map +1 -1
- package/dist/daemon/config-store.js +14 -5
- package/dist/daemon/config-store.js.map +1 -1
- package/dist/daemon/event-parser.d.ts.map +1 -1
- package/dist/daemon/event-parser.js +5 -0
- package/dist/daemon/event-parser.js.map +1 -1
- package/dist/daemon/handlers/post-tool-use.d.ts +24 -16
- package/dist/daemon/handlers/post-tool-use.d.ts.map +1 -1
- package/dist/daemon/handlers/post-tool-use.js +76 -116
- package/dist/daemon/handlers/post-tool-use.js.map +1 -1
- package/dist/daemon/handlers/pre-tool-use.d.ts +35 -10
- package/dist/daemon/handlers/pre-tool-use.d.ts.map +1 -1
- package/dist/daemon/handlers/pre-tool-use.js +71 -38
- package/dist/daemon/handlers/pre-tool-use.js.map +1 -1
- package/dist/daemon/handlers/stop.d.ts +20 -0
- package/dist/daemon/handlers/stop.d.ts.map +1 -1
- package/dist/daemon/handlers/stop.js +96 -8
- package/dist/daemon/handlers/stop.js.map +1 -1
- package/dist/daemon/handlers/user-prompt.d.ts +16 -1
- package/dist/daemon/handlers/user-prompt.d.ts.map +1 -1
- package/dist/daemon/handlers/user-prompt.js +97 -56
- 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/index.d.ts +19 -0
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +125 -200
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/rules/defaults.d.ts.map +1 -1
- package/dist/daemon/rules/defaults.js +151 -64
- package/dist/daemon/rules/defaults.js.map +1 -1
- package/dist/daemon/rules/types.d.ts +28 -22
- package/dist/daemon/rules/types.d.ts.map +1 -1
- package/dist/daemon/rules/workflow-defaults.js +9 -9
- package/dist/daemon/rules/workflow-defaults.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/decision-hint.d.ts +47 -10
- package/dist/daemon/services/decision-hint.d.ts.map +1 -1
- package/dist/daemon/services/decision-hint.js +99 -24
- package/dist/daemon/services/decision-hint.js.map +1 -1
- package/dist/daemon/services/event-ttl-sweep.d.ts.map +1 -1
- package/dist/daemon/services/event-ttl-sweep.js +3 -2
- package/dist/daemon/services/event-ttl-sweep.js.map +1 -1
- package/dist/daemon/services/feedback-aggregator.d.ts +14 -26
- package/dist/daemon/services/feedback-aggregator.d.ts.map +1 -1
- package/dist/daemon/services/feedback-aggregator.js +23 -63
- package/dist/daemon/services/feedback-aggregator.js.map +1 -1
- package/dist/daemon/services/heartbeat-writer.d.ts +6 -15
- package/dist/daemon/services/heartbeat-writer.d.ts.map +1 -1
- package/dist/daemon/services/heartbeat-writer.js +7 -36
- package/dist/daemon/services/heartbeat-writer.js.map +1 -1
- package/dist/daemon/services/kb-injector.d.ts +1 -1
- package/dist/daemon/services/kb-injector.d.ts.map +1 -1
- package/dist/daemon/services/kb-injector.js +10 -2
- package/dist/daemon/services/kb-injector.js.map +1 -1
- 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.js +1 -1
- package/dist/daemon/services/outcome-classification-service.js.map +1 -1
- package/dist/daemon/services/task-segmenter.d.ts +11 -0
- package/dist/daemon/services/task-segmenter.d.ts.map +1 -1
- package/dist/daemon/services/task-segmenter.js +48 -2
- package/dist/daemon/services/task-segmenter.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 +1 -0
- package/dist/daemon/templates/agents/coder.md +165 -8
- package/dist/daemon/templates/agents/decision-maker.md +107 -21
- package/dist/daemon/templates/agents/doc-reviewer.md +4 -1
- package/dist/daemon/templates/agents/harness-debug-full.md +85 -3
- package/dist/daemon/templates/agents/knowledge-builder.md +1 -0
- package/dist/daemon/templates/agents/patch-applier.md +1 -0
- package/dist/daemon/templates/agents/planner.md +55 -3
- package/dist/daemon/templates/agents/safety-net-implementer.md +278 -0
- package/dist/daemon/templates/agents/skill-distiller.md +1 -0
- package/dist/daemon/templates/agents/task-boundary-classifier.md +1 -0
- package/dist/daemon/templates/agents/verify-agent.md +128 -5
- package/dist/hooks/stop.sh +7 -1
- package/dist/knowledge/builder.js +36 -7
- package/dist/knowledge/builder.js.map +1 -1
- package/dist/knowledge/constants.d.ts +10 -5
- package/dist/knowledge/constants.d.ts.map +1 -1
- package/dist/knowledge/constants.js +10 -5
- package/dist/knowledge/constants.js.map +1 -1
- 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/prompt.d.ts +9 -0
- package/dist/knowledge/prompt.d.ts.map +1 -1
- package/dist/knowledge/prompt.js +17 -5
- package/dist/knowledge/prompt.js.map +1 -1
- package/dist/knowledge/query.d.ts +13 -0
- package/dist/knowledge/query.d.ts.map +1 -1
- package/dist/knowledge/query.js +107 -10
- package/dist/knowledge/query.js.map +1 -1
- package/dist/knowledge/repo-map.d.ts +11 -5
- package/dist/knowledge/repo-map.d.ts.map +1 -1
- package/dist/knowledge/repo-map.js +42 -3
- package/dist/knowledge/repo-map.js.map +1 -1
- package/dist/knowledge/validator.d.ts.map +1 -1
- package/dist/knowledge/validator.js +69 -2
- package/dist/knowledge/validator.js.map +1 -1
- package/dist/mcp/server.d.ts +64 -8
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +233 -18
- package/dist/mcp/server.js.map +1 -1
- package/dist/skills/distill/distiller.js +1 -1
- package/dist/skills/distill/distiller.js.map +1 -1
- package/dist/skills/distilled/distilled-api-design.md +4 -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 +5 -2
- 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 +85 -50
- 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 +1 -1
- package/dist/skills/distilled/distilled-receiving-code-review.md +185 -0
- package/dist/skills/distilled/distilled-subagent-driven-development.md +124 -0
- package/dist/skills/distilled/distilled-systematic-debugging.md +108 -260
- 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 +88 -78
- package/dist/skills/distilled/distilled-writing-skills.md +175 -0
- package/dist/skills/registry.d.ts +10 -50
- package/dist/skills/registry.d.ts.map +1 -1
- package/dist/skills/registry.js +7 -118
- package/dist/skills/registry.js.map +1 -1
- package/dist/skills/tools/pipeline-suggest.js +2 -2
- package/dist/skills/tools/pipeline-suggest.js.map +1 -1
- package/dist/skills/tools/skill-invoke.d.ts +2 -1
- package/dist/skills/tools/skill-invoke.d.ts.map +1 -1
- package/dist/skills/tools/skill-invoke.js +3 -1
- 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-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.js +1 -1
- package/dist/web/routes/decisions.js.map +1 -1
- 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 +2 -1
- package/dist/web/routes/events.js.map +1 -1
- 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 +43 -2
- package/dist/web/routes/knowledge.d.ts.map +1 -1
- package/dist/web/routes/knowledge.js +117 -6
- package/dist/web/routes/knowledge.js.map +1 -1
- package/dist/web/routes/pipeline.d.ts +0 -9
- package/dist/web/routes/pipeline.d.ts.map +1 -1
- package/dist/web/routes/pipeline.js +0 -4
- package/dist/web/routes/pipeline.js.map +1 -1
- package/dist/web/routes/rules.d.ts.map +1 -1
- package/dist/web/routes/rules.js +20 -6
- 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 +8 -7
- package/dist/web/routes/sessions.js.map +1 -1
- 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.js +1 -1
- package/dist/web/routes/skills-distill.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 +95 -19
- package/dist/web/routes/task-timeline.d.ts.map +1 -1
- package/dist/web/routes/task-timeline.js +344 -88
- package/dist/web/routes/task-timeline.js.map +1 -1
- package/dist/web/routes/tasks.d.ts.map +1 -1
- package/dist/web/routes/tasks.js +52 -30
- package/dist/web/routes/tasks.js.map +1 -1
- package/dist/web/routes/violations.d.ts +1 -1
- package/dist/web/routes/violations.d.ts.map +1 -1
- package/dist/web/routes/violations.js +3 -2
- package/dist/web/routes/violations.js.map +1 -1
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +20 -0
- 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/distill-manager.d.ts +47 -0
- package/dist/web/services/distill-manager.d.ts.map +1 -1
- package/dist/web/services/distill-manager.js +103 -0
- package/dist/web/services/distill-manager.js.map +1 -1
- 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-DZmTl-8J.js → MarkdownRenderer-DlDQNihj.js} +2 -2
- package/dist/web/static/assets/{MarkdownRenderer-DZmTl-8J.js.map → MarkdownRenderer-DlDQNihj.js.map} +1 -1
- package/dist/web/static/assets/NotFound-LMzbP51V.js +2 -0
- package/dist/web/static/assets/{NotFound-BQPh0vaF.js.map → NotFound-LMzbP51V.js.map} +1 -1
- 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-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/{index-7bl3kbcx.css → index-B_v_MKlb.css} +1 -1
- 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/markdown-CA7ePUts.js +30 -0
- package/dist/web/static/assets/markdown-CA7ePUts.js.map +1 -0
- package/dist/web/static/assets/{outcome-DUn1NjlC.js → outcome-BKGy9azt.js} +2 -2
- package/dist/web/static/assets/{outcome-DUn1NjlC.js.map → outcome-BKGy9azt.js.map} +1 -1
- package/dist/web/static/assets/{query-S6X1S7K9.js → query-CgCOpYWf.js} +2 -2
- package/dist/web/static/assets/{query-S6X1S7K9.js.map → query-CgCOpYWf.js.map} +1 -1
- package/dist/web/static/assets/{react-router-JVUrkhdd.js → react-router-Cxmg8RuL.js} +3 -3
- package/dist/web/static/assets/{react-router-JVUrkhdd.js.map → react-router-Cxmg8RuL.js.map} +1 -1
- package/dist/web/static/assets/{syntax-highlighter-BkZfCDsz.js → syntax-highlighter-BDYycNja.js} +3 -3
- package/dist/web/static/assets/{syntax-highlighter-BkZfCDsz.js.map → syntax-highlighter-BDYycNja.js.map} +1 -1
- package/dist/web/static/assets/task-title-BhOcemuR.js +2 -0
- package/dist/web/static/assets/task-title-BhOcemuR.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 +6 -6
- package/package.json +5 -3
- package/dist/core/storage/workflow-recommendations.d.ts +0 -124
- package/dist/core/storage/workflow-recommendations.d.ts.map +0 -1
- package/dist/core/storage/workflow-recommendations.js +0 -274
- package/dist/core/storage/workflow-recommendations.js.map +0 -1
- package/dist/daemon/services/experience-extractor.d.ts.map +0 -1
- package/dist/daemon/services/experience-extractor.js.map +0 -1
- package/dist/daemon/services/violation-reporter.d.ts.map +0 -1
- package/dist/daemon/services/violation-reporter.js.map +0 -1
- package/dist/daemon/templates/agents/harness-hotfix.md +0 -99
- package/dist/daemon/templates/agents/hybrid-feature-with-safety.md +0 -104
- package/dist/daemon/templates/agents/refactor-specialist.md +0 -98
- package/dist/skills/distill/claude-cli-resolver.d.ts.map +0 -1
- package/dist/skills/distill/claude-cli-resolver.js.map +0 -1
- package/dist/skills/distilled/distilled-defi-amm-security.md +0 -293
- package/dist/skills/keyword-score.d.ts +0 -29
- package/dist/skills/keyword-score.d.ts.map +0 -1
- package/dist/skills/keyword-score.js +0 -54
- package/dist/skills/keyword-score.js.map +0 -1
- package/dist/web/static/assets/AgentContentPage-DkeRNxok.js +0 -2
- package/dist/web/static/assets/AgentContentPage-DkeRNxok.js.map +0 -1
- package/dist/web/static/assets/AgentDelegationTable-ByBa0x1l.js +0 -2
- package/dist/web/static/assets/AgentDelegationTable-ByBa0x1l.js.map +0 -1
- package/dist/web/static/assets/ContextInsightsPage-oUk7_I8u.js +0 -3
- package/dist/web/static/assets/ContextInsightsPage-oUk7_I8u.js.map +0 -1
- package/dist/web/static/assets/DaemonHealthPage-DG2fyOP7.js +0 -2
- package/dist/web/static/assets/DaemonHealthPage-DG2fyOP7.js.map +0 -1
- package/dist/web/static/assets/DecisionsPage-CMAPEnKb.js +0 -2
- package/dist/web/static/assets/DecisionsPage-CMAPEnKb.js.map +0 -1
- package/dist/web/static/assets/DiagnosticsPage-DQd-Zm4r.js +0 -2
- package/dist/web/static/assets/DiagnosticsPage-DQd-Zm4r.js.map +0 -1
- package/dist/web/static/assets/DriftTab-DqpepOhI.js +0 -2
- package/dist/web/static/assets/DriftTab-DqpepOhI.js.map +0 -1
- package/dist/web/static/assets/HealthHomePage-CN6zNIie.js +0 -3
- package/dist/web/static/assets/HealthHomePage-CN6zNIie.js.map +0 -1
- package/dist/web/static/assets/KbHitRateTable-ByEIWujF.js +0 -2
- package/dist/web/static/assets/KbHitRateTable-ByEIWujF.js.map +0 -1
- package/dist/web/static/assets/NotFound-BQPh0vaF.js +0 -2
- package/dist/web/static/assets/ProjectSwitcher-D3lZMFd3.js +0 -2
- package/dist/web/static/assets/ProjectSwitcher-D3lZMFd3.js.map +0 -1
- package/dist/web/static/assets/SettingsPage-oLJBNzQj.js +0 -2
- package/dist/web/static/assets/SettingsPage-oLJBNzQj.js.map +0 -1
- package/dist/web/static/assets/SkillContentPage-DK5rgfgw.js +0 -2
- package/dist/web/static/assets/SkillContentPage-DK5rgfgw.js.map +0 -1
- package/dist/web/static/assets/SkillStatsTable-DYMzjEUV.js +0 -2
- package/dist/web/static/assets/SkillStatsTable-DYMzjEUV.js.map +0 -1
- package/dist/web/static/assets/SkillsDistillTab-C7qaG8q3.js +0 -2
- package/dist/web/static/assets/SkillsDistillTab-C7qaG8q3.js.map +0 -1
- package/dist/web/static/assets/TasksHubPage-03wsRRsJ.js +0 -6
- package/dist/web/static/assets/TasksHubPage-03wsRRsJ.js.map +0 -1
- package/dist/web/static/assets/ViolationsPage-DSiLr-9O.js +0 -3
- package/dist/web/static/assets/ViolationsPage-DSiLr-9O.js.map +0 -1
- package/dist/web/static/assets/arco-Bhi3a6Qp.js +0 -14
- package/dist/web/static/assets/arco-Bhi3a6Qp.js.map +0 -1
- package/dist/web/static/assets/charts-BuHQWDbQ.js +0 -37
- package/dist/web/static/assets/charts-BuHQWDbQ.js.map +0 -1
- package/dist/web/static/assets/index-BIYnq1Dx.js +0 -4
- package/dist/web/static/assets/index-BIYnq1Dx.js.map +0 -1
- package/dist/web/static/assets/useTabsParam-k8qte_0C.js +0 -2
- package/dist/web/static/assets/useTabsParam-k8qte_0C.js.map +0 -1
- package/dist/web/static/assets/vendor-DWgdB1eY.js +0 -65
- package/dist/web/static/assets/vendor-DWgdB1eY.js.map +0 -1
- /package/dist/{skills/distill → core/utils}/claude-cli-resolver.d.ts +0 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{r as x,j as e}from"./react-vendor-tkvCrao7.js";import{D as T,J as y,T as n,R as l,a1 as v,F as z,N as b,b as p}from"./arco-DV6xCLhr.js";import{u as w,f as C,k as I,s as S,a as R,o as k,b as W}from"./useDecisions-D-G2Ft5T.js";import{u as _}from"./react-router-Cxmg8RuL.js";import"./vendor-DS-q4Eyc.js";import"./query-CgCOpYWf.js";const A=l.Group;function D(i){return e.jsx(p,{color:R(i),size:"small",children:S(i)})}function E(i){return e.jsx(p,{color:W(i),size:"small",bordered:!i,children:k(i)})}function F(i){return e.jsx(p,{color:i==="spec"?"purple":"arcoblue",size:"small",children:I(i)})}function $(){const i=_(),{rows:r,loading:f,isError:g,error:u}=w(),[a,m]=x.useState("all"),h=x.useMemo(()=>a==="all"?r:r.filter(s=>s.status===a),[r,a]),d=x.useMemo(()=>{let s=0,t=0,c=0;for(const o of r)o.status==="pending"&&(s+=1),o.status==="resolved"&&(t+=1),(o.status==="resolved"||o.status==="advisory")&&!o.outcome&&(c+=1);return{total:r.length,pending:s,resolved:t,unfilled:c}},[r]);if(g)return e.jsx("div",{style:{padding:16},children:e.jsx(T,{status:"error",title:"加载决策失败",subTitle:(u==null?void 0:u.message)||"/api/decisions 端点不可用"})});const j=[{title:"intent 摘要",dataIndex:"intent",render:(s,t)=>e.jsxs("div",{style:{minWidth:0},children:[e.jsx(n.Paragraph,{style:{margin:0,fontSize:13,fontWeight:500},ellipsis:{rows:2,showTooltip:!0},children:t.intent}),e.jsxs(n.Text,{type:"secondary",style:{fontSize:12,fontFamily:"monospace"},children:["#",t.id]})]})},{title:"kind",dataIndex:"kind",width:96,render:(s,t)=>F(t.kind)},{title:"status",dataIndex:"status",width:100,render:(s,t)=>D(t.status)},{title:"outcome",dataIndex:"outcome",width:96,render:(s,t)=>E(t.outcome)},{title:"source",dataIndex:"source",width:130,render:(s,t)=>e.jsx(n.Text,{type:"secondary",style:{fontSize:12},children:t.source})},{title:"日期",dataIndex:"createdAt",width:120,sorter:(s,t)=>s.createdAt<t.createdAt?-1:s.createdAt>t.createdAt?1:0,render:(s,t)=>e.jsx(n.Text,{type:"secondary",style:{fontSize:12},children:C(t.createdAt)})},{title:"操作",dataIndex:"op",width:76,align:"right",render:(s,t)=>e.jsxs(z,{type:"text",size:"mini",onClick:c=>{c.stopPropagation(),i(`/decisions/${encodeURIComponent(t.id)}`)},children:["详情 ",e.jsx(b,{})]})}];return e.jsxs("div",{style:{padding:16,display:"flex",flexDirection:"column",gap:16},children:[e.jsxs(y,{bordered:!0,children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12,flexWrap:"wrap"},children:[e.jsx(n.Title,{heading:6,style:{margin:0},children:"决策"}),e.jsx(n.Text,{type:"secondary",style:{fontSize:12},children:"统一批准子系统 · decisions 表(kind=decision|spec)"}),e.jsx("div",{style:{flex:1}}),e.jsxs(n.Text,{type:"secondary",style:{fontSize:12},children:["总数 ",e.jsx(n.Text,{style:{fontWeight:600},children:d.total})]}),e.jsxs(n.Text,{type:"secondary",style:{fontSize:12},children:["待批准 ",e.jsx(n.Text,{style:{fontWeight:600,color:"rgb(var(--orange-6))"},children:d.pending})]}),e.jsxs(n.Text,{type:"secondary",style:{fontSize:12},children:["已批准 ",e.jsx(n.Text,{style:{fontWeight:600,color:"rgb(var(--green-6))"},children:d.resolved})]}),e.jsxs(n.Text,{type:"secondary",style:{fontSize:12},children:["outcome 待回填 ",e.jsx(n.Text,{style:{fontWeight:600},children:d.unfilled})]})]}),e.jsx("div",{style:{marginTop:12},children:e.jsxs(A,{type:"button",size:"small",value:a,onChange:s=>m(s),children:[e.jsx(l,{value:"all",children:"全部"}),e.jsx(l,{value:"pending",children:"待批准"}),e.jsx(l,{value:"resolved",children:"已批准"}),e.jsx(l,{value:"advisory",children:"已记录"})]})})]}),e.jsx(y,{bordered:!0,style:{padding:0},children:e.jsx(v,{rowKey:"id",loading:f,data:h,columns:j,pagination:h.length>20?{pageSize:20,showTotal:!0}:!1,border:{wrapper:!1,cell:!1},onRow:s=>({onClick:()=>i(`/decisions/${encodeURIComponent(s.id)}`),style:{cursor:"pointer"}})})})]})}export{$ as default};
|
|
2
|
+
//# sourceMappingURL=DecisionsPage-a3NRo_T7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DecisionsPage-a3NRo_T7.js","sources":["../../src/pages/DecisionsPage.tsx"],"sourcesContent":["/**\n * DecisionsPage — 治理 · 决策列表 (Phase 3a, decision 29688066).\n *\n * 替换 `/decisions` 的占位组件 + 旧 Drawer 版 DecisionsPage。把原型「决策」\n * 列表翻译成真 Arco 组件(**严禁直搬原型 Tailwind CSS**):Card 页头汇总 + Arco\n * Table(按创建时间倒序),列:intent 摘要 / kind / status / outcome / source /\n * 日期 / 操作。点行进整页详情 `/decisions/:id`。\n *\n * 数据接真实端点 GET /api/decisions(裸数组),取数 + 派生在 useDecisions /\n * decisions-derive,本组件只渲染。决策端点不吃 window 参数(非时间窗聚合),故本页\n * 不受全局时间窗驱动(与 KB/Skill 页不同,按端点真实形状)。\n */\nimport { useMemo, useState } from 'react'\nimport { useNavigate } from 'react-router-dom'\n\nimport Card from '@arco-design/web-react/es/Card'\nimport Table from '@arco-design/web-react/es/Table'\nimport Tag from '@arco-design/web-react/es/Tag'\nimport Typography from '@arco-design/web-react/es/Typography'\nimport Button from '@arco-design/web-react/es/Button'\nimport Radio from '@arco-design/web-react/es/Radio'\nimport Result from '@arco-design/web-react/es/Result'\nimport { IconRight } from '@arco-design/web-react/icon'\n\nimport { useDecisions } from '../hooks/useDecisions'\nimport {\n statusLabel,\n statusColor,\n outcomeLabel,\n outcomeColor,\n kindLabel,\n fmtCreated,\n type DecisionListRow,\n} from '../hooks/decisions-derive'\n\nconst RadioGroup = Radio.Group\n\nfunction statusTag(status: string) {\n return (\n <Tag color={statusColor(status)} size=\"small\">\n {statusLabel(status)}\n </Tag>\n )\n}\n\nfunction outcomeTag(outcome: DecisionListRow['outcome']) {\n return (\n <Tag color={outcomeColor(outcome)} size=\"small\" bordered={!outcome}>\n {outcomeLabel(outcome)}\n </Tag>\n )\n}\n\nfunction kindTag(kind: string) {\n return (\n <Tag color={kind === 'spec' ? 'purple' : 'arcoblue'} size=\"small\">\n {kindLabel(kind)}\n </Tag>\n )\n}\n\ntype StatusFilter = 'all' | 'pending' | 'resolved' | 'advisory'\n\nexport default function DecisionsPage() {\n const navigate = useNavigate()\n const { rows, loading, isError, error } = useDecisions()\n const [filter, setFilter] = useState<StatusFilter>('all')\n\n const filtered = useMemo(() => {\n if (filter === 'all') return rows\n return rows.filter((r) => r.status === filter)\n }, [rows, filter])\n\n const counts = useMemo(() => {\n let pending = 0\n let resolved = 0\n let unfilled = 0\n for (const r of rows) {\n if (r.status === 'pending') pending += 1\n if (r.status === 'resolved') resolved += 1\n if ((r.status === 'resolved' || r.status === 'advisory') && !r.outcome) unfilled += 1\n }\n return { total: rows.length, pending, resolved, unfilled }\n }, [rows])\n\n if (isError) {\n return (\n <div style={{ padding: 16 }}>\n <Result\n status=\"error\"\n title=\"加载决策失败\"\n subTitle={error?.message || '/api/decisions 端点不可用'}\n />\n </div>\n )\n }\n\n const columns = [\n {\n title: 'intent 摘要',\n dataIndex: 'intent',\n render: (_: unknown, row: DecisionListRow) => (\n <div style={{ minWidth: 0 }}>\n <Typography.Paragraph\n style={{ margin: 0, fontSize: 13, fontWeight: 500 }}\n ellipsis={{ rows: 2, showTooltip: true }}\n >\n {row.intent}\n </Typography.Paragraph>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12, fontFamily: 'monospace' }}>\n #{row.id}\n </Typography.Text>\n </div>\n ),\n },\n {\n title: 'kind',\n dataIndex: 'kind',\n width: 96,\n render: (_: unknown, row: DecisionListRow) => kindTag(row.kind),\n },\n {\n title: 'status',\n dataIndex: 'status',\n width: 100,\n render: (_: unknown, row: DecisionListRow) => statusTag(row.status),\n },\n {\n title: 'outcome',\n dataIndex: 'outcome',\n width: 96,\n render: (_: unknown, row: DecisionListRow) => outcomeTag(row.outcome),\n },\n {\n title: 'source',\n dataIndex: 'source',\n width: 130,\n render: (_: unknown, row: DecisionListRow) => (\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n {row.source}\n </Typography.Text>\n ),\n },\n {\n title: '日期',\n dataIndex: 'createdAt',\n width: 120,\n sorter: (a: DecisionListRow, b: DecisionListRow) =>\n a.createdAt < b.createdAt ? -1 : a.createdAt > b.createdAt ? 1 : 0,\n render: (_: unknown, row: DecisionListRow) => (\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n {fmtCreated(row.createdAt)}\n </Typography.Text>\n ),\n },\n {\n title: '操作',\n dataIndex: 'op',\n width: 76,\n align: 'right' as const,\n render: (_: unknown, row: DecisionListRow) => (\n <Button\n type=\"text\"\n size=\"mini\"\n onClick={(e) => {\n e.stopPropagation()\n navigate(`/decisions/${encodeURIComponent(row.id)}`)\n }}\n >\n 详情 <IconRight />\n </Button>\n ),\n },\n ]\n\n return (\n <div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 16 }}>\n <Card bordered>\n <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>\n <Typography.Title heading={6} style={{ margin: 0 }}>决策</Typography.Title>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n 统一批准子系统 · decisions 表(kind=decision|spec)\n </Typography.Text>\n <div style={{ flex: 1 }} />\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n 总数 <Typography.Text style={{ fontWeight: 600 }}>{counts.total}</Typography.Text>\n </Typography.Text>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n 待批准 <Typography.Text style={{ fontWeight: 600, color: 'rgb(var(--orange-6))' }}>{counts.pending}</Typography.Text>\n </Typography.Text>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n 已批准 <Typography.Text style={{ fontWeight: 600, color: 'rgb(var(--green-6))' }}>{counts.resolved}</Typography.Text>\n </Typography.Text>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n outcome 待回填 <Typography.Text style={{ fontWeight: 600 }}>{counts.unfilled}</Typography.Text>\n </Typography.Text>\n </div>\n <div style={{ marginTop: 12 }}>\n <RadioGroup\n type=\"button\"\n size=\"small\"\n value={filter}\n onChange={(v) => setFilter(v as StatusFilter)}\n >\n <Radio value=\"all\">全部</Radio>\n <Radio value=\"pending\">待批准</Radio>\n <Radio value=\"resolved\">已批准</Radio>\n <Radio value=\"advisory\">已记录</Radio>\n </RadioGroup>\n </div>\n </Card>\n\n <Card bordered style={{ padding: 0 }}>\n <Table<DecisionListRow>\n rowKey=\"id\"\n loading={loading}\n data={filtered}\n columns={columns}\n pagination={filtered.length > 20 ? { pageSize: 20, showTotal: true } : false}\n border={{ wrapper: false, cell: false }}\n onRow={(row) => ({\n onClick: () => navigate(`/decisions/${encodeURIComponent(row.id)}`),\n style: { cursor: 'pointer' },\n })}\n />\n </Card>\n </div>\n )\n}\n"],"names":["RadioGroup","Radio","statusTag","status","jsx","Tag","statusColor","statusLabel","outcomeTag","outcome","outcomeColor","outcomeLabel","kindTag","kind","kindLabel","DecisionsPage","navigate","useNavigate","rows","loading","isError","error","useDecisions","filter","setFilter","useState","filtered","useMemo","r","counts","pending","resolved","unfilled","Result","columns","_","row","jsxs","Typography","a","b","fmtCreated","Button","e","IconRight","Card","v","Table"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{r as j,j as e}from"./react-vendor-tkvCrao7.js";import{a as P,u as F,c as _}from"./query-CgCOpYWf.js";import{a as I}from"./auth-Bnf8ZcqN.js";import{J as a,T as r,F as f,ad as O,g as R,S as L,K as T,a1 as $,ah as A,ac as E,i as K,b,az as S}from"./arco-DV6xCLhr.js";import"./vendor-DS-q4Eyc.js";const q=T.Row,c=T.Col,Q={pass:"green",warn:"orange",fail:"red",skip:"gray"};function x({label:p,value:u,color:o}){return e.jsxs(a,{bordered:!0,bodyStyle:{padding:12,textAlign:"center"},children:[e.jsx(r.Text,{type:"secondary",style:{fontSize:12},children:p}),e.jsx("div",{style:{fontSize:24,fontWeight:600,color:o??"inherit",marginTop:4},children:u})]})}function H(){var g;const p=P(),[u,o]=j.useState(!1),[i,v]=j.useState(null),{data:s,isLoading:w,error:m,refetch:C}=F({queryKey:["diagnostics-page"],queryFn:async()=>{const t=await fetch("/api/diagnostics?refresh=1");if(!t.ok)throw new Error(`HTTP ${t.status}`);return t.json()},refetchInterval:3e4,retry:1}),y=_({mutationFn:async()=>{const t=await I("/api/diagnostics/fix",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({confirm:!0})});if(!t.ok){const n=await t.json().catch(()=>null);throw new Error((n==null?void 0:n.message)??`HTTP ${t.status}`)}return t.json()},onSuccess:t=>{v(t),S.success({content:t.ok?"Fixes applied":"Some fixes failed (see output)"}),p.invalidateQueries({queryKey:["diagnostics-page"]}),p.invalidateQueries({queryKey:["diagnostics-badge"]})},onError:t=>{S.error({content:`Fix failed: ${String(t)}`})}}),l=(s==null?void 0:s.checks.filter(t=>t.fixable_by==="cf fix"&&t.status!=="pass"&&t.status!=="skip"))??[],d=((g=s==null?void 0:s.meta)==null?void 0:g.current_project_path)??null,h=!d,k=l.length===0||y.isPending||h,z=[{title:"#",dataIndex:"id",width:56,render:t=>e.jsx("span",{style:{fontFamily:"monospace"},children:t})},{title:"状态",dataIndex:"status",width:88,render:t=>e.jsx(b,{color:Q[t],children:t.toUpperCase()})},{title:"检查项",dataIndex:"name",width:200,render:t=>e.jsx("span",{style:{fontFamily:"monospace"},children:t})},{title:"详情",dataIndex:"message",render:(t,n)=>e.jsxs("div",{children:[e.jsx("div",{children:n.message}),n.details&&e.jsx("div",{style:{fontSize:12,color:"var(--color-text-3)",marginTop:4},children:n.details}),n.fix_hint&&(n.status==="warn"||n.status==="fail")&&e.jsxs("div",{style:{marginTop:4,fontSize:12},children:[e.jsx(r.Text,{code:!0,children:n.fix_hint}),n.fixable_by==="cf fix"&&e.jsx(b,{color:"cyan",size:"small",style:{marginLeft:6},children:"fixable"})]})]})}];return e.jsxs("div",{style:{padding:16,display:"flex",flexDirection:"column",gap:16},children:[e.jsx(a,{bordered:!0,children:e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12,flexWrap:"wrap"},children:[e.jsx(r.Title,{heading:6,style:{margin:0},children:"诊断"}),e.jsxs(r.Text,{type:"secondary",style:{fontSize:12},children:["SQLite 主库自检与健康检查",s?` · ${s.checks.length} 项 doctor 检查`:""]}),e.jsx("div",{style:{flex:1}}),e.jsx(f,{size:"small",icon:e.jsx(O,{}),onClick:()=>C(),children:"刷新"}),e.jsx(f,{size:"small",type:"primary",status:"warning",icon:e.jsx(R,{}),disabled:k,onClick:()=>o(!0),children:h?"无项目上下文":l.length===0?"无可修复项":`一键修复 (${l.length})`})]})}),s&&e.jsx(a,{bordered:!0,style:{borderLeft:`4px solid ${h?"rgb(var(--red-6))":"rgb(var(--arcoblue-6))"}`},bodyStyle:{padding:12},children:d?e.jsxs(r.Text,{children:[e.jsx(r.Text,{type:"secondary",style:{marginRight:8},children:"当前项目:"}),e.jsx(r.Text,{code:!0,children:d}),e.jsx(r.Text,{type:"secondary",style:{marginLeft:8,fontSize:12},children:"(最近活跃)"})]}):e.jsx(r.Text,{type:"warning",children:"尚无项目活动 — 在某个项目目录下打开 Claude Code 让 daemon 记录事件后,项目级检查 (5/6) 与一键修复才会启用。"})}),w&&e.jsx(a,{bordered:!0,children:e.jsx("div",{style:{textAlign:"center",padding:32},children:e.jsx(L,{})})}),m&&e.jsx(a,{bordered:!0,children:e.jsxs(r.Text,{type:"error",children:["加载诊断失败: ",String(m)]})}),s&&e.jsxs(e.Fragment,{children:[e.jsxs(q,{gutter:[12,12],children:[e.jsx(c,{xs:12,sm:8,md:4,children:e.jsx(x,{label:"PASS",value:s.summary.pass,color:"rgb(var(--green-6))"})}),e.jsx(c,{xs:12,sm:8,md:4,children:e.jsx(x,{label:"WARN",value:s.summary.warn,color:"rgb(var(--orange-6))"})}),e.jsx(c,{xs:12,sm:8,md:4,children:e.jsx(x,{label:"FAIL",value:s.summary.fail,color:"rgb(var(--red-6))"})}),e.jsx(c,{xs:12,sm:8,md:4,children:e.jsx(x,{label:"SKIP",value:s.summary.skip,color:"rgb(var(--gray-6))"})}),e.jsx(c,{xs:12,sm:8,md:4,children:e.jsx(x,{label:"可自动修复",value:s.summary.fixable,color:"rgb(var(--arcoblue-6))"})})]}),e.jsx(a,{bordered:!0,title:`${s.checks.length} 项检查`,bodyStyle:{padding:0},children:e.jsx($,{rowKey:"id",data:s.checks,columns:z,pagination:!1,border:!1,size:"small"})}),i&&e.jsxs(a,{bordered:!0,title:`修复结果 (exit ${i.exit_code})`,children:[e.jsx(r.Paragraph,{code:!0,children:i.command}),i.cwd&&e.jsxs(r.Paragraph,{type:"secondary",style:{fontSize:12,marginTop:-8},children:["cwd: ",e.jsx(r.Text,{code:!0,children:i.cwd})]}),i.stdout&&e.jsx("pre",{style:{fontSize:12,whiteSpace:"pre-wrap",background:"var(--color-fill-1)",padding:8,borderRadius:4},children:i.stdout}),i.stderr&&e.jsx("pre",{style:{fontSize:12,whiteSpace:"pre-wrap",color:"rgb(var(--red-6))",background:"var(--color-fill-1)",padding:8,borderRadius:4},children:i.stderr})]}),e.jsx(a,{bordered:!0,bodyStyle:{padding:12},children:e.jsxs(r.Text,{type:"secondary",style:{fontSize:12},children:["生成时间: ",s.generated_at]})})]}),e.jsxs(A,{title:"确认自动修复",visible:u,onCancel:()=>o(!1),onOk:()=>{o(!1),y.mutate()},okText:"确认运行",cancelText:"取消",okButtonProps:{status:"warning",loading:y.isPending,disabled:h},children:[d?e.jsx(E,{type:"info",style:{marginBottom:12},content:e.jsxs(K,{direction:"vertical",size:2,children:[e.jsx(r.Text,{type:"secondary",style:{fontSize:12},children:"将在以下目录执行:"}),e.jsx(r.Text,{code:!0,style:{fontSize:13},children:d})]})}):e.jsx(r.Text,{type:"error",children:"没有可用的项目上下文 — 修复被阻止以免污染 daemon 目录。"}),e.jsxs(r.Paragraph,{children:["以下 ",l.length," 项将通过 ",e.jsx(r.Text,{code:!0,children:"cf fix --apply --yes"})," 自动修复:"]}),e.jsx("ul",{style:{paddingLeft:20},children:l.map(t=>e.jsxs("li",{style:{marginBottom:4},children:["#",t.id," ",t.name," → ",e.jsx(r.Text,{code:!0,children:t.fix_hint})]},t.id))})]})]})}export{H as default};
|
|
2
|
+
//# sourceMappingURL=DiagnosticsPage-DIVdiIQG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DiagnosticsPage-DIVdiIQG.js","sources":["../../src/pages/DiagnosticsPage.tsx"],"sourcesContent":["/**\n * /system/diagnostics — 系统 · 诊断。\n *\n * Arco Phase 4b(decision 29688066):视觉对齐新 Arco shell(全宽容器 + 头部 Card +\n * Arco Table + Grid 统计卡),与其它系统页观感一致。**纯视觉对齐**——数据端点\n * (`/api/diagnostics` + `POST /api/diagnostics/fix`)、查询/mutation 逻辑、确认 Modal、\n * 字段口径全部不变。原页用 maxWidth 居中 + 裸 <table> 渲染检查项,对齐后改用\n * 全宽 padding 容器 + 头部 Card + Arco Table,统计卡用 Grid.Row 排布。\n *\n * 渲染 doctor 报告 + 一键修复(确认 Modal 列出计划命令再 POST\n * /api/diagnostics/fix `{ confirm: true }`)。检查项数量动态取 `data.checks.length`\n * (后端现发 12 项,不再写死数字 — Phase 4c 标签动态化)。\n *\n * Spec: docs/design/2026-06-12/0941-arco-redesign-rollout-spec.md Phase 4\n * (上游:docs/design/2026-06-01/1030-cf-doctor-diagnostic-spec.md)\n */\n\nimport { useState } from 'react'\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'\nimport {\n Alert,\n Button,\n Card,\n Grid,\n Modal,\n Notification,\n Space,\n Spin,\n Table,\n Tag,\n Typography,\n} from '@arco-design/web-react'\nimport { IconRefresh, IconCheck } from '@arco-design/web-react/icon'\nimport { authFetch } from '../utils/auth'\n\nconst Row = Grid.Row\nconst Col = Grid.Col\n\ntype Status = 'pass' | 'warn' | 'fail' | 'skip'\n\ninterface CheckResult {\n id: number\n name: string\n status: Status\n message: string\n details?: string\n fix_hint?: string\n fixable_by?: 'cf fix' | 'manual'\n}\n\ninterface DiagnosticsMeta {\n current_project_path: string | null\n project_source: 'recent-event' | 'none'\n}\n\ninterface DiagnosticsResponse {\n summary: { pass: number; warn: number; fail: number; skip: number; fixable: number }\n checks: CheckResult[]\n generated_at: string\n /** spec e5b845c4: project resolved by the server (most-recent or null). */\n meta?: DiagnosticsMeta\n}\n\ninterface FixResponse {\n ok: boolean\n exit_code: number | null\n stdout: string\n stderr: string\n command: string\n /** spec e5b845c4: cwd actually used by the spawned `cf fix`. */\n cwd?: string\n}\n\nconst STATUS_COLOR: Record<Status, string> = {\n pass: 'green',\n warn: 'orange',\n fail: 'red',\n skip: 'gray',\n}\n\n/** 统计卡:复用语义配色,排进 Grid.Row(替原裸 flex)。 */\nfunction SummaryCard({ label, value, color }: { label: string; value: number; color?: string }) {\n return (\n <Card bordered bodyStyle={{ padding: 12, textAlign: 'center' }}>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>{label}</Typography.Text>\n <div style={{ fontSize: 24, fontWeight: 600, color: color ?? 'inherit', marginTop: 4 }}>\n {value}\n </div>\n </Card>\n )\n}\n\nexport default function DiagnosticsPage() {\n const qc = useQueryClient()\n const [modalOpen, setModalOpen] = useState(false)\n const [fixOutput, setFixOutput] = useState<FixResponse | null>(null)\n\n const { data, isLoading, error, refetch } = useQuery<DiagnosticsResponse>({\n queryKey: ['diagnostics-page'],\n queryFn: async () => {\n const res = await fetch('/api/diagnostics?refresh=1')\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n return res.json()\n },\n refetchInterval: 30_000,\n retry: 1,\n })\n\n const fixMutation = useMutation<FixResponse>({\n mutationFn: async () => {\n const res = await authFetch('/api/diagnostics/fix', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ confirm: true }),\n })\n if (!res.ok) {\n const body = (await res.json().catch(() => null)) as { message?: string } | null\n throw new Error(body?.message ?? `HTTP ${res.status}`)\n }\n return res.json()\n },\n onSuccess: (out) => {\n setFixOutput(out)\n Notification.success({ content: out.ok ? 'Fixes applied' : 'Some fixes failed (see output)' })\n qc.invalidateQueries({ queryKey: ['diagnostics-page'] })\n qc.invalidateQueries({ queryKey: ['diagnostics-badge'] })\n },\n onError: (err) => {\n Notification.error({ content: `Fix failed: ${String(err)}` })\n },\n })\n\n const fixable = data?.checks.filter((c) => c.fixable_by === 'cf fix' && c.status !== 'pass' && c.status !== 'skip') ?? []\n const projectPath = data?.meta?.current_project_path ?? null\n const noProject = !projectPath\n const fixDisabled = fixable.length === 0 || fixMutation.isPending || noProject\n\n const checkColumns = [\n { title: '#', dataIndex: 'id', width: 56, render: (v: number) => <span style={{ fontFamily: 'monospace' }}>{v}</span> },\n {\n title: '状态',\n dataIndex: 'status',\n width: 88,\n render: (s: Status) => <Tag color={STATUS_COLOR[s]}>{s.toUpperCase()}</Tag>,\n },\n {\n title: '检查项',\n dataIndex: 'name',\n width: 200,\n render: (v: string) => <span style={{ fontFamily: 'monospace' }}>{v}</span>,\n },\n {\n title: '详情',\n dataIndex: 'message',\n render: (_: unknown, c: CheckResult) => (\n <div>\n <div>{c.message}</div>\n {c.details && (\n <div style={{ fontSize: 12, color: 'var(--color-text-3)', marginTop: 4 }}>{c.details}</div>\n )}\n {c.fix_hint && (c.status === 'warn' || c.status === 'fail') && (\n <div style={{ marginTop: 4, fontSize: 12 }}>\n <Typography.Text code>{c.fix_hint}</Typography.Text>\n {c.fixable_by === 'cf fix' && (\n <Tag color=\"cyan\" size=\"small\" style={{ marginLeft: 6 }}>fixable</Tag>\n )}\n </div>\n )}\n </div>\n ),\n },\n ]\n\n return (\n <div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 16 }}>\n <Card bordered>\n <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>\n <Typography.Title heading={6} style={{ margin: 0 }}>诊断</Typography.Title>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n SQLite 主库自检与健康检查{data ? ` · ${data.checks.length} 项 doctor 检查` : ''}\n </Typography.Text>\n <div style={{ flex: 1 }} />\n <Button size=\"small\" icon={<IconRefresh />} onClick={() => refetch()}>刷新</Button>\n <Button\n size=\"small\"\n type=\"primary\"\n status=\"warning\"\n icon={<IconCheck />}\n disabled={fixDisabled}\n onClick={() => setModalOpen(true)}\n >\n {noProject\n ? '无项目上下文'\n : fixable.length === 0\n ? '无可修复项'\n : `一键修复 (${fixable.length})`}\n </Button>\n </div>\n </Card>\n\n {/* spec e5b845c4: surface the project that the server picked. */}\n {data && (\n <Card\n bordered\n style={{ borderLeft: `4px solid ${noProject ? 'rgb(var(--red-6))' : 'rgb(var(--arcoblue-6))'}` }}\n bodyStyle={{ padding: 12 }}\n >\n {projectPath ? (\n <Typography.Text>\n <Typography.Text type=\"secondary\" style={{ marginRight: 8 }}>当前项目:</Typography.Text>\n <Typography.Text code>{projectPath}</Typography.Text>\n <Typography.Text type=\"secondary\" style={{ marginLeft: 8, fontSize: 12 }}>\n (最近活跃)\n </Typography.Text>\n </Typography.Text>\n ) : (\n <Typography.Text type=\"warning\">\n 尚无项目活动 — 在某个项目目录下打开 Claude Code 让 daemon 记录事件后,项目级检查 (5/6) 与一键修复才会启用。\n </Typography.Text>\n )}\n </Card>\n )}\n\n {isLoading && (\n <Card bordered>\n <div style={{ textAlign: 'center', padding: 32 }}><Spin /></div>\n </Card>\n )}\n {error && (\n <Card bordered>\n <Typography.Text type=\"error\">加载诊断失败: {String(error)}</Typography.Text>\n </Card>\n )}\n\n {data && (\n <>\n <Row gutter={[12, 12]}>\n <Col xs={12} sm={8} md={4}><SummaryCard label=\"PASS\" value={data.summary.pass} color=\"rgb(var(--green-6))\" /></Col>\n <Col xs={12} sm={8} md={4}><SummaryCard label=\"WARN\" value={data.summary.warn} color=\"rgb(var(--orange-6))\" /></Col>\n <Col xs={12} sm={8} md={4}><SummaryCard label=\"FAIL\" value={data.summary.fail} color=\"rgb(var(--red-6))\" /></Col>\n <Col xs={12} sm={8} md={4}><SummaryCard label=\"SKIP\" value={data.summary.skip} color=\"rgb(var(--gray-6))\" /></Col>\n <Col xs={12} sm={8} md={4}><SummaryCard label=\"可自动修复\" value={data.summary.fixable} color=\"rgb(var(--arcoblue-6))\" /></Col>\n </Row>\n\n <Card bordered title={`${data.checks.length} 项检查`} bodyStyle={{ padding: 0 }}>\n <Table\n rowKey=\"id\"\n data={data.checks}\n columns={checkColumns}\n pagination={false}\n border={false}\n size=\"small\"\n />\n </Card>\n\n {fixOutput && (\n <Card bordered title={`修复结果 (exit ${fixOutput.exit_code})`}>\n <Typography.Paragraph code>{fixOutput.command}</Typography.Paragraph>\n {fixOutput.cwd && (\n <Typography.Paragraph type=\"secondary\" style={{ fontSize: 12, marginTop: -8 }}>\n cwd: <Typography.Text code>{fixOutput.cwd}</Typography.Text>\n </Typography.Paragraph>\n )}\n {fixOutput.stdout && (\n <pre style={{ fontSize: 12, whiteSpace: 'pre-wrap', background: 'var(--color-fill-1)', padding: 8, borderRadius: 4 }}>\n {fixOutput.stdout}\n </pre>\n )}\n {fixOutput.stderr && (\n <pre style={{ fontSize: 12, whiteSpace: 'pre-wrap', color: 'rgb(var(--red-6))', background: 'var(--color-fill-1)', padding: 8, borderRadius: 4 }}>\n {fixOutput.stderr}\n </pre>\n )}\n </Card>\n )}\n\n <Card bordered bodyStyle={{ padding: 12 }}>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n 生成时间: {data.generated_at}\n </Typography.Text>\n </Card>\n </>\n )}\n\n <Modal\n title=\"确认自动修复\"\n visible={modalOpen}\n onCancel={() => setModalOpen(false)}\n onOk={() => {\n setModalOpen(false)\n fixMutation.mutate()\n }}\n okText=\"确认运行\"\n cancelText=\"取消\"\n okButtonProps={{\n status: 'warning',\n loading: fixMutation.isPending,\n disabled: noProject,\n }}\n >\n {/* spec e5b845c4 OQ#4: P0 safety — always show target cwd so user\n can verify before letting `cf project init` write to disk. */}\n {projectPath ? (\n <Alert\n type=\"info\"\n style={{ marginBottom: 12 }}\n content={\n <Space direction=\"vertical\" size={2}>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>将在以下目录执行:</Typography.Text>\n <Typography.Text code style={{ fontSize: 13 }}>{projectPath}</Typography.Text>\n </Space>\n }\n />\n ) : (\n <Typography.Text type=\"error\">\n 没有可用的项目上下文 — 修复被阻止以免污染 daemon 目录。\n </Typography.Text>\n )}\n <Typography.Paragraph>\n 以下 {fixable.length} 项将通过 <Typography.Text code>cf fix --apply --yes</Typography.Text> 自动修复:\n </Typography.Paragraph>\n <ul style={{ paddingLeft: 20 }}>\n {fixable.map((c) => (\n <li key={c.id} style={{ marginBottom: 4 }}>\n #{c.id} {c.name} → <Typography.Text code>{c.fix_hint}</Typography.Text>\n </li>\n ))}\n </ul>\n </Modal>\n </div>\n )\n}\n"],"names":["Row","Grid","Col","STATUS_COLOR","SummaryCard","label","value","color","jsxs","Card","jsx","Typography","DiagnosticsPage","qc","useQueryClient","modalOpen","setModalOpen","useState","fixOutput","setFixOutput","data","isLoading","error","refetch","useQuery","res","fixMutation","useMutation","authFetch","body","out","Notification","err","fixable","c","projectPath","_a","noProject","fixDisabled","checkColumns","v","s","Tag","_","Button","IconRefresh","IconCheck","Spin","Fragment","Table","Modal","Alert","Space"],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{j as e}from"./react-vendor-tkvCrao7.js";import{J as r,d as v,D as S,F as x,X as z,ab as T,T as l,b as a,f,K as j,E as n,$ as I,N as k,O as w,a9 as C,aa as R,a5 as D}from"./arco-DV6xCLhr.js";import{M as L}from"./MarkdownRenderer-DlDQNihj.js";import{b as W,f as p,c as m,a as B,d as $}from"./useDistill-21dZkXlT.js";import{d as M,u as P}from"./react-router-Cxmg8RuL.js";import"./vendor-DS-q4Eyc.js";import"./syntax-highlighter-BDYycNja.js";import"./markdown-CA7ePUts.js";import"./query-CgCOpYWf.js";const E=j.Row,h=j.Col;function y(t){const s=$(t),i=s.icon==="check"?e.jsx(w,{}):s.icon==="minus"?e.jsx(C,{}):e.jsx(R,{});return e.jsx(a,{color:s.color,size:"small",icon:i,children:s.label})}function F(t){const s=Math.round(t.value*100),i=t.value>=1?"rgb(var(--green-6))":t.value>0?"rgb(var(--orange-6))":"rgb(var(--gray-4))";return e.jsxs("div",{children:[e.jsxs("div",{style:{display:"flex",justifyContent:"space-between",marginBottom:4},children:[e.jsx(l.Text,{style:{fontSize:13},children:t.label}),e.jsxs(l.Text,{type:"secondary",style:{fontSize:12},children:[t.value.toFixed(1)," / 1"]})]}),e.jsx(D,{percent:s,showText:!1,color:i,size:"small"})]},t.key)}function K(t){return e.jsxs("div",{style:{padding:"10px 0",borderBottom:"1px solid var(--color-border-1)"},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,flexWrap:"wrap"},children:[e.jsx(f,{style:{color:"var(--color-text-3)"}}),e.jsx(l.Text,{style:{fontSize:13,fontWeight:600},title:t.url,children:t.repo}),t.license&&e.jsx(a,{size:"small",color:"arcoblue",children:t.license}),t.commit&&e.jsx(l.Text,{code:!0,style:{fontSize:11},children:t.commit})]}),t.paths.length>0&&e.jsx("div",{style:{marginTop:4,paddingLeft:22},children:t.paths.map(s=>e.jsx(l.Text,{type:"secondary",style:{fontSize:11,display:"block",fontFamily:"monospace"},children:s},s))})]},`${t.url}-${t.paths.join(",")}`)}function q(){const{topicId:t}=M(),s=P(),{view:i,loading:u,isError:g,error:d}=W(t);if(u)return e.jsx("div",{style:{padding:16},children:e.jsx(r,{bordered:!0,children:e.jsx(v,{animation:!0,text:{rows:8}})})});if(g||!i)return e.jsx("div",{style:{padding:16},children:e.jsx(S,{status:"error",title:"加载蒸馏详情失败",subTitle:(d==null?void 0:d.message)||"该 topic 不存在或端点不可用(本地回环)",extra:e.jsx(x,{type:"primary",onClick:()=>s("/ai/distill"),children:"返回蒸馏"})})});const c=i.decision==="distilled",b=i.id.startsWith("distilled-")?i.id:`distilled-${i.id}`;return e.jsxs("div",{style:{padding:16,display:"flex",flexDirection:"column",gap:16},children:[e.jsxs(r,{bordered:!0,children:[e.jsx(x,{type:"text",size:"small",icon:e.jsx(z,{}),style:{marginBottom:8,paddingLeft:0},onClick:()=>s("/ai/distill"),children:"返回蒸馏"}),e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"},children:[e.jsx(T,{style:{color:"rgb(var(--arcoblue-6))"}}),e.jsx(l.Title,{heading:5,style:{margin:0,fontFamily:"monospace"},children:i.id}),i.score!==null&&e.jsx(a,{color:i.score>=3?"green":"orange",size:"small",children:p(i.score)}),y(i.decision)]}),i.description&&e.jsx(l.Text,{type:"secondary",style:{fontSize:12,display:"block",marginTop:6},children:i.description}),i.attributions.length>0&&e.jsxs("div",{style:{display:"flex",gap:10,flexWrap:"wrap",marginTop:8},children:[e.jsx(l.Text,{type:"secondary",style:{fontSize:12},children:"上游归属:"}),i.attributions.map(o=>e.jsxs(a,{size:"small",icon:e.jsx(f,{}),children:[o.repo,o.commit?` @${o.commit}`:""]},`${o.url}-${o.paths.join(",")}`))]})]}),e.jsxs(E,{gutter:16,align:"start",children:[e.jsx(h,{xs:24,xl:16,style:{marginBottom:16},children:e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:16},children:[e.jsx(r,{bordered:!0,title:e.jsx("span",{style:{fontSize:14,fontWeight:600},children:"📐 5 维 IT 通用评分"}),extra:i.score!==null?e.jsxs(l.Text,{style:{fontSize:13,fontWeight:600},children:["合计 ",p(i.score)]}):null,children:c?e.jsxs(e.Fragment,{children:[e.jsx("div",{style:{display:"flex",flexDirection:"column",gap:12},children:i.dims.map(F)}),i.rationale&&e.jsxs("div",{style:{marginTop:16,padding:"10px 14px",background:"var(--color-fill-1)",borderRadius:4},children:[e.jsx(l.Text,{type:"secondary",style:{fontSize:12},children:"评分依据"}),e.jsx(l.Paragraph,{style:{margin:"4px 0 0",fontSize:13},children:i.rationale})]})]}):i.decision==="skipped"?e.jsx(n,{description:"该 topic 被跳过(IT 通用分 <3,未蒸馏成 SKILL)"}):e.jsx(n,{description:"该 topic 因正文含项目锚点被拒(ProjectAnchorRejection),未产出可移植 SKILL"})}),c&&e.jsxs(r,{bordered:!0,title:e.jsx("span",{style:{fontSize:14,fontWeight:600},children:"📦 SKILL 封装预览"}),children:[m(i.frontmatter)&&e.jsx("pre",{style:{margin:"0 0 12px",padding:"12px 14px",background:"var(--color-fill-2)",borderRadius:4,fontSize:12,lineHeight:1.6,overflow:"auto",whiteSpace:"pre-wrap"},children:`---
|
|
2
|
+
${m(i.frontmatter)}
|
|
3
|
+
---`}),i.body?e.jsx("div",{style:{border:"1px solid var(--color-border-2)",borderRadius:4,background:"var(--color-fill-1)",padding:"12px 16px",maxHeight:520,overflow:"auto"},children:e.jsx(L,{content:i.body})}):e.jsx(n,{description:"封装正文为空(diff 端点未返回 distilledMarkdown)"})]})]})}),e.jsx(h,{xs:24,xl:8,style:{marginBottom:16},children:e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:16},children:[e.jsx(r,{bordered:!0,title:e.jsx("span",{style:{fontSize:14,fontWeight:600},children:"概要"}),children:e.jsx(I,{colon:" :",size:"small",column:1,labelStyle:{width:92,color:"var(--color-text-3)"},data:[{label:"name",value:e.jsx(l.Text,{code:!0,style:{fontSize:11},children:i.name})},{label:"version",value:i.version??"—"},{label:"IT 通用分",value:p(i.score)},{label:"决定",value:y(i.decision)},{label:"distilled_by",value:i.distilledBy??"—"},{label:"distilled_at",value:B(i.distilledAt)},{label:"spawn_agent",value:i.spawnAgent??"—"}]})}),e.jsx(r,{bordered:!0,title:e.jsx("span",{style:{fontSize:14,fontWeight:600},children:"上游归属"}),children:i.attributions.length>0?e.jsx("div",{style:{display:"flex",flexDirection:"column"},children:i.attributions.map(K)}):e.jsx(n,{description:"无上游归属信息(distilled_from 缺省)"})}),c&&e.jsxs(r,{bordered:!0,title:e.jsx("span",{style:{fontSize:14,fontWeight:600},children:"后续调用"}),children:[e.jsx(l.Text,{type:"secondary",style:{fontSize:12,display:"block",marginBottom:10},children:"此蒸馏 SKILL 在 agent 调用与有用性自评的明细,见 Skill 调用页。"}),e.jsxs(x,{type:"outline",long:!0,onClick:()=>s(`/ai/skills/${encodeURIComponent(b)}`),children:["查看 Skill 调用明细 ",e.jsx(k,{})]})]})]})})]})]})}export{q as default};
|
|
4
|
+
//# sourceMappingURL=DistillDetailPage-U6a3l2iP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DistillDetailPage-U6a3l2iP.js","sources":["../../src/pages/ai/DistillDetailPage.tsx"],"sourcesContent":["/**\n * DistillDetailPage — AI 资源 · 蒸馏详情整页 (Phase 2e, decision 29688066).\n *\n * 替换 `/ai/distill/:topicId` 的占位组件。整页(非抽屉)布局,翻译原型\n * 「蒸馏详情」成真 Arco 组件(**严禁直搬原型 Tailwind CSS**):\n * A. 页头横条:输出 id + score Tag + 决定 Tag + 上游归属(repo/commit/paths)\n * B. 左右双栏:\n * 左 = 5 维 D1-D5 评分条(各 0/0.5/1)+ 每维归在 rationale + SKILL 封装预览\n * (frontmatter + body);skip 展示 SKIP 形状、rejected 展示被拒锚点\n * 右 360 = 概要 Descriptions(name/version/score/decision/distilled_by/\n * distilled_at/spawn_agent)+ distilled_from 上游归属 + 后续调用链到\n * 对应 Skill 页 /ai/skills/:id\n *\n * 数据接真实只读端点(GET /api/skills/distill/review/:topicId/diff + /status),\n * 取数 + 派生在 useDistillDetail / distill-derive,本组件只渲染。\n */\nimport { useParams, useNavigate } from 'react-router-dom'\n\nimport Card from '@arco-design/web-react/es/Card'\nimport Grid from '@arco-design/web-react/es/Grid'\nimport Tag from '@arco-design/web-react/es/Tag'\nimport Typography from '@arco-design/web-react/es/Typography'\nimport Descriptions from '@arco-design/web-react/es/Descriptions'\nimport Button from '@arco-design/web-react/es/Button'\nimport Empty from '@arco-design/web-react/es/Empty'\nimport Skeleton from '@arco-design/web-react/es/Skeleton'\nimport Result from '@arco-design/web-react/es/Result'\nimport Progress from '@arco-design/web-react/es/Progress'\nimport {\n IconLeft,\n IconExperiment,\n IconStorage,\n IconRight,\n IconCheckCircle,\n IconMinusCircle,\n IconCloseCircle,\n} from '@arco-design/web-react/icon'\n\nimport MarkdownRenderer from '../../components/MarkdownRenderer'\nimport { useDistillDetail } from '../../hooks/useDistill'\nimport {\n formatScore,\n formatIso,\n decisionMeta,\n frontmatterPreview,\n type DimBar,\n type DistillDecision,\n type UpstreamAttribution,\n} from '../../hooks/distill-derive'\n\nconst Row = Grid.Row\nconst Col = Grid.Col\n\nfunction decisionTag(d: DistillDecision) {\n const m = decisionMeta(d)\n const icon =\n m.icon === 'check' ? (\n <IconCheckCircle />\n ) : m.icon === 'minus' ? (\n <IconMinusCircle />\n ) : (\n <IconCloseCircle />\n )\n return (\n <Tag color={m.color} size=\"small\" icon={icon}>\n {m.label}\n </Tag>\n )\n}\n\n/** 5 维评分条(各 0/0.5/1 → 0/50/100%)。 */\nfunction dimBar(d: DimBar) {\n const pct = Math.round(d.value * 100)\n const color =\n d.value >= 1\n ? 'rgb(var(--green-6))'\n : d.value > 0\n ? 'rgb(var(--orange-6))'\n : 'rgb(var(--gray-4))'\n return (\n <div key={d.key}>\n <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 4 }}>\n <Typography.Text style={{ fontSize: 13 }}>{d.label}</Typography.Text>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n {d.value.toFixed(1)} / 1\n </Typography.Text>\n </div>\n <Progress percent={pct} showText={false} color={color} size=\"small\" />\n </div>\n )\n}\n\nfunction attributionItem(a: UpstreamAttribution) {\n return (\n <div\n key={`${a.url}-${a.paths.join(',')}`}\n style={{\n padding: '10px 0',\n borderBottom: '1px solid var(--color-border-1)',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>\n <IconStorage style={{ color: 'var(--color-text-3)' }} />\n <Typography.Text style={{ fontSize: 13, fontWeight: 600 }} title={a.url}>\n {a.repo}\n </Typography.Text>\n {a.license && (\n <Tag size=\"small\" color=\"arcoblue\">\n {a.license}\n </Tag>\n )}\n {a.commit && (\n <Typography.Text code style={{ fontSize: 11 }}>\n {a.commit}\n </Typography.Text>\n )}\n </div>\n {a.paths.length > 0 && (\n <div style={{ marginTop: 4, paddingLeft: 22 }}>\n {a.paths.map((p) => (\n <Typography.Text\n key={p}\n type=\"secondary\"\n style={{ fontSize: 11, display: 'block', fontFamily: 'monospace' }}\n >\n {p}\n </Typography.Text>\n ))}\n </div>\n )}\n </div>\n )\n}\n\nexport default function DistillDetailPage() {\n const { topicId } = useParams<{ topicId: string }>()\n const navigate = useNavigate()\n const { view, loading, isError, error } = useDistillDetail(topicId)\n\n if (loading) {\n return (\n <div style={{ padding: 16 }}>\n <Card bordered>\n <Skeleton animation text={{ rows: 8 }} />\n </Card>\n </div>\n )\n }\n\n if (isError || !view) {\n return (\n <div style={{ padding: 16 }}>\n <Result\n status=\"error\"\n title=\"加载蒸馏详情失败\"\n subTitle={error?.message || '该 topic 不存在或端点不可用(本地回环)'}\n extra={\n <Button type=\"primary\" onClick={() => navigate('/ai/distill')}>\n 返回蒸馏\n </Button>\n }\n />\n </div>\n )\n }\n\n const isDistilled = view.decision === 'distilled'\n // 对应 Skill 页 id:distilled-xxx 直接用;否则补前缀(详情页后续调用链到 /ai/skills/:id)。\n const skillId = view.id.startsWith('distilled-') ? view.id : `distilled-${view.id}`\n\n return (\n <div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 16 }}>\n {/* ── A. 页头横条 ─────────────────────────────────────────────── */}\n <Card bordered>\n <Button\n type=\"text\"\n size=\"small\"\n icon={<IconLeft />}\n style={{ marginBottom: 8, paddingLeft: 0 }}\n onClick={() => navigate('/ai/distill')}\n >\n 返回蒸馏\n </Button>\n <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>\n <IconExperiment style={{ color: 'rgb(var(--arcoblue-6))' }} />\n <Typography.Title heading={5} style={{ margin: 0, fontFamily: 'monospace' }}>\n {view.id}\n </Typography.Title>\n {view.score !== null && (\n <Tag color={view.score >= 3 ? 'green' : 'orange'} size=\"small\">\n {formatScore(view.score)}\n </Tag>\n )}\n {decisionTag(view.decision)}\n </div>\n {view.description && (\n <Typography.Text type=\"secondary\" style={{ fontSize: 12, display: 'block', marginTop: 6 }}>\n {view.description}\n </Typography.Text>\n )}\n {view.attributions.length > 0 && (\n <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginTop: 8 }}>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n 上游归属:\n </Typography.Text>\n {view.attributions.map((a) => (\n <Tag key={`${a.url}-${a.paths.join(',')}`} size=\"small\" icon={<IconStorage />}>\n {a.repo}\n {a.commit ? ` @${a.commit}` : ''}\n </Tag>\n ))}\n </div>\n )}\n </Card>\n\n {/* ── B. 左右双栏 ─────────────────────────────────────────────── */}\n <Row gutter={16} align=\"start\">\n {/* 左主栏:5 维评分 + rationale + SKILL 封装预览 */}\n <Col xs={24} xl={16} style={{ marginBottom: 16 }}>\n <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>\n <Card\n bordered\n title={<span style={{ fontSize: 14, fontWeight: 600 }}>📐 5 维 IT 通用评分</span>}\n extra={\n view.score !== null ? (\n <Typography.Text style={{ fontSize: 13, fontWeight: 600 }}>\n 合计 {formatScore(view.score)}\n </Typography.Text>\n ) : null\n }\n >\n {isDistilled ? (\n <>\n <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>\n {view.dims.map(dimBar)}\n </div>\n {view.rationale && (\n <div\n style={{\n marginTop: 16,\n padding: '10px 14px',\n background: 'var(--color-fill-1)',\n borderRadius: 4,\n }}\n >\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n 评分依据\n </Typography.Text>\n <Typography.Paragraph style={{ margin: '4px 0 0', fontSize: 13 }}>\n {view.rationale}\n </Typography.Paragraph>\n </div>\n )}\n </>\n ) : view.decision === 'skipped' ? (\n <Empty description={`该 topic 被跳过(IT 通用分 <3,未蒸馏成 SKILL)`} />\n ) : (\n <Empty description=\"该 topic 因正文含项目锚点被拒(ProjectAnchorRejection),未产出可移植 SKILL\" />\n )}\n </Card>\n\n {isDistilled && (\n <Card\n bordered\n title={<span style={{ fontSize: 14, fontWeight: 600 }}>📦 SKILL 封装预览</span>}\n >\n {frontmatterPreview(view.frontmatter) && (\n <pre\n style={{\n margin: '0 0 12px',\n padding: '12px 14px',\n background: 'var(--color-fill-2)',\n borderRadius: 4,\n fontSize: 12,\n lineHeight: 1.6,\n overflow: 'auto',\n whiteSpace: 'pre-wrap',\n }}\n >\n {`---\\n${frontmatterPreview(view.frontmatter)}\\n---`}\n </pre>\n )}\n {view.body ? (\n <div\n style={{\n border: '1px solid var(--color-border-2)',\n borderRadius: 4,\n background: 'var(--color-fill-1)',\n padding: '12px 16px',\n maxHeight: 520,\n overflow: 'auto',\n }}\n >\n <MarkdownRenderer content={view.body} />\n </div>\n ) : (\n <Empty description=\"封装正文为空(diff 端点未返回 distilledMarkdown)\" />\n )}\n </Card>\n )}\n </div>\n </Col>\n\n {/* 右侧栏:概要 + 上游归属 + 后续调用 */}\n <Col xs={24} xl={8} style={{ marginBottom: 16 }}>\n <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>\n <Card bordered title={<span style={{ fontSize: 14, fontWeight: 600 }}>概要</span>}>\n <Descriptions\n colon=\" :\"\n size=\"small\"\n column={1}\n labelStyle={{ width: 92, color: 'var(--color-text-3)' }}\n data={[\n { label: 'name', value: <Typography.Text code style={{ fontSize: 11 }}>{view.name}</Typography.Text> },\n { label: 'version', value: view.version ?? '—' },\n { label: 'IT 通用分', value: formatScore(view.score) },\n { label: '决定', value: decisionTag(view.decision) },\n { label: 'distilled_by', value: view.distilledBy ?? '—' },\n { label: 'distilled_at', value: formatIso(view.distilledAt) },\n { label: 'spawn_agent', value: view.spawnAgent ?? '—' },\n ]}\n />\n </Card>\n\n <Card bordered title={<span style={{ fontSize: 14, fontWeight: 600 }}>上游归属</span>}>\n {view.attributions.length > 0 ? (\n <div style={{ display: 'flex', flexDirection: 'column' }}>\n {view.attributions.map(attributionItem)}\n </div>\n ) : (\n <Empty description=\"无上游归属信息(distilled_from 缺省)\" />\n )}\n </Card>\n\n {isDistilled && (\n <Card bordered title={<span style={{ fontSize: 14, fontWeight: 600 }}>后续调用</span>}>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12, display: 'block', marginBottom: 10 }}>\n 此蒸馏 SKILL 在 agent 调用与有用性自评的明细,见 Skill 调用页。\n </Typography.Text>\n <Button\n type=\"outline\"\n long\n onClick={() => navigate(`/ai/skills/${encodeURIComponent(skillId)}`)}\n >\n 查看 Skill 调用明细 <IconRight />\n </Button>\n </Card>\n )}\n </div>\n </Col>\n </Row>\n </div>\n )\n}\n"],"names":["Row","Grid","Col","decisionTag","d","m","decisionMeta","icon","IconCheckCircle","jsx","IconMinusCircle","IconCloseCircle","Tag","dimBar","pct","color","jsxs","Typography","Progress","attributionItem","a","IconStorage","p","DistillDetailPage","topicId","useParams","navigate","useNavigate","view","loading","isError","error","useDistillDetail","Card","Skeleton","Result","Button","isDistilled","skillId","IconLeft","IconExperiment","formatScore","Fragment","Empty","frontmatterPreview","MarkdownRenderer","Descriptions","formatIso","IconRight"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{j as e}from"./react-vendor-tkvCrao7.js";import{D as y,J as a,T as i,F as c,w as g,b as d,a1 as m,N as f,f as j,O as u,a9 as T,aa as C}from"./arco-DV6xCLhr.js";import{u as I,f as b,a as S,d as v}from"./useDistill-21dZkXlT.js";import{u as z}from"./react-router-Cxmg8RuL.js";import"./vendor-DS-q4Eyc.js";import"./query-CgCOpYWf.js";function k(s){const t=v(s.decision),o=t.icon==="check"?e.jsx(u,{}):t.icon==="minus"?e.jsx(T,{}):e.jsx(C,{});return e.jsx(d,{color:t.color,size:"small",icon:o,children:t.label})}function w(s){return e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:2,padding:"8px 12px",border:"1px solid var(--color-border-2)",borderRadius:6,minWidth:150,background:s.isSkipSource?"var(--color-fill-1)":"transparent"},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6},children:[e.jsx(j,{style:{color:"var(--color-text-3)",fontSize:13}}),e.jsx(i.Text,{style:{fontSize:13,fontWeight:600},children:s.label}),s.isSkipSource&&e.jsx(d,{size:"small",color:"gray",style:{marginLeft:2},children:"skip"})]}),e.jsxs(i.Text,{type:"secondary",style:{fontSize:11},children:["commit"," ",s.commit?e.jsx(i.Text,{code:!0,style:{fontSize:11},children:s.commit}):"未知"]})]},s.key)}function K(){const s=z(),{view:t,loading:o,isError:x,error:l}=I();if(x)return e.jsx("div",{style:{padding:16},children:e.jsx(y,{status:"error",title:"加载蒸馏状态失败",subTitle:(l==null?void 0:l.message)||"/api/skills/distill/status 端点不可用(本地回环)"})});const p=[{title:"输出 id",dataIndex:"id",render:(n,r)=>e.jsx(i.Text,{code:!0,style:{fontSize:13},children:r.id})},{title:"IT 通用分",dataIndex:"score",width:130,sorter:(n,r)=>(n.score??-1)-(r.score??-1),render:(n,r)=>r.score===null?e.jsx(i.Text,{type:"secondary",style:{fontSize:12},children:"—"}):e.jsx(i.Text,{style:{fontWeight:600,color:r.score>=3?"rgb(var(--green-6))":"rgb(var(--orange-6))"},children:b(r.score)})},{title:"决定",dataIndex:"decision",width:110,render:(n,r)=>k(r)},{title:"时间",dataIndex:"time",width:150,render:()=>e.jsx(i.Text,{type:"secondary",style:{fontSize:12},children:S(t.lastRunAt)})},{title:"操作",dataIndex:"op",width:76,align:"right",render:(n,r)=>e.jsxs(c,{type:"text",size:"mini",onClick:h=>{h.stopPropagation(),s(`/ai/distill/${encodeURIComponent(r.id)}`)},children:["详情 ",e.jsx(f,{})]})}];return e.jsxs("div",{style:{padding:16,display:"flex",flexDirection:"column",gap:16},children:[e.jsx(a,{bordered:!0,children:e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12,flexWrap:"wrap"},children:[e.jsx(i.Title,{heading:6,style:{margin:0},children:"蒸馏"}),e.jsx(i.Text,{type:"secondary",style:{fontSize:12},children:"上游 SKILL → IT 通用方法论蒸馏 · 5 维评分(<3 跳过、≥3 蒸馏、含项目锚点拒)"}),e.jsx("div",{style:{flex:1}}),e.jsxs(i.Text,{type:"secondary",style:{fontSize:12},children:["蒸馏"," ",e.jsx(i.Text,{style:{fontWeight:600,color:"rgb(var(--green-6))"},children:t.distilledCount})," · ","跳过"," ",e.jsx(i.Text,{style:{fontWeight:600},children:t.skippedCount})," · ","锚点拒"," ",e.jsx(i.Text,{style:{fontWeight:600,color:"rgb(var(--red-6))"},children:t.rejectedCount})]}),e.jsx(c,{type:"primary",icon:e.jsx(g,{}),onClick:()=>s("/ai/distill/run"),children:"执行蒸馏"})]})}),e.jsx(a,{bordered:!0,title:e.jsx("span",{style:{fontSize:14,fontWeight:600},children:"上游源"}),extra:e.jsxs(d,{color:t.cacheReady?"green":"gray",size:"small",children:["cache ",t.cacheReady?"就绪":"未就绪"," · ",t.phase]}),children:e.jsx("div",{style:{display:"flex",gap:12,flexWrap:"wrap"},children:t.upstreams.map(w)})}),e.jsx(a,{bordered:!0,style:{padding:0},children:e.jsx(m,{rowKey:"id",loading:o,data:t.rows,columns:p,pagination:t.rows.length>20?{pageSize:20,showTotal:!0}:!1,border:{wrapper:!1,cell:!1},noDataElement:e.jsx(i.Text,{type:"secondary",children:"暂无蒸馏产出记录"}),onRow:n=>({onClick:()=>s(`/ai/distill/${encodeURIComponent(n.id)}`),style:{cursor:"pointer"}})})})]})}export{K as default};
|
|
2
|
+
//# sourceMappingURL=DistillPage-O7BHtRN8.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DistillPage-O7BHtRN8.js","sources":["../../src/pages/ai/DistillPage.tsx"],"sourcesContent":["/**\n * DistillPage — AI 资源 · 蒸馏列表 (Phase 2e, decision 29688066).\n *\n * 替换 `/ai/distill` 的占位组件。把原型「蒸馏」列表翻译成真 Arco 组件\n * (**严禁直搬原型 Tailwind CSS**):\n * - 顶部上游源状态条(3 蒸馏源 + karpathy skip 源 + commit 短哈希 + cache 状态)\n * - Arco Table:输出 id / it_universal_score(0-5) / 决定(蒸馏✓/跳过⊘/锚点拒✗)/\n * 上游源(统一在顶部条,行内标注主源)/ 时间(lastRunAt)\n * - 右上「执行蒸馏」按钮链到 /ai/distill/run(Phase 2f 已落地为真实向导)\n *\n * 数据接真实只读端点(GET /api/skills/distill/status + /review),见 useDistill。\n * 蒸馏不随时间窗变化(state 文件快照),故不受全局窗驱动。\n */\nimport { useNavigate } from 'react-router-dom'\n\nimport Card from '@arco-design/web-react/es/Card'\nimport Table from '@arco-design/web-react/es/Table'\nimport Tag from '@arco-design/web-react/es/Tag'\nimport Typography from '@arco-design/web-react/es/Typography'\nimport Button from '@arco-design/web-react/es/Button'\nimport Result from '@arco-design/web-react/es/Result'\nimport {\n IconRight,\n IconCheckCircle,\n IconMinusCircle,\n IconCloseCircle,\n IconStorage,\n IconThunderbolt,\n} from '@arco-design/web-react/icon'\n\nimport { useDistill } from '../../hooks/useDistill'\nimport {\n formatScore,\n formatIso,\n decisionMeta,\n type DistillRow,\n type UpstreamSourceStatus,\n} from '../../hooks/distill-derive'\n\nfunction decisionTag(row: DistillRow) {\n const m = decisionMeta(row.decision)\n const icon =\n m.icon === 'check' ? (\n <IconCheckCircle />\n ) : m.icon === 'minus' ? (\n <IconMinusCircle />\n ) : (\n <IconCloseCircle />\n )\n return (\n <Tag color={m.color} size=\"small\" icon={icon}>\n {m.label}\n </Tag>\n )\n}\n\nfunction upstreamChip(u: UpstreamSourceStatus) {\n return (\n <div\n key={u.key}\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: 2,\n padding: '8px 12px',\n border: '1px solid var(--color-border-2)',\n borderRadius: 6,\n minWidth: 150,\n background: u.isSkipSource ? 'var(--color-fill-1)' : 'transparent',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n <IconStorage style={{ color: 'var(--color-text-3)', fontSize: 13 }} />\n <Typography.Text style={{ fontSize: 13, fontWeight: 600 }}>\n {u.label}\n </Typography.Text>\n {u.isSkipSource && (\n <Tag size=\"small\" color=\"gray\" style={{ marginLeft: 2 }}>\n skip\n </Tag>\n )}\n </div>\n <Typography.Text type=\"secondary\" style={{ fontSize: 11 }}>\n commit{' '}\n {u.commit ? (\n <Typography.Text code style={{ fontSize: 11 }}>\n {u.commit}\n </Typography.Text>\n ) : (\n '未知'\n )}\n </Typography.Text>\n </div>\n )\n}\n\nexport default function DistillPage() {\n const navigate = useNavigate()\n const { view, loading, isError, error } = useDistill()\n\n if (isError) {\n return (\n <div style={{ padding: 16 }}>\n <Result\n status=\"error\"\n title=\"加载蒸馏状态失败\"\n subTitle={error?.message || '/api/skills/distill/status 端点不可用(本地回环)'}\n />\n </div>\n )\n }\n\n const columns = [\n {\n title: '输出 id',\n dataIndex: 'id',\n render: (_: unknown, row: DistillRow) => (\n <Typography.Text code style={{ fontSize: 13 }}>\n {row.id}\n </Typography.Text>\n ),\n },\n {\n title: 'IT 通用分',\n dataIndex: 'score',\n width: 130,\n sorter: (a: DistillRow, b: DistillRow) => (a.score ?? -1) - (b.score ?? -1),\n render: (_: unknown, row: DistillRow) =>\n row.score === null ? (\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n —\n </Typography.Text>\n ) : (\n <Typography.Text\n style={{\n fontWeight: 600,\n color:\n row.score >= 3\n ? 'rgb(var(--green-6))'\n : 'rgb(var(--orange-6))',\n }}\n >\n {formatScore(row.score)}\n </Typography.Text>\n ),\n },\n {\n title: '决定',\n dataIndex: 'decision',\n width: 110,\n render: (_: unknown, row: DistillRow) => decisionTag(row),\n },\n {\n title: '时间',\n dataIndex: 'time',\n width: 150,\n render: () => (\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n {formatIso(view.lastRunAt)}\n </Typography.Text>\n ),\n },\n {\n title: '操作',\n dataIndex: 'op',\n width: 76,\n align: 'right' as const,\n render: (_: unknown, row: DistillRow) => (\n <Button\n type=\"text\"\n size=\"mini\"\n onClick={(e) => {\n e.stopPropagation()\n navigate(`/ai/distill/${encodeURIComponent(row.id)}`)\n }}\n >\n 详情 <IconRight />\n </Button>\n ),\n },\n ]\n\n return (\n <div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 16 }}>\n {/* ── 页头 + 执行蒸馏入口 ───────────────────────────────────────── */}\n <Card bordered>\n <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>\n <Typography.Title heading={6} style={{ margin: 0 }}>\n 蒸馏\n </Typography.Title>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n 上游 SKILL → IT 通用方法论蒸馏 · 5 维评分(<3 跳过、≥3 蒸馏、含项目锚点拒)\n </Typography.Text>\n <div style={{ flex: 1 }} />\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n 蒸馏{' '}\n <Typography.Text style={{ fontWeight: 600, color: 'rgb(var(--green-6))' }}>\n {view.distilledCount}\n </Typography.Text>\n {' · '}跳过{' '}\n <Typography.Text style={{ fontWeight: 600 }}>{view.skippedCount}</Typography.Text>\n {' · '}锚点拒{' '}\n <Typography.Text style={{ fontWeight: 600, color: 'rgb(var(--red-6))' }}>\n {view.rejectedCount}\n </Typography.Text>\n </Typography.Text>\n <Button\n type=\"primary\"\n icon={<IconThunderbolt />}\n onClick={() => navigate('/ai/distill/run')}\n >\n 执行蒸馏\n </Button>\n </div>\n </Card>\n\n {/* ── 上游源状态条 ─────────────────────────────────────────────── */}\n <Card\n bordered\n title={<span style={{ fontSize: 14, fontWeight: 600 }}>上游源</span>}\n extra={\n <Tag color={view.cacheReady ? 'green' : 'gray'} size=\"small\">\n cache {view.cacheReady ? '就绪' : '未就绪'} · {view.phase}\n </Tag>\n }\n >\n <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>\n {view.upstreams.map(upstreamChip)}\n </div>\n </Card>\n\n {/* ── 蒸馏产出列表 ─────────────────────────────────────────────── */}\n <Card bordered style={{ padding: 0 }}>\n <Table<DistillRow>\n rowKey=\"id\"\n loading={loading}\n data={view.rows}\n columns={columns}\n pagination={view.rows.length > 20 ? { pageSize: 20, showTotal: true } : false}\n border={{ wrapper: false, cell: false }}\n noDataElement={\n <Typography.Text type=\"secondary\">暂无蒸馏产出记录</Typography.Text>\n }\n onRow={(row) => ({\n onClick: () => navigate(`/ai/distill/${encodeURIComponent(row.id)}`),\n style: { cursor: 'pointer' },\n })}\n />\n </Card>\n </div>\n )\n}\n"],"names":["decisionTag","row","m","decisionMeta","icon","IconCheckCircle","jsx","IconMinusCircle","IconCloseCircle","Tag","upstreamChip","u","jsxs","IconStorage","Typography","DistillPage","navigate","useNavigate","view","loading","isError","error","useDistill","Result","columns","_","a","b","formatScore","formatIso","Button","e","IconRight","Card","IconThunderbolt","Table"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{r as p,j as e}from"./react-vendor-tkvCrao7.js";import{J as E,F as b,X as K,T as u,b as m,V as F,ac as T,S as P,ad as Q,i as M,ae as Y,af as W,ag as H,w as V,O as U,D as L,f as X,aa as G}from"./arco-DV6xCLhr.js";import{a as B,u as Z,c as ee}from"./query-CgCOpYWf.js";import{a as N}from"./auth-Bnf8ZcqN.js";import{u as te}from"./react-router-Cxmg8RuL.js";import"./vendor-DS-q4Eyc.js";const ne=["connected","start","progress","phase-changed","skill-distilled","done","cancelled","error"],O={"obra-superpowers":"obra/superpowers","anthropics-skills":"anthropics/skills","affaan-m-ecc":"affaan-m/ECC","multica-karpathy":"multica/karpathy"},_=new Set(["multica-karpathy"]);function D(t){if(!t||typeof t!="string")return null;const n=t.trim();return!n||n==="unknown"?null:n.slice(0,7)}function se(t,n){var c;const r=(t==null?void 0:t.fetchResults)??[];if(r.length>0)return r.map(d=>{var x,f;const h=((x=d.upstream)==null?void 0:x.id)??"unknown";return{key:h,label:O[h]??h,status:d.status??null,commit:D(d.commit),isSkipSource:((f=d.upstream)==null?void 0:f.skip)===!0||_.has(h),error:d.error??null}});const i=((c=n==null?void 0:n.state)==null?void 0:c.upstreamCommits)??{};return(Object.keys(i).length>0?Object.keys(i):Object.keys(O)).map(d=>({key:d,label:O[d]??d,status:null,commit:D(i[d]),isSkipSource:_.has(d),error:null}))}function re(t){if(t.length===0)return!1;const n=t.filter(r=>!r.isSkipSource);return n.length===0?!1:n.every(r=>r.error===null&&(r.commit!==null||r.status!==null))}function ie(t){return typeof t!="number"||!Number.isFinite(t)?5:Math.min(50,Math.max(1,Math.floor(t)))}const le=/^[a-z0-9][a-z0-9-]*$/;function oe(t){if(!Array.isArray(t))return[];const n=new Set,r=[];for(const i of t)typeof i=="string"&&le.test(i)&&(n.has(i)||(n.add(i),r.push(i)));return r}function J(t){const n=oe(t.topicIds),r={};return n.length>0?r.topicIds=n:r.topicCap=ie(t.topicCap),t.force&&(r.force=!0),r}function ce(t){return JSON.stringify(J(t),null,2)}function ae(t){if(!t)return null;const n=t.match(/chars=(\d+)/);return n?parseInt(n[1],10):null}const de=new Set(["done","cancelled","error"]);function ue(t){const n=new Map,r=[];let i=!1,a="idle",c=null,d=null,h=null,x=null,f=null,g=null,s=!1;const S=o=>{let C=n.get(o);return C||(C={topicId:o,charCount:null,distilled:!1},n.set(o,C),r.push(o)),C};for(const o of t){switch(o.type){case"connected":i=!0,a==="idle"&&(a="connecting");break;case"start":case"phase-changed":s||(a="running");break;case"progress":{if(s||(a="running"),o.topicId){const C=S(o.topicId),w=ae(o.message);w!=null&&(C.charCount=w),c=o.topicId}break}case"skill-distilled":{s||(a="running"),o.topicId&&(S(o.topicId).distilled=!0);break}case"done":a="done",s=!0,d=o.completed??null,h=o.skipped??null,x=o.distilledCount??null,f=o.message??null,c=null;break;case"cancelled":a="cancelled",s=!0,d=o.completed??null,x=o.distilledCount??null,f=o.message??"已取消",c=null;break;case"error":a="error",s=!0,g=o.errorMessage??o.message??"未知错误",f=g,c=null;break}de.has(o.type)&&(s=!0)}return{phase:a,connected:i,topics:r.map(o=>n.get(o)),currentTopicId:c,completed:d,skipped:h,distilledCount:x,terminalMessage:f,isTerminal:s,errorMessage:g,log:t}}function pe(t){if(!t||t.isBusy!==!0)return null;const n=t.currentRunId;return typeof n!="string"||n.length===0?null:n}const q=2;function fe(t){switch(t){case"connected":return{color:"gray",label:"建连"};case"start":return{color:"arcoblue",label:"启动"};case"progress":return{color:"gray",label:"进度"};case"phase-changed":return{color:"blue",label:"阶段"};case"skill-distilled":return{color:"green",label:"蒸馏✓"};case"done":return{color:"green",label:"完成"};case"cancelled":return{color:"orange",label:"取消"};case"error":return{color:"red",label:"错误"};default:return{color:"gray",label:String(t)}}}function A(t){if(!t)return"蒸馏失败,未知错误";const n=t.trim();return n==="distill_in_progress"||n.includes("409")?"已有蒸馏在进行中,请稍后再试":n.includes("403")?"无权限触发蒸馏(403,loopback only)":n.includes("401")||n==="unauthorized"?"未授权:请检查 daemon token":n.includes("500")?"后端蒸馏出错(500),请查看 daemon 日志":n.toLowerCase().includes("failed to fetch")?"无法连接 daemon,请确认服务已启动":n}async function he(){const t=await fetch("/api/skills/distill/status");if(!t.ok)throw new Error(`status → ${t.status}`);return t.json()}async function ye(t){const n=await N("/api/skills/distill/init",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({skipFetch:t})});if(!n.ok)throw new Error(`init → ${n.status}`);return n.json()}async function xe(t){const n=await N("/api/skills/distill/run",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(J(t))});if(n.status===409)throw new Error("distill_in_progress");if(!n.ok)throw new Error(`run → ${n.status}`);return n.json()}async function me(t){const n=await N(`/api/skills/distill/cancel/${encodeURIComponent(t)}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({})});if(!n.ok)throw new Error(`cancel → ${n.status}`)}function ge(){const t=B(),n=Z({queryKey:["distill-status"],queryFn:he,refetchInterval:i=>{var a;return(a=i.state.data)!=null&&a.isBusy?5e3:6e4}}),r=ee({mutationFn:i=>ye(i),onSuccess:()=>{t.invalidateQueries({queryKey:["distill-status"]})}});return{status:n.data,loading:n.isLoading,isError:n.isError,refetch:()=>void n.refetch(),initResult:r.data,initPending:r.isPending,initError:r.error??null,runInit:(i=!1)=>r.mutate(i)}}function je(){const t=B(),[n,r]=p.useState([]),[i,a]=p.useState(null),[c,d]=p.useState(!1),[h,x]=p.useState(null),f=p.useRef(null),g=p.useCallback(()=>{f.current&&(f.current.close(),f.current=null)},[]);p.useEffect(()=>g,[g]);const s=p.useCallback(v=>{g();const j=new EventSource(`/api/skills/distill/run/${encodeURIComponent(v)}/stream`);f.current=j;const z=y=>k=>{let l={};try{l=JSON.parse(k.data||"{}")}catch{}const I={...l,type:y};r(R=>[...R,I]),(y==="done"||y==="error"||y==="cancelled")&&(j.close(),f.current=null,t.invalidateQueries({queryKey:["distill-status"]}),t.invalidateQueries({queryKey:["distill-review"]}))};for(const y of ne)j.addEventListener(y,z(y));j.onerror=()=>{r(y=>{const k=y[y.length-1];return k&&(k.type==="done"||k.type==="error"||k.type==="cancelled")?y:[...y,{type:"error",errorMessage:"SSE 连接中断(daemon 不可达或已断流)"}]})}},[g,t]),S=p.useCallback(async v=>{x(null),d(!0),r([]);try{const{runId:j}=await xe(v);a(j),s(j)}catch(j){x(j)}finally{d(!1)}},[s]),o=p.useCallback(v=>{i===v&&f.current||(x(null),r([]),a(v),s(v))},[i,s]),C=p.useCallback(async()=>{if(i)try{await me(i)}catch{}},[i]),w=p.useCallback(()=>{g(),r([]),a(null),x(null)},[g]);return{view:ue(n),runId:i,submitting:c,submitError:h,start:S,reconnect:o,cancel:C,reset:w}}const $=F.Step;function be(t){return t.error?e.jsx(m,{color:"red",size:"small",icon:e.jsx(G,{}),children:"失败"}):t.status==="cloned"||t.status==="updated"?e.jsx(m,{color:"green",size:"small",icon:e.jsx(U,{}),children:t.status==="cloned"?"已克隆":"已更新"}):t.status==="cached"?e.jsx(m,{color:"cyan",size:"small",children:"cache"}):t.status==="skipped"||t.isSkipSource?e.jsx(m,{color:"gray",size:"small",children:"skip"}):e.jsx(m,{color:"gray",size:"small",children:t.commit?"就绪":"未拉取"})}function Se({row:t}){return e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:4,padding:"10px 14px",border:"1px solid var(--color-border-2)",borderRadius:6,minWidth:170,background:t.isSkipSource?"var(--color-fill-1)":"transparent"},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6},children:[e.jsx(X,{style:{color:"var(--color-text-3)",fontSize:13}}),e.jsx(u.Text,{style:{fontSize:13,fontWeight:600},children:t.label}),e.jsx("div",{style:{flex:1}}),be(t)]}),e.jsxs(u.Text,{type:"secondary",style:{fontSize:11},children:["commit"," ",t.commit?e.jsx(u.Text,{code:!0,style:{fontSize:11},children:t.commit}):"未知"]}),t.error&&e.jsx(u.Text,{type:"error",style:{fontSize:11},children:t.error})]})}function ze(){var k;const t=te(),[n,r]=p.useState(0),[i,a]=p.useState({topicCap:5,topicIds:[],force:!1}),{status:c,loading:d,initResult:h,initPending:x,initError:f,runInit:g}=ge(),s=je(),S=pe(c),o=p.useRef(!1);p.useEffect(()=>{o.current||S&&(s.runId||(o.current=!0,r(q),s.reconnect(S)))},[S,s]);const C=p.useMemo(()=>se(h,c),[h,c]),w=re(C),v=(c==null?void 0:c.isBusy)===!0,j=(c==null?void 0:c.claudeCliAvailable)!==!1,z=((k=c==null?void 0:c.state)==null?void 0:k.completed)??[],y=p.useMemo(()=>ce(i),[i]);return e.jsxs("div",{style:{padding:16,display:"flex",flexDirection:"column",gap:16},children:[e.jsxs(E,{bordered:!0,children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12,flexWrap:"wrap"},children:[e.jsx(b,{type:"text",icon:e.jsx(K,{}),onClick:()=>t("/ai/distill"),style:{paddingLeft:0},children:"返回蒸馏列表"}),e.jsx(u.Title,{heading:6,style:{margin:0},children:"执行蒸馏向导"}),e.jsx(u.Text,{type:"secondary",style:{fontSize:12},children:"上游 SKILL → IT 通用方法论蒸馏(spawn claude -p · 每 topic ~10min 真烧 LLM)"}),e.jsx("div",{style:{flex:1}}),v&&S&&e.jsx(m,{color:"arcoblue",size:"small",style:{cursor:"pointer"},onClick:()=>{o.current=!0,r(q),s.reconnect(S)},title:"点击重连查看进度",children:"另有蒸馏进行中 · 点击查看进度"}),v&&!S&&e.jsx(m,{color:"arcoblue",size:"small",children:"另有蒸馏进行中"})]}),e.jsxs(F,{current:n,style:{marginTop:16},size:"small",children:[e.jsx($,{title:"上游就绪",description:"拉取/克隆 3 上游到 cache"}),e.jsx($,{title:"选范围",description:"topicCap / topicIds / force"}),e.jsx($,{title:"运行与产出",description:"连 SSE 逐 topic 揭示"})]})]}),!j&&e.jsx(T,{type:"warning",content:"未检测到 claude CLI(status.claudeCliAvailable=false)——蒸馏需要本机已登录的 claude CLI,请先安装/登录后再执行。"}),n===0&&e.jsx(E,{bordered:!0,title:e.jsx("span",{style:{fontSize:14,fontWeight:600},children:"① 上游就绪"}),extra:e.jsx(b,{type:"outline",size:"small",icon:e.jsx(Q,{}),loading:x,onClick:()=>g(!1),children:"拉取上游 (init)"}),children:d?e.jsx(P,{}):e.jsxs(e.Fragment,{children:[e.jsx("div",{style:{display:"flex",gap:12,flexWrap:"wrap"},children:C.map(l=>e.jsx(Se,{row:l},l.key))}),f&&e.jsx(T,{style:{marginTop:12},type:"error",content:`拉取上游失败:${f.message}`}),h&&e.jsx(T,{style:{marginTop:12},type:"success",content:`上游已就绪(NOTICE ${h.noticeWritten?"已写":"未写"} · catalog ${h.catalogWritten?"已写":"未写"})。`}),e.jsx("div",{style:{marginTop:16,display:"flex",justifyContent:"flex-end"},children:e.jsx(b,{type:"primary",disabled:!w,onClick:()=>r(1),children:"下一步:选范围"})}),!w&&e.jsx(u.Text,{type:"secondary",style:{fontSize:12},children:"先点「拉取上游 (init)」把 3 上游克隆/更新到 cache,就绪后才能进入下一步。"})]})}),n===1&&e.jsx(E,{bordered:!0,title:e.jsx("span",{style:{fontSize:14,fontWeight:600},children:"② 选 topic 范围"}),children:e.jsxs(M,{direction:"vertical",size:"large",style:{width:"100%"},children:[e.jsxs("div",{children:[e.jsx(u.Text,{style:{fontSize:13,fontWeight:600},children:"topicCap(1-50,默认 5)"}),e.jsxs("div",{style:{marginTop:6,display:"flex",alignItems:"center",gap:8},children:[e.jsx(Y,{min:1,max:50,value:i.topicCap,onChange:l=>a(I=>({...I,topicCap:typeof l=="number"?l:5})),style:{width:120},disabled:i.topicIds.length>0}),e.jsx(u.Text,{type:"secondary",style:{fontSize:12},children:"最多蒸馏 N 个 topic(勾选具体 topicIds 时此项被忽略)。建议自测设 1。"})]})]}),e.jsxs("div",{children:[e.jsx(u.Text,{style:{fontSize:13,fontWeight:600},children:"指定 topicIds(可选;勾选后只跑这些)"}),z.length>0?e.jsx("div",{style:{marginTop:6},children:e.jsx(W.Group,{value:i.topicIds,onChange:l=>a(I=>({...I,topicIds:l})),children:e.jsx("div",{style:{display:"flex",gap:12,flexWrap:"wrap"},children:z.map(l=>e.jsx(W,{value:l,children:e.jsx(u.Text,{code:!0,style:{fontSize:12},children:l})},l))})})}):e.jsx(u.Text,{type:"secondary",style:{fontSize:12,display:"block",marginTop:6},children:"暂无已知 topic(state.completed 为空)——按 topicCap 自动选候选。"})]}),e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsx(H,{checked:i.force,onChange:l=>a(I=>({...I,force:l}))}),e.jsx(u.Text,{style:{fontSize:13},children:"force —— 强制重蒸(无视 completedSet / topicCap 跳过已完成)"})]}),e.jsxs("div",{children:[e.jsx(u.Text,{type:"secondary",style:{fontSize:12},children:"将发起的 POST /api/skills/distill/run 请求体:"}),e.jsx("pre",{style:{marginTop:6,padding:12,background:"var(--color-fill-1)",borderRadius:4,fontSize:12,fontFamily:"monospace",overflowX:"auto"},children:y})]}),e.jsxs("div",{style:{display:"flex",justifyContent:"space-between"},children:[e.jsx(b,{onClick:()=>r(0),children:"上一步"}),e.jsx(b,{type:"primary",onClick:()=>r(2),children:"下一步:运行"})]})]})}),n===2&&e.jsxs(E,{bordered:!0,title:e.jsx("span",{style:{fontSize:14,fontWeight:600},children:"③ 运行与产出"}),children:[!s.runId&&e.jsxs(M,{direction:"vertical",size:"medium",style:{width:"100%"},children:[e.jsx(T,{type:"warning",content:"点「执行蒸馏」将真 spawn claude -p,每 topic ~10min 真烧 LLM。确认范围(见上一步 JSON 预览)后再执行。"}),s.submitError&&e.jsx(T,{type:"error",content:A(s.submitError.message)}),e.jsxs("div",{style:{display:"flex",justifyContent:"space-between"},children:[e.jsx(b,{onClick:()=>r(1),children:"上一步"}),e.jsx(b,{type:"primary",icon:e.jsx(V,{}),loading:s.submitting,disabled:v||!j,onClick:()=>void s.start(i),children:"执行蒸馏"})]})]}),s.runId&&e.jsxs(M,{direction:"vertical",size:"medium",style:{width:"100%"},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12,flexWrap:"wrap"},children:[e.jsx(m,{size:"small",style:{fontFamily:"monospace"},children:s.runId}),e.jsx(m,{color:s.view.phase==="done"?"green":s.view.phase==="error"?"red":s.view.phase==="cancelled"?"orange":"arcoblue",size:"small",children:s.view.phase}),s.view.currentTopicId&&e.jsxs(m,{color:"arcoblue",size:"small",children:["当前: ",s.view.currentTopicId]}),e.jsx("div",{style:{flex:1}}),!s.view.isTerminal&&e.jsx(b,{size:"small",status:"danger",onClick:()=>void s.cancel(),children:"取消"})]}),!s.view.isTerminal&&!s.view.connected&&e.jsx(P,{tip:"连接 SSE 流…"}),s.view.topics.length>0&&e.jsx("div",{style:{display:"flex",flexDirection:"column",gap:6},children:s.view.topics.map(l=>e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,padding:"6px 10px",border:"1px solid var(--color-border-2)",borderRadius:4},children:[e.jsx(u.Text,{code:!0,style:{fontSize:12},children:l.topicId}),e.jsx("div",{style:{flex:1}}),l.charCount!=null&&e.jsxs(u.Text,{type:"secondary",style:{fontSize:11},children:[l.charCount.toLocaleString()," chars"]}),l.distilled?e.jsx(m,{color:"green",size:"small",icon:e.jsx(U,{}),children:"蒸馏✓"}):e.jsx(m,{color:"arcoblue",size:"small",children:"运行中"})]},l.topicId))}),s.view.phase==="done"&&e.jsx(L,{status:"success",title:"蒸馏完成",subTitle:s.view.terminalMessage??`完成 ${s.view.completed??"?"} · 蒸馏 ${s.view.distilledCount??"?"} · 跳过 ${s.view.skipped??"?"}`,extra:[e.jsx(b,{type:"primary",onClick:()=>t("/ai/distill"),children:"查看产出(带 D1-D5)"},"list"),e.jsx(b,{onClick:s.reset,children:"再跑一次"},"again")]}),s.view.phase==="cancelled"&&e.jsx(L,{status:"warning",title:"已取消",subTitle:s.view.terminalMessage??"蒸馏已被取消",extra:[e.jsx(b,{type:"primary",onClick:s.reset,children:"重新执行"},"again")]}),s.view.phase==="error"&&e.jsx(L,{status:"error",title:"蒸馏出错",subTitle:A(s.view.errorMessage??void 0),extra:[e.jsx(b,{type:"primary",onClick:s.reset,children:"重试"},"again")]}),e.jsxs("div",{children:[e.jsxs(u.Text,{type:"secondary",style:{fontSize:12},children:["SSE 事件流(",s.view.log.length,"):"]}),e.jsxs("div",{style:{marginTop:6,maxHeight:220,overflowY:"auto",fontSize:12,fontFamily:"monospace",background:"var(--color-fill-1)",padding:8,borderRadius:4},children:[s.view.log.length===0&&e.jsx(u.Text,{type:"secondary",children:"等待第一个 SSE 事件…"}),s.view.log.map((l,I)=>{const R=fe(l.type);return e.jsxs("div",{style:{display:"flex",gap:8,lineHeight:"20px"},children:[e.jsx(m,{color:R.color,size:"small",style:{minWidth:56,textAlign:"center"},children:R.label}),e.jsxs("span",{style:{flex:1},children:[l.topicId?`${l.topicId} `:"",l.message??"",l.errorMessage?` — ${l.errorMessage}`:"",l.completed!=null?` (completed=${l.completed})`:""]})]},I)})]})]})]})]})]})}export{ze as default};
|
|
2
|
+
//# sourceMappingURL=DistillRunPage-D1JuRWWr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DistillRunPage-D1JuRWWr.js","sources":["../../src/hooks/distill-run-derive.ts","../../src/hooks/useDistillRun.ts","../../src/pages/ai/DistillRunPage.tsx"],"sourcesContent":["/**\n * distill-run-derive — 执行蒸馏向导 (Phase 2f, decision 29688066) 纯派生层。\n *\n * 项目前端单测跑在 environment:'node'(无 jsdom / RTL,见 workplace-data.test.ts\n * 注解),故所有「SSE 事件流 → 向导视图模型」「向导参数 → run 请求体」「init 结果 →\n * 上游就绪条」的计算都抽进本纯函数模块,页面组件 / hook 只渲染派生结果。这样 SSE\n * 解析逻辑可喂模拟事件流单测,无需真正触发 10min 全量蒸馏。\n *\n * ⚠️ 真实端点契约(对 localhost:3721 实抓 + 读 src/web/services/distill-manager.ts\n * 源码确认,严禁造服务端不发的字段):\n *\n * POST /api/skills/distill/init\n * body { skipFetch?: boolean }\n * → { fetchResults: [{ upstream:{id,url,license,skip?},\n * status:'cloned'|'updated'|'cached'|'skipped'|'error',\n * path, commit?, error? }],\n * noticeWritten: boolean, catalogWritten: boolean }\n *\n * POST /api/skills/distill/run\n * body { topicCap?:1-50, topicIds?:string[], outputIds?:string[],\n * skip?:string[], force?:boolean, regenerateAll?:boolean }\n * → 202 { runId, streamUrl } | 409 { error:'distill_in_progress' }\n *\n * GET /api/skills/distill/run/:runId/stream (SSE,每条 `event: <type>\\ndata:<JSON>\\n\\n`)\n * 真实事件类型(distill-manager.ts DistillEventType)+ payload 字段:\n * connected data: {} (SSE 建连)\n * start { type, at, message, runId }\n * phase-changed { type, at, phase:'running', message, runId }\n * progress { type, at, topicId?, message:\"chars=N\"?, runId } ← 逐 topic 字符进度\n * skill-distilled{ type, at, topicId, runId } ← 该 topic 蒸馏成 SKILL\n * done { type, at, message, phase, completed, skipped,\n * distilledCount, pausedAtGate:false, runId }\n * cancelled { type, at, message, phase?, completed?, distilledCount?, runId }\n * error { type, at, errorMessage, runId }\n *\n * ⚠️ 重要口径:SSE 流里**没有** per-topic 的 D1-D5 评分 / 三态决定事件——\n * distill-manager 只发粗粒度进度(progress/skill-distilled)。D1-D5 五维分 + 三态\n * 决定(蒸馏≥3 / 跳过<3 / 锚点拒)是 run **完成后**从 GET /review + /review/:id/diff\n * 端点读出(见 distill-derive.ts)。故向导 Step 3 的「逐 topic 出 D1-D5 + 封装预览」\n * 是:SSE 实时揭示 spawn / 进度 / 蒸馏完成,done 后回列表(Phase 2e /ai/distill)即可\n * 看到带 D1-D5 的新记录;本向导在 done 态把 completed/distilled/skipped 计数 +「查看\n * 产出」链接呈现,不在流里伪造服务端从不发的 D1-D5 事件(避免 Phase 2b 血泪坑)。\n */\n\n// ─── endpoint response shapes (严格按真实 payload) ──────────────────────────────\n\n/** POST /api/skills/distill/init 的 fetchResult.upstream。 */\nexport interface InitUpstream {\n id: string\n url?: string\n license?: string\n skip?: boolean\n sparsePaths?: string[]\n}\n\n/** POST /api/skills/distill/init 的单条 fetchResult。 */\nexport interface InitFetchResult {\n upstream: InitUpstream\n status: 'cloned' | 'updated' | 'cached' | 'skipped' | 'error' | string\n path?: string\n commit?: string\n error?: string\n}\n\n/** POST /api/skills/distill/init 完整响应。 */\nexport interface InitResp {\n fetchResults?: InitFetchResult[]\n noticeWritten?: boolean\n catalogWritten?: boolean\n}\n\n/** GET /api/skills/distill/status 完整响应(向导只读 isBusy / state / claudeCli)。 */\nexport interface RunStatusResp {\n stateFileExists?: boolean\n state?: {\n phase?: string\n upstreamCommits?: Record<string, string>\n completed?: string[]\n skipped?: string[]\n rejected?: string[]\n } | null\n isBusy?: boolean\n currentRunId?: string | null\n lastRunId?: string | null\n claudeCliAvailable?: boolean\n claudeCliPath?: string | null\n}\n\n/** SSE 事件类型(与 distill-manager.ts DistillEventType 严格一致)。 */\nexport type DistillRunEventType =\n | 'connected'\n | 'start'\n | 'progress'\n | 'phase-changed'\n | 'skill-distilled'\n | 'done'\n | 'cancelled'\n | 'error'\n\n/** 单条 SSE 事件(data JSON 解析后 + type)。 */\nexport interface DistillRunEvent {\n type: DistillRunEventType\n at?: string\n message?: string\n phase?: string\n completed?: number\n pending?: number\n skipped?: number\n topicId?: string\n distilledCount?: number\n pausedAtGate?: boolean\n errorMessage?: string\n runId?: string\n}\n\nexport const DISTILL_RUN_EVENT_TYPES: DistillRunEventType[] = [\n 'connected',\n 'start',\n 'progress',\n 'phase-changed',\n 'skill-distilled',\n 'done',\n 'cancelled',\n 'error',\n]\n\n// ─── Step 1:上游就绪 ────────────────────────────────────────────────────────\n\n/** 已知 3 蒸馏源 + 1 skip 源(与 distill-derive UPSTREAM_LABELS 对齐)。 */\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/** 上游就绪条单条(init 结果 / status.upstreamCommits 派生)。 */\nexport interface UpstreamReadyRow {\n key: string\n label: string\n /** init 后的 fetch 状态;仅 status 时为 null。 */\n status: InitFetchResult['status'] | null\n /** 短哈希;unknown / 缺省 → null。 */\n commit: string | null\n isSkipSource: boolean\n error: string | null\n}\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 * 装配上游就绪条。优先用 init 的 fetchResults(含 status + commit),缺则回退\n * status.upstreamCommits(只有 commit)。两者都缺时用已知 4 源占位(status=null)。\n */\nexport function buildUpstreamReadyRows(\n init: InitResp | undefined,\n status: RunStatusResp | undefined,\n): UpstreamReadyRow[] {\n const results = init?.fetchResults ?? []\n if (results.length > 0) {\n return results.map((r) => {\n const key = r.upstream?.id ?? 'unknown'\n return {\n key,\n label: UPSTREAM_LABELS[key] ?? key,\n status: r.status ?? null,\n commit: shortCommit(r.commit),\n isSkipSource: r.upstream?.skip === true || SKIP_SOURCE_KEYS.has(key),\n error: r.error ?? null,\n }\n })\n }\n\n const commits = status?.state?.upstreamCommits ?? {}\n const keys =\n Object.keys(commits).length > 0 ? Object.keys(commits) : Object.keys(UPSTREAM_LABELS)\n return keys.map((key) => ({\n key,\n label: UPSTREAM_LABELS[key] ?? key,\n status: null,\n commit: shortCommit(commits[key]),\n isSkipSource: SKIP_SOURCE_KEYS.has(key),\n error: null,\n }))\n}\n\n/** init 结果是否「就绪」(至少一条非 error,且 NOTICE/catalog 已写 或 已有 commit)。 */\nexport function isUpstreamReady(rows: UpstreamReadyRow[]): boolean {\n if (rows.length === 0) return false\n const nonSkip = rows.filter((r) => !r.isSkipSource)\n if (nonSkip.length === 0) return false\n // 全部非 skip 源要么有 commit、要么 fetch 状态非 error。\n return nonSkip.every((r) => r.error === null && (r.commit !== null || r.status !== null))\n}\n\n// ─── Step 2:run 请求预览 ────────────────────────────────────────────────────\n\n/** 向导 Step 2 表单状态。 */\nexport interface RunFormState {\n topicCap: number\n topicIds: string[]\n force: boolean\n}\n\n/** POST /run 请求体(只放服务端真实接受的字段)。 */\nexport interface RunRequestBody {\n topicCap?: number\n topicIds?: string[]\n force?: boolean\n}\n\n/** topicCap 夹到 [1,50],非数值回退 5(与后端 parseInt 兜底一致)。 */\nexport function clampTopicCap(n: number | null | undefined): number {\n if (typeof n !== 'number' || !Number.isFinite(n)) return 5\n return Math.min(50, Math.max(1, Math.floor(n)))\n}\n\n/** topicId 白名单正则(与后端 TOPIC_ID_RE 一致:小写字母数字 + 连字符,首字符非连字符)。 */\nconst TOPIC_ID_RE = /^[a-z0-9][a-z0-9-]*$/\n\n/** 过滤非法 topicId(与后端 filter 一致),去重。 */\nexport function sanitizeTopicIds(ids: string[] | null | undefined): string[] {\n if (!Array.isArray(ids)) return []\n const seen = new Set<string>()\n const out: string[] = []\n for (const id of ids) {\n if (typeof id !== 'string') continue\n if (!TOPIC_ID_RE.test(id)) continue\n if (seen.has(id)) continue\n seen.add(id)\n out.push(id)\n }\n return out\n}\n\n/**\n * 表单 → run 请求体。topicIds 非空时省略 topicCap(后端按 topicIds 跑),否则带 topicCap。\n * force 仅在 true 时带(避免无意义字段)。这是 Step 2「实时 JSON 预览」的数据源。\n */\nexport function buildRunRequest(form: RunFormState): RunRequestBody {\n const topicIds = sanitizeTopicIds(form.topicIds)\n const body: RunRequestBody = {}\n if (topicIds.length > 0) {\n body.topicIds = topicIds\n } else {\n body.topicCap = clampTopicCap(form.topicCap)\n }\n if (form.force) body.force = true\n return body\n}\n\n/** run 请求体 → 美化 JSON 字符串(Step 2 预览块)。 */\nexport function previewRunRequest(form: RunFormState): string {\n return JSON.stringify(buildRunRequest(form), null, 2)\n}\n\n// ─── Step 3:SSE 事件流 → 向导运行视图 ───────────────────────────────────────\n\nexport type RunPhase = 'idle' | 'connecting' | 'running' | 'done' | 'cancelled' | 'error'\n\n/** 单 topic 的运行态(从 progress / skill-distilled 事件累积)。 */\nexport interface TopicProgressRow {\n topicId: string\n /** 最近一次 progress 的字符数(spawn claude -p 流式产出)。 */\n charCount: number | null\n /** 已收到 skill-distilled 事件 → 蒸馏完成。 */\n distilled: boolean\n}\n\n/** Step 3 运行视图模型(喂模拟事件流可单测)。 */\nexport interface RunView {\n phase: RunPhase\n /** 已建 SSE 连接(收到 connected 事件)。 */\n connected: boolean\n /** 逐 topic 进度行(按首次出现顺序稳定)。 */\n topics: TopicProgressRow[]\n /** 当前正在处理的 topicId(最近 progress 事件)。 */\n currentTopicId: string | null\n /** done 事件携带的计数。 */\n completed: number | null\n skipped: number | null\n distilledCount: number | null\n /** 终态消息(done.message / cancelled.message / error.errorMessage)。 */\n terminalMessage: string | null\n /** 是否处于终态(done / cancelled / error)。 */\n isTerminal: boolean\n /** error 态详情。 */\n errorMessage: string | null\n /** 原始事件日志(UI 滚动日志区)。 */\n log: DistillRunEvent[]\n}\n\n/** 解析 progress.message 的 \"chars=N\"。 */\nexport function parseCharCount(message: string | undefined): number | null {\n if (!message) return null\n const m = message.match(/chars=(\\d+)/)\n return m ? parseInt(m[1], 10) : null\n}\n\nconst TERMINAL_TYPES = new Set<DistillRunEventType>(['done', 'cancelled', 'error'])\n\n/**\n * 把一串 SSE 事件 reduce 成 Step 3 运行视图。**这是本 Phase 的核心纯函数**,\n * 喂模拟事件流即可断言向导渲染,无需真正触发 10min 全量蒸馏。\n *\n * 状态机:\n * [] → idle\n * [connected] → connecting(已建连,等 start)\n * [...,start|phase-changed] → running\n * progress(topicId) → 累积 topic.charCount + currentTopicId\n * skill-distilled(topicId) → 标记该 topic.distilled\n * done → done(含 completed/skipped/distilledCount)\n * cancelled → cancelled\n * error → error(errorMessage)\n */\nexport function reduceDistillRunEvents(events: DistillRunEvent[]): RunView {\n const topicMap = new Map<string, TopicProgressRow>()\n const order: string[] = []\n let connected = false\n let phase: RunPhase = 'idle'\n let currentTopicId: string | null = null\n let completed: number | null = null\n let skipped: number | null = null\n let distilledCount: number | null = null\n let terminalMessage: string | null = null\n let errorMessage: string | null = null\n let isTerminal = false\n\n const ensureTopic = (id: string): TopicProgressRow => {\n let row = topicMap.get(id)\n if (!row) {\n row = { topicId: id, charCount: null, distilled: false }\n topicMap.set(id, row)\n order.push(id)\n }\n return row\n }\n\n for (const ev of events) {\n switch (ev.type) {\n case 'connected':\n connected = true\n if (phase === 'idle') phase = 'connecting'\n break\n case 'start':\n case 'phase-changed':\n if (!isTerminal) phase = 'running'\n break\n case 'progress': {\n if (!isTerminal) phase = 'running'\n if (ev.topicId) {\n const row = ensureTopic(ev.topicId)\n const cc = parseCharCount(ev.message)\n if (cc != null) row.charCount = cc\n currentTopicId = ev.topicId\n }\n break\n }\n case 'skill-distilled': {\n if (!isTerminal) phase = 'running'\n if (ev.topicId) ensureTopic(ev.topicId).distilled = true\n break\n }\n case 'done':\n phase = 'done'\n isTerminal = true\n completed = ev.completed ?? null\n skipped = ev.skipped ?? null\n distilledCount = ev.distilledCount ?? null\n terminalMessage = ev.message ?? null\n currentTopicId = null\n break\n case 'cancelled':\n phase = 'cancelled'\n isTerminal = true\n completed = ev.completed ?? null\n distilledCount = ev.distilledCount ?? null\n terminalMessage = ev.message ?? '已取消'\n currentTopicId = null\n break\n case 'error':\n phase = 'error'\n isTerminal = true\n errorMessage = ev.errorMessage ?? ev.message ?? '未知错误'\n terminalMessage = errorMessage\n currentTopicId = null\n break\n default:\n break\n }\n if (TERMINAL_TYPES.has(ev.type)) isTerminal = true\n }\n\n return {\n phase,\n connected,\n topics: order.map((id) => topicMap.get(id)!),\n currentTopicId,\n completed,\n skipped,\n distilledCount,\n terminalMessage,\n isTerminal,\n errorMessage,\n log: events,\n }\n}\n\n// ─── 刷新重连:status → 应否重连进行中的 run(decision 6c92809c) ──────────────\n\n/**\n * 决定挂载时(或刷新后)是否要重连一个进行中的 run。\n *\n * 背景:蒸馏向导进度只活在 React 本地 state;刷新即丢、向导回 Step 1。但\n * `status` 端点知道有 run 在跑(`isBusy` + `currentRunId`)。本纯函数把\n * 「该不该重连 + 重连哪个 runId」从组件里抽出来,便于喂 status fixture 单测。\n *\n * 仅当后端确实在跑(`isBusy === true`)且给了一个非空 `currentRunId` 时才重连。\n * run 已结束(`isBusy` 落回 false / `currentRunId` 为 null)时返回 null —— 避免\n * 「run 结束后刷新却卡在 Step 3 假装还在跑」。\n *\n * @returns 要重连的 runId;不需重连时为 null。\n */\nexport function reconnectableRunId(\n status: RunStatusResp | undefined | null,\n): string | null {\n if (!status) return null\n if (status.isBusy !== true) return null\n const id = status.currentRunId\n if (typeof id !== 'string' || id.length === 0) return null\n return id\n}\n\n/** 向导步骤序号(与 DistillRunPage 的 Steps 对齐:0 上游 / 1 选范围 / 2 运行)。 */\nexport const WIZARD_STEP_UPSTREAM = 0\nexport const WIZARD_STEP_SCOPE = 1\nexport const WIZARD_STEP_RUN = 2\n\n/**\n * 挂载时由 status 决定向导初始落在哪一步。\n *\n * - 有进行中的 run(reconnectableRunId 非空)→ 直接跳 Step 3「运行与产出」,\n * 组件据此重连该 run 的 SSE 流恢复进度。\n * - 否则维持 Step 1(上游就绪),走正常新建流程。\n *\n * 注意:这只决定「初始」步骤;用户手动前进/后退由组件自身的 setCurrent 接管,\n * 本函数不强制覆盖用户已切走的步骤(组件用「只在首次、且尚未重连过」守卫调用)。\n */\nexport function initialWizardStep(\n status: RunStatusResp | undefined | null,\n): number {\n return reconnectableRunId(status) !== null ? WIZARD_STEP_RUN : WIZARD_STEP_UPSTREAM\n}\n\n/** SSE 事件 type → 中文 badge(Step 3 日志区)。 */\nexport function runEventBadge(\n type: DistillRunEventType,\n): { color: string; label: string } {\n switch (type) {\n case 'connected':\n return { color: 'gray', label: '建连' }\n case 'start':\n return { color: 'arcoblue', label: '启动' }\n case 'progress':\n return { color: 'gray', label: '进度' }\n case 'phase-changed':\n return { color: 'blue', label: '阶段' }\n case 'skill-distilled':\n return { color: 'green', label: '蒸馏✓' }\n case 'done':\n return { color: 'green', label: '完成' }\n case 'cancelled':\n return { color: 'orange', label: '取消' }\n case 'error':\n return { color: 'red', label: '错误' }\n default:\n return { color: 'gray', label: String(type) }\n }\n}\n\n/** 友好化 run 提交错误(与 distillApi.friendlyDistillError 对齐)。 */\nexport function friendlyRunError(message: string | undefined): string {\n if (!message) return '蒸馏失败,未知错误'\n const m = message.trim()\n if (m === 'distill_in_progress') return '已有蒸馏在进行中,请稍后再试'\n if (m.includes('409')) return '已有蒸馏在进行中,请稍后再试'\n if (m.includes('403')) return '无权限触发蒸馏(403,loopback only)'\n if (m.includes('401') || m === 'unauthorized') return '未授权:请检查 daemon token'\n if (m.includes('500')) return '后端蒸馏出错(500),请查看 daemon 日志'\n if (m.toLowerCase().includes('failed to fetch')) return '无法连接 daemon,请确认服务已启动'\n return m\n}\n","/**\n * useDistillRun — 执行蒸馏向导 (Phase 2f, decision 29688066) 取数 + 副作用 hook。\n *\n * 封装向导三步的真实端点对接(**不 mock**):\n * Step1 useDistillRunStatus() — GET /status(上游 commit + isBusy + claudeCli)\n * + initMutation — POST /init(拉取/克隆 3 上游到 cache)\n * Step2 (纯表单,预览走 distill-run-derive.previewRunRequest,无副作用)\n * Step3 startRun() — POST /run 拿 runId → EventSource 连 SSE 流,\n * 逐事件 reduce 成 RunView(distill-run-derive.reduceDistillRunEvents)。\n *\n * SSE 解析逻辑全在纯函数 distill-run-derive.ts,本 hook 只负责 EventSource 生命周期 +\n * 把累积事件交给纯 reducer。故「SSE 解析」可喂模拟事件流单测,无需真触发 10min 全量跑。\n *\n * 真实成本警示:POST /run 真正会 spawn `claude -p --agent skill-distiller`,每 topic\n * ~10min 真烧 LLM。向导默认 topicCap=5;自测请用 topicCap=1 或 topicIds 限定单条。\n */\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'\n\nimport { authFetch } from '../utils/auth'\nimport {\n reduceDistillRunEvents,\n buildRunRequest,\n DISTILL_RUN_EVENT_TYPES,\n type DistillRunEvent,\n type DistillRunEventType,\n type InitResp,\n type RunStatusResp,\n type RunFormState,\n type RunView,\n} from './distill-run-derive'\n\n// ─── fetch helpers ───────────────────────────────────────────────────────────\n\nasync function fetchRunStatus(): Promise<RunStatusResp> {\n const r = await fetch('/api/skills/distill/status')\n if (!r.ok) throw new Error(`status → ${r.status}`)\n return r.json() as Promise<RunStatusResp>\n}\n\nasync function postInit(skipFetch: boolean): Promise<InitResp> {\n const r = await authFetch('/api/skills/distill/init', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ skipFetch }),\n })\n if (!r.ok) throw new Error(`init → ${r.status}`)\n return r.json() as Promise<InitResp>\n}\n\nasync function postRun(form: RunFormState): Promise<{ runId: string; streamUrl: string }> {\n const r = await authFetch('/api/skills/distill/run', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(buildRunRequest(form)),\n })\n if (r.status === 409) throw new Error('distill_in_progress')\n if (!r.ok) throw new Error(`run → ${r.status}`)\n return r.json() as Promise<{ runId: string; streamUrl: string }>\n}\n\nasync function postCancel(runId: string): Promise<void> {\n const r = await authFetch(`/api/skills/distill/cancel/${encodeURIComponent(runId)}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({}),\n })\n if (!r.ok) throw new Error(`cancel → ${r.status}`)\n}\n\n// ─── Step 1:status + init ───────────────────────────────────────────────────\n\nexport interface DistillRunStatusResult {\n status: RunStatusResp | undefined\n loading: boolean\n isError: boolean\n refetch: () => void\n /** init 结果(拉取上游后填充)。 */\n initResult: InitResp | undefined\n initPending: boolean\n initError: Error | null\n runInit: (skipFetch?: boolean) => void\n}\n\nexport function useDistillRunStatus(): DistillRunStatusResult {\n const qc = useQueryClient()\n const statusQ = useQuery({\n queryKey: ['distill-status'],\n queryFn: fetchRunStatus,\n refetchInterval: (q) =>\n (q.state.data as RunStatusResp | undefined)?.isBusy ? 5_000 : 60_000,\n })\n const initM = useMutation({\n mutationFn: (skipFetch: boolean) => postInit(skipFetch),\n onSuccess: () => {\n void qc.invalidateQueries({ queryKey: ['distill-status'] })\n },\n })\n\n return {\n status: statusQ.data,\n loading: statusQ.isLoading,\n isError: statusQ.isError,\n refetch: () => void statusQ.refetch(),\n initResult: initM.data,\n initPending: initM.isPending,\n initError: (initM.error as Error) ?? null,\n runInit: (skipFetch = false) => initM.mutate(skipFetch),\n }\n}\n\n// ─── Step 3:run + SSE ───────────────────────────────────────────────────────\n\nexport interface DistillRunController {\n /** 当前 SSE reduce 出的运行视图。 */\n view: RunView\n /** 已发起的 runId(null = 未启动)。 */\n runId: string | null\n /** POST /run 提交中。 */\n submitting: boolean\n /** POST /run 提交错误(非 SSE 内错误)。 */\n submitError: Error | null\n /** 发起一次蒸馏(POST /run → 连 SSE)。 */\n start: (form: RunFormState) => Promise<void>\n /**\n * 重连一个已在跑的 run(刷新后恢复进度,decision 6c92809c):不 POST /run,\n * 直接连该 runId 的 SSE 流。后端 SSE 在(重)连时先回放 session.events 累积\n * 进度(distill-manager.ts),故重连即可看到「跑到哪了」并续推后续事件。\n * 幂等:已重连/已在连同一个 runId 时不重复建流。\n */\n reconnect: (runId: string) => void\n /** 取消当前运行(POST /cancel;SSE 收到 cancelled 终结)。 */\n cancel: () => Promise<void>\n /** 复位(回到 Step 2 重新选范围)。 */\n reset: () => void\n}\n\nexport function useDistillRunController(): DistillRunController {\n const qc = useQueryClient()\n const [events, setEvents] = useState<DistillRunEvent[]>([])\n const [runId, setRunId] = useState<string | null>(null)\n const [submitting, setSubmitting] = useState(false)\n const [submitError, setSubmitError] = useState<Error | null>(null)\n const esRef = useRef<EventSource | null>(null)\n\n const closeStream = useCallback(() => {\n if (esRef.current) {\n esRef.current.close()\n esRef.current = null\n }\n }, [])\n\n useEffect(() => closeStream, [closeStream])\n\n const subscribe = useCallback(\n (id: string) => {\n closeStream()\n const es = new EventSource(\n `/api/skills/distill/run/${encodeURIComponent(id)}/stream`,\n )\n esRef.current = es\n const dispatch = (type: DistillRunEventType) => (msg: MessageEvent) => {\n let data: Record<string, unknown> = {}\n try {\n data = JSON.parse((msg.data as string) || '{}')\n } catch {\n /* malformed — keep type only */\n }\n const ev = { ...data, type } as DistillRunEvent\n setEvents((prev) => [...prev, ev])\n if (type === 'done' || type === 'error' || type === 'cancelled') {\n es.close()\n esRef.current = null\n // run 终结后刷新列表/状态,使 /ai/distill 出现新记录。\n void qc.invalidateQueries({ queryKey: ['distill-status'] })\n void qc.invalidateQueries({ queryKey: ['distill-review'] })\n }\n }\n for (const t of DISTILL_RUN_EVENT_TYPES) {\n es.addEventListener(t, dispatch(t) as EventListener)\n }\n es.onerror = () => {\n // 浏览器会自动重连;只有在尚未终结时把它表达成一条 error 事件供 UI 兜底。\n setEvents((prev) => {\n const last = prev[prev.length - 1]\n if (last && (last.type === 'done' || last.type === 'error' || last.type === 'cancelled')) {\n return prev\n }\n return [\n ...prev,\n { type: 'error', errorMessage: 'SSE 连接中断(daemon 不可达或已断流)' },\n ]\n })\n }\n },\n [closeStream, qc],\n )\n\n const start = useCallback(\n async (form: RunFormState) => {\n setSubmitError(null)\n setSubmitting(true)\n setEvents([])\n try {\n const { runId: id } = await postRun(form)\n setRunId(id)\n subscribe(id)\n } catch (err) {\n setSubmitError(err as Error)\n } finally {\n setSubmitting(false)\n }\n },\n [subscribe],\n )\n\n const reconnect = useCallback(\n (id: string) => {\n // 幂等:已在连同一个 runId(state 已是它且流还开着)→ 不重复建流,避免\n // 同一 run 开两条 SSE 泄漏。换 runId 时 subscribe 会先 closeStream 旧流。\n if (runId === id && esRef.current) return\n setSubmitError(null)\n setEvents([])\n setRunId(id)\n subscribe(id)\n },\n [runId, subscribe],\n )\n\n const cancel = useCallback(async () => {\n if (!runId) return\n try {\n await postCancel(runId)\n } catch {\n /* best-effort; SSE cancelled/closed will terminate */\n }\n }, [runId])\n\n const reset = useCallback(() => {\n closeStream()\n setEvents([])\n setRunId(null)\n setSubmitError(null)\n }, [closeStream])\n\n return {\n view: reduceDistillRunEvents(events),\n runId,\n submitting,\n submitError,\n start,\n reconnect,\n cancel,\n reset,\n }\n}\n","/**\n * DistillRunPage — AI 资源 · 执行蒸馏向导 /ai/distill/run (Phase 2f, decision 29688066).\n *\n * 替换 App.tsx 里 `/ai/distill/run` 的占位组件。把原型「执行蒸馏整页三步向导」\n * 翻译成真 Arco 组件(**严禁直搬原型 Tailwind CSS**):\n * ① 上游就绪:显示 3 上游 cache/commit 状态 + 「拉取上游(init)」按钮(POST init)。\n * ② 选 topic 范围:topicCap(1-50 默认 5) + 可选 topicIds 勾选 + force 开关;\n * 实时 JSON 预览将发的 run 请求体。\n * ③ 运行:点执行 → POST run 拿 runId → 连 SSE 流,逐 topic 实时渲染进度/蒸馏完成;\n * 完成后可回列表(/ai/distill)看带 D1-D5 的新记录。\n *\n * 真实端点 + SSE(不 mock)见 useDistillRun.ts / distill-run-derive.ts。\n *\n * ⚠️ 成本:点 Step3「执行蒸馏」会真 spawn `claude -p`,每 topic ~10min 真烧 LLM。\n * 向导默认 topicCap=5;自测请把 topicCap 调到 1 或用 topicIds 限定单条再执行。\n */\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { useNavigate } from 'react-router-dom'\n\nimport Card from '@arco-design/web-react/es/Card'\nimport Steps from '@arco-design/web-react/es/Steps'\nimport Tag from '@arco-design/web-react/es/Tag'\nimport Typography from '@arco-design/web-react/es/Typography'\nimport Button from '@arco-design/web-react/es/Button'\nimport InputNumber from '@arco-design/web-react/es/InputNumber'\nimport Switch from '@arco-design/web-react/es/Switch'\nimport Checkbox from '@arco-design/web-react/es/Checkbox'\nimport Alert from '@arco-design/web-react/es/Alert'\nimport Spin from '@arco-design/web-react/es/Spin'\nimport Result from '@arco-design/web-react/es/Result'\nimport Space from '@arco-design/web-react/es/Space'\nimport {\n IconLeft,\n IconStorage,\n IconCheckCircle,\n IconCloseCircle,\n IconThunderbolt,\n IconRefresh,\n} from '@arco-design/web-react/icon'\n\nimport {\n useDistillRunStatus,\n useDistillRunController,\n} from '../../hooks/useDistillRun'\nimport {\n buildUpstreamReadyRows,\n isUpstreamReady,\n previewRunRequest,\n runEventBadge,\n friendlyRunError,\n reconnectableRunId,\n WIZARD_STEP_RUN,\n type RunFormState,\n type UpstreamReadyRow,\n} from '../../hooks/distill-run-derive'\n\nconst Step = Steps.Step\n\n// ── 已知可勾选 topic(status.completed 派生 + 已知 4 源);用户也可不选跑 topicCap。 ──\n\nfunction upstreamStatusTag(row: UpstreamReadyRow) {\n if (row.error) {\n return (\n <Tag color=\"red\" size=\"small\" icon={<IconCloseCircle />}>\n 失败\n </Tag>\n )\n }\n if (row.status === 'cloned' || row.status === 'updated') {\n return (\n <Tag color=\"green\" size=\"small\" icon={<IconCheckCircle />}>\n {row.status === 'cloned' ? '已克隆' : '已更新'}\n </Tag>\n )\n }\n if (row.status === 'cached') {\n return (\n <Tag color=\"cyan\" size=\"small\">\n cache\n </Tag>\n )\n }\n if (row.status === 'skipped' || row.isSkipSource) {\n return (\n <Tag color=\"gray\" size=\"small\">\n skip\n </Tag>\n )\n }\n return (\n <Tag color=\"gray\" size=\"small\">\n {row.commit ? '就绪' : '未拉取'}\n </Tag>\n )\n}\n\nfunction UpstreamCard({ row }: { row: UpstreamReadyRow }) {\n return (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n padding: '10px 14px',\n border: '1px solid var(--color-border-2)',\n borderRadius: 6,\n minWidth: 170,\n background: row.isSkipSource ? 'var(--color-fill-1)' : 'transparent',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n <IconStorage style={{ color: 'var(--color-text-3)', fontSize: 13 }} />\n <Typography.Text style={{ fontSize: 13, fontWeight: 600 }}>{row.label}</Typography.Text>\n <div style={{ flex: 1 }} />\n {upstreamStatusTag(row)}\n </div>\n <Typography.Text type=\"secondary\" style={{ fontSize: 11 }}>\n commit{' '}\n {row.commit ? (\n <Typography.Text code style={{ fontSize: 11 }}>\n {row.commit}\n </Typography.Text>\n ) : (\n '未知'\n )}\n </Typography.Text>\n {row.error && (\n <Typography.Text type=\"error\" style={{ fontSize: 11 }}>\n {row.error}\n </Typography.Text>\n )}\n </div>\n )\n}\n\nexport default function DistillRunPage() {\n const navigate = useNavigate()\n const [current, setCurrent] = useState(0)\n\n // Step 2 表单\n const [form, setForm] = useState<RunFormState>({ topicCap: 5, topicIds: [], force: false })\n\n const { status, loading, initResult, initPending, initError, runInit } = useDistillRunStatus()\n const run = useDistillRunController()\n\n // ── 刷新重连(decision 6c92809c)─────────────────────────────────────────────\n // 进度只活在 React 本地 state,刷新即丢、向导回 Step 1。但 status 知道有 run\n // 在跑(isBusy + currentRunId)。挂载/status 到位后:若有进行中的 run 且本地尚\n // 未连任何 run → 跳 Step 3 + 重连该 run 的 SSE(后端回放 session.events 累积\n // 进度),恢复显示「跑到哪了」并续推后续事件。\n //\n // 守卫:autoReconnectedRef 确保只在「本次进入页面、用户尚未手动启动/重连」时\n // 自动重连一次——不抢用户手动新建的 run,run 结束(isBusy→false)后刷新也不会\n // 误跳 Step 3。\n const busyRunId = reconnectableRunId(status)\n const autoReconnectedRef = useRef(false)\n useEffect(() => {\n if (autoReconnectedRef.current) return\n if (!busyRunId) return\n if (run.runId) return // 用户已手动启动/重连,别覆盖\n autoReconnectedRef.current = true\n setCurrent(WIZARD_STEP_RUN)\n run.reconnect(busyRunId)\n }, [busyRunId, run])\n\n const rows = useMemo(\n () => buildUpstreamReadyRows(initResult, status),\n [initResult, status],\n )\n const ready = isUpstreamReady(rows)\n const isBusy = status?.isBusy === true\n const claudeOk = status?.claudeCliAvailable !== false\n\n // 可勾选 topic 来自 status.state.completed(已蒸馏过的 topic 名,可强制重蒸)。\n const selectableTopics = status?.state?.completed ?? []\n\n const runReqPreview = useMemo(() => previewRunRequest(form), [form])\n\n return (\n <div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 16 }}>\n {/* ── 页头 ─────────────────────────────────────────────────────── */}\n <Card bordered>\n <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>\n <Button\n type=\"text\"\n icon={<IconLeft />}\n onClick={() => navigate('/ai/distill')}\n style={{ paddingLeft: 0 }}\n >\n 返回蒸馏列表\n </Button>\n <Typography.Title heading={6} style={{ margin: 0 }}>\n 执行蒸馏向导\n </Typography.Title>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n 上游 SKILL → IT 通用方法论蒸馏(spawn claude -p · 每 topic ~10min 真烧 LLM)\n </Typography.Text>\n <div style={{ flex: 1 }} />\n {isBusy && busyRunId && (\n <Tag\n color=\"arcoblue\"\n size=\"small\"\n style={{ cursor: 'pointer' }}\n onClick={() => {\n autoReconnectedRef.current = true\n setCurrent(WIZARD_STEP_RUN)\n run.reconnect(busyRunId)\n }}\n title=\"点击重连查看进度\"\n >\n 另有蒸馏进行中 · 点击查看进度\n </Tag>\n )}\n {isBusy && !busyRunId && (\n <Tag color=\"arcoblue\" size=\"small\">\n 另有蒸馏进行中\n </Tag>\n )}\n </div>\n <Steps current={current} style={{ marginTop: 16 }} size=\"small\">\n <Step title=\"上游就绪\" description=\"拉取/克隆 3 上游到 cache\" />\n <Step title=\"选范围\" description=\"topicCap / topicIds / force\" />\n <Step title=\"运行与产出\" description=\"连 SSE 逐 topic 揭示\" />\n </Steps>\n </Card>\n\n {!claudeOk && (\n <Alert\n type=\"warning\"\n content=\"未检测到 claude CLI(status.claudeCliAvailable=false)——蒸馏需要本机已登录的 claude CLI,请先安装/登录后再执行。\"\n />\n )}\n\n {/* ── Step 1:上游就绪 ─────────────────────────────────────────── */}\n {current === 0 && (\n <Card\n bordered\n title={<span style={{ fontSize: 14, fontWeight: 600 }}>① 上游就绪</span>}\n extra={\n <Button\n type=\"outline\"\n size=\"small\"\n icon={<IconRefresh />}\n loading={initPending}\n onClick={() => runInit(false)}\n >\n 拉取上游 (init)\n </Button>\n }\n >\n {loading ? (\n <Spin />\n ) : (\n <>\n <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>\n {rows.map((r) => (\n <UpstreamCard key={r.key} row={r} />\n ))}\n </div>\n {initError && (\n <Alert\n style={{ marginTop: 12 }}\n type=\"error\"\n content={`拉取上游失败:${initError.message}`}\n />\n )}\n {initResult && (\n <Alert\n style={{ marginTop: 12 }}\n type=\"success\"\n content={`上游已就绪(NOTICE ${initResult.noticeWritten ? '已写' : '未写'} · catalog ${initResult.catalogWritten ? '已写' : '未写'})。`}\n />\n )}\n <div style={{ marginTop: 16, display: 'flex', justifyContent: 'flex-end' }}>\n <Button\n type=\"primary\"\n disabled={!ready}\n onClick={() => setCurrent(1)}\n >\n 下一步:选范围\n </Button>\n </div>\n {!ready && (\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n 先点「拉取上游 (init)」把 3 上游克隆/更新到 cache,就绪后才能进入下一步。\n </Typography.Text>\n )}\n </>\n )}\n </Card>\n )}\n\n {/* ── Step 2:选 topic 范围 ───────────────────────────────────── */}\n {current === 1 && (\n <Card bordered title={<span style={{ fontSize: 14, fontWeight: 600 }}>② 选 topic 范围</span>}>\n <Space direction=\"vertical\" size=\"large\" style={{ width: '100%' }}>\n <div>\n <Typography.Text style={{ fontSize: 13, fontWeight: 600 }}>topicCap(1-50,默认 5)</Typography.Text>\n <div style={{ marginTop: 6, display: 'flex', alignItems: 'center', gap: 8 }}>\n <InputNumber\n min={1}\n max={50}\n value={form.topicCap}\n onChange={(v) => setForm((f) => ({ ...f, topicCap: typeof v === 'number' ? v : 5 }))}\n style={{ width: 120 }}\n disabled={form.topicIds.length > 0}\n />\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n 最多蒸馏 N 个 topic(勾选具体 topicIds 时此项被忽略)。建议自测设 1。\n </Typography.Text>\n </div>\n </div>\n\n <div>\n <Typography.Text style={{ fontSize: 13, fontWeight: 600 }}>\n 指定 topicIds(可选;勾选后只跑这些)\n </Typography.Text>\n {selectableTopics.length > 0 ? (\n <div style={{ marginTop: 6 }}>\n <Checkbox.Group\n value={form.topicIds}\n onChange={(v) => setForm((f) => ({ ...f, topicIds: v as string[] }))}\n >\n <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>\n {selectableTopics.map((t) => (\n <Checkbox key={t} value={t}>\n <Typography.Text code style={{ fontSize: 12 }}>\n {t}\n </Typography.Text>\n </Checkbox>\n ))}\n </div>\n </Checkbox.Group>\n </div>\n ) : (\n <Typography.Text type=\"secondary\" style={{ fontSize: 12, display: 'block', marginTop: 6 }}>\n 暂无已知 topic(state.completed 为空)——按 topicCap 自动选候选。\n </Typography.Text>\n )}\n </div>\n\n <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n <Switch\n checked={form.force}\n onChange={(v) => setForm((f) => ({ ...f, force: v }))}\n />\n <Typography.Text style={{ fontSize: 13 }}>\n force —— 强制重蒸(无视 completedSet / topicCap 跳过已完成)\n </Typography.Text>\n </div>\n\n <div>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n 将发起的 POST /api/skills/distill/run 请求体:\n </Typography.Text>\n <pre\n style={{\n marginTop: 6,\n padding: 12,\n background: 'var(--color-fill-1)',\n borderRadius: 4,\n fontSize: 12,\n fontFamily: 'monospace',\n overflowX: 'auto',\n }}\n >\n {runReqPreview}\n </pre>\n </div>\n\n <div style={{ display: 'flex', justifyContent: 'space-between' }}>\n <Button onClick={() => setCurrent(0)}>上一步</Button>\n <Button type=\"primary\" onClick={() => setCurrent(2)}>\n 下一步:运行\n </Button>\n </div>\n </Space>\n </Card>\n )}\n\n {/* ── Step 3:运行与产出 ───────────────────────────────────────── */}\n {current === 2 && (\n <Card bordered title={<span style={{ fontSize: 14, fontWeight: 600 }}>③ 运行与产出</span>}>\n {!run.runId && (\n <Space direction=\"vertical\" size=\"medium\" style={{ width: '100%' }}>\n <Alert\n type=\"warning\"\n content=\"点「执行蒸馏」将真 spawn claude -p,每 topic ~10min 真烧 LLM。确认范围(见上一步 JSON 预览)后再执行。\"\n />\n {run.submitError && (\n <Alert type=\"error\" content={friendlyRunError(run.submitError.message)} />\n )}\n <div style={{ display: 'flex', justifyContent: 'space-between' }}>\n <Button onClick={() => setCurrent(1)}>上一步</Button>\n <Button\n type=\"primary\"\n icon={<IconThunderbolt />}\n loading={run.submitting}\n disabled={isBusy || !claudeOk}\n onClick={() => void run.start(form)}\n >\n 执行蒸馏\n </Button>\n </div>\n </Space>\n )}\n\n {run.runId && (\n <Space direction=\"vertical\" size=\"medium\" style={{ width: '100%' }}>\n {/* 运行态横条 */}\n <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>\n <Tag size=\"small\" style={{ fontFamily: 'monospace' }}>\n {run.runId}\n </Tag>\n <Tag\n color={\n run.view.phase === 'done'\n ? 'green'\n : run.view.phase === 'error'\n ? 'red'\n : run.view.phase === 'cancelled'\n ? 'orange'\n : 'arcoblue'\n }\n size=\"small\"\n >\n {run.view.phase}\n </Tag>\n {run.view.currentTopicId && (\n <Tag color=\"arcoblue\" size=\"small\">\n 当前: {run.view.currentTopicId}\n </Tag>\n )}\n <div style={{ flex: 1 }} />\n {!run.view.isTerminal && (\n <Button size=\"small\" status=\"danger\" onClick={() => void run.cancel()}>\n 取消\n </Button>\n )}\n </div>\n\n {!run.view.isTerminal && !run.view.connected && <Spin tip=\"连接 SSE 流…\" />}\n\n {/* 逐 topic 进度行 */}\n {run.view.topics.length > 0 && (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>\n {run.view.topics.map((t) => (\n <div\n key={t.topicId}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n padding: '6px 10px',\n border: '1px solid var(--color-border-2)',\n borderRadius: 4,\n }}\n >\n <Typography.Text code style={{ fontSize: 12 }}>\n {t.topicId}\n </Typography.Text>\n <div style={{ flex: 1 }} />\n {t.charCount != null && (\n <Typography.Text type=\"secondary\" style={{ fontSize: 11 }}>\n {t.charCount.toLocaleString()} chars\n </Typography.Text>\n )}\n {t.distilled ? (\n <Tag color=\"green\" size=\"small\" icon={<IconCheckCircle />}>\n 蒸馏✓\n </Tag>\n ) : (\n <Tag color=\"arcoblue\" size=\"small\">\n 运行中\n </Tag>\n )}\n </div>\n ))}\n </div>\n )}\n\n {/* 终态结果 */}\n {run.view.phase === 'done' && (\n <Result\n status=\"success\"\n title=\"蒸馏完成\"\n subTitle={\n run.view.terminalMessage ??\n `完成 ${run.view.completed ?? '?'} · 蒸馏 ${run.view.distilledCount ?? '?'} · 跳过 ${run.view.skipped ?? '?'}`\n }\n extra={[\n <Button key=\"list\" type=\"primary\" onClick={() => navigate('/ai/distill')}>\n 查看产出(带 D1-D5)\n </Button>,\n <Button key=\"again\" onClick={run.reset}>\n 再跑一次\n </Button>,\n ]}\n />\n )}\n {run.view.phase === 'cancelled' && (\n <Result\n status=\"warning\"\n title=\"已取消\"\n subTitle={run.view.terminalMessage ?? '蒸馏已被取消'}\n extra={[\n <Button key=\"again\" type=\"primary\" onClick={run.reset}>\n 重新执行\n </Button>,\n ]}\n />\n )}\n {run.view.phase === 'error' && (\n <Result\n status=\"error\"\n title=\"蒸馏出错\"\n subTitle={friendlyRunError(run.view.errorMessage ?? undefined)}\n extra={[\n <Button key=\"again\" type=\"primary\" onClick={run.reset}>\n 重试\n </Button>,\n ]}\n />\n )}\n\n {/* SSE 事件日志 */}\n <div>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n SSE 事件流({run.view.log.length}):\n </Typography.Text>\n <div\n style={{\n marginTop: 6,\n maxHeight: 220,\n overflowY: 'auto',\n fontSize: 12,\n fontFamily: 'monospace',\n background: 'var(--color-fill-1)',\n padding: 8,\n borderRadius: 4,\n }}\n >\n {run.view.log.length === 0 && (\n <Typography.Text type=\"secondary\">等待第一个 SSE 事件…</Typography.Text>\n )}\n {run.view.log.map((ev, i) => {\n const badge = runEventBadge(ev.type)\n return (\n <div key={i} style={{ display: 'flex', gap: 8, lineHeight: '20px' }}>\n <Tag color={badge.color} size=\"small\" style={{ minWidth: 56, textAlign: 'center' }}>\n {badge.label}\n </Tag>\n <span style={{ flex: 1 }}>\n {ev.topicId ? `${ev.topicId} ` : ''}\n {ev.message ?? ''}\n {ev.errorMessage ? ` — ${ev.errorMessage}` : ''}\n {ev.completed != null ? ` (completed=${ev.completed})` : ''}\n </span>\n </div>\n )\n })}\n </div>\n </div>\n </Space>\n )}\n </Card>\n )}\n </div>\n )\n}\n"],"names":["DISTILL_RUN_EVENT_TYPES","UPSTREAM_LABELS","SKIP_SOURCE_KEYS","shortCommit","commit","c","buildUpstreamReadyRows","init","status","results","r","key","_a","_b","commits","isUpstreamReady","rows","nonSkip","clampTopicCap","n","TOPIC_ID_RE","sanitizeTopicIds","ids","seen","out","id","buildRunRequest","form","topicIds","body","previewRunRequest","parseCharCount","message","m","TERMINAL_TYPES","reduceDistillRunEvents","events","topicMap","order","connected","phase","currentTopicId","completed","skipped","distilledCount","terminalMessage","errorMessage","isTerminal","ensureTopic","row","ev","cc","reconnectableRunId","WIZARD_STEP_RUN","runEventBadge","type","friendlyRunError","fetchRunStatus","postInit","skipFetch","authFetch","postRun","postCancel","runId","useDistillRunStatus","qc","useQueryClient","statusQ","useQuery","q","initM","useMutation","useDistillRunController","setEvents","useState","setRunId","submitting","setSubmitting","submitError","setSubmitError","esRef","useRef","closeStream","useCallback","useEffect","subscribe","es","dispatch","msg","data","prev","t","last","start","err","reconnect","cancel","reset","Step","Steps","upstreamStatusTag","jsx","Tag","IconCloseCircle","IconCheckCircle","UpstreamCard","jsxs","IconStorage","Typography","DistillRunPage","navigate","useNavigate","current","setCurrent","setForm","loading","initResult","initPending","initError","runInit","run","busyRunId","autoReconnectedRef","useMemo","ready","isBusy","claudeOk","selectableTopics","runReqPreview","Card","Button","IconLeft","Alert","IconRefresh","Spin","Fragment","Space","InputNumber","v","f","Checkbox","Switch","IconThunderbolt","Result","i","badge"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{j as r}from"./react-vendor-tkvCrao7.js";import{b as t,T as i,a8 as a}from"./arco-DV6xCLhr.js";function l(e){if(!e)return"";const n=e.replace(/\/+$/,""),o=n.lastIndexOf("/");return o>=0?n.slice(o+1):n}function u({project:e,isAllProjects:n,usageLabel:o="使用统计"}){if(n||!e)return null;const s=l(e)||e;return r.jsx(t,{color:"arcoblue",size:"small",icon:r.jsx(a,{}),style:{borderRadius:4},children:r.jsxs(i.Text,{style:{fontSize:12},children:["定义全局 · ",o,"按当前项目(",s,")"]})})}export{u as G};
|
|
2
|
+
//# sourceMappingURL=GlobalScopeHint-Q3wTJx3F.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GlobalScopeHint-Q3wTJx3F.js","sources":["../../src/components/ai/GlobalScopeHint.tsx"],"sourcesContent":["/**\n * GlobalScopeHint — 「定义全局 · 使用统计按当前项目」提示 (decision dd79010a).\n *\n * Skill / Agent 定义(catalog / 模板 / 蒸馏正文)是全局一套库——不随全局项目\n * 选择器变空。但这些页的 usage 维度(调用次数 / 有用性 / 委托 / 体检)已按当前\n * 项目过滤。当用户选了一个具体项目(非全部项目)时,渲染这条小提示,避免误读\n * 为「选了项目就没数据」。选「全部项目」时不渲染(无歧义)。\n */\nimport Tag from '@arco-design/web-react/es/Tag'\nimport Typography from '@arco-design/web-react/es/Typography'\nimport { IconInfoCircle } from '@arco-design/web-react/icon'\n\n/** Trailing basename of an absolute project path (display only). */\nfunction projectBasename(path: string): string {\n if (!path) return ''\n const trimmed = path.replace(/\\/+$/, '')\n const idx = trimmed.lastIndexOf('/')\n return idx >= 0 ? trimmed.slice(idx + 1) : trimmed\n}\n\nexport interface GlobalScopeHintProps {\n /** Effective project path the usage stats are scoped to ('' = all projects). */\n project: string\n /** True when the explicit all-projects view is selected. */\n isAllProjects: boolean\n /** What the usage dimension is, for the hint copy (e.g. '使用统计' / '委托统计'). */\n usageLabel?: string\n}\n\n/**\n * Render the global-definition hint. Returns null for the all-projects view or\n * when no concrete project is resolved (nothing is being filtered → no hint).\n */\nexport default function GlobalScopeHint({\n project,\n isAllProjects,\n usageLabel = '使用统计',\n}: GlobalScopeHintProps) {\n if (isAllProjects || !project) return null\n const name = projectBasename(project) || project\n return (\n <Tag\n color=\"arcoblue\"\n size=\"small\"\n icon={<IconInfoCircle />}\n style={{ borderRadius: 4 }}\n >\n <Typography.Text style={{ fontSize: 12 }}>\n 定义全局 · {usageLabel}按当前项目({name})\n </Typography.Text>\n </Tag>\n )\n}\n"],"names":["projectBasename","path","trimmed","idx","GlobalScopeHint","project","isAllProjects","usageLabel","name","jsx","Tag","IconInfoCircle","jsxs","Typography"],"mappings":"qGAaA,SAASA,EAAgBC,EAAsB,CAC7C,GAAI,CAACA,EAAM,MAAO,GAClB,MAAMC,EAAUD,EAAK,QAAQ,OAAQ,EAAE,EACjCE,EAAMD,EAAQ,YAAY,GAAG,EACnC,OAAOC,GAAO,EAAID,EAAQ,MAAMC,EAAM,CAAC,EAAID,CAC7C,CAeA,SAAwBE,EAAgB,CACtC,QAAAC,EACA,cAAAC,EACA,WAAAC,EAAa,MACf,EAAyB,CACvB,GAAID,GAAiB,CAACD,EAAS,OAAO,KACtC,MAAMG,EAAOR,EAAgBK,CAAO,GAAKA,EACzC,OACEI,EAAAA,IAACC,EAAA,CACC,MAAM,WACN,KAAK,QACL,WAAOC,EAAA,EAAe,EACtB,MAAO,CAAE,aAAc,CAAA,EAEvB,SAAAC,EAAAA,KAACC,EAAW,KAAX,CAAgB,MAAO,CAAE,SAAU,IAAM,SAAA,CAAA,UAChCN,EAAW,SAAOC,EAAK,GAAA,CAAA,CACjC,CAAA,CAAA,CAGN"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{r as f,j as e}from"./react-vendor-tkvCrao7.js";import{J as l,d as R,D as W,F as c,X as F,t as $,T as t,N as j,a2 as D,K as T,ai as E,a8 as L,aj as H,$ as M,a3 as P,b as z}from"./arco-DV6xCLhr.js";import{u as N,e as U,g as X,f as m,t as h,c as S,a as G,d as J}from"./useIssuesFeed-CFiyQkAL.js";import{d as K,u as q}from"./react-router-Cxmg8RuL.js";import"./vendor-DS-q4Eyc.js";import"./query-CgCOpYWf.js";import"./index-DileOOE4.js";import"./lucide-CnlPQoG8.js";const u=T.Row,o=T.Col;function v(i){return e.jsx(z,{color:G(i),size:"small",children:h(i)})}function b(i){return e.jsx(z,{color:J(i),size:"small",children:S(i)})}function y({icon:i,title:n,children:r}){return e.jsxs(l,{bordered:!0,children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,marginBottom:10},children:[i,e.jsx(t.Text,{style:{fontSize:15,fontWeight:600},children:n})]}),r]})}function se(){const{id:i}=K(),n=q(),{issues:r,loading:I,isError:k,error:p}=N(),s=f.useMemo(()=>U(r,i),[r,i]),a=f.useMemo(()=>s?X(r,s):0,[r,s]);if(I)return e.jsx("div",{style:{padding:16},children:e.jsx(l,{bordered:!0,children:e.jsx(R,{animation:!0,text:{rows:10}})})});if(k||!s)return e.jsx("div",{style:{padding:16},children:e.jsx(W,{status:"error",title:"加载问题详情失败",subTitle:(p==null?void 0:p.message)||"问题不存在(id 可能已不在当前时间窗内)或端点不可用",extra:e.jsx(c,{type:"primary",onClick:()=>n("/issues"),children:"返回问题"})})});const C=()=>{var g;try{(g=navigator.clipboard)==null||g.writeText(s.rule),P.success(`已复制规则 ${s.rule}`)}catch{}},d=s.type==="failure",x=s.type==="drift",w=!d&&!x?e.jsx("pre",{style:{margin:0,padding:"12px 14px",background:"#1D2129",color:"#E5E6EB",borderRadius:6,fontSize:12,lineHeight:1.6,whiteSpace:"pre-wrap",wordBreak:"break-word",overflowX:"auto"},children:s.what}):e.jsx("div",{style:{borderLeft:`3px solid ${d?"rgb(var(--red-5))":"rgb(var(--gold-5))"}`,background:"var(--color-fill-1)",borderRadius:"0 6px 6px 0",padding:"12px 14px",fontSize:13,lineHeight:1.6},children:s.what}),B=d?"verify-agent verdict / 失败摘要":x?"漂移实测 vs 期望":`被 ${s.rule} 拦下的${s.action==="Bash"?"命令":"动作"}(端点未返回原文,下为摘要兜底)`;return e.jsxs("div",{style:{padding:16,display:"flex",flexDirection:"column",gap:16},children:[e.jsxs(l,{bordered:!0,children:[e.jsx(c,{type:"text",size:"small",icon:e.jsx(F,{}),style:{marginBottom:8,paddingLeft:0},onClick:()=>n("/issues"),children:"返回问题"}),e.jsxs("div",{style:{display:"flex",alignItems:"flex-start",justifyContent:"space-between",gap:16,flexWrap:"wrap"},children:[e.jsxs("div",{style:{minWidth:0,flex:1},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"},children:[e.jsx($,{style:{color:"rgb(var(--red-6))"}}),e.jsx(t.Title,{heading:5,style:{margin:0},children:s.title}),v(s.type),b(s.severity)]}),e.jsxs("div",{style:{display:"flex",gap:12,flexWrap:"wrap",marginTop:8,alignItems:"center"},children:[e.jsxs(t.Text,{type:"secondary",style:{fontSize:12},children:["规则 ",e.jsx(t.Text,{style:{fontFamily:"monospace"},children:s.rule})]}),e.jsxs(t.Text,{type:"secondary",style:{fontSize:12},children:["动作 ",e.jsx(t.Text,{style:{fontWeight:600},children:s.action})]}),e.jsx(t.Text,{type:"secondary",style:{fontSize:12,fontFamily:"monospace"},children:s.session?`${s.session.slice(0,12)}…`:"session 未返回"}),e.jsx(t.Text,{type:"secondary",style:{fontSize:12},children:m(s.time)}),s.relatedTaskId?e.jsxs(c,{type:"text",size:"mini",style:{paddingLeft:0,fontFamily:"monospace",fontSize:12},onClick:()=>n(`/tasks/${encodeURIComponent(s.relatedTaskId)}`),children:["关联任务 ",s.relatedTaskId.slice(0,8),"… ",e.jsx(j,{})]}):e.jsx(t.Text,{type:"secondary",style:{fontSize:12},children:"无关联任务"})]})]}),e.jsx("div",{style:{display:"flex",gap:8,flexShrink:0},children:e.jsx(c,{size:"small",icon:e.jsx(D,{}),onClick:C,children:"复制规则名"})})]})]}),e.jsx(l,{bordered:!0,children:e.jsxs(u,{children:[e.jsxs(o,{span:6,children:[e.jsx(t.Text,{type:"secondary",style:{fontSize:12},children:"类型"}),e.jsx("div",{style:{fontSize:13,fontWeight:500,marginTop:4},children:h(s.type)})]}),e.jsxs(o,{span:6,children:[e.jsx(t.Text,{type:"secondary",style:{fontSize:12},children:"触发动作"}),e.jsx("div",{style:{fontSize:13,fontWeight:500,marginTop:4},children:s.action})]}),e.jsxs(o,{span:6,children:[e.jsx(t.Text,{type:"secondary",style:{fontSize:12},children:"严重度"}),e.jsx("div",{style:{fontSize:13,fontWeight:500,marginTop:4},children:S(s.severity)})]}),e.jsxs(o,{span:6,children:[e.jsx(t.Text,{type:"secondary",style:{fontSize:12},children:"近 7 天同类"}),e.jsxs("div",{style:{fontSize:13,fontWeight:500,marginTop:4},children:[a," 次"]})]})]})}),e.jsxs(u,{gutter:16,children:[e.jsx(o,{xs:24,lg:16,children:e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:16},children:[e.jsxs(y,{icon:e.jsx(E,{style:{color:"var(--color-text-3)"}}),title:`① ${d?"发生了什么(失败)":x?"发生了什么(漂移)":"发生了什么"}`,children:[e.jsx(t.Text,{type:"secondary",style:{fontSize:12,display:"block",marginBottom:6},children:B}),w]}),e.jsx(y,{icon:e.jsx(L,{style:{color:"rgb(var(--orange-6))"}}),title:`② 为什么${d?"失败":x?"判定漂移":"拦"}`,children:e.jsx("div",{style:{background:"var(--color-warning-light-1)",border:"1px solid var(--color-warning-light-3)",borderRadius:6,padding:14,fontSize:13,lineHeight:1.7},children:s.why})}),e.jsx(y,{icon:e.jsx(H,{style:{color:"rgb(var(--arcoblue-6))"}}),title:"③ 建议怎么做",children:e.jsx("div",{style:{background:"var(--color-primary-light-1)",border:"1px solid var(--color-primary-light-3)",borderRadius:6,padding:14,fontSize:13,lineHeight:1.7},children:s.hint})})]})}),e.jsx(o,{xs:24,lg:8,children:e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:16},children:[e.jsx(l,{bordered:!0,title:"概要",children:e.jsx(M,{column:1,size:"small",colon:" ",data:[{label:"ID",value:e.jsx("span",{style:{fontFamily:"monospace",fontSize:12},children:s.id})},{label:"规则",value:e.jsx("span",{style:{fontFamily:"monospace",fontSize:12},children:s.rule})},{label:"类型",value:v(s.type)},{label:"严重度",value:b(s.severity)},{label:"触发动作",value:s.action},{label:"session",value:e.jsx("span",{style:{fontFamily:"monospace",fontSize:12},children:s.session??"端点未返回"})},{label:"来源",value:s.source},{label:"时间",value:m(s.time)}]})}),e.jsxs(l,{bordered:!0,title:"同类问题计数",children:[e.jsxs("div",{style:{display:"flex",alignItems:"flex-end",gap:8},children:[e.jsx(t.Text,{style:{fontSize:28,fontWeight:600,lineHeight:1,color:"rgb(var(--red-6))"},children:a}),e.jsx(t.Text,{type:"secondary",style:{fontSize:13,paddingBottom:2},children:"次 / 当前时间窗"})]}),e.jsx(t.Paragraph,{type:"secondary",style:{fontSize:12,marginTop:8,marginBottom:0},children:s.type==="intercept"||s.type==="violation"?e.jsxs(e.Fragment,{children:["规则 ",e.jsx("span",{style:{fontFamily:"monospace"},children:s.rule})," 命中"," ",e.jsx(t.Text,{style:{fontWeight:600},children:a})," 次",a>=4?",已成高频信号,建议从命令写法 / 委托流程规避。":",偶发,注意复盘。"]}):e.jsxs(e.Fragment,{children:["同类「",h(s.type),"」共 ",e.jsx(t.Text,{style:{fontWeight:600},children:a})," 条(当前时间窗内)。"]})})]}),e.jsx(l,{bordered:!0,title:"关联任务",children:s.relatedTaskId?e.jsxs(c,{type:"outline",long:!0,onClick:()=>n(`/tasks/${encodeURIComponent(s.relatedTaskId)}`),children:["查看任务 ",s.relatedTaskId.slice(0,8),"… ",e.jsx(j,{})]}):e.jsx(t.Text,{type:"secondary",style:{fontSize:13},children:s.source==="violations"?"违规拦截源端点未返回关联任务(降级)":"该问题类型无关联任务"})})]})})]})]})}export{se as default};
|
|
2
|
+
//# sourceMappingURL=IssueDetailPage-BDfrtk2C.js.map
|