@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
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--border-radius-medium: 4px;--color-bg-1: #ffffff;--color-bg-2: #f7f8fa;--color-bg-3: #f2f3f5;--color-border: #e5e6eb;--color-border-2: #f2f3f5;--color-text-1: #1d2129;--color-text-2: #4e5969;--color-text-3: #86909c;--color-text-4: #c9cdd4;--cf-kpi-wash-blue: #e8f3ff;--cf-kpi-wash-green: #e8ffea;--cf-kpi-wash-yellow: #fff7e8;--cf-kpi-wash-purple: #f5e8ff;--cf-tag-orange: #ff7d00;--cf-tag-blue: #165dff;--cf-tag-purple: #722ed1;--cf-tag-green: #00b42a;--cf-tag-red: #f53f3f;--cf-tag-gray: #86909c}body{background-color:var(--color-bg-2)}.kpi-card-wash-blue{background:var(--cf-kpi-wash-blue)}.kpi-card-wash-green{background:var(--cf-kpi-wash-green)}.kpi-card-wash-yellow{background:var(--cf-kpi-wash-yellow)}.kpi-card-wash-purple{background:var(--cf-kpi-wash-purple)}.kpi-icon-chip{width:40px;height:40px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;color:#fff}.kpi-icon-chip-blue{background:linear-gradient(135deg,#165dff,#14c9c9)}.kpi-icon-chip-purple{background:linear-gradient(135deg,#722ed1,#f53f3f)}.kpi-icon-chip-orange{background:linear-gradient(135deg,#ff7d00,#f53f3f)}.kpi-icon-chip-green{background:linear-gradient(135deg,#00b42a,#14c9c9)}.arco-layout-sider{border-right:1px solid var(--color-border)}.arco-layout-header{border-bottom:1px solid var(--color-border)}.cf-tab-pinned .arco-tabs-header-title-text:before{content:"";display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--cf-tag-blue);margin-right:6px;vertical-align:1px}.arco-menu .arco-menu-group-title{font-size:12px;color:var(--color-text-3);letter-spacing:.05em;text-transform:uppercase;padding-top:12px}.cf-menu-divider{height:1px;margin:4px 12px;padding:0;background:var(--color-fill-3);list-style:none;pointer-events:none}.cf-brand-chip{width:32px;height:32px;border-radius:8px;background:linear-gradient(135deg,#165dff,#722ed1);color:#fff;font-weight:700;font-size:12px;display:inline-flex;align-items:center;justify-content:center}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.card{border-radius:.75rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(244 244 245 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1));--tw-shadow: 0 1px 2px 0 rgba(0,0,0,.04);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.right-4{right:1rem}.top-4{top:1rem}.z-\[9999\]{z-index:9999}.mx-4{margin-left:1rem;margin-right:1rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mr-2{margin-right:.5rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-7{margin-top:1.75rem}.mt-8{margin-top:2rem}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-full{height:100%}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-\[800px\]{width:800px}.w-full{width:100%}.min-w-full{min-width:100%}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(229 231 235 / var(--tw-divide-opacity, 1))}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre{white-space:pre}.whitespace-pre-wrap{white-space:pre-wrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-r-lg{border-top-right-radius:.5rem;border-bottom-right-radius:.5rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l-4{border-left-width:4px}.border-t{border-top-width:1px}.border-blue-200{--tw-border-opacity: 1;border-color:rgb(191 219 254 / var(--tw-border-opacity, 1))}.border-gray-100{--tw-border-opacity: 1;border-color:rgb(243 244 246 / var(--tw-border-opacity, 1))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1))}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.border-green-200{--tw-border-opacity: 1;border-color:rgb(187 247 208 / var(--tw-border-opacity, 1))}.border-indigo-200{--tw-border-opacity: 1;border-color:rgb(199 210 254 / var(--tw-border-opacity, 1))}.border-red-200{--tw-border-opacity: 1;border-color:rgb(254 202 202 / var(--tw-border-opacity, 1))}.border-slate-700{--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity, 1))}.border-yellow-200{--tw-border-opacity: 1;border-color:rgb(254 240 138 / var(--tw-border-opacity, 1))}.border-t-blue-500{--tw-border-opacity: 1;border-top-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.bg-blue-100{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.bg-green-100{--tw-bg-opacity: 1;background-color:rgb(220 252 231 / var(--tw-bg-opacity, 1))}.bg-indigo-50\/50{background-color:#eef2ff80}.bg-indigo-600{--tw-bg-opacity: 1;background-color:rgb(79 70 229 / var(--tw-bg-opacity, 1))}.bg-red-600{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1))}.bg-slate-800{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity, 1))}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-yellow-600{--tw-bg-opacity: 1;background-color:rgb(202 138 4 / var(--tw-bg-opacity, 1))}.bg-opacity-50{--tw-bg-opacity: .5}.p-2{padding:.5rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.pb-1\.5{padding-bottom:.375rem}.pb-2{padding-bottom:.5rem}.pb-4{padding-bottom:1rem}.pl-1{padding-left:.25rem}.pl-4{padding-left:1rem}.pl-5{padding-left:1.25rem}.pr-3{padding-right:.75rem}.pt-3{padding-top:.75rem}.text-left{text-align:left}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-\[10px\]{font-size:10px}.text-\[13px\]{font-size:13px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-relaxed{line-height:1.625}.tracking-wider{letter-spacing:.05em}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.text-blue-700{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity, 1))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-green-700{--tw-text-opacity: 1;color:rgb(21 128 61 / var(--tw-text-opacity, 1))}.text-indigo-600{--tw-text-opacity: 1;color:rgb(79 70 229 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.text-slate-100{--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity, 1))}.text-slate-300{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-500{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.text-yellow-600{--tw-text-opacity: 1;color:rgb(202 138 4 / var(--tw-text-opacity, 1))}.underline{text-decoration-line:underline}.decoration-indigo-300{text-decoration-color:#a5b4fc}.shadow-lg{--tw-shadow: 0 12px 24px -8px rgba(0,0,0,.1), 0 4px 8px -4px rgba(0,0,0,.06);--tw-shadow-colored: 0 12px 24px -8px var(--tw-shadow-color), 0 4px 8px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 24px 48px -12px rgba(0,0,0,.18);--tw-shadow-colored: 0 24px 48px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}:root{--bg-page: #fafafa;--bg-card: #ffffff;--border-soft: #f4f4f5;--text-strong: #18181b;--text-muted: #71717a;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,sans-serif;line-height:1.5;font-weight:400;color-scheme:light;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{margin:0;min-height:100vh}.first\:mt-0:first-child{margin-top:0}.hover\:bg-gray-50:hover{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.hover\:bg-indigo-700:hover{--tw-bg-opacity: 1;background-color:rgb(67 56 202 / var(--tw-bg-opacity, 1))}.hover\:bg-red-700:hover{--tw-bg-opacity: 1;background-color:rgb(185 28 28 / var(--tw-bg-opacity, 1))}.hover\:bg-yellow-700:hover{--tw-bg-opacity: 1;background-color:rgb(161 98 7 / var(--tw-bg-opacity, 1))}.hover\:text-gray-600:hover{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.hover\:text-indigo-800:hover{--tw-text-opacity: 1;color:rgb(55 48 163 / var(--tw-text-opacity, 1))}.hover\:decoration-indigo-500:hover{text-decoration-color:#6366f1}
|
|
1
|
+
:root{--border-radius-medium: 4px;--color-bg-1: #ffffff;--color-bg-2: #f7f8fa;--color-bg-3: #f2f3f5;--color-border: #e5e6eb;--color-border-2: #f2f3f5;--color-text-1: #1d2129;--color-text-2: #4e5969;--color-text-3: #86909c;--color-text-4: #c9cdd4;--cf-kpi-wash-blue: #e8f3ff;--cf-kpi-wash-green: #e8ffea;--cf-kpi-wash-yellow: #fff7e8;--cf-kpi-wash-purple: #f5e8ff;--cf-tag-orange: #ff7d00;--cf-tag-blue: #165dff;--cf-tag-purple: #722ed1;--cf-tag-green: #00b42a;--cf-tag-red: #f53f3f;--cf-tag-gray: #86909c}body{background-color:var(--color-bg-2)}.kpi-card-wash-blue{background:var(--cf-kpi-wash-blue)}.kpi-card-wash-green{background:var(--cf-kpi-wash-green)}.kpi-card-wash-yellow{background:var(--cf-kpi-wash-yellow)}.kpi-card-wash-purple{background:var(--cf-kpi-wash-purple)}.kpi-icon-chip{width:40px;height:40px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;color:#fff}.kpi-icon-chip-blue{background:linear-gradient(135deg,#165dff,#14c9c9)}.kpi-icon-chip-purple{background:linear-gradient(135deg,#722ed1,#f53f3f)}.kpi-icon-chip-orange{background:linear-gradient(135deg,#ff7d00,#f53f3f)}.kpi-icon-chip-green{background:linear-gradient(135deg,#00b42a,#14c9c9)}.arco-layout-sider{border-right:1px solid var(--color-border)}.arco-layout-header{border-bottom:1px solid var(--color-border)}.cf-tab-pinned .arco-tabs-header-title-text:before{content:"";display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--cf-tag-blue);margin-right:6px;vertical-align:1px}.arco-menu .arco-menu-group-title{font-size:12px;color:var(--color-text-3);letter-spacing:.05em;text-transform:uppercase;padding-top:12px}.cf-menu-divider{height:1px;margin:4px 12px;padding:0;background:var(--color-fill-3);list-style:none;pointer-events:none}.cf-brand-chip{width:32px;height:32px;border-radius:8px;background:linear-gradient(135deg,#165dff,#722ed1);color:#fff;font-weight:700;font-size:12px;display:inline-flex;align-items:center;justify-content:center}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.card{border-radius:.75rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(244 244 245 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1));--tw-shadow: 0 1px 2px 0 rgba(0,0,0,.04);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.right-4{right:1rem}.top-4{top:1rem}.z-\[9999\]{z-index:9999}.mx-4{margin-left:1rem;margin-right:1rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mr-2{margin-right:.5rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-7{margin-top:1.75rem}.mt-8{margin-top:2rem}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-full{height:100%}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-\[800px\]{width:800px}.w-full{width:100%}.min-w-full{min-width:100%}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(229 231 235 / var(--tw-divide-opacity, 1))}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre{white-space:pre}.whitespace-pre-wrap{white-space:pre-wrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-r-lg{border-top-right-radius:.5rem;border-bottom-right-radius:.5rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l-4{border-left-width:4px}.border-t{border-top-width:1px}.border-blue-200{--tw-border-opacity: 1;border-color:rgb(191 219 254 / var(--tw-border-opacity, 1))}.border-gray-100{--tw-border-opacity: 1;border-color:rgb(243 244 246 / var(--tw-border-opacity, 1))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1))}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.border-green-200{--tw-border-opacity: 1;border-color:rgb(187 247 208 / var(--tw-border-opacity, 1))}.border-indigo-200{--tw-border-opacity: 1;border-color:rgb(199 210 254 / var(--tw-border-opacity, 1))}.border-red-200{--tw-border-opacity: 1;border-color:rgb(254 202 202 / var(--tw-border-opacity, 1))}.border-slate-700{--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity, 1))}.border-yellow-200{--tw-border-opacity: 1;border-color:rgb(254 240 138 / var(--tw-border-opacity, 1))}.border-t-blue-500{--tw-border-opacity: 1;border-top-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.bg-blue-100{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.bg-green-100{--tw-bg-opacity: 1;background-color:rgb(220 252 231 / var(--tw-bg-opacity, 1))}.bg-indigo-50\/50{background-color:#eef2ff80}.bg-indigo-600{--tw-bg-opacity: 1;background-color:rgb(79 70 229 / var(--tw-bg-opacity, 1))}.bg-red-600{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1))}.bg-slate-800{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity, 1))}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-yellow-600{--tw-bg-opacity: 1;background-color:rgb(202 138 4 / var(--tw-bg-opacity, 1))}.bg-opacity-50{--tw-bg-opacity: .5}.p-2{padding:.5rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.pb-1\.5{padding-bottom:.375rem}.pb-2{padding-bottom:.5rem}.pb-4{padding-bottom:1rem}.pl-1{padding-left:.25rem}.pl-4{padding-left:1rem}.pl-5{padding-left:1.25rem}.pr-3{padding-right:.75rem}.pt-3{padding-top:.75rem}.text-left{text-align:left}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-\[10px\]{font-size:10px}.text-\[13px\]{font-size:13px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-relaxed{line-height:1.625}.tracking-wider{letter-spacing:.05em}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.text-blue-700{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity, 1))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-green-700{--tw-text-opacity: 1;color:rgb(21 128 61 / var(--tw-text-opacity, 1))}.text-indigo-600{--tw-text-opacity: 1;color:rgb(79 70 229 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.text-slate-100{--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity, 1))}.text-slate-300{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-500{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.text-yellow-600{--tw-text-opacity: 1;color:rgb(202 138 4 / var(--tw-text-opacity, 1))}.underline{text-decoration-line:underline}.decoration-indigo-300{text-decoration-color:#a5b4fc}.shadow-lg{--tw-shadow: 0 12px 24px -8px rgba(0,0,0,.1), 0 4px 8px -4px rgba(0,0,0,.06);--tw-shadow-colored: 0 12px 24px -8px var(--tw-shadow-color), 0 4px 8px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 24px 48px -12px rgba(0,0,0,.18);--tw-shadow-colored: 0 24px 48px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}:root{--bg-page: #fafafa;--bg-card: #ffffff;--border-soft: #f4f4f5;--text-strong: #18181b;--text-muted: #71717a;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,sans-serif;line-height:1.5;font-weight:400;color-scheme:light;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{margin:0;min-height:100vh}.first\:mt-0:first-child{margin-top:0}.hover\:bg-gray-50:hover{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.hover\:bg-indigo-700:hover{--tw-bg-opacity: 1;background-color:rgb(67 56 202 / var(--tw-bg-opacity, 1))}.hover\:bg-red-700:hover{--tw-bg-opacity: 1;background-color:rgb(185 28 28 / var(--tw-bg-opacity, 1))}.hover\:bg-yellow-700:hover{--tw-bg-opacity: 1;background-color:rgb(161 98 7 / var(--tw-bg-opacity, 1))}.hover\:text-gray-600:hover{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.hover\:text-indigo-800:hover{--tw-text-opacity: 1;color:rgb(55 48 163 / var(--tw-text-opacity, 1))}.hover\:decoration-indigo-500:hover{text-decoration-color:#6366f1}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/WorkplacePage-DHrp5VxS.js","assets/react-vendor-tkvCrao7.js","assets/arco-DV6xCLhr.js","assets/vendor-DS-q4Eyc.js","assets/charts-BSV4cyC4.js","assets/outcome-BKGy9azt.js","assets/query-CgCOpYWf.js","assets/react-router-Cxmg8RuL.js","assets/lucide-CnlPQoG8.js","assets/arco-DFQA6dO_.css","assets/TaskDetailPage-1ckxnGhw.js","assets/MarkdownRenderer-DlDQNihj.js","assets/syntax-highlighter-BDYycNja.js","assets/task-title-BhOcemuR.js","assets/date-fns-sbWH3_uq.js","assets/KbHitsPage-Cljl7H9p.js","assets/useKbHits-xKXWgqh9.js","assets/useEffectiveProject-DQiyX54y.js","assets/KbDetailPage-Yna86Na8.js","assets/SkillsPage-aojkJpBc.js","assets/useSkillStats-B5hbIwdf.js","assets/GlobalScopeHint-Q3wTJx3F.js","assets/SkillDetailPage-BuBJJ_NX.js","assets/AgentsPage-Qd9FExLG.js","assets/useAgentStats-B-uTgqBd.js","assets/AgentDetailPage-DlUeA1sX.js","assets/DistillPage-O7BHtRN8.js","assets/useDistill-21dZkXlT.js","assets/DistillDetailPage-U6a3l2iP.js","assets/DistillRunPage-D1JuRWWr.js","assets/auth-Bnf8ZcqN.js","assets/AgentDistillRunPage-Cybo4bii.js","assets/DecisionsPage-a3NRo_T7.js","assets/useDecisions-D-G2Ft5T.js","assets/DecisionDetailPage-b4BA8dhc.js","assets/IssuesPage-SKmhlCrw.js","assets/useIssuesFeed-CFiyQkAL.js","assets/IssueDetailPage-BDfrtk2C.js","assets/TasksHubPage-C2PLh3eg.js","assets/DaemonHealthPage-DTSVqtrI.js","assets/DiagnosticsPage-DIVdiIQG.js","assets/SettingsPage-DzoK4PKg.js","assets/NotFound-LMzbP51V.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
var Se=Object.defineProperty;var Ce=(t,s,r)=>s in t?Se(t,s,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[s]=r;var M=(t,s,r)=>Ce(t,typeof s!="symbol"?s+"":s,r);import{r as o,j as e,h as Ee,R as Ie}from"./react-vendor-tkvCrao7.js";import{u as L,a as Pe,b as Te,O as Le,R as Re,c as f,N as De,B as Ae}from"./react-router-Cxmg8RuL.js";import{u as I,a as $e,Q as Oe,b as ze}from"./query-CgCOpYWf.js";import{I as ue,a as me,S as Me,T as q,E as V,b as Y,c as N,d as ee,e as he,f as A,g as Ne,h as T,L as G,M as J,i as te,j as Fe,k as Ue,P as se,R as ne,B as We,l as Be,m as Ke,n as qe,A as Ve,o as Ye,p as F,q as re,r as Ge,s as He,t as Qe,u as oe,v as Je,w as Ze,x as Xe,y as et,z as tt,C as st,D as nt,F as rt,G as ot,H as it}from"./arco-DV6xCLhr.js";import{T as at}from"./vendor-DS-q4Eyc.js";import{X as lt,I as ct,C as dt,a as ut,b as mt,T as ht}from"./lucide-CnlPQoG8.js";(function(){const s=document.createElement("link").relList;if(s&&s.supports&&s.supports("modulepreload"))return;for(const n of document.querySelectorAll('link[rel="modulepreload"]'))l(n);new MutationObserver(n=>{for(const a of n)if(a.type==="childList")for(const c of a.addedNodes)c.tagName==="LINK"&&c.rel==="modulepreload"&&l(c)}).observe(document,{childList:!0,subtree:!0});function r(n){const a={};return n.integrity&&(a.integrity=n.integrity),n.referrerPolicy&&(a.referrerPolicy=n.referrerPolicy),n.crossOrigin==="use-credentials"?a.credentials="include":n.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function l(n){if(n.ep)return;n.ep=!0;const a=r(n);fetch(n.href,a)}})();const pt="modulepreload",ft=function(t){return"/"+t},ie={},b=function(s,r,l){let n=Promise.resolve();if(r&&r.length>0){document.getElementsByTagName("link");const c=document.querySelector("meta[property=csp-nonce]"),d=(c==null?void 0:c.nonce)||(c==null?void 0:c.getAttribute("nonce"));n=Promise.allSettled(r.map(i=>{if(i=ft(i),i in ie)return;ie[i]=!0;const p=i.endsWith(".css"),y=p?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${i}"]${y}`))return;const j=document.createElement("link");if(j.rel=p?"stylesheet":pt,p||(j.as="script"),j.crossOrigin="",j.href=i,d&&j.setAttribute("nonce",d),document.head.appendChild(j),p)return new Promise((w,u)=>{j.addEventListener("load",w),j.addEventListener("error",()=>u(new Error(`Unable to preload CSS for ${i}`)))})}))}function a(c){const d=new Event("vite:preloadError",{cancelable:!0});if(d.payload=c,window.dispatchEvent(d),!d.defaultPrevented)throw c}return n.then(c=>{for(const d of c||[])d.status==="rejected"&&a(d.reason);return s().catch(a)})},D={label:"AI 资源"},ae={label:"治理"},U={label:"系统"},$={"/workplace":{tabLabel:"工作台",breadcrumbs:[{label:"工作台"}]},"/tasks":{tabLabel:"任务",breadcrumbs:[{label:"任务"}]},"/ai/kb":{tabLabel:"KB 命中",breadcrumbs:[D,{label:"KB 命中"}]},"/ai/skills":{tabLabel:"Skill 调用",breadcrumbs:[D,{label:"Skill 调用"}]},"/ai/agents":{tabLabel:"Agent 委托",breadcrumbs:[D,{label:"Agent 委托"}]},"/ai/distill":{tabLabel:"蒸馏",breadcrumbs:[D,{label:"蒸馏"}]},"/decisions":{tabLabel:"决策",breadcrumbs:[ae,{label:"决策"}]},"/issues":{tabLabel:"问题",breadcrumbs:[ae,{label:"问题"}]},"/system/daemon":{tabLabel:"Daemon",breadcrumbs:[U,{label:"Daemon"}]},"/system/diagnostics":{tabLabel:"诊断",breadcrumbs:[U,{label:"诊断"}]},"/system/settings":{tabLabel:"设置",breadcrumbs:[U,{label:"设置"}]}},xt=[{prefix:"/tasks",listPath:"/tasks",detailLabel:"任务详情"},{prefix:"/ai/kb",listPath:"/ai/kb",detailLabel:"KB 详情"},{prefix:"/ai/skills",listPath:"/ai/skills",detailLabel:"Skill 详情"},{prefix:"/ai/agents",listPath:"/ai/agents",detailLabel:"Agent 详情"},{prefix:"/ai/distill",listPath:"/ai/distill",detailLabel:"蒸馏详情"},{prefix:"/decisions",listPath:"/decisions",detailLabel:"决策详情"},{prefix:"/issues",listPath:"/issues",detailLabel:"问题详情"}],bt={"/ai/distill/run":"执行蒸馏"};function gt(t){return t.length>1&&t.endsWith("/")?t.slice(0,-1):t}function yt(t){const s=gt(t),r=$[s];if(r)return r;const l=bt[s];if(l){const a=$["/ai/distill"];return{tabLabel:l,breadcrumbs:[...a.breadcrumbs.slice(0,-1),{label:"蒸馏",path:"/ai/distill"},{label:l}]}}let n=null;for(const a of xt)s.startsWith(a.prefix+"/")&&(!n||a.prefix.length>n.prefix.length)&&(n=a);if(n){const a=$[n.listPath];if(!a)return null;const c=a.breadcrumbs.slice(0,-1),d=a.breadcrumbs[a.breadcrumbs.length-1].label;return{tabLabel:n.detailLabel,breadcrumbs:[...c,{label:d,path:n.listPath},{label:n.detailLabel}]}}return null}new Set(Object.keys($));const z=[{kind:"leaf",key:"/workplace",label:"工作台"},{kind:"leaf",key:"/tasks",label:"任务"},{kind:"group",key:"group:ai",label:"AI 资源",children:[{key:"/ai/kb",label:"KB 命中"},{key:"/ai/skills",label:"Skill 调用"},{key:"/ai/agents",label:"Agent 委托"},{key:"/ai/distill",label:"蒸馏"}]},{kind:"group",key:"group:governance",label:"治理",children:[{key:"/decisions",label:"决策"},{key:"/issues",label:"问题"}]},{kind:"group",key:"group:system",label:"系统",children:[{key:"/system/daemon",label:"Daemon"},{key:"/system/diagnostics",label:"诊断"},{key:"/system/settings",label:"设置"}]}],le="/workplace",jt=z.filter(t=>t.kind==="group").map(t=>t.key),kt=z.flatMap(t=>t.kind==="group"?t.children.map(s=>s.key):[t.key]);(()=>{const t={};for(const s of z)if(s.kind==="group")for(const r of s.children)t[r.key]=s.key;return t})();function wt(t){return t.length>1&&t.endsWith("/")?t.slice(0,-1):t}function vt(t){const s=wt(t)||le;let r=null;for(const l of kt)(s===l||s.startsWith(l+"/"))&&(!r||l.length>r.length)&&(r=l);return r??le}const _t=[7,30,90],H=30,pe="cf.timeWindow";function fe(t){const s=typeof t=="string"?Number(t):t;return s===7||s===30||s===90?s:H}function St(){if(typeof window>"u")return H;try{return fe(window.localStorage.getItem(pe))}catch{return H}}const xe=o.createContext(null);function Ct({children:t}){const[s,r]=o.useState(()=>St()),l=o.useCallback(a=>{r(fe(a))},[]);o.useEffect(()=>{try{window.localStorage.setItem(pe,String(s))}catch{}},[s]);const n=o.useMemo(()=>({window:s,setWindow:l}),[s,l]);return e.jsx(xe.Provider,{value:n,children:t})}function Et(){const t=o.useContext(xe);if(!t)throw new Error("useTimeWindow must be used within a <TimeWindowProvider>");return t}const be="claude-forge:theme";function It(){try{const t=localStorage.getItem(be);if(t==="light"||t==="dark")return t}catch{}try{if(typeof window<"u"&&window.matchMedia)return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}catch{}return"light"}function ge(t){typeof document>"u"||(t==="dark"?document.body.setAttribute("arco-theme","dark"):document.body.removeAttribute("arco-theme"))}let O=It();const Q=new Set;ge(O);function Pt(){return O}function Tt(t){if(t!==O){O=t;try{localStorage.setItem(be,t)}catch{}ge(t),Q.forEach(s=>s(t))}}function Lt(t){return Q.add(t),()=>{Q.delete(t)}}function Rt(){const[t,s]=o.useState(Pt);return o.useEffect(()=>Lt(s),[]),[t,Tt]}const Dt=250,W=5;async function B(t){const s=await fetch(t);if(!s.ok)throw new Error(`${t} → ${s.status}`);return s.json()}async function At(t){const s=t.trim().slice(0,200);if(!s)return{sessions:[],tasks:[],kb:[]};const r=encodeURIComponent(s),[l,n,a]=await Promise.allSettled([B(`/api/sessions?search=${r}&limit=${W}`),B(`/api/tasks?search=${r}&limit=${W}`),B(`/api/knowledge/query?q=${r}&strategy=keyword&max=${W}`)]);return{sessions:l.status==="fulfilled"?l.value:[],tasks:n.status==="fulfilled"?n.value.tasks??[]:[],kb:a.status==="fulfilled"?a.value.pages??[]:[]}}function $t({onNavigate:t}){const s=L(),[r,l]=o.useState(""),[n,a]=o.useState(null),[c,d]=o.useState(!1),i=o.useRef(null),p=o.useRef(0);o.useEffect(()=>{i.current&&clearTimeout(i.current);const u=r.trim();if(!u){a(null),d(!1);return}d(!0);const g=++p.current;return i.current=setTimeout(async()=>{const k=await At(u);g===p.current&&(a(k),d(!1))},Dt),()=>{i.current&&clearTimeout(i.current)}},[r]);const y=o.useCallback(()=>{if(!n)return;const u=[{key:"sessions",path:"/tasks",n:n.sessions.length},{key:"tasks",path:"/tasks",n:n.tasks.length},{key:"kb",path:"/context?tab=kb",n:n.kb.length}],g=u.reduce((v,h)=>h.n>v.n?h:v,u[0]);if(g.n===0)return;const k=encodeURIComponent(r.trim()),S=g.path.includes("?")?`${g.path}&q=${k}`:`${g.path}?q=${k}`;s(S),t==null||t()},[n,r,s,t]),j=((n==null?void 0:n.sessions.length)??0)+((n==null?void 0:n.tasks.length)??0)+((n==null?void 0:n.kb.length)??0),w=o.useMemo(()=>n?[{label:"会话",path:"/tasks",items:n.sessions.map(u=>({key:`s-${u.session_id}`,label:u.first_prompt||`(${u.session_id.slice(0,8)})`,onClick:()=>{s(`/tasks?session=${encodeURIComponent(u.session_id)}`),t==null||t()}}))},{label:"任务",path:"/tasks",items:n.tasks.map(u=>({key:`t-${u.id}`,label:u.title||u.first_prompt||`(任务 ${u.id.slice(0,8)})`,onClick:()=>{s(`/tasks?task=${encodeURIComponent(u.id)}`),t==null||t()}}))},{label:"知识库",path:"/context?tab=kb",items:n.kb.map(u=>({key:`k-${u.page.name}`,label:u.page.title||u.page.name,onClick:()=>{s(`/context?tab=kb&page=${encodeURIComponent(u.page.name)}`),t==null||t()}}))}]:[],[n,s,t]);return e.jsxs("div",{style:{width:360,maxHeight:480,overflowY:"auto"},children:[e.jsx(ue.Search,{autoFocus:!0,value:r,onChange:l,onPressEnter:y,placeholder:"搜索 sessions / tasks / 知识库...",allowClear:!0,prefix:e.jsx(me,{}),style:{width:"100%"}}),e.jsx("div",{style:{marginTop:12},children:c?e.jsx("div",{style:{display:"flex",justifyContent:"center",padding:"24px 0"},children:e.jsx(Me,{size:20})}):n?j===0?e.jsx(V,{description:"无匹配结果",imgSrc:"",style:{padding:"12px 0"}}):e.jsx("div",{style:{display:"flex",flexDirection:"column",gap:12},children:w.map(u=>u.items.length===0?null:e.jsxs("div",{children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,marginBottom:4},children:[e.jsx(q.Text,{style:{fontSize:11,color:"var(--color-text-3)"},children:u.label}),e.jsx(Y,{size:"small",color:"gray",children:u.items.length})]}),e.jsx("ul",{style:{listStyle:"none",padding:0,margin:0},children:u.items.map(g=>e.jsx("li",{onClick:g.onClick,style:{padding:"6px 8px",fontSize:12,color:"var(--color-text-1)",cursor:"pointer",borderRadius:4,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},onMouseEnter:k=>{k.currentTarget.style.background="var(--color-fill-2)"},onMouseLeave:k=>{k.currentTarget.style.background="transparent"},children:g.label},g.key))})]},u.label))}):e.jsx(q.Text,{type:"secondary",style:{fontSize:12},children:"输入关键词后回车跳转到结果最多的页面。"})})]})}function Ot({onClose:t}){const s=L(),{data:r,isLoading:l}=I({queryKey:["notifications-violations"],queryFn:async()=>{const i=await fetch("/api/violations?days=7&limit=10");if(!i.ok)throw new Error("Failed");return i.json()},refetchOnMount:"always"}),{data:n,isLoading:a}=I({queryKey:["notifications-insights"],queryFn:async()=>{const i=await fetch("/api/insights?days=7");if(!i.ok)throw new Error("Failed");return i.json()},refetchOnMount:"always"}),c=(r==null?void 0:r.count)??0,d=((n==null?void 0:n.summary.critical)??0)+((n==null?void 0:n.summary.warn)??0);return e.jsx("div",{style:{width:360,maxHeight:480,overflowY:"auto"},children:e.jsxs(N,{defaultActiveTab:"violations",size:"mini",children:[e.jsx(N.TabPane,{title:`违规${c>0?` (${c})`:""}`,children:l?e.jsx(ee,{text:{rows:3},animation:!0}):!r||r.count===0?e.jsx(V,{description:"近 7 天无违规",imgSrc:"",style:{padding:"12px 0"}}):e.jsx("ul",{style:{listStyle:"none",padding:0,margin:0},children:r.violations.map(i=>e.jsxs("li",{style:{padding:"8px 4px",borderBottom:"1px solid var(--color-border-2)"},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:8},children:[e.jsx(Y,{size:"small",color:i.signal==="user_keyword"?"red":"orange",children:i.signal==="user_keyword"?"关键词":"路由"}),e.jsx("span",{style:{fontSize:11,color:"var(--color-text-3)"},children:i.relativeTime})]}),e.jsxs("div",{style:{fontSize:12,color:"var(--color-text-1)",marginTop:4,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},title:i.summary,children:[i.summary.slice(0,60),i.summary.length>60?"…":""]})]},i.timestamp+i.summary.slice(0,16)))})},"violations"),e.jsx(N.TabPane,{title:`反模式${d>0?` (${d})`:""}`,children:a?e.jsx(ee,{text:{rows:3},animation:!0}):!n||n.patterns.length===0?e.jsx(V,{description:"近 7 天无反模式",imgSrc:"",style:{padding:"12px 0"}}):e.jsx("ul",{style:{listStyle:"none",padding:0,margin:0},children:n.patterns.slice(0,10).map(i=>e.jsxs("li",{style:{padding:"8px 4px",borderBottom:"1px solid var(--color-border-2)",cursor:i.sessionId?"pointer":"default"},onClick:()=>{i.sessionId&&(s(`/tasks?session=${encodeURIComponent(i.sessionId)}`),t==null||t())},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6},children:[e.jsx(Y,{size:"small",color:i.severity==="critical"?"red":i.severity==="warn"?"orange":"gray",children:i.severity}),e.jsx(q.Text,{style:{fontSize:12,fontWeight:500},children:i.title})]}),e.jsx("div",{style:{fontSize:11,color:"var(--color-text-3)",marginTop:4,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},title:i.description,children:i.description})]},i.id))})},"insights")]})})}const _="__all__";function qs(t,s){if(!s)return t;const r=t.includes("?")?"&":"?";return`${t}${r}project=${encodeURIComponent(s)}`}function zt(){return["kb-projects"]}const Mt=[["kb-list"],["kb-page"],["kb-audit"],["kb-stats"]];async function Nt(){const t=await fetch("/api/knowledge/projects");if(!t.ok)throw new Error(`projects failed: ${t.status}`);return t.json()}const Ft="claude-forge:kb:last-project";function Ut(t){if(!(typeof window>"u"))try{window.localStorage.setItem(Ft,t)}catch{}}const ye="cf.project";function je(t){return typeof t!="string"?"":t.trim()}function Vs(t,s){return t===_?"":t||s}function Wt(t,s){return t===_?t:t||s}function Bt(t){return t===_}function Kt(){if(typeof window>"u")return"";try{return je(window.localStorage.getItem(ye))}catch{return""}}const ke=o.createContext(null);function qt({children:t}){const[s,r]=o.useState(()=>Kt()),l=o.useCallback(a=>{r(je(a))},[]);o.useEffect(()=>{try{window.localStorage.setItem(ye,s)}catch{}},[s]);const n=o.useMemo(()=>({project:s,setProject:l}),[s,l]);return e.jsx(ke.Provider,{value:n,children:t})}function Vt(){const t=o.useContext(ke);if(!t)throw new Error("useProject must be used within a <ProjectProvider>");return t}const ce=he.Option;function Yt({showAll:t=!1,showAllProjectsOption:s=!1}){const{data:r,isLoading:l}=I({queryKey:zt(),queryFn:Nt,staleTime:3e4}),[n,a]=Pe(),c=$e(),{project:d,setProject:i}=Vt(),p=n.get("project")??"";o.useEffect(()=>{p&&p!==d&&i(p)},[p]);const y=Bt(d),j=(r==null?void 0:r.current)??"",w=Wt(d,j),g=((r==null?void 0:r.projects)??[]).filter(h=>t||h.kb_built),k=h=>{i(h);const C=new URLSearchParams(n);h===_?C.set("project",_):h?C.set("project",h):C.delete("project"),C.delete("page"),a(C),h&&h!==_&&Ut(h);for(const m of Mt)c.invalidateQueries({queryKey:m})};if(l)return e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,fontSize:13,color:"var(--color-text-3)"},children:[e.jsx(A,{style:{fontSize:14}}),e.jsx("span",{children:"Loading projects..."})]});if(g.length===0)return e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,fontSize:13,color:"var(--color-text-3)"},children:[e.jsx(A,{style:{fontSize:14}}),e.jsx("span",{style:{fontFamily:"monospace"},children:w||"no project"}),e.jsx("span",{style:{fontSize:11,color:"var(--color-text-4)"},children:"(KB not built)"})]});const S=g.find(h=>h.path===w),v=!!(S!=null&&S.kb_built);return e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},title:"切换知识库项目(每个项目独立缓存,切换后会自动刷新页面列表)",children:[e.jsx(A,{style:{fontSize:14,color:"var(--color-text-3)"}}),e.jsxs(he,{value:w,onChange:h=>k(h),size:"small",style:{width:240,fontFamily:"monospace"},children:[s&&e.jsx(ce,{value:_,children:"全部项目"},_),g.map(h=>e.jsxs(ce,{value:h.path,children:[h.name," ",h.kb_built?`(${h.page_count})`:"(empty)",h.is_current&&h.path===j?" • current":""]},h.path))]}),w&&!y&&e.jsx("span",{style:{fontSize:11,display:"inline-flex",alignItems:"center",gap:2,color:v?"var(--color-success-6, #52c41a)":"var(--color-text-4)"},children:v?e.jsxs(e.Fragment,{children:[e.jsx(Ne,{style:{fontSize:11}}),"built"]}):"not built"})]})}function Ys(t){if(!t)return new Date(0);const s=t.trim();return s.endsWith("Z")||/[+-]\d{2}:\d{2}$/.test(s)?new Date(s):new Date(s+"Z")}function Gt(t){return t?t.endsWith("Z")?t:t+"Z":new Date().toISOString()}function we(t){if(typeof t=="number")return new Date(t);try{return new Date(Gt(t))}catch{return new Date(0)}}function P(t){return t<10?`0${t}`:`${t}`}function Gs(t,s){try{const r=we(t);if(isNaN(r.getTime()))return"—";const l=r.getFullYear(),n=P(r.getMonth()+1),a=P(r.getDate());if(s!=null&&s.dateOnly)return`${l}-${n}-${a}`;const c=P(r.getHours()),d=P(r.getMinutes()),i=`${l}-${n}-${a} ${c}:${d}`,p=s!=null&&s.includeSeconds?`:${P(r.getSeconds())}`:"",y=(s==null?void 0:s.tzSuffix)!==void 0?s.tzSuffix:"CST";return y?`${i}${p} ${y}`:`${i}${p}`}catch{return"—"}}function Ht(t){try{const s=we(t);if(isNaN(s.getTime()))return"—";const r=Date.now()-s.getTime(),l=Math.floor(r/6e4);if(l<1)return"刚刚";if(l<60)return`${l} 分钟前`;const n=Math.floor(l/60);return n<24?`${n} 小时前`:`${Math.floor(n/24)} 天前`}catch{return"—"}}function Qt(t){return t==null?"no heartbeat":Ht(Date.now()-t)}const Jt={alive:{color:"#00b42a",label:"Daemon ALIVE",dotStyle:{background:"#00b42a"}},stale:{color:"#ff7d00",label:"Daemon STALE",dotStyle:{background:"#ff7d00"}},dead:{color:"#f53f3f",label:"Daemon DEAD",dotStyle:{background:"#f53f3f"}}};function Zt(){var d,i,p;const t=L(),{data:s}=I({queryKey:["daemon-health"],queryFn:async()=>{const y=await fetch("/api/health");if(!y.ok)throw new Error("health check failed");return y.json()},refetchInterval:3e4,retry:!1,staleTime:15e3}),r=((d=s==null?void 0:s.daemon)==null?void 0:d.status)??"dead",l=Jt[r],n=((i=s==null?void 0:s.daemon)==null?void 0:i.heartbeat_age_ms)??null,a=(p=s==null?void 0:s.daemon)==null?void 0:p.pid,c=[`Status: ${r.toUpperCase()}`,a!=null?`PID: ${a}`:"PID: not running",`Heartbeat: ${Qt(n)}`].join(`
|
|
3
|
+
`);return e.jsx(T,{content:e.jsx("span",{style:{whiteSpace:"pre-line"},children:c}),position:"bottom",children:e.jsxs("button",{onClick:()=>t("/daemon-health"),style:{display:"inline-flex",alignItems:"center",gap:5,border:"none",background:"transparent",cursor:"pointer",padding:"4px 8px",borderRadius:6,color:"var(--color-text-2)",fontSize:12},"aria-label":`daemon-badge-${r}`,children:[e.jsx("span",{style:{width:8,height:8,borderRadius:"50%",display:"inline-block",...l.dotStyle,...r==="alive"?{boxShadow:`0 0 0 2px ${l.color}33`,animation:"daemon-pulse 2s infinite"}:{}}}),e.jsx("span",{style:{color:l.color,fontWeight:500},children:r.toUpperCase()})]})})}function Xt(t){return t?t.summary.fail>0?"fail":t.summary.warn>0?"warn":"pass":"unknown"}const es={pass:{color:"#00b42a",label:"Doctor OK"},warn:{color:"#ff7d00",label:"Doctor WARN"},fail:{color:"#f53f3f",label:"Doctor FAIL"},unknown:{color:"#86909c",label:"Doctor ?"}};function ts(){const t=L(),{data:s}=I({queryKey:["diagnostics-badge"],queryFn:async()=>{const a=await fetch("/api/diagnostics");if(!a.ok)throw new Error("diagnostics failed");return a.json()},refetchInterval:6e4,retry:!1,staleTime:3e4}),r=Xt(s),l=es[r],n=s?[`PASS=${s.summary.pass}`,`WARN=${s.summary.warn}`,`FAIL=${s.summary.fail}`,`SKIP=${s.summary.skip}`,s.summary.fixable>0?`${s.summary.fixable} fixable`:""].filter(Boolean).join(" · "):"Loading diagnostics…";return e.jsx(T,{content:n,position:"bottom",children:e.jsxs("button",{onClick:()=>t("/diagnostics"),style:{display:"inline-flex",alignItems:"center",gap:5,border:"none",background:"transparent",cursor:"pointer",padding:"4px 8px",borderRadius:6,color:"var(--color-text-2)",fontSize:12},"aria-label":`doctor-badge-${r}`,children:[e.jsx("span",{style:{width:8,height:8,borderRadius:"50%",display:"inline-block",background:l.color}}),e.jsx("span",{style:{color:l.color,fontWeight:500},children:l.label})]})})}const{Sider:ss,Header:ns,Content:rs}=G,de=J.Item,os=J.SubMenu,K={"/workplace":e.jsx(st,{}),"/tasks":e.jsx(tt,{}),"group:ai":e.jsx(et,{}),"/ai/kb":e.jsx(Xe,{}),"/ai/skills":e.jsx(Ze,{}),"/ai/agents":e.jsx(Je,{}),"/ai/distill":e.jsx(A,{}),"group:governance":e.jsx(oe,{}),"/decisions":e.jsx(oe,{}),"/issues":e.jsx(Qe,{}),"group:system":e.jsx(He,{}),"/system/daemon":e.jsx(re,{}),"/system/diagnostics":e.jsx(Ge,{}),"/system/settings":e.jsx(re,{})};function is(t){return t.kind==="group"?e.jsx(os,{title:e.jsxs("span",{children:[K[t.key],t.label]}),children:t.children.map(s=>e.jsxs(de,{children:[K[s.key],s.label]},s.key))},t.key):e.jsxs(de,{children:[K[t.key],t.label]},t.key)}function as(){const t=Te(),s=L(),[r,l]=o.useState(!1),[n,a]=Rt(),{window:c,setWindow:d}=Et(),i=o.useMemo(()=>vt(t.pathname),[t.pathname]),[p,y]=o.useState(()=>[...jt]),j=o.useCallback(m=>{m.startsWith("/")&&m!==t.pathname&&s(m)},[t.pathname,s]),w=o.useMemo(()=>{const m=yt(t.pathname);return(m==null?void 0:m.breadcrumbs)??[{label:"工作台"}]},[t.pathname]),u=o.useCallback(()=>{a(n==="light"?"dark":"light")},[n,a]),[g,k]=o.useState(!1),[S,v]=o.useState(!1),{data:h}=I({queryKey:["notifications-badge"],queryFn:async()=>{var m,E;try{const[R,Z]=await Promise.all([fetch("/api/violations?days=7&limit=1"),fetch("/api/insights?days=7")]),_e=R.ok?await R.json():{count:0},X=Z.ok?await Z.json():{summary:{critical:0,warn:0}};return{hasUnread:(_e.count??0)>0||(((m=X.summary)==null?void 0:m.critical)??0)+(((E=X.summary)==null?void 0:E.warn)??0)>0}}catch{return{hasUnread:!1}}},refetchInterval:6e4}),C=(h==null?void 0:h.hasUnread)??!1;return e.jsxs(G,{style:{minHeight:"100vh"},children:[e.jsxs(ss,{collapsed:r,collapsible:!0,collapsedWidth:64,width:220,trigger:null,breakpoint:"lg",style:{background:"var(--color-bg-2)",borderRight:"1px solid var(--color-border)"},children:[e.jsxs("div",{style:{height:64,display:"flex",alignItems:"center",justifyContent:r?"center":"flex-start",padding:r?0:"0 20px",borderBottom:"1px solid var(--color-border-2)",gap:10},children:[e.jsx("span",{className:"cf-brand-chip",children:"CF"}),!r&&e.jsx("span",{style:{fontSize:14,fontWeight:600,color:"var(--color-text-1)"},children:"Claude Forge"})]}),e.jsx(J,{selectedKeys:[i],openKeys:p,mode:"vertical",onClickMenuItem:j,onClickSubMenu:(m,E)=>y(E),style:{width:"100%",border:"none",background:"transparent"},children:z.map(m=>is(m))}),!r&&e.jsxs("div",{style:{position:"absolute",bottom:0,left:0,right:0,padding:"12px 16px",borderTop:"1px solid var(--color-border-2)",fontSize:11,color:"var(--color-text-3)",display:"flex",justifyContent:"space-between"},children:[e.jsx("span",{children:"claude-forge"}),e.jsxs("span",{style:{fontFamily:"monospace"},children:["v","9.12.0"]})]})]}),e.jsxs(G,{children:[e.jsxs(ns,{style:{height:60,background:"var(--color-bg-2)",borderBottom:"1px solid var(--color-border)",display:"flex",alignItems:"center",justifyContent:"space-between",padding:"0 20px"},children:[e.jsxs(te,{size:12,children:[e.jsx(T,{content:r?"展开侧栏":"收起侧栏",children:e.jsx("button",{onClick:()=>l(m=>!m),style:{border:"none",background:"transparent",cursor:"pointer",color:"var(--color-text-2)",padding:6,display:"inline-flex",alignItems:"center"},"aria-label":"toggle-sider",children:r?e.jsx(Fe,{}):e.jsx(Ue,{})})}),e.jsx(se,{trigger:"click",position:"bl",popupVisible:g,onVisibleChange:k,content:e.jsx($t,{onNavigate:()=>k(!1)}),children:e.jsx(ue.Search,{placeholder:"搜索 sessions / tasks / 知识库...",style:{width:280},allowClear:!0,readOnly:!0,prefix:e.jsx(me,{}),onClick:()=>k(!0)})}),e.jsx(Yt,{showAllProjectsOption:!0})]}),e.jsxs(te,{size:16,children:[e.jsx(ne.Group,{type:"button",size:"small",value:c,onChange:m=>d(m),"aria-label":"time-window",children:_t.map(m=>e.jsxs(ne,{value:m,children:[m,"d"]},m))}),e.jsx(Zt,{}),e.jsx(ts,{}),e.jsx(se,{trigger:"click",position:"br",popupVisible:S,onVisibleChange:v,content:e.jsx(Ot,{onClose:()=>v(!1)}),children:e.jsx(T,{content:"通知",children:e.jsx("button",{style:{border:"none",background:"transparent",cursor:"pointer",color:"var(--color-text-2)",padding:6,display:"inline-flex",alignItems:"center"},"aria-label":"notifications",children:e.jsx(We,{dot:C,count:0,offset:[-2,2],children:e.jsx(Be,{})})})})}),e.jsx(T,{content:n==="light"?"切换深色主题":"切换浅色主题",children:e.jsx("button",{onClick:u,style:{border:"none",background:"transparent",cursor:"pointer",color:"var(--color-text-2)",padding:6,display:"inline-flex",alignItems:"center"},"aria-label":"toggle-theme",children:n==="light"?e.jsx(Ke,{}):e.jsx(qe,{})})}),e.jsx(Ve,{size:32,style:{background:"linear-gradient(135deg,#165DFF,#722ED1)"},children:e.jsx(Ye,{})})]})]}),e.jsxs(rs,{style:{padding:0,background:"var(--color-bg-2)",display:"flex",flexDirection:"column",minHeight:"calc(100vh - 60px)"},children:[e.jsx("div",{style:{padding:"12px 20px 0"},children:e.jsx(F,{children:w.map((m,E)=>m.path?e.jsx(F.Item,{children:e.jsx("a",{onClick:R=>{R.preventDefault(),m.path&&s(m.path)},href:m.path,style:{color:"var(--color-text-2)"},children:m.label})},`${m.label}-${E}`):e.jsx(F.Item,{children:m.label},`${m.label}-${E}`))})}),e.jsx("div",{style:{padding:"16px 20px 24px",flex:1},children:e.jsx(Le,{})})]})]})]})}class ls extends o.Component{constructor(){super(...arguments);M(this,"state",{hasError:!1,error:null});M(this,"handleReload",()=>{window.location.reload()})}static getDerivedStateFromError(r){return{hasError:!0,error:r}}componentDidCatch(r,l){console.error("[RouteErrorBoundary] route render failed:",r,l)}render(){var r;return this.state.hasError?e.jsx("div",{style:{padding:16},children:e.jsx(nt,{status:"error",title:"页面加载失败",subTitle:((r=this.state.error)==null?void 0:r.message)||"资源加载异常,可能是版本已更新。请刷新页面重试。",extra:e.jsx(rt,{type:"primary",onClick:this.handleReload,children:"刷新页面"})})}):this.props.children}}const cs=o.lazy(()=>b(()=>import("./WorkplacePage-DHrp5VxS.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9]))),ds=o.lazy(()=>b(()=>import("./TaskDetailPage-1ckxnGhw.js"),__vite__mapDeps([10,1,7,3,2,11,12,6,13,14,8,9]))),us=o.lazy(()=>b(()=>import("./KbHitsPage-Cljl7H9p.js"),__vite__mapDeps([15,1,2,3,16,6,17,7,8,9]))),ms=o.lazy(()=>b(()=>import("./KbDetailPage-Yna86Na8.js"),__vite__mapDeps([18,1,2,3,11,12,16,6,17,7,8,9]))),hs=o.lazy(()=>b(()=>import("./SkillsPage-aojkJpBc.js"),__vite__mapDeps([19,1,2,3,20,6,17,21,7,8,9]))),ps=o.lazy(()=>b(()=>import("./SkillDetailPage-BuBJJ_NX.js"),__vite__mapDeps([22,1,2,3,11,12,20,6,17,21,7,8,9]))),fs=o.lazy(()=>b(()=>import("./AgentsPage-Qd9FExLG.js"),__vite__mapDeps([23,1,2,3,24,6,17,21,7,8,9]))),xs=o.lazy(()=>b(()=>import("./AgentDetailPage-DlUeA1sX.js"),__vite__mapDeps([25,1,2,3,24,6,17,21,7,8,9]))),bs=o.lazy(()=>b(()=>import("./DistillPage-O7BHtRN8.js"),__vite__mapDeps([26,1,2,3,27,6,7,9]))),gs=o.lazy(()=>b(()=>import("./DistillDetailPage-U6a3l2iP.js"),__vite__mapDeps([28,1,2,3,11,12,27,6,7,9]))),ys=o.lazy(()=>b(()=>import("./DistillRunPage-D1JuRWWr.js"),__vite__mapDeps([29,1,2,3,6,30,7,9]))),js=o.lazy(()=>b(()=>import("./AgentDistillRunPage-Cybo4bii.js"),__vite__mapDeps([31,1,2,3,6,30,7,9]))),ks=o.lazy(()=>b(()=>import("./DecisionsPage-a3NRo_T7.js"),__vite__mapDeps([32,1,2,3,33,6,7,9]))),ws=o.lazy(()=>b(()=>import("./DecisionDetailPage-b4BA8dhc.js"),__vite__mapDeps([34,1,2,3,33,6,7,9]))),vs=o.lazy(()=>b(()=>import("./IssuesPage-SKmhlCrw.js"),__vite__mapDeps([35,1,2,3,36,6,7,8,9]))),_s=o.lazy(()=>b(()=>import("./IssueDetailPage-BDfrtk2C.js"),__vite__mapDeps([37,1,2,3,36,6,7,8,9]))),Ss=o.lazy(()=>b(()=>import("./TasksHubPage-C2PLh3eg.js"),__vite__mapDeps([38,1,7,3,6,2,13,30,14,8,5,9]))),Cs=o.lazy(()=>b(()=>import("./DaemonHealthPage-DTSVqtrI.js"),__vite__mapDeps([39,1,6,2,3,7,8,9]))),Es=o.lazy(()=>b(()=>import("./DiagnosticsPage-DIVdiIQG.js"),__vite__mapDeps([40,1,6,30,2,3,9]))),Is=o.lazy(()=>b(()=>import("./SettingsPage-DzoK4PKg.js"),__vite__mapDeps([41,1,7,3,6,30,2,8,9]))),Ps=o.lazy(()=>b(()=>import("./NotFound-LMzbP51V.js"),__vite__mapDeps([42,1,7,3,2,9])));function Ts(){return e.jsx("div",{className:"flex items-center justify-center h-full py-16",children:e.jsxs("div",{className:"flex items-center gap-3 text-sm text-gray-500",children:[e.jsx("div",{className:"w-4 h-4 border-2 border-gray-300 border-t-blue-500 rounded-full animate-spin"}),"加载中..."]})})}function x({children:t}){return e.jsx(ls,{children:e.jsx(o.Suspense,{fallback:e.jsx(Ts,{}),children:t})})}function Ls(){return e.jsx(Re,{children:e.jsxs(f,{path:"/",element:e.jsx(as,{}),children:[e.jsx(f,{index:!0,element:e.jsx(De,{to:"/workplace",replace:!0})}),e.jsx(f,{path:"workplace",element:e.jsx(x,{children:e.jsx(cs,{})})}),e.jsx(f,{path:"tasks",element:e.jsx(x,{children:e.jsx(Ss,{})})}),e.jsx(f,{path:"tasks/:taskId",element:e.jsx(x,{children:e.jsx(ds,{})})}),e.jsx(f,{path:"ai/kb",element:e.jsx(x,{children:e.jsx(us,{})})}),e.jsx(f,{path:"ai/kb/:name",element:e.jsx(x,{children:e.jsx(ms,{})})}),e.jsx(f,{path:"ai/skills",element:e.jsx(x,{children:e.jsx(hs,{})})}),e.jsx(f,{path:"ai/skills/:id",element:e.jsx(x,{children:e.jsx(ps,{})})}),e.jsx(f,{path:"ai/agents",element:e.jsx(x,{children:e.jsx(fs,{})})}),e.jsx(f,{path:"ai/agents/:name",element:e.jsx(x,{children:e.jsx(xs,{})})}),e.jsx(f,{path:"ai/agents/:name/distill",element:e.jsx(x,{children:e.jsx(js,{})})}),e.jsx(f,{path:"ai/distill",element:e.jsx(x,{children:e.jsx(bs,{})})}),e.jsx(f,{path:"ai/distill/run",element:e.jsx(x,{children:e.jsx(ys,{})})}),e.jsx(f,{path:"ai/distill/:topicId",element:e.jsx(x,{children:e.jsx(gs,{})})}),e.jsx(f,{path:"decisions",element:e.jsx(x,{children:e.jsx(ks,{})})}),e.jsx(f,{path:"decisions/:id",element:e.jsx(x,{children:e.jsx(ws,{})})}),e.jsx(f,{path:"issues",element:e.jsx(x,{children:e.jsx(vs,{})})}),e.jsx(f,{path:"issues/:id",element:e.jsx(x,{children:e.jsx(_s,{})})}),e.jsx(f,{path:"system/daemon",element:e.jsx(x,{children:e.jsx(Cs,{})})}),e.jsx(f,{path:"system/diagnostics",element:e.jsx(x,{children:e.jsx(Es,{})})}),e.jsx(f,{path:"system/settings",element:e.jsx(x,{children:e.jsx(Is,{})})}),e.jsx(f,{path:"*",element:e.jsx(x,{children:e.jsx(Ps,{})})})]})})}const Rs=o.createContext(null);let Ds=1;function As({children:t}){const[s,r]=o.useState([]),l=o.useCallback(c=>{r(d=>d.filter(i=>i.id!==c))},[]),n=o.useCallback((c,d)=>{const i=Ds++;r(p=>[...p,{id:i,type:c,message:d}]),setTimeout(()=>l(i),4e3)},[l]),a={show:n,success:c=>n("success",c),error:c=>n("error",c),warning:c=>n("warning",c),info:c=>n("info",c)};return e.jsxs(Rs.Provider,{value:a,children:[t,e.jsx("div",{className:"fixed top-4 right-4 z-[9999] space-y-2 max-w-md",children:s.map(c=>e.jsx($s,{toast:c,onClose:()=>l(c.id)},c.id))})]})}function $s({toast:t,onClose:s}){const r={success:e.jsx(mt,{className:"h-5 w-5 text-green-500"}),error:e.jsx(ut,{className:"h-5 w-5 text-red-500"}),warning:e.jsx(dt,{className:"h-5 w-5 text-yellow-500"}),info:e.jsx(ct,{className:"h-5 w-5 text-blue-500"})},l={success:"border-green-200",error:"border-red-200",warning:"border-yellow-200",info:"border-blue-200"};return e.jsxs("div",{className:at("bg-white shadow-lg rounded-lg border px-4 py-3 flex items-start gap-3 animate-in slide-in-from-right",l[t.type]),children:[r[t.type],e.jsx("div",{className:"flex-1 text-sm text-gray-800",children:t.message}),e.jsx("button",{onClick:s,className:"text-gray-400 hover:text-gray-600",children:e.jsx(lt,{className:"h-4 w-4"})})]})}const ve=o.createContext(null);function Hs(){const t=o.useContext(ve);if(!t)throw new Error("useConfirm must be used within ConfirmProvider");return t.confirm}function Os({children:t}){var i;const[s,r]=o.useState({open:!1,options:null,resolve:null}),l=o.useCallback(p=>new Promise(y=>{r({open:!0,options:p,resolve:y})}),[]),n=p=>{s.resolve&&s.resolve(p),r({open:!1,options:null,resolve:null})},a=((i=s.options)==null?void 0:i.variant)||"danger",c={danger:"text-red-600",warning:"text-yellow-600",info:"text-blue-600"}[a],d={danger:"bg-red-600 hover:bg-red-700",warning:"bg-yellow-600 hover:bg-yellow-700",info:"bg-indigo-600 hover:bg-indigo-700"}[a];return e.jsxs(ve.Provider,{value:{confirm:l},children:[t,s.open&&s.options&&e.jsxs("div",{className:"fixed inset-0 z-[9999] flex items-center justify-center",children:[e.jsx("div",{className:"absolute inset-0 bg-black bg-opacity-50",onClick:()=>n(!1)}),e.jsxs("div",{className:"relative bg-white rounded-lg shadow-xl max-w-md w-full mx-4 p-6",children:[e.jsxs("div",{className:"flex items-start gap-4",children:[e.jsx("div",{className:`flex-shrink-0 ${c}`,children:e.jsx(ht,{className:"h-6 w-6"})}),e.jsxs("div",{className:"flex-1",children:[e.jsx("h3",{className:"text-lg font-semibold text-gray-900 mb-2",children:s.options.title}),e.jsx("p",{className:"text-sm text-gray-600 whitespace-pre-wrap",children:s.options.message})]})]}),e.jsxs("div",{className:"flex justify-end gap-2 mt-6",children:[e.jsx("button",{onClick:()=>n(!1),className:"px-4 py-2 text-sm text-gray-700 bg-white border border-gray-300 rounded hover:bg-gray-50",children:s.options.cancelText||"取消"}),e.jsx("button",{onClick:()=>n(!0),className:`px-4 py-2 text-sm text-white rounded ${d}`,children:s.options.confirmText||"确定"})]})]})]})]})}const zs=new Oe({defaultOptions:{queries:{refetchOnWindowFocus:!1,retry:1,staleTime:6e4,gcTime:5*6e4}}});Ee.createRoot(document.getElementById("root")).render(e.jsx(Ie.StrictMode,{children:e.jsx(ze,{client:zs,children:e.jsx(ot,{locale:it,children:e.jsx(As,{children:e.jsx(Os,{children:e.jsx(Ct,{children:e.jsx(qt,{children:e.jsx(Ae,{children:e.jsx(Ls,{})})})})})})})})}));export{_ as A,Vt as a,qs as b,Hs as c,Ht as d,Rt as e,Gs as f,zt as k,Nt as l,Ys as p,Vs as r,Et as u};
|
|
4
|
+
//# sourceMappingURL=index-DileOOE4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"mappings":"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","names":["GROUP_AI","GROUP_GOV","GROUP_SYS","ROUTE_META","DETAIL_ROUTES","SPECIAL_DETAIL_LABEL","stripTrailingSlash","p","resolveRouteMeta","pathname","clean","exact","special","listMeta","best","dr","groupCrumbs","viewLabel","NAV_NODES","DEFAULT_ROUTE","ALL_GROUP_KEYS","n","g","NAV_LEAF_KEYS","c","m","node","child","deriveMenuKey","key","TIME_WINDOW_OPTIONS","DEFAULT_TIME_WINDOW","STORAGE_KEY","normalizeWindow","raw","readStored","TimeWindowContext","createContext","TimeWindowProvider","children","win","setWin","useState","setWindow","useCallback","w","useEffect","value","useMemo","jsx","useTimeWindow","ctx","useContext","KEY","detect","saved","apply","current","subs","getTheme","setTheme","cb","subscribeTheme","useTheme","setT","DEBOUNCE_MS","PER_ENTITY_LIMIT","fetchJson","url","res","runAll","q","trimmed","encoded","sessRes","taskRes","kbRes","GlobalSearch","onNavigate","navigate","useNavigate","query","setQuery","results","setResults","loading","setLoading","timer","useRef","seqRef","seq","r","goToBestEntity","counts","acc","target","totalHits","groups","s","t","k","jsxs","Input","IconSearch","Spin","Empty","Typography","Tag","it","e","NotificationPanel","onClose","vio","vLoading","useQuery","ins","iLoading","vCount","iCount","Tabs","Skeleton","v","ALL_PROJECTS","appendProject","project","sep","kbProjectsKey","KB_QUERY_PREFIXES","listKbProjects","LAST_PROJECT_LS_KEY","writeLastProject","path","PROJECT_STORAGE_KEY","normalizeProject","resolveEffectiveProject","selection","daemonCurrent","resolveDisplayProject","isAllProjects","ProjectContext","ProjectProvider","setProjectState","setProject","useProject","Option","Select","ProjectSwitcher","showAll","showAllProjectsOption","data","isLoading","searchParams","setSearchParams","useSearchParams","queryClient","useQueryClient","rawParam","isAllSelected","currentDaemon","effectiveCurrent","projects","onChange","newPath","next","prefix","IconStorage","currentProject","isBuilt","Fragment","IconCheck","parseUTC","timestamp","normalizeTimestamp","parseTimestamp","ts","pad2","formatLocalDisplay","opts","d","yyyy","mm","dd","hh","min","base","withSec","suffix","formatRelative","diff","mins","hours","formatAge","ms","STATUS_CONFIG","DaemonBadge","status","_a","cfg","heartbeatAgeMs","_b","pid","_c","tooltipContent","Tooltip","pickStatus","DoctorBadge","Sider","Header","Content","ArcoLayout","MenuItem","Menu","SubMenu","ICON_BY_KEY","IconDashboard","IconList","IconRobot","IconBook","IconThunderbolt","IconCode","IconBranch","IconExclamationCircle","IconDesktop","IconSettings","IconBug","renderNavNode","Layout","location","useLocation","collapsed","setCollapsed","theme","timeWindow","setTimeWindow","menuSelectedKey","openKeys","setOpenKeys","handleMenuClick","breadcrumbs","meta","toggleTheme","searchOpen","setSearchOpen","notifOpen","setNotifOpen","notifBadge","vRes","iRes","i","hasUnread","_key","currentOpenKeys","Space","IconMenuUnfold","IconMenuFold","Popover","Radio","opt","Badge","IconNotification","IconMoon","IconSun","Avatar","IconUser","Breadcrumb","Outlet","RouteErrorBoundary","Component","__publicField","error","info","Result","Button","WorkplacePage","lazy","TaskDetailPage","KbHitsPage","__vitePreload","KbDetailPage","SkillsPage","SkillDetailPage","AgentsPage","AgentDetailPage","DistillPage","DistillDetailPage","DistillRunPage","AgentDistillRunPage","DecisionsPage","DecisionDetailPage","IssuesPage","IssueDetailPage","TasksHubPage","DaemonHealthPage","DiagnosticsPage","SettingsPage","NotFound","PageFallback","Lazy","Suspense","App","Routes","Route","Navigate","ToastContext","nextId","ToastProvider","toasts","setToasts","remove","id","prev","show","type","message","msg","ToastItem","toast","icons","CheckCircle","XCircle","AlertCircle","Info","borderColors","clsx","X","ConfirmContext","useConfirm","ConfirmProvider","state","setState","confirm","options","resolve","handleClose","result","variant","iconColor","btnColor","AlertTriangle","QueryClient","ReactDOM","React","QueryClientProvider","ConfigProvider","zhCN","BrowserRouter"],"ignoreList":[],"sources":["../../src/lib/breadcrumb-map.ts","../../src/lib/nav-model.ts","../../src/lib/time-window.tsx","../../src/lib/theme.ts","../../src/components/GlobalSearch.tsx","../../src/components/NotificationPanel.tsx","../../src/utils/kbProject.ts","../../src/utils/kbApi.ts","../../src/utils/kbDefaultProject.ts","../../src/lib/project-resolve.ts","../../src/lib/project.tsx","../../src/components/ProjectSwitcher.tsx","../../src/utils/time.ts","../../src/components/DaemonBadge.tsx","../../src/components/DoctorBadge.tsx","../../src/components/Layout.tsx","../../src/components/RouteErrorBoundary.tsx","../../src/App.tsx","../../src/components/Toast.tsx","../../src/components/Confirm.tsx","../../src/main.tsx"],"sourcesContent":["/**\n * Path → breadcrumb segments map.\n *\n * Arco Pro 重设计 IA (Phase 0, decision 29688066): 分组 11 视图 → 两级面包屑\n * (控制台 / 分组 / 视图〔/ 详情〕)。AI 资源四页 + 系统三页 + 治理两页在分组下,\n * 顶层两项(工作台 / 任务)只有单级。整页详情路由(/tasks/:taskId、/ai/kb/:name\n * 等)解析为「分组 / 视图 / 详情」三级,链接段回到视图列表。\n *\n * 保留 `resolveRouteMeta` 签名供 Layout 复用(Phase 0 护栏)。\n */\n\nexport interface BreadcrumbItem {\n label: string;\n /** When present, the segment is a link; otherwise it's a plain text leaf. */\n path?: string;\n}\n\nexport interface RouteMeta {\n /** Short label shown in headers / tabs. */\n tabLabel: string;\n /** Crumbs for non-dynamic routes. Dynamic detail routes resolve dynamically. */\n breadcrumbs: BreadcrumbItem[];\n}\n\n// Group-level (non-clickable) crumb labels.\nconst GROUP_AI: BreadcrumbItem = { label: 'AI 资源' };\nconst GROUP_GOV: BreadcrumbItem = { label: '治理' };\nconst GROUP_SYS: BreadcrumbItem = { label: '系统' };\n\n/** Static route meta for the 11 list views. */\nexport const ROUTE_META: Record<string, RouteMeta> = {\n '/workplace': {\n tabLabel: '工作台',\n breadcrumbs: [{ label: '工作台' }],\n },\n '/tasks': {\n tabLabel: '任务',\n breadcrumbs: [{ label: '任务' }],\n },\n '/ai/kb': {\n tabLabel: 'KB 命中',\n breadcrumbs: [GROUP_AI, { label: 'KB 命中' }],\n },\n '/ai/skills': {\n tabLabel: 'Skill 调用',\n breadcrumbs: [GROUP_AI, { label: 'Skill 调用' }],\n },\n '/ai/agents': {\n tabLabel: 'Agent 委托',\n breadcrumbs: [GROUP_AI, { label: 'Agent 委托' }],\n },\n '/ai/distill': {\n tabLabel: '蒸馏',\n breadcrumbs: [GROUP_AI, { label: '蒸馏' }],\n },\n '/decisions': {\n tabLabel: '决策',\n breadcrumbs: [GROUP_GOV, { label: '决策' }],\n },\n '/issues': {\n tabLabel: '问题',\n breadcrumbs: [GROUP_GOV, { label: '问题' }],\n },\n '/system/daemon': {\n tabLabel: 'Daemon',\n breadcrumbs: [GROUP_SYS, { label: 'Daemon' }],\n },\n '/system/diagnostics': {\n tabLabel: '诊断',\n breadcrumbs: [GROUP_SYS, { label: '诊断' }],\n },\n '/system/settings': {\n tabLabel: '设置',\n breadcrumbs: [GROUP_SYS, { label: '设置' }],\n },\n};\n\n/**\n * Dynamic detail routes → the list view they hang off. Each entry maps a route\n * prefix to the list path (used to build a clickable \"back to list\" crumb) and\n * the leaf label of the detail level. The `:param` segment is matched by prefix.\n */\ninterface DetailRoute {\n /** Path prefix that must be followed by a `/{param}` segment. */\n prefix: string;\n /** The list view this detail belongs to (its ROUTE_META key). */\n listPath: string;\n /** Label for the detail (leaf) crumb. */\n detailLabel: string;\n}\n\nconst DETAIL_ROUTES: DetailRoute[] = [\n { prefix: '/tasks', listPath: '/tasks', detailLabel: '任务详情' },\n { prefix: '/ai/kb', listPath: '/ai/kb', detailLabel: 'KB 详情' },\n { prefix: '/ai/skills', listPath: '/ai/skills', detailLabel: 'Skill 详情' },\n { prefix: '/ai/agents', listPath: '/ai/agents', detailLabel: 'Agent 详情' },\n // /ai/distill/run is the wizard; /ai/distill/:topicId is a detail.\n { prefix: '/ai/distill', listPath: '/ai/distill', detailLabel: '蒸馏详情' },\n { prefix: '/decisions', listPath: '/decisions', detailLabel: '决策详情' },\n { prefix: '/issues', listPath: '/issues', detailLabel: '问题详情' },\n];\n\n// Special-case dynamic leaves that are not plain \"详情\" pages.\nconst SPECIAL_DETAIL_LABEL: Record<string, string> = {\n '/ai/distill/run': '执行蒸馏',\n};\n\nfunction stripTrailingSlash(p: string): string {\n return p.length > 1 && p.endsWith('/') ? p.slice(0, -1) : p;\n}\n\n/**\n * Resolve breadcrumb + label for an arbitrary pathname. Static views hit\n * ROUTE_META directly; integer/string detail routes resolve to a 3-level\n * crumb (分组 / 视图〔链接〕 / 详情). Returns null for unknown paths so callers\n * can fall back to a default.\n */\nexport function resolveRouteMeta(pathname: string): RouteMeta | null {\n const clean = stripTrailingSlash(pathname);\n\n // 1) Exact static match.\n const exact = ROUTE_META[clean];\n if (exact) return exact;\n\n // 2) Special-cased dynamic leaves (e.g. the distill wizard).\n const special = SPECIAL_DETAIL_LABEL[clean];\n if (special) {\n const listMeta = ROUTE_META['/ai/distill'];\n return {\n tabLabel: special,\n breadcrumbs: [\n ...listMeta.breadcrumbs.slice(0, -1),\n { label: '蒸馏', path: '/ai/distill' },\n { label: special },\n ],\n };\n }\n\n // 3) Detail routes: `<prefix>/<param>` → 分组 / 视图(链接) / 详情.\n // Match the longest prefix so /ai/kb wins over a hypothetical /ai.\n let best: DetailRoute | null = null;\n for (const dr of DETAIL_ROUTES) {\n if (clean.startsWith(dr.prefix + '/')) {\n if (!best || dr.prefix.length > best.prefix.length) best = dr;\n }\n }\n if (best) {\n const listMeta = ROUTE_META[best.listPath];\n if (!listMeta) return null;\n const groupCrumbs = listMeta.breadcrumbs.slice(0, -1); // group level(s)\n const viewLabel = listMeta.breadcrumbs[listMeta.breadcrumbs.length - 1].label;\n return {\n tabLabel: best.detailLabel,\n breadcrumbs: [\n ...groupCrumbs,\n { label: viewLabel, path: best.listPath },\n { label: best.detailLabel },\n ],\n };\n }\n\n return null;\n}\n\n/** Set of every concrete top-level pathname known to the router. */\nexport const KNOWN_ROUTES: ReadonlySet<string> = new Set(Object.keys(ROUTE_META));\n\n/**\n * Validator for arbitrary path keys. Kept for backward compatibility with\n * any external caller (previously used by the removed TabStore).\n */\nexport function isKnownRoute(key: string): boolean {\n const path = key.split('?')[0];\n const clean = stripTrailingSlash(path);\n return KNOWN_ROUTES.has(clean);\n}\n","/**\n * Sidebar navigation model — Arco Pro 重设计 IA (Phase 0, decision 29688066).\n *\n * v4 的 6 项扁平导航 → 分组 11 视图:两顶层项(工作台 / 任务)+ 三个分组\n * SubMenu(AI 资源[4] / 治理[2] / 系统[3])。原型菜单 id 见\n * docs/design/2026-06-11/redesign-arco.html 的 MENU 常量。\n *\n * This module is intentionally **pure** (no React, no DOM) so the IA contract\n * — group membership, selectedKey + openKeys derivation, prefix matching — is\n * unit-testable from `tests/unit/web/` in a node environment (the web package\n * has no jsdom). Layout.tsx consumes these for rendering.\n */\n\nexport interface NavLeaf {\n /** Route key (also the navigate target). */\n key: string;\n /** Sidebar label. */\n label: string;\n}\n\nexport interface NavGroup {\n /** SubMenu key (used as the openKeys entry). */\n key: string;\n /** Group label. */\n label: string;\n /** Leaf items under this group. */\n children: NavLeaf[];\n}\n\n/** A top-level node is either a flat leaf or a group with children. */\nexport type NavNode =\n | ({ kind: 'leaf' } & NavLeaf)\n | ({ kind: 'group' } & NavGroup);\n\n/**\n * Grouped 11-view IA. Two flat top-level items + three SubMenu groups.\n * Order matches the prototype sidebar.\n */\nexport const NAV_NODES: NavNode[] = [\n { kind: 'leaf', key: '/workplace', label: '工作台' },\n { kind: 'leaf', key: '/tasks', label: '任务' },\n {\n kind: 'group',\n key: 'group:ai',\n label: 'AI 资源',\n children: [\n { key: '/ai/kb', label: 'KB 命中' },\n { key: '/ai/skills', label: 'Skill 调用' },\n { key: '/ai/agents', label: 'Agent 委托' },\n { key: '/ai/distill', label: '蒸馏' },\n ],\n },\n {\n kind: 'group',\n key: 'group:governance',\n label: '治理',\n children: [\n { key: '/decisions', label: '决策' },\n { key: '/issues', label: '问题' },\n ],\n },\n {\n kind: 'group',\n key: 'group:system',\n label: '系统',\n children: [\n { key: '/system/daemon', label: 'Daemon' },\n { key: '/system/diagnostics', label: '诊断' },\n { key: '/system/settings', label: '设置' },\n ],\n },\n];\n\n/** Default landing route (index redirects here). */\nexport const DEFAULT_ROUTE = '/workplace';\n\n/**\n * All SubMenu group keys, in sidebar order (`['group:ai', 'group:governance',\n * 'group:system']`). Used as the sidebar's *initial* openKeys so every group is\n * expanded on first load — subsequent user toggles take over via controlled\n * state (see Layout.tsx). This is intentionally the full group set, not the\n * route-derived active-only set returned by {@link deriveOpenKeys}.\n */\nexport const ALL_GROUP_KEYS: readonly string[] = NAV_NODES.filter(\n (n): n is { kind: 'group' } & NavGroup => n.kind === 'group',\n).map((g) => g.key);\n\n/**\n * All concrete leaf route keys (the 11 views), in sidebar order. Useful for\n * tests / dev tools to assert完整性.\n */\nexport const NAV_LEAF_KEYS: readonly string[] = NAV_NODES.flatMap((n) =>\n n.kind === 'group' ? n.children.map((c) => c.key) : [n.key],\n);\n\n/** Map a leaf route key → its owning group key (or null for flat top items). */\nconst LEAF_TO_GROUP: Record<string, string> = (() => {\n const m: Record<string, string> = {};\n for (const node of NAV_NODES) {\n if (node.kind === 'group') {\n for (const child of node.children) m[child.key] = node.key;\n }\n }\n return m;\n})();\n\nfunction stripTrailingSlash(p: string): string {\n return p.length > 1 && p.endsWith('/') ? p.slice(0, -1) : p;\n}\n\n/**\n * Derive the sidebar Menu's `selectedKey` for a given pathname. Matches the\n * longest leaf-key prefix so整页详情路由 highlight their parent leaf, e.g.\n * /tasks/abc → /tasks\n * /ai/kb/some-page → /ai/kb\n * /ai/distill/run → /ai/distill\n * /system/settings → /system/settings\n * Falls back to DEFAULT_ROUTE for unknown / transient paths.\n */\nexport function deriveMenuKey(pathname: string): string {\n const clean = stripTrailingSlash(pathname) || DEFAULT_ROUTE;\n // Longest-prefix match so deeper detail routes resolve to their leaf.\n let best: string | null = null;\n for (const key of NAV_LEAF_KEYS) {\n if (clean === key || clean.startsWith(key + '/')) {\n if (!best || key.length > best.length) best = key;\n }\n }\n return best ?? DEFAULT_ROUTE;\n}\n\n/**\n * Derive which SubMenu group(s) should be open for a given pathname. Returns\n * the group key owning the active leaf, or [] when the active leaf is a flat\n * top-level item (工作台 / 任务).\n */\nexport function deriveOpenKeys(pathname: string): string[] {\n const selected = deriveMenuKey(pathname);\n const group = LEAF_TO_GROUP[selected];\n return group ? [group] : [];\n}\n","/**\n * Global time-window context — Arco Pro 重设计 (Phase 0, decision 29688066).\n *\n * 顶栏 7d / 30d / 90d 切换,选择持久化到 localStorage。后续各页 react-query\n * queryKey 带 window 维度消费 `useTimeWindow()`(Risk R7:context 必须贯穿各页\n * queryKey,否则切换无效)。\n *\n * The pure parsing/normalisation helper (`normalizeWindow`) is exported so the\n * persistence contract is unit-testable without a DOM.\n */\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n type ReactNode,\n} from 'react';\n\n/** Allowed time-window values, in days. */\nexport type TimeWindow = 7 | 30 | 90;\n\nexport const TIME_WINDOW_OPTIONS: readonly TimeWindow[] = [7, 30, 90];\n\nexport const DEFAULT_TIME_WINDOW: TimeWindow = 30;\n\nconst STORAGE_KEY = 'cf.timeWindow';\n\n/**\n * Normalise an arbitrary stored value into a valid TimeWindow. Accepts a number\n * or a numeric string (e.g. from localStorage); falls back to the default for\n * anything unrecognised. Pure — no DOM access.\n */\nexport function normalizeWindow(raw: unknown): TimeWindow {\n const n = typeof raw === 'string' ? Number(raw) : raw;\n if (n === 7 || n === 30 || n === 90) return n;\n return DEFAULT_TIME_WINDOW;\n}\n\nfunction readStored(): TimeWindow {\n if (typeof window === 'undefined') return DEFAULT_TIME_WINDOW;\n try {\n return normalizeWindow(window.localStorage.getItem(STORAGE_KEY));\n } catch {\n return DEFAULT_TIME_WINDOW;\n }\n}\n\ninterface TimeWindowContextValue {\n window: TimeWindow;\n setWindow: (w: TimeWindow) => void;\n}\n\nconst TimeWindowContext = createContext<TimeWindowContextValue | null>(null);\n\nexport function TimeWindowProvider({ children }: { children: ReactNode }) {\n const [win, setWin] = useState<TimeWindow>(() => readStored());\n\n const setWindow = useCallback((w: TimeWindow) => {\n setWin(normalizeWindow(w));\n }, []);\n\n useEffect(() => {\n try {\n window.localStorage.setItem(STORAGE_KEY, String(win));\n } catch {\n /* localStorage unavailable (private mode / SSR) — ignore. */\n }\n }, [win]);\n\n const value = useMemo<TimeWindowContextValue>(\n () => ({ window: win, setWindow }),\n [win, setWindow],\n );\n\n return (\n <TimeWindowContext.Provider value={value}>\n {children}\n </TimeWindowContext.Provider>\n );\n}\n\n/**\n * Consume the global time window. Throws if used outside a provider so missing\n * wiring fails loudly rather than silently defaulting.\n */\nexport function useTimeWindow(): TimeWindowContextValue {\n const ctx = useContext(TimeWindowContext);\n if (!ctx) {\n throw new Error('useTimeWindow must be used within a <TimeWindowProvider>');\n }\n return ctx;\n}\n\nexport { STORAGE_KEY as TIME_WINDOW_STORAGE_KEY };\n","/**\n * Theme module — light / dark with localStorage persistence.\n *\n * Detection order on first read:\n * 1. localStorage `claude-forge:theme` (if `light` or `dark`)\n * 2. window.matchMedia('(prefers-color-scheme: dark)')\n * 3. fallback `light`\n *\n * Apply mechanism: Arco's dark mode uses `body[arco-theme='dark']`. We set or\n * remove that attribute; no ConfigProvider change required.\n *\n * Subscribers (e.g. Layout's toggle button) get notified via `subscribeTheme`.\n */\n\nimport { useEffect, useState } from 'react'\n\nexport type Theme = 'light' | 'dark'\n\nconst KEY = 'claude-forge:theme'\n\nfunction detect(): Theme {\n try {\n const saved = localStorage.getItem(KEY)\n if (saved === 'light' || saved === 'dark') return saved\n } catch {\n // localStorage may throw in restricted environments — ignore.\n }\n try {\n if (typeof window !== 'undefined' && window.matchMedia) {\n return window.matchMedia('(prefers-color-scheme: dark)').matches\n ? 'dark'\n : 'light'\n }\n } catch {\n // ignore\n }\n return 'light'\n}\n\nfunction apply(t: Theme): void {\n if (typeof document === 'undefined') return\n if (t === 'dark') {\n document.body.setAttribute('arco-theme', 'dark')\n } else {\n document.body.removeAttribute('arco-theme')\n }\n}\n\nlet current: Theme = detect()\nconst subs = new Set<(t: Theme) => void>()\n\n// Apply on module import so we don't flash the wrong theme.\napply(current)\n\nexport function getTheme(): Theme {\n return current\n}\n\nexport function setTheme(t: Theme): void {\n if (t === current) return\n current = t\n try {\n localStorage.setItem(KEY, t)\n } catch {\n // ignore\n }\n apply(t)\n subs.forEach((cb) => cb(t))\n}\n\nexport function toggleTheme(): Theme {\n const next: Theme = current === 'light' ? 'dark' : 'light'\n setTheme(next)\n return next\n}\n\nexport function subscribeTheme(cb: (t: Theme) => void): () => void {\n subs.add(cb)\n return () => {\n subs.delete(cb)\n }\n}\n\n/** React hook — returns [theme, setTheme]. */\nexport function useTheme(): [Theme, (t: Theme) => void] {\n const [t, setT] = useState<Theme>(getTheme)\n useEffect(() => subscribeTheme(setT), [])\n return [t, setTheme]\n}\n","/**\n * GlobalSearch — topbar Popover that fans out to 3 endpoints in parallel.\n *\n * Entities scanned (v4 + spec 3 partial revert):\n * - Sessions → /api/sessions?search= → land on /tasks?session=…\n * - Tasks → /api/tasks?search= → land on /tasks?task=…\n * - Knowledge → /api/knowledge/query?q=&… → land on /context?tab=kb&page=…\n *\n * v4 cleanup (C-1): removed the \"Events\" group entirely (no events landing\n * page in v4; the old /events route has since been removed in the Arco cutover).\n *\n * Spec 3 partial revert (2026-05-27): the Knowledge group was deleted in the\n * original Option B cut and restored here after user feedback (/context page\n * + /api/knowledge route both came back).\n *\n * Behaviour:\n * - Debounce 250ms before firing the queries (Promise.allSettled — partial\n * failures don't block the rest).\n * - Enter jumps to the entity list page with the most matches, carrying\n * `?q=` (TasksHub) or `?tab=kb` (Context).\n * - Clicking a result row jumps to that entity's detail (or list w/ filter).\n * - ESC / external click closes the Popover (handled by Arco Popover).\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { useNavigate } from 'react-router-dom'\nimport Input from '@arco-design/web-react/es/Input'\nimport Spin from '@arco-design/web-react/es/Spin'\nimport Empty from '@arco-design/web-react/es/Empty'\nimport Typography from '@arco-design/web-react/es/Typography'\nimport Tag from '@arco-design/web-react/es/Tag'\nimport { IconSearch } from '@arco-design/web-react/icon'\n\ninterface SessionHit {\n session_id: string\n first_prompt: string\n}\ninterface TaskHit {\n id: string\n title?: string\n first_prompt?: string\n}\ninterface KbHit {\n page: { name: string; title?: string }\n score?: number\n}\n\ninterface AllResults {\n sessions: SessionHit[]\n tasks: TaskHit[]\n kb: KbHit[]\n}\n\nconst DEBOUNCE_MS = 250\nconst PER_ENTITY_LIMIT = 5\n\nasync function fetchJson<T>(url: string): Promise<T> {\n const res = await fetch(url)\n if (!res.ok) throw new Error(`${url} → ${res.status}`)\n return res.json() as Promise<T>\n}\n\nasync function runAll(q: string): Promise<AllResults> {\n const trimmed = q.trim().slice(0, 200)\n if (!trimmed) {\n return { sessions: [], tasks: [], kb: [] }\n }\n const encoded = encodeURIComponent(trimmed)\n const [sessRes, taskRes, kbRes] = await Promise.allSettled([\n fetchJson<SessionHit[]>(`/api/sessions?search=${encoded}&limit=${PER_ENTITY_LIMIT}`),\n fetchJson<{ tasks: TaskHit[] }>(`/api/tasks?search=${encoded}&limit=${PER_ENTITY_LIMIT}`),\n fetchJson<{ pages: KbHit[] }>(`/api/knowledge/query?q=${encoded}&strategy=keyword&max=${PER_ENTITY_LIMIT}`),\n ])\n return {\n sessions: sessRes.status === 'fulfilled' ? sessRes.value : [],\n tasks: taskRes.status === 'fulfilled' ? (taskRes.value.tasks ?? []) : [],\n kb: kbRes.status === 'fulfilled' ? (kbRes.value.pages ?? []) : [],\n }\n}\n\ninterface GlobalSearchProps {\n /** Called after the user navigates somewhere — Layout uses this to close\n * the Popover. */\n onNavigate?: () => void\n}\n\nexport default function GlobalSearch({ onNavigate }: GlobalSearchProps) {\n const navigate = useNavigate()\n const [query, setQuery] = useState('')\n const [results, setResults] = useState<AllResults | null>(null)\n const [loading, setLoading] = useState(false)\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null)\n const seqRef = useRef(0)\n\n useEffect(() => {\n if (timer.current) clearTimeout(timer.current)\n const q = query.trim()\n if (!q) {\n setResults(null)\n setLoading(false)\n return\n }\n setLoading(true)\n const seq = ++seqRef.current\n timer.current = setTimeout(async () => {\n const r = await runAll(q)\n if (seq !== seqRef.current) return // stale\n setResults(r)\n setLoading(false)\n }, DEBOUNCE_MS)\n return () => {\n if (timer.current) clearTimeout(timer.current)\n }\n }, [query])\n\n const goToBestEntity = useCallback(() => {\n if (!results) return\n // v4 (C-1): sessions/tasks both land at TasksHub (?q= is the search param\n // TasksHubPage reads, not ?search=). KB lands at the Context KB tab.\n const counts: Array<{ key: keyof AllResults; path: string; n: number }> = [\n { key: 'sessions', path: '/tasks', n: results.sessions.length },\n { key: 'tasks', path: '/tasks', n: results.tasks.length },\n { key: 'kb', path: '/context?tab=kb', n: results.kb.length },\n ]\n const best = counts.reduce((acc, c) => (c.n > acc.n ? c : acc), counts[0])\n if (best.n === 0) return\n const q = encodeURIComponent(query.trim())\n // Append ?q= to TasksHub; KB path already has its own query.\n const target = best.path.includes('?')\n ? `${best.path}&q=${q}`\n : `${best.path}?q=${q}`\n navigate(target)\n onNavigate?.()\n }, [results, query, navigate, onNavigate])\n\n const totalHits =\n (results?.sessions.length ?? 0) +\n (results?.tasks.length ?? 0) +\n (results?.kb.length ?? 0)\n\n const groups = useMemo(() => {\n if (!results) return []\n // v4 (C-1): all row clicks land directly on real routes — no /sessions/:id\n // redirect double-hop (the legacy redirect table was removed in the Arco cutover).\n return [\n {\n label: '会话',\n path: '/tasks',\n items: results.sessions.map((s) => ({\n key: `s-${s.session_id}`,\n label: s.first_prompt || `(${s.session_id.slice(0, 8)})`,\n onClick: () => {\n navigate(`/tasks?session=${encodeURIComponent(s.session_id)}`)\n onNavigate?.()\n },\n })),\n },\n {\n label: '任务',\n path: '/tasks',\n items: results.tasks.map((t) => ({\n key: `t-${t.id}`,\n label: t.title || t.first_prompt || `(任务 ${t.id.slice(0, 8)})`,\n onClick: () => {\n navigate(`/tasks?task=${encodeURIComponent(t.id)}`)\n onNavigate?.()\n },\n })),\n },\n {\n label: '知识库',\n path: '/context?tab=kb',\n items: results.kb.map((k) => ({\n key: `k-${k.page.name}`,\n label: k.page.title || k.page.name,\n onClick: () => {\n // ContextInsightsPage may consume ?page= for deep-scroll into a\n // specific KB page; for now landing on the KB tab is enough.\n navigate(`/context?tab=kb&page=${encodeURIComponent(k.page.name)}`)\n onNavigate?.()\n },\n })),\n },\n ]\n }, [results, navigate, onNavigate])\n\n return (\n <div style={{ width: 360, maxHeight: 480, overflowY: 'auto' }}>\n <Input.Search\n autoFocus\n value={query}\n onChange={setQuery}\n onPressEnter={goToBestEntity}\n placeholder=\"搜索 sessions / tasks / 知识库...\"\n allowClear\n prefix={<IconSearch />}\n style={{ width: '100%' }}\n />\n <div style={{ marginTop: 12 }}>\n {loading ? (\n <div style={{ display: 'flex', justifyContent: 'center', padding: '24px 0' }}>\n <Spin size={20} />\n </div>\n ) : !results ? (\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n 输入关键词后回车跳转到结果最多的页面。\n </Typography.Text>\n ) : totalHits === 0 ? (\n <Empty description=\"无匹配结果\" imgSrc=\"\" style={{ padding: '12px 0' }} />\n ) : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>\n {groups.map((g) =>\n g.items.length === 0 ? null : (\n <div key={g.label}>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n marginBottom: 4,\n }}\n >\n <Typography.Text style={{ fontSize: 11, color: 'var(--color-text-3)' }}>\n {g.label}\n </Typography.Text>\n <Tag size=\"small\" color=\"gray\">{g.items.length}</Tag>\n </div>\n <ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>\n {g.items.map((it) => (\n <li\n key={it.key}\n onClick={it.onClick}\n style={{\n padding: '6px 8px',\n fontSize: 12,\n color: 'var(--color-text-1)',\n cursor: 'pointer',\n borderRadius: 4,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.background = 'var(--color-fill-2)'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.background = 'transparent'\n }}\n >\n {it.label}\n </li>\n ))}\n </ul>\n </div>\n ),\n )}\n </div>\n )}\n </div>\n </div>\n )\n}\n","/**\n * NotificationPanel — topbar bell Popover content.\n *\n * Two tabs:\n * - 违规 → /api/violations?days=7&limit=10\n * - 反模式 → /api/insights?days=7 (severity = critical | warn | info)\n *\n * v1 doesn't track read-state — the red dot is purely a function of \"any\n * violations or any critical/warn anti-patterns in the past 7 days\".\n */\n\nimport { useQuery } from '@tanstack/react-query'\nimport { useNavigate } from 'react-router-dom'\nimport Tabs from '@arco-design/web-react/es/Tabs'\nimport Empty from '@arco-design/web-react/es/Empty'\nimport Tag from '@arco-design/web-react/es/Tag'\nimport Skeleton from '@arco-design/web-react/es/Skeleton'\nimport Typography from '@arco-design/web-react/es/Typography'\n\ninterface ApiViolation {\n timestamp: string\n summary: string\n signal: 'routing_disobeyed' | 'user_keyword'\n detectedKeyword: string | null\n expectedAgent: string | null\n relativeTime: string\n}\ninterface ViolationsResponse {\n count: number\n violations: ApiViolation[]\n}\n\ninterface AntiPattern {\n id: string\n type: string\n severity: 'critical' | 'warn' | 'info'\n title: string\n description: string\n detectedAt: string\n sessionId?: string\n}\ninterface InsightsResponse {\n summary: { total: number; critical: number; warn: number; info: number }\n patterns: AntiPattern[]\n}\n\ninterface NotificationPanelProps {\n onClose?: () => void\n}\n\nexport default function NotificationPanel({ onClose }: NotificationPanelProps) {\n const navigate = useNavigate()\n\n const { data: vio, isLoading: vLoading } = useQuery({\n queryKey: ['notifications-violations'],\n queryFn: async (): Promise<ViolationsResponse> => {\n const res = await fetch('/api/violations?days=7&limit=10')\n if (!res.ok) throw new Error('Failed')\n return res.json()\n },\n refetchOnMount: 'always',\n })\n\n const { data: ins, isLoading: iLoading } = useQuery({\n queryKey: ['notifications-insights'],\n queryFn: async (): Promise<InsightsResponse> => {\n const res = await fetch('/api/insights?days=7')\n if (!res.ok) throw new Error('Failed')\n return res.json()\n },\n refetchOnMount: 'always',\n })\n\n const vCount = vio?.count ?? 0\n const iCount = (ins?.summary.critical ?? 0) + (ins?.summary.warn ?? 0)\n\n return (\n <div style={{ width: 360, maxHeight: 480, overflowY: 'auto' }}>\n <Tabs defaultActiveTab=\"violations\" size=\"mini\">\n <Tabs.TabPane key=\"violations\" title={`违规${vCount > 0 ? ` (${vCount})` : ''}`}>\n {vLoading ? (\n <Skeleton text={{ rows: 3 }} animation />\n ) : !vio || vio.count === 0 ? (\n <Empty description=\"近 7 天无违规\" imgSrc=\"\" style={{ padding: '12px 0' }} />\n ) : (\n <ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>\n {vio.violations.map((v) => (\n <li\n key={v.timestamp + v.summary.slice(0, 16)}\n style={{\n padding: '8px 4px',\n borderBottom: '1px solid var(--color-border-2)',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>\n <Tag size=\"small\" color={v.signal === 'user_keyword' ? 'red' : 'orange'}>\n {v.signal === 'user_keyword' ? '关键词' : '路由'}\n </Tag>\n <span style={{ fontSize: 11, color: 'var(--color-text-3)' }}>{v.relativeTime}</span>\n </div>\n <div\n style={{\n fontSize: 12,\n color: 'var(--color-text-1)',\n marginTop: 4,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n title={v.summary}\n >\n {v.summary.slice(0, 60)}\n {v.summary.length > 60 ? '…' : ''}\n </div>\n </li>\n ))}\n </ul>\n )}\n </Tabs.TabPane>\n <Tabs.TabPane key=\"insights\" title={`反模式${iCount > 0 ? ` (${iCount})` : ''}`}>\n {iLoading ? (\n <Skeleton text={{ rows: 3 }} animation />\n ) : !ins || ins.patterns.length === 0 ? (\n <Empty description=\"近 7 天无反模式\" imgSrc=\"\" style={{ padding: '12px 0' }} />\n ) : (\n <ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>\n {ins.patterns.slice(0, 10).map((p) => (\n <li\n key={p.id}\n style={{\n padding: '8px 4px',\n borderBottom: '1px solid var(--color-border-2)',\n cursor: p.sessionId ? 'pointer' : 'default',\n }}\n onClick={() => {\n if (p.sessionId) {\n // v4 (C-2): direct to /tasks?session=… avoids a\n // /sessions/:id redirect double-hop (legacy redirects removed in Arco cutover).\n navigate(`/tasks?session=${encodeURIComponent(p.sessionId)}`)\n onClose?.()\n }\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n <Tag\n size=\"small\"\n color={\n p.severity === 'critical' ? 'red' : p.severity === 'warn' ? 'orange' : 'gray'\n }\n >\n {p.severity}\n </Tag>\n <Typography.Text style={{ fontSize: 12, fontWeight: 500 }}>\n {p.title}\n </Typography.Text>\n </div>\n <div\n style={{\n fontSize: 11,\n color: 'var(--color-text-3)',\n marginTop: 4,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n title={p.description}\n >\n {p.description}\n </div>\n </li>\n ))}\n </ul>\n )}\n </Tabs.TabPane>\n </Tabs>\n </div>\n )\n}\n","/**\n * Pure helpers for KB multi-project URL/cache-key construction.\n *\n * Extracted from kbApi.ts so they are unit-testable in plain Node without a\n * DOM. The web bundle imports both this module and its DOM-bound wrappers\n * (readProjectFromUrl) from kbApi.\n *\n * Hotfix v9.5.x: query keys MUST include the project string so that\n * react-query treats different projects as separate cache entries —\n * otherwise switching projects shows stale content from the previous one.\n */\n\n/**\n * Append `?project=<path>` (or `&project=...` if a query string is already\n * present) to `url`. When `project` is empty the url is returned unchanged.\n *\n * Behavior is intentionally conservative: we never mutate or de-dupe an\n * existing `project=` parameter; callers are expected to compose the URL\n * fresh per request.\n */\n/**\n * Sentinel value used in the `?project=` URL param to mean \"explicitly show\n * all projects\" (as opposed to no param = default scoped to the current daemon\n * project). It is intentionally not a valid filesystem path so it can never\n * collide with a real `sessions.project_path`. (decision c4200ef6)\n */\nexport const ALL_PROJECTS = '__all__';\n\nexport function appendProject(url: string, project: string): string {\n if (!project) return url;\n const sep = url.includes('?') ? '&' : '?';\n return `${url}${sep}project=${encodeURIComponent(project)}`;\n}\n\n/**\n * Build a react-query key for a KB endpoint. The project string is the LAST\n * element so the prefix `[domain]` (e.g. `['kb-list']`) still works for\n * partial-match invalidation of every project at once.\n */\nexport function kbListKey(project: string): readonly unknown[] {\n return ['kb-list', project] as const;\n}\n\nexport function kbPageKey(name: string | null, project: string): readonly unknown[] {\n return ['kb-page', name, project] as const;\n}\n\nexport function kbAuditKey(project: string): readonly unknown[] {\n return ['kb-audit', project] as const;\n}\n\nexport function kbStatsKey(project: string): readonly unknown[] {\n return ['kb-stats', project] as const;\n}\n\nexport function kbProjectsKey(): readonly unknown[] {\n return ['kb-projects'] as const;\n}\n\n/**\n * Prefix used by `queryClient.invalidateQueries({ queryKey: KB_QUERY_PREFIX })`\n * to invalidate every KB-scoped query in one shot.\n *\n * NOTE: react-query does prefix matching, so `['kb-']` does NOT match\n * `['kb-list']`. Each domain (list, page, audit, stats) needs an explicit\n * invalidate call OR all keys must share a common prefix array element.\n *\n * We standardize on the convention \"every KB query starts with a string\n * beginning with `kb-`\" and provide an explicit list of prefixes for\n * invalidation.\n */\nexport const KB_QUERY_PREFIXES: ReadonlyArray<readonly unknown[]> = [\n ['kb-list'],\n ['kb-page'],\n ['kb-audit'],\n ['kb-stats'],\n];\n","/**\n * KB-related fetch helpers for the dashboard SPA.\n *\n * All read endpoints use plain `fetch` (anonymous). Write endpoints use\n * `authFetch` so the daemon bearer token is attached.\n *\n * v9.5: All endpoints support ?project=<path> query param. Read it from\n * window.location URL and append via `withProject()` helper.\n *\n * Hotfix: pure URL/key helpers live in kbProject.ts (Node-testable).\n */\n\nimport { authFetch } from './auth'\nimport { appendProject } from './kbProject'\n\n// ─── v9.5: project parameter ────────────────────────────────────────────────\n\n/** Read current project selection from URL (?project=...). */\nfunction readProjectFromUrl(): string {\n if (typeof window === 'undefined') return ''\n return new URLSearchParams(window.location.search).get('project') ?? ''\n}\n\n/** Append ?project=<path> from URL state to any KB endpoint URL. */\nfunction withProject(url: string): string {\n return appendProject(url, readProjectFromUrl())\n}\n\nexport interface KbProject {\n path: string\n name: string\n kb_built: boolean\n last_event_at: string | null\n page_count: number\n is_current: boolean\n}\n\nexport interface KbProjectsResponse {\n current: string\n projects: KbProject[]\n}\n\nexport interface KbPageSummary {\n name: string\n title: string\n kind: 'module' | 'cross'\n refs_count: number\n audit_status: 'ok' | 'stale' | 'error'\n source_hash: string\n generated_at: string\n ai_model?: string\n}\n\nexport interface KbListResponse {\n kb_built: boolean\n hint?: string\n pages?: KbPageSummary[]\n stats?: {\n total: number\n by_kind: { module: number; cross: number }\n by_audit_status: { ok: number; stale: number; error: number }\n }\n generated_at?: string\n source_hash?: string\n}\n\nexport interface KbPageDetail {\n name: string\n title: string\n content: string\n kind: 'module' | 'cross'\n refs: Array<{ file: string; lineStart: number; lineEnd?: number; symbol?: string }>\n generated_at: string\n source_hash: string\n audit_status: 'ok' | 'stale' | 'error'\n ai_model?: string\n}\n\nexport interface KbQueryHit {\n page: { name: string; title: string; content: string; refs: any[] }\n score: number\n matched_keywords: string[]\n matched_in: string[]\n}\n\nexport interface KbQueryResponse {\n query: string\n pages: KbQueryHit[]\n repo_map_hits?: Array<{\n file: string\n line: number\n name: string\n kind: string\n signature: string\n }>\n strategy: 'keyword' | 'rerank'\n total_pages_scanned: number\n rerank_failed?: boolean\n}\n\nexport interface RepoMapResponse {\n total: number\n truncated: boolean\n symbols: Array<{\n file: string\n line: number\n kind: string\n name: string\n signature: string\n exports: boolean\n docComment?: string\n }>\n repo_map_meta: {\n version: string\n generated_at: string\n source_hash: string\n symbol_count: number\n file_count: number\n }\n}\n\nexport interface AuditResponse {\n kb_built: boolean\n hint?: string\n summary?: { total: number; ok: number; stale: number; error: number }\n per_page?: Array<{\n name: string\n kind: 'module' | 'cross'\n audit_status: 'ok' | 'stale' | 'error'\n refs_count: number\n source_hash: string\n ai_model: string\n }>\n log?: string\n log_truncated?: boolean\n generated_at?: string\n}\n\nexport interface KbStatsResponse {\n kb_built: boolean\n kb_size_bytes: number\n page_count: number\n last_build_at: string | null\n last_build_stats: {\n built: number\n cached: number\n total: number\n crossModuleBuilt?: number\n crossModuleCached?: number\n } | null\n last_build_status?: 'running' | 'done' | 'error' | null\n total_queries: number\n rerank_hit_rate: number | null\n rerank_failure_rate?: number | null\n total_ai_calls?: number\n total_tokens?: { input: number; output: number }\n}\n\nexport interface StartBuildBody {\n apply?: boolean\n force?: boolean\n skipCrossModule?: boolean\n modules?: string[] | null\n}\n\nexport async function listKbProjects(): Promise<KbProjectsResponse> {\n const r = await fetch('/api/knowledge/projects')\n if (!r.ok) throw new Error(`projects failed: ${r.status}`)\n return r.json()\n}\n\nexport async function listKb(kind?: 'module' | 'cross'): Promise<KbListResponse> {\n const qs = kind ? `?kind=${encodeURIComponent(kind)}` : ''\n const r = await fetch(withProject(`/api/knowledge/list${qs}`))\n if (!r.ok) throw new Error(`list failed: ${r.status}`)\n return r.json()\n}\n\nexport async function getKbPage(name: string): Promise<KbPageDetail> {\n const r = await fetch(withProject(`/api/knowledge/page/${encodeURIComponent(name)}`))\n if (r.status === 404) throw new Error('page_not_found')\n if (!r.ok) throw new Error(`page failed: ${r.status}`)\n return r.json()\n}\n\nexport async function queryKb(opts: {\n q: string\n strategy?: 'keyword' | 'rerank'\n pool?: number\n max?: number\n includeContent?: boolean\n}): Promise<KbQueryResponse> {\n const params = new URLSearchParams()\n params.set('q', opts.q)\n if (opts.strategy) params.set('strategy', opts.strategy)\n if (opts.pool != null) params.set('pool', String(opts.pool))\n if (opts.max != null) params.set('max', String(opts.max))\n if (opts.includeContent) params.set('include_content', 'true')\n const r = await fetch(withProject(`/api/knowledge/query?${params.toString()}`))\n if (!r.ok) throw new Error(`query failed: ${r.status}`)\n return r.json()\n}\n\nexport async function queryRepoMap(opts: {\n symbol?: string\n contains?: string\n module?: string\n kind?: string\n max?: number\n}): Promise<RepoMapResponse> {\n const params = new URLSearchParams()\n if (opts.symbol) params.set('symbol', opts.symbol)\n if (opts.contains) params.set('contains', opts.contains)\n if (opts.module) params.set('module', opts.module)\n if (opts.kind) params.set('kind', opts.kind)\n if (opts.max != null) params.set('max', String(opts.max))\n const r = await fetch(withProject(`/api/knowledge/repo-map?${params.toString()}`))\n if (!r.ok) throw new Error(`repo-map failed: ${r.status}`)\n return r.json()\n}\n\nexport async function getAudit(): Promise<AuditResponse> {\n const r = await fetch(withProject('/api/knowledge/audit'))\n if (!r.ok) throw new Error(`audit failed: ${r.status}`)\n return r.json()\n}\n\nexport async function runAuditFix(\n pageName?: string,\n): Promise<{ ok: boolean; summary: any; outcome: any; scope: string | null }> {\n const base = '/api/knowledge/audit/fix'\n const url = pageName\n ? withProject(`${base}?page=${encodeURIComponent(pageName)}`)\n : withProject(base)\n const r = await authFetch(url, { method: 'POST' })\n if (!r.ok) throw new Error(`audit fix failed: ${r.status}`)\n return r.json()\n}\n\nexport async function startBuild(body: StartBuildBody): Promise<{ buildId: string; streamUrl: string }> {\n const r = await authFetch(withProject('/api/knowledge/build'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n if (r.status === 409) throw new Error('build_in_progress')\n if (!r.ok) throw new Error(`build failed: ${r.status}`)\n return r.json()\n}\n\nexport async function getKbStats(): Promise<KbStatsResponse> {\n const r = await fetch(withProject('/api/knowledge/stats'))\n if (!r.ok) throw new Error(`stats failed: ${r.status}`)\n return r.json()\n}\n\nexport interface KbUsageStatsResponse {\n total_calls: number\n by_tool: Record<string, number>\n recent_sessions: string[]\n last_used_at: string | null\n}\n\n/**\n * Fetch usage stats for the current project (default) or an explicit project.\n *\n * When `projectOverride` is provided, that project is used regardless of the\n * URL `?project=` value. Used by the multi-project ranking panel.\n */\nexport async function getKbUsageStats(\n days?: number,\n projectOverride?: string,\n): Promise<KbUsageStatsResponse> {\n const qs = days ? `?days=${days}` : ''\n const baseUrl = `/api/knowledge/usage-stats${qs}`\n const url =\n projectOverride !== undefined\n ? appendProject(baseUrl, projectOverride)\n : withProject(baseUrl)\n const r = await fetch(url)\n if (!r.ok) throw new Error(`usage-stats failed: ${r.status}`)\n return r.json()\n}\n\nexport interface KbBuildReportResponse {\n exists: boolean\n content?: string\n generated_at?: string\n size_bytes?: number\n}\n\n/** Fetch the global build report markdown (`~/.claude-forge/knowledge-build-report.md`). */\nexport async function getKbBuildReport(): Promise<KbBuildReportResponse> {\n const r = await fetch('/api/knowledge/build-report')\n if (!r.ok) throw new Error(`build-report failed: ${r.status}`)\n return r.json()\n}\n\n/** Get current project param from URL (for EventSource etc). */\nexport function getCurrentProject(): string {\n return readProjectFromUrl()\n}\n\n// ─── Build SSE helpers ──────────────────────────────────────────────────────\n\nexport type BuildEventType =\n | 'connected'\n | 'start'\n | 'repo-map'\n | 'module'\n | 'cross-module'\n | 'done'\n | 'error'\n\nexport interface BuildEvent {\n type: BuildEventType\n name?: string\n status?: 'compiling' | 'ok' | 'cached' | 'issues' | 'failed' | string\n modules?: string[]\n symbolCount?: number\n fileCount?: number\n sourceHash?: string\n refsValid?: number\n refsTotal?: number\n durationMs?: number\n cached?: boolean\n force?: boolean\n apply?: boolean\n skipCrossModule?: boolean\n stats?: {\n built: number\n cached: number\n total: number\n crossModuleBuilt?: number\n crossModuleCached?: number\n }\n reportPath?: string\n appliedTo?: string\n message?: string\n step?: string\n}\n\n/** Build the `/api/knowledge/build/:id/stream` URL with project param. */\nexport function buildStreamUrl(buildId: string): string {\n return withProject(`/api/knowledge/build/${encodeURIComponent(buildId)}/stream`)\n}\n\nconst BUILD_EVENT_TYPES: BuildEventType[] = [\n 'connected',\n 'start',\n 'repo-map',\n 'module',\n 'cross-module',\n 'done',\n 'error',\n]\n\n/**\n * Subscribe to a build's SSE stream. Returns a cleanup function that closes\n * the EventSource. The `onEvent` callback receives every parsed event with\n * its `type` populated. `onTerminal` is called once when `done` or `error`\n * arrives (the EventSource is auto-closed in that case).\n */\nexport function subscribeBuild(\n buildId: string,\n handlers: {\n onEvent: (ev: BuildEvent) => void\n onTerminal?: (ev: BuildEvent) => void\n },\n): () => void {\n const es = new EventSource(buildStreamUrl(buildId))\n const dispatch = (type: BuildEventType) => (msg: MessageEvent) => {\n let data: any = {}\n try {\n data = JSON.parse(msg.data || '{}')\n } catch {\n // ignore malformed payload\n }\n const ev: BuildEvent = { ...data, type }\n handlers.onEvent(ev)\n if (type === 'done' || type === 'error') {\n handlers.onTerminal?.(ev)\n es.close()\n }\n }\n for (const t of BUILD_EVENT_TYPES) {\n es.addEventListener(t, dispatch(t))\n }\n return () => es.close()\n}\n\n/**\n * Map raw error messages from `startBuild()` and SSE error payloads to\n * friendly Chinese strings shown in the UI.\n */\nexport function friendlyBuildError(message: string | undefined): string {\n if (!message) return '构建失败,未知错误'\n const m = message.trim()\n if (m === 'build_in_progress') return '已有构建在进行中,请稍后再试'\n if (m === 'unauthorized' || m.startsWith('build failed: 401')) {\n return '未授权:请检查 daemon token 配置'\n }\n if (m.startsWith('build failed: 403')) return '无权限触发构建(403)'\n if (m.startsWith('build failed: 404')) return '构建端点不存在(404),请确认 daemon 版本'\n if (m.startsWith('build failed: 500')) return '后端构建出错(500),请查看 daemon 日志'\n if (m.startsWith('build failed: 503')) return '后端暂时不可用,请稍后再试'\n if (m.toLowerCase().includes('failed to fetch')) return '无法连接 daemon,请确认服务已启动'\n if (m.startsWith('build failed: ')) return `启动构建失败:${m.replace('build failed: ', '')}`\n return m\n}\n","/**\n * Pure picker + DOM wrappers for resolving the default KB project at /knowledge\n * landing time (URL has no ?project=).\n *\n * Priority for picking:\n * (a) localStorage last selection — must still be in projects list and built\n * (b) project flagged `is_current` by daemon and built\n * (c) most recently active by last_event_at (built only)\n * (d) first built project alphabetically (by path) as final fallback\n *\n * pickDefaultProject is pure (no DOM), so it is exhaustively unit-testable\n * without jsdom. readLastProject/writeLastProject wrap localStorage with\n * try/catch to degrade gracefully when storage is disabled.\n */\n\nimport type { KbProject } from './kbApi'\n\nexport const LAST_PROJECT_LS_KEY = 'claude-forge:kb:last-project'\n\nexport interface PickInput {\n projects: KbProject[]\n lastSaved: string | null\n}\n\nexport function pickDefaultProject(input: PickInput): string | null {\n const built = input.projects.filter((p) => p.kb_built)\n if (built.length === 0) return null\n\n if (input.lastSaved) {\n const match = built.find((p) => p.path === input.lastSaved)\n if (match) return match.path\n }\n\n const current = built.find((p) => p.is_current)\n if (current) return current.path\n\n const byRecency = [...built].sort((a, b) => {\n const ta = a.last_event_at ? Date.parse(a.last_event_at) : 0\n const tb = b.last_event_at ? Date.parse(b.last_event_at) : 0\n if (tb !== ta) return tb - ta\n // Stable tie-break: alphabetical by path so test outcomes are deterministic\n // even when all built projects have null last_event_at.\n return a.path.localeCompare(b.path)\n })\n return byRecency[0]?.path ?? null\n}\n\nexport function readLastProject(): string | null {\n if (typeof window === 'undefined') return null\n try {\n return window.localStorage.getItem(LAST_PROJECT_LS_KEY)\n } catch {\n return null\n }\n}\n\nexport function writeLastProject(path: string): void {\n if (typeof window === 'undefined') return\n try {\n window.localStorage.setItem(LAST_PROJECT_LS_KEY, path)\n } catch {\n /* ignore quota / disabled storage */\n }\n}\n","/**\n * Pure project-selection resolution helpers (decision 39839e30).\n *\n * The global project selector's authoritative source is `ProjectContext`\n * (localStorage-persisted via `project.tsx`), NOT the URL `?project=` param.\n * URL persistence alone broke cross-page survival: left-nav `navigate(key)`\n * drops search params, so the selection reset to the daemon-current project on\n * every page switch (Bug 1). These pure helpers encode the resolution + storage\n * contract so it is unit-testable in plain Node without a DOM, mirroring\n * `time-window.tsx` / `kbDefaultProject.ts`.\n *\n * Selection model (a stored selection is one of):\n * - '' (empty) → DEFAULT: scoped to the daemon-current project.\n * - ALL_PROJECTS → user explicitly chose the all-projects view.\n * - '/abs/path' → a concrete project path.\n */\n\nimport { ALL_PROJECTS } from '../utils/kbProject';\n\nexport const PROJECT_STORAGE_KEY = 'cf.project';\n\n/** A persisted project selection. '' = default (daemon current). */\nexport type ProjectSelection = string;\n\n/**\n * Normalise an arbitrary stored / URL value into a valid ProjectSelection.\n * Pure — no DOM access. Trims whitespace; rejects nothing else (a path we do\n * not recognise yet is still a legal selection — the project list may be\n * loading). Falsy / null → '' (default scope).\n */\nexport function normalizeProject(raw: unknown): ProjectSelection {\n if (typeof raw !== 'string') return '';\n const trimmed = raw.trim();\n return trimmed;\n}\n\n/**\n * Resolve the EFFECTIVE project path to send to a per-project backend filter.\n *\n * - selection === ALL_PROJECTS → '' (no filter → all projects; user's\n * explicit choice — distinct from default but identical filter semantics).\n * - selection is a concrete path → that path.\n * - selection === '' (default) → fall back to `daemonCurrent` so the default\n * view is scoped-to-current (matches tasks-hub, decision c4200ef6 / 76a7241a).\n *\n * This is the single source of truth for \"what `?project=` value does the\n * backend receive\", shared by the workplace hook and the per-project pages so\n * the all-projects / default semantics never drift.\n */\nexport function resolveEffectiveProject(\n selection: ProjectSelection,\n daemonCurrent: string,\n): string {\n if (selection === ALL_PROJECTS) return '';\n return selection || daemonCurrent;\n}\n\n/**\n * Resolve the value the <Select> should DISPLAY (its bound value).\n *\n * - ALL_PROJECTS stays the sentinel (so the \"全部项目\" option highlights).\n * - a concrete path stays itself.\n * - '' (default) → daemonCurrent so the dropdown shows the current project\n * rather than an empty box.\n */\nexport function resolveDisplayProject(\n selection: ProjectSelection,\n daemonCurrent: string,\n): string {\n if (selection === ALL_PROJECTS) return selection;\n return selection || daemonCurrent;\n}\n\n/** True when the selection is the explicit all-projects view. */\nexport function isAllProjects(selection: ProjectSelection): boolean {\n return selection === ALL_PROJECTS;\n}\n","/**\n * Global project-selection context — decision 39839e30 (Bug 1 root-cause fix).\n *\n * The project selector previously lived ONLY in the URL `?project=` param\n * (ProjectSwitcher + per-page useSearchParams). Left-nav `navigate(key)` jumps\n * to a bare path and drops search params, so the selection reset to the\n * daemon-current project on every page switch. This context makes the\n * authoritative source a localStorage-persisted value (key `cf.project`) that\n * survives navigation, exactly mirroring `time-window.tsx`.\n *\n * The selection value follows the model in `project-resolve.ts`:\n * - '' → default (scoped to the daemon-current project)\n * - ALL_PROJECTS → explicit all-projects view\n * - '/abs/path' → a concrete project\n *\n * The pure helpers (`normalizeProject`, `resolveEffectiveProject`, …) live in\n * project-resolve.ts so the storage/resolution contract is unit-testable\n * without a DOM.\n */\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n type ReactNode,\n} from 'react'\nimport {\n normalizeProject,\n PROJECT_STORAGE_KEY,\n type ProjectSelection,\n} from './project-resolve'\n\nfunction readStored(): ProjectSelection {\n if (typeof window === 'undefined') return ''\n try {\n return normalizeProject(window.localStorage.getItem(PROJECT_STORAGE_KEY))\n } catch {\n return ''\n }\n}\n\ninterface ProjectContextValue {\n /** Raw stored selection: '' (default) | ALL_PROJECTS | '/abs/path'. */\n project: ProjectSelection\n setProject: (p: ProjectSelection) => void\n}\n\nconst ProjectContext = createContext<ProjectContextValue | null>(null)\n\nexport function ProjectProvider({ children }: { children: ReactNode }) {\n const [project, setProjectState] = useState<ProjectSelection>(() => readStored())\n\n const setProject = useCallback((p: ProjectSelection) => {\n setProjectState(normalizeProject(p))\n }, [])\n\n useEffect(() => {\n try {\n window.localStorage.setItem(PROJECT_STORAGE_KEY, project)\n } catch {\n /* localStorage unavailable (private mode / SSR) — ignore. */\n }\n }, [project])\n\n const value = useMemo<ProjectContextValue>(\n () => ({ project, setProject }),\n [project, setProject],\n )\n\n return <ProjectContext.Provider value={value}>{children}</ProjectContext.Provider>\n}\n\n/**\n * Consume the global project selection. Throws if used outside a provider so\n * missing wiring fails loudly rather than silently defaulting.\n */\nexport function useProject(): ProjectContextValue {\n const ctx = useContext(ProjectContext)\n if (!ctx) {\n throw new Error('useProject must be used within a <ProjectProvider>')\n }\n return ctx\n}\n","/**\n * ProjectSwitcher (v9.5 → 2026-05-26 Arco-ified)\n *\n * Top-of-page dropdown for switching the KB project context.\n * Persists selection in URL (?project=<path>), invalidates all KB\n * queries on change so every tab refetches with the new project.\n *\n * Hotfix: previously invalidated ['kb'] which never matched any actual\n * query key ('kb-list', 'kb-page', 'kb-audit', 'kb-stats'). Now we\n * invalidate each known prefix from KB_QUERY_PREFIXES, AND we strip\n * page-detail-specific URL params (?page=) so the new project doesn't\n * try to load a page name that only exists in the previous project.\n *\n * 2026-05-26 polish: native <select> → Arco <Select> + lucide → Arco icons.\n * lucide-react stays in package.json (4 other components still use it).\n */\n\nimport { useEffect } from 'react'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { useSearchParams } from 'react-router-dom'\nimport Select from '@arco-design/web-react/es/Select'\nimport { IconStorage, IconCheck } from '@arco-design/web-react/icon'\nimport { listKbProjects, type KbProject } from '../utils/kbApi'\nimport { KB_QUERY_PREFIXES, kbProjectsKey, ALL_PROJECTS } from '../utils/kbProject'\nimport { writeLastProject } from '../utils/kbDefaultProject'\nimport { useProject } from '../lib/project'\nimport { resolveDisplayProject, isAllProjects } from '../lib/project-resolve'\n\nconst Option = Select.Option\n\ninterface ProjectSwitcherProps {\n /** Show projects without .forge-knowledge/ built (default: false). */\n showAll?: boolean\n /**\n * Render an explicit \"全部项目\" (all-projects) option in the dropdown.\n * Pages that scope their queries per-project (e.g. tasks-hub) opt in so the\n * user can deliberately choose the all-projects view; selecting it writes the\n * `__all__` sentinel to `?project=` (distinct from \"no param\" = default\n * scoped-to-current). Default false to keep KB pages unchanged. (decision c4200ef6)\n */\n showAllProjectsOption?: boolean\n}\n\nexport function ProjectSwitcher({ showAll = false, showAllProjectsOption = false }: ProjectSwitcherProps) {\n const { data, isLoading } = useQuery({\n queryKey: kbProjectsKey(),\n queryFn: listKbProjects,\n staleTime: 30_000,\n })\n const [searchParams, setSearchParams] = useSearchParams()\n const queryClient = useQueryClient()\n // Authoritative source for the selection is the ProjectContext (localStorage-\n // persisted), so the choice survives left-nav `navigate(key)` that drops\n // search params (Bug 1, decision 39839e30). The URL `?project=` is a MIRROR\n // kept for deep-link / share, not the source of truth.\n const { project: selection, setProject } = useProject()\n\n // Deep-link adoption: if the URL carries an explicit ?project= but context is\n // still on the default, hydrate context from the URL once (e.g. someone\n // opened a shared link). After that, context drives the URL — not vice versa.\n const rawParam = searchParams.get('project') ?? ''\n useEffect(() => {\n if (rawParam && rawParam !== selection) {\n setProject(rawParam)\n }\n // Only re-run when the URL param changes; we intentionally do NOT depend on\n // `selection` so context→URL writes (below) don't loop back into here.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [rawParam])\n\n const isAllSelected = isAllProjects(selection)\n const currentDaemon = data?.current ?? ''\n // Select's bound value: an explicit all → the sentinel; an explicit project →\n // that path; otherwise (default) → scoped to the current daemon project, so\n // display and query stay consistent. (decision c4200ef6 / 39839e30)\n const effectiveCurrent = resolveDisplayProject(selection, currentDaemon)\n\n const allProjects: KbProject[] = data?.projects ?? []\n const projects = allProjects.filter((p) => showAll || p.kb_built)\n\n const onChange = (newPath: string) => {\n // 1) Write the authoritative context value (survives page switches).\n setProject(newPath)\n // 2) Mirror to the URL so deep-link / share / refresh still reflect it.\n const next = new URLSearchParams(searchParams)\n if (newPath === ALL_PROJECTS) {\n next.set('project', ALL_PROJECTS)\n } else if (newPath) {\n next.set('project', newPath)\n } else {\n next.delete('project')\n }\n // Hotfix: clear ?page= so KbPages doesn't try to fetch a page that\n // only existed in the previous project (the cause of \"page_not_found\"\n // toast on project switch).\n next.delete('page')\n setSearchParams(next)\n // Persist only a concrete project path as the \"last project\"; the all\n // sentinel is a view-mode, not a project, so it must not be remembered.\n if (newPath && newPath !== ALL_PROJECTS) writeLastProject(newPath)\n for (const prefix of KB_QUERY_PREFIXES) {\n queryClient.invalidateQueries({ queryKey: prefix })\n }\n }\n\n if (isLoading) {\n return (\n <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, color: 'var(--color-text-3)' }}>\n <IconStorage style={{ fontSize: 14 }} />\n <span>Loading projects...</span>\n </div>\n )\n }\n\n if (projects.length === 0) {\n return (\n <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, color: 'var(--color-text-3)' }}>\n <IconStorage style={{ fontSize: 14 }} />\n <span style={{ fontFamily: 'monospace' }}>{effectiveCurrent || 'no project'}</span>\n <span style={{ fontSize: 11, color: 'var(--color-text-4)' }}>(KB not built)</span>\n </div>\n )\n }\n\n const currentProject = projects.find((p) => p.path === effectiveCurrent)\n const isBuilt = !!currentProject?.kb_built\n\n return (\n <div\n style={{ display: 'flex', alignItems: 'center', gap: 8 }}\n title=\"切换知识库项目(每个项目独立缓存,切换后会自动刷新页面列表)\"\n >\n <IconStorage style={{ fontSize: 14, color: 'var(--color-text-3)' }} />\n <Select\n value={effectiveCurrent}\n onChange={(v: string) => onChange(v)}\n size=\"small\"\n style={{ width: 240, fontFamily: 'monospace' }}\n >\n {showAllProjectsOption && (\n <Option key={ALL_PROJECTS} value={ALL_PROJECTS}>\n 全部项目\n </Option>\n )}\n {projects.map((p) => (\n <Option key={p.path} value={p.path}>\n {p.name} {p.kb_built ? `(${p.page_count})` : '(empty)'}\n {p.is_current && p.path === currentDaemon ? ' • current' : ''}\n </Option>\n ))}\n </Select>\n {effectiveCurrent && !isAllSelected && (\n <span\n style={{\n fontSize: 11,\n display: 'inline-flex',\n alignItems: 'center',\n gap: 2,\n color: isBuilt ? 'var(--color-success-6, #52c41a)' : 'var(--color-text-4)',\n }}\n >\n {isBuilt ? (\n <>\n <IconCheck style={{ fontSize: 11 }} />\n built\n </>\n ) : (\n 'not built'\n )}\n </span>\n )}\n </div>\n )\n}\n","/**\n * SQLite stores ISO timestamps without 'Z' suffix.\n * JS `new Date()` treats such strings as local time, causing an offset.\n * This helper ensures the timestamp is always parsed as UTC.\n *\n * @deprecated Use parseTimestamp() for new code.\n */\nexport function parseUTC(timestamp: string | null | undefined): Date {\n if (!timestamp) return new Date(0);\n const s = timestamp.trim();\n if (s.endsWith('Z') || /[+-]\\d{2}:\\d{2}$/.test(s)) {\n return new Date(s);\n }\n return new Date(s + 'Z');\n}\n\n// ─── Mirrored from src/core/utils/time.ts (spec 1635) ─────────────────────\n// Browser-compatible: no process.env, no Node-only APIs.\n\n/**\n * 归一化时间戳,确保带 Z 后缀\n */\nfunction normalizeTimestamp(timestamp: string): string {\n if (!timestamp) return new Date().toISOString();\n return timestamp.endsWith('Z') ? timestamp : timestamp + 'Z';\n}\n\n/**\n * 将\"可能 naive 的 UTC ISO 串\"安全转换为 Date 实例。\n * string 入参走 normalizeTimestamp 补 Z;number 入参直通 new Date(n)(毫秒值)。\n * 非法输入返回 epoch(不抛错)。\n *\n * 例:'2026-05-27T08:24:13.123' (naive UTC) → Date 表示 16:24 local (UTC+8)\n */\nexport function parseTimestamp(ts: string | number): Date {\n if (typeof ts === 'number') {\n return new Date(ts);\n }\n try {\n return new Date(normalizeTimestamp(ts));\n } catch {\n return new Date(0);\n }\n}\n\nfunction pad2(n: number): string {\n return n < 10 ? `0${n}` : `${n}`;\n}\n\n/**\n * 格式化为本地时区显示,默认 `2026-05-27 16:24 CST`。\n * opts.includeSeconds: 输出 `2026-05-27 16:24:13 CST`\n * opts.dateOnly: 输出 `2026-05-27`\n * opts.tzSuffix: 默认 'CST';传 '' 跳过后缀\n * 非法输入返回 '—'。\n */\nexport function formatLocalDisplay(\n ts: string | number,\n opts?: { includeSeconds?: boolean; dateOnly?: boolean; tzSuffix?: string },\n): string {\n try {\n const d = parseTimestamp(ts);\n if (isNaN(d.getTime())) return '—';\n const yyyy = d.getFullYear();\n const mm = pad2(d.getMonth() + 1);\n const dd = pad2(d.getDate());\n if (opts?.dateOnly) return `${yyyy}-${mm}-${dd}`;\n const hh = pad2(d.getHours());\n const min = pad2(d.getMinutes());\n const base = `${yyyy}-${mm}-${dd} ${hh}:${min}`;\n const withSec = opts?.includeSeconds ? `:${pad2(d.getSeconds())}` : '';\n const suffix = opts?.tzSuffix !== undefined ? opts.tzSuffix : 'CST';\n return suffix ? `${base}${withSec} ${suffix}` : `${base}${withSec}`;\n } catch {\n return '—';\n }\n}\n\n/**\n * 格式化为 UTC 显示,`2026-05-27 08:24 UTC`。\n * opts.includeSeconds: 加 `:13`\n * opts.dateOnly: 仅 `2026-05-27`(UTC 日期)\n * 非法输入返回 '—'。\n */\nexport function formatUTCDisplay(\n ts: string | number,\n opts?: { includeSeconds?: boolean; dateOnly?: boolean },\n): string {\n try {\n const d = parseTimestamp(ts);\n if (isNaN(d.getTime())) return '—';\n const yyyy = d.getUTCFullYear();\n const mm = pad2(d.getUTCMonth() + 1);\n const dd = pad2(d.getUTCDate());\n if (opts?.dateOnly) return `${yyyy}-${mm}-${dd}`;\n const hh = pad2(d.getUTCHours());\n const min = pad2(d.getUTCMinutes());\n const base = `${yyyy}-${mm}-${dd} ${hh}:${min}`;\n const withSec = opts?.includeSeconds ? `:${pad2(d.getUTCSeconds())}` : '';\n return `${base}${withSec} UTC`;\n } catch {\n return '—';\n }\n}\n\n/**\n * 相对时间:`刚刚` / `5 分钟前` / `2 小时前` / `3 天前`。\n * 非法或未来时间返回 '刚刚'。\n */\nexport function formatRelative(ts: string | number): string {\n try {\n const d = parseTimestamp(ts);\n if (isNaN(d.getTime())) return '—';\n const diff = Date.now() - d.getTime();\n const mins = Math.floor(diff / 60000);\n if (mins < 1) return '刚刚';\n if (mins < 60) return `${mins} 分钟前`;\n const hours = Math.floor(mins / 60);\n if (hours < 24) return `${hours} 小时前`;\n return `${Math.floor(hours / 24)} 天前`;\n } catch {\n return '—';\n }\n}\n\n/**\n * 本地日期串(用于文件名),`2026-05-27`(本地时区)。\n * 省略参数时使用 Date.now()。\n */\nexport function formatLocalDateForFilename(ts?: string | number): string {\n const d = ts !== undefined ? parseTimestamp(ts) : new Date();\n if (isNaN(d.getTime())) return formatLocalDateForFilename();\n const yyyy = d.getFullYear();\n const mm = pad2(d.getMonth() + 1);\n const dd = pad2(d.getDate());\n return `${yyyy}-${mm}-${dd}`;\n}\n","/**\n * DaemonBadge — top-bar indicator for daemon liveness.\n *\n * Polls /api/health every 30s and renders a small colored dot + label:\n * green = ALIVE (heartbeat fresh)\n * orange = STALE (heartbeat > 3min ago but PID still alive)\n * red = DEAD (no PID or heartbeat absent)\n *\n * Clicking the badge navigates to /daemon-health.\n *\n * Spec: docs/design/2026-05-28/0843-daemon-watchdog-spec.md §5 Commit 3 Q4\n */\n\nimport { useQuery } from '@tanstack/react-query'\nimport { useNavigate } from 'react-router-dom'\nimport { Tooltip } from '@arco-design/web-react'\nimport { formatRelative } from '../utils/time'\n\ninterface HealthResponse {\n daemon: {\n status: 'alive' | 'stale' | 'dead'\n pid: number | null\n heartbeat_age_ms: number | null\n started_at: number | null\n version: string | null\n }\n}\n\nfunction formatAge(ms: number | null): string {\n if (ms == null) return 'no heartbeat'\n // Convert age-in-ms to a past timestamp, then format relative\n return formatRelative(Date.now() - ms)\n}\n\nconst STATUS_CONFIG = {\n alive: {\n color: '#00b42a', // green\n label: 'Daemon ALIVE',\n dotStyle: { background: '#00b42a' },\n },\n stale: {\n color: '#ff7d00', // orange\n label: 'Daemon STALE',\n dotStyle: { background: '#ff7d00' },\n },\n dead: {\n color: '#f53f3f', // red\n label: 'Daemon DEAD',\n dotStyle: { background: '#f53f3f' },\n },\n} as const\n\nexport default function DaemonBadge() {\n const navigate = useNavigate()\n\n const { data } = useQuery<HealthResponse>({\n queryKey: ['daemon-health'],\n queryFn: async () => {\n const res = await fetch('/api/health')\n if (!res.ok) throw new Error('health check failed')\n return res.json()\n },\n refetchInterval: 30_000,\n retry: false,\n staleTime: 15_000,\n })\n\n const status = data?.daemon?.status ?? 'dead'\n const cfg = STATUS_CONFIG[status]\n const heartbeatAgeMs = data?.daemon?.heartbeat_age_ms ?? null\n const pid = data?.daemon?.pid\n\n const tooltipContent = [\n `Status: ${status.toUpperCase()}`,\n pid != null ? `PID: ${pid}` : 'PID: not running',\n `Heartbeat: ${formatAge(heartbeatAgeMs)}`,\n ].join('\\n')\n\n return (\n <Tooltip\n content={<span style={{ whiteSpace: 'pre-line' }}>{tooltipContent}</span>}\n position=\"bottom\"\n >\n <button\n onClick={() => navigate('/daemon-health')}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: 5,\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n padding: '4px 8px',\n borderRadius: 6,\n color: 'var(--color-text-2)',\n fontSize: 12,\n }}\n aria-label={`daemon-badge-${status}`}\n >\n <span\n style={{\n width: 8,\n height: 8,\n borderRadius: '50%',\n display: 'inline-block',\n ...cfg.dotStyle,\n ...(status === 'alive'\n ? {\n boxShadow: `0 0 0 2px ${cfg.color}33`,\n animation: 'daemon-pulse 2s infinite',\n }\n : {}),\n }}\n />\n <span style={{ color: cfg.color, fontWeight: 500 }}>{status.toUpperCase()}</span>\n </button>\n </Tooltip>\n )\n}\n","/**\n * DoctorBadge — top-bar indicator for `cf doctor` aggregate health.\n *\n * Polls /api/diagnostics every 60s. Colors:\n * green = all checks pass (or only skip)\n * orange = some warn but no fail\n * red = at least one fail\n *\n * Clicking the badge navigates to /diagnostics.\n *\n * Spec: docs/design/2026-06-01/1030-cf-doctor-diagnostic-spec.md\n */\n\nimport { useQuery } from '@tanstack/react-query'\nimport { useNavigate } from 'react-router-dom'\nimport { Tooltip } from '@arco-design/web-react'\n\ninterface DiagnosticsResponse {\n summary: {\n pass: number\n warn: number\n fail: number\n skip: number\n fixable: number\n }\n checks: Array<{ id: number; name: string; status: string }>\n generated_at: string\n}\n\ntype BadgeStatus = 'pass' | 'warn' | 'fail' | 'unknown'\n\nfunction pickStatus(d: DiagnosticsResponse | undefined): BadgeStatus {\n if (!d) return 'unknown'\n if (d.summary.fail > 0) return 'fail'\n if (d.summary.warn > 0) return 'warn'\n return 'pass'\n}\n\nconst STATUS_CONFIG: Record<BadgeStatus, { color: string; label: string }> = {\n pass: { color: '#00b42a', label: 'Doctor OK' },\n warn: { color: '#ff7d00', label: 'Doctor WARN' },\n fail: { color: '#f53f3f', label: 'Doctor FAIL' },\n unknown: { color: '#86909c', label: 'Doctor ?' },\n}\n\nexport default function DoctorBadge() {\n const navigate = useNavigate()\n const { data } = useQuery<DiagnosticsResponse>({\n queryKey: ['diagnostics-badge'],\n queryFn: async () => {\n const res = await fetch('/api/diagnostics')\n if (!res.ok) throw new Error('diagnostics failed')\n return res.json()\n },\n refetchInterval: 60_000,\n retry: false,\n staleTime: 30_000,\n })\n\n const status = pickStatus(data)\n const cfg = STATUS_CONFIG[status]\n\n const tooltipContent = data\n ? [\n `PASS=${data.summary.pass}`,\n `WARN=${data.summary.warn}`,\n `FAIL=${data.summary.fail}`,\n `SKIP=${data.summary.skip}`,\n data.summary.fixable > 0 ? `${data.summary.fixable} fixable` : '',\n ]\n .filter(Boolean)\n .join(' · ')\n : 'Loading diagnostics…'\n\n return (\n <Tooltip content={tooltipContent} position=\"bottom\">\n <button\n onClick={() => navigate('/diagnostics')}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: 5,\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n padding: '4px 8px',\n borderRadius: 6,\n color: 'var(--color-text-2)',\n fontSize: 12,\n }}\n aria-label={`doctor-badge-${status}`}\n >\n <span\n style={{\n width: 8,\n height: 8,\n borderRadius: '50%',\n display: 'inline-block',\n background: cfg.color,\n }}\n />\n <span style={{ color: cfg.color, fontWeight: 500 }}>{cfg.label}</span>\n </button>\n </Tooltip>\n )\n}\n","/**\n * Top-level Arco Layout for claude-forge web.\n *\n * Implements PR3-arco-1 + post-arco-2 cleanup:\n * - <Layout.Sider> with 220↔64 collapse + sectioned <Menu>\n * - <Layout.Header> with brand chip + search + topbar icons + avatar\n * - <Layout.Content> renders <Breadcrumb> + active page <Outlet>\n *\n * Multi-tab UI has been removed (user decision: sidebar-only navigation).\n * Breadcrumb is kept as an independent component driven by breadcrumb-map.\n */\n\nimport { Outlet, useLocation, useNavigate } from 'react-router-dom'\nimport { useCallback, useMemo, useState } from 'react'\nimport {\n Layout as ArcoLayout,\n Menu,\n Breadcrumb,\n Input,\n Space,\n Avatar,\n Tooltip,\n Popover,\n Badge,\n Radio,\n} from '@arco-design/web-react'\nimport { useQuery } from '@tanstack/react-query'\nimport {\n IconBook,\n IconSettings,\n IconSearch,\n IconNotification,\n IconSun,\n IconMoon,\n IconMenuFold,\n IconMenuUnfold,\n IconUser,\n IconDashboard,\n IconList,\n IconExclamationCircle,\n IconBranch,\n IconRobot,\n IconDesktop,\n IconStorage,\n IconCode,\n IconThunderbolt,\n IconBug,\n} from '@arco-design/web-react/icon'\n\nimport {\n resolveRouteMeta,\n ROUTE_META,\n} from '../lib/breadcrumb-map'\nimport {\n NAV_NODES,\n ALL_GROUP_KEYS,\n deriveMenuKey,\n DEFAULT_ROUTE,\n type NavNode,\n} from '../lib/nav-model'\nimport {\n useTimeWindow,\n TIME_WINDOW_OPTIONS,\n} from '../lib/time-window'\nimport { useTheme } from '../lib/theme'\nimport GlobalSearch from './GlobalSearch'\nimport NotificationPanel from './NotificationPanel'\nimport { ProjectSwitcher } from './ProjectSwitcher'\nimport DaemonBadge from './DaemonBadge'\nimport DoctorBadge from './DoctorBadge'\n\nconst { Sider, Header, Content } = ArcoLayout\nconst MenuItem = Menu.Item\nconst SubMenu = Menu.SubMenu\n\nconst PIN_DASHBOARD_KEY = DEFAULT_ROUTE\n\n// --- sidebar icon map --------------------------------------------------------\n\n/**\n * Arco Pro 重设计 IA (Phase 0, decision 29688066): 分组 11 视图。Nav model\n * (NAV_NODES / deriveMenuKey / deriveOpenKeys)抽到纯模块 `lib/nav-model.ts`\n * 以便 node 环境单测;这里只负责渲染(图标 + SubMenu/Item)。\n */\nconst ICON_BY_KEY: Record<string, React.ReactNode> = {\n '/workplace': <IconDashboard />,\n '/tasks': <IconList />,\n 'group:ai': <IconRobot />,\n '/ai/kb': <IconBook />,\n '/ai/skills': <IconThunderbolt />,\n '/ai/agents': <IconCode />,\n '/ai/distill': <IconStorage />,\n 'group:governance': <IconBranch />,\n '/decisions': <IconBranch />,\n '/issues': <IconExclamationCircle />,\n 'group:system': <IconDesktop />,\n '/system/daemon': <IconSettings />,\n '/system/diagnostics': <IconBug />,\n '/system/settings': <IconSettings />,\n}\n\nfunction renderNavNode(node: NavNode): React.ReactNode {\n if (node.kind === 'group') {\n return (\n <SubMenu\n key={node.key}\n title={\n <span>\n {ICON_BY_KEY[node.key]}\n {node.label}\n </span>\n }\n >\n {node.children.map((child) => (\n <MenuItem key={child.key}>\n {ICON_BY_KEY[child.key]}\n {child.label}\n </MenuItem>\n ))}\n </SubMenu>\n )\n }\n return (\n <MenuItem key={node.key}>\n {ICON_BY_KEY[node.key]}\n {node.label}\n </MenuItem>\n )\n}\n\n// --- component ---------------------------------------------------------------\n\nexport default function Layout() {\n const location = useLocation()\n const navigate = useNavigate()\n const [collapsed, setCollapsed] = useState(false)\n const [theme, setTheme] = useTheme()\n const { window: timeWindow, setWindow: setTimeWindow } = useTimeWindow()\n\n // --- menu handlers ---------------------------------------------------------\n\n const menuSelectedKey = useMemo(\n () => deriveMenuKey(location.pathname),\n [location.pathname],\n )\n\n // SubMenu open state: every group is expanded on first load (initial openKeys\n // = ALL_GROUP_KEYS, decision f2654cdb) so all child items are visible at a\n // glance. Controlled state: user toggles (onClickSubMenu) take over from there,\n // so groups can still be collapsed/expanded manually.\n const [openKeys, setOpenKeys] = useState<string[]>(() => [...ALL_GROUP_KEYS])\n\n const handleMenuClick = useCallback(\n (key: string) => {\n // Only leaf route keys navigate; group keys are handled by onClickSubMenu.\n if (key.startsWith('/') && key !== location.pathname) navigate(key)\n },\n [location.pathname, navigate],\n )\n\n // --- breadcrumb ------------------------------------------------------------\n\n const breadcrumbs = useMemo(() => {\n const meta = resolveRouteMeta(location.pathname)\n return meta?.breadcrumbs ?? [{ label: '工作台' }]\n }, [location.pathname])\n\n // --- theme toggle (wired in PR3-arco-4, persisted via lib/theme) -----------\n\n const toggleTheme = useCallback(() => {\n setTheme(theme === 'light' ? 'dark' : 'light')\n }, [theme, setTheme])\n\n // --- topbar search + notifications (PR3-arco-4) ---------------------------\n\n const [searchOpen, setSearchOpen] = useState(false)\n const [notifOpen, setNotifOpen] = useState(false)\n\n // Red dot: any violation OR any critical/warn anti-pattern in past 7d.\n const { data: notifBadge } = useQuery({\n queryKey: ['notifications-badge'],\n queryFn: async (): Promise<{ hasUnread: boolean }> => {\n try {\n const [vRes, iRes] = await Promise.all([\n fetch('/api/violations?days=7&limit=1'),\n fetch('/api/insights?days=7'),\n ])\n const v = vRes.ok ? await vRes.json() : { count: 0 }\n const i = iRes.ok ? await iRes.json() : { summary: { critical: 0, warn: 0 } }\n return {\n hasUnread:\n (v.count ?? 0) > 0 ||\n (i.summary?.critical ?? 0) + (i.summary?.warn ?? 0) > 0,\n }\n } catch {\n return { hasUnread: false }\n }\n },\n refetchInterval: 60000,\n })\n const hasUnread = notifBadge?.hasUnread ?? false\n\n // --- render ----------------------------------------------------------------\n\n return (\n <ArcoLayout style={{ minHeight: '100vh' }}>\n <Sider\n collapsed={collapsed}\n collapsible\n collapsedWidth={64}\n width={220}\n trigger={null}\n breakpoint=\"lg\"\n style={{\n background: 'var(--color-bg-2)',\n borderRight: '1px solid var(--color-border)',\n }}\n >\n <div\n style={{\n height: 64,\n display: 'flex',\n alignItems: 'center',\n justifyContent: collapsed ? 'center' : 'flex-start',\n padding: collapsed ? 0 : '0 20px',\n borderBottom: '1px solid var(--color-border-2)',\n gap: 10,\n }}\n >\n <span className=\"cf-brand-chip\">CF</span>\n {!collapsed && (\n <span style={{ fontSize: 14, fontWeight: 600, color: 'var(--color-text-1)' }}>\n Claude Forge\n </span>\n )}\n </div>\n\n <Menu\n selectedKeys={[menuSelectedKey]}\n openKeys={openKeys}\n mode=\"vertical\"\n onClickMenuItem={handleMenuClick}\n onClickSubMenu={(_key, currentOpenKeys) =>\n setOpenKeys(currentOpenKeys)\n }\n style={{ width: '100%', border: 'none', background: 'transparent' }}\n >\n {NAV_NODES.map((node) => renderNavNode(node))}\n </Menu>\n\n {!collapsed && (\n <div\n style={{\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n padding: '12px 16px',\n borderTop: '1px solid var(--color-border-2)',\n fontSize: 11,\n color: 'var(--color-text-3)',\n display: 'flex',\n justifyContent: 'space-between',\n }}\n >\n <span>claude-forge</span>\n <span style={{ fontFamily: 'monospace' }}>v{__APP_VERSION__}</span>\n </div>\n )}\n </Sider>\n\n <ArcoLayout>\n <Header\n style={{\n height: 60,\n background: 'var(--color-bg-2)',\n borderBottom: '1px solid var(--color-border)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '0 20px',\n }}\n >\n <Space size={12}>\n <Tooltip content={collapsed ? '展开侧栏' : '收起侧栏'}>\n <button\n onClick={() => setCollapsed((c) => !c)}\n style={{\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n color: 'var(--color-text-2)',\n padding: 6,\n display: 'inline-flex',\n alignItems: 'center',\n }}\n aria-label=\"toggle-sider\"\n >\n {collapsed ? <IconMenuUnfold /> : <IconMenuFold />}\n </button>\n </Tooltip>\n <Popover\n trigger=\"click\"\n position=\"bl\"\n popupVisible={searchOpen}\n onVisibleChange={setSearchOpen}\n content={\n <GlobalSearch onNavigate={() => setSearchOpen(false)} />\n }\n >\n <Input.Search\n placeholder=\"搜索 sessions / tasks / 知识库...\"\n style={{ width: 280 }}\n allowClear\n readOnly\n prefix={<IconSearch />}\n onClick={() => setSearchOpen(true)}\n />\n </Popover>\n {/* 项目选择器(Phase 0:复用既有 ProjectSwitcher,占位单项目) */}\n <ProjectSwitcher showAllProjectsOption />\n </Space>\n\n <Space size={16}>\n {/* 全局时间窗 7d/30d/90d(Phase 0:TimeWindowContext,供后续页消费) */}\n <Radio.Group\n type=\"button\"\n size=\"small\"\n value={timeWindow}\n onChange={(v) => setTimeWindow(v)}\n aria-label=\"time-window\"\n >\n {TIME_WINDOW_OPTIONS.map((opt) => (\n <Radio key={opt} value={opt}>\n {opt}d\n </Radio>\n ))}\n </Radio.Group>\n {/* Daemon health badge (watchdog spec 0843) */}\n <DaemonBadge />\n {/* Doctor diagnostic badge (spec 1a41b43a) */}\n <DoctorBadge />\n <Popover\n trigger=\"click\"\n position=\"br\"\n popupVisible={notifOpen}\n onVisibleChange={setNotifOpen}\n content={\n <NotificationPanel onClose={() => setNotifOpen(false)} />\n }\n >\n <Tooltip content=\"通知\">\n <button\n style={{\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n color: 'var(--color-text-2)',\n padding: 6,\n display: 'inline-flex',\n alignItems: 'center',\n }}\n aria-label=\"notifications\"\n >\n <Badge dot={hasUnread} count={0} offset={[-2, 2]}>\n <IconNotification />\n </Badge>\n </button>\n </Tooltip>\n </Popover>\n <Tooltip content={theme === 'light' ? '切换深色主题' : '切换浅色主题'}>\n <button\n onClick={toggleTheme}\n style={{\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n color: 'var(--color-text-2)',\n padding: 6,\n display: 'inline-flex',\n alignItems: 'center',\n }}\n aria-label=\"toggle-theme\"\n >\n {theme === 'light' ? <IconMoon /> : <IconSun />}\n </button>\n </Tooltip>\n <Avatar\n size={32}\n style={{ background: 'linear-gradient(135deg,#165DFF,#722ED1)' }}\n >\n <IconUser />\n </Avatar>\n </Space>\n </Header>\n\n <Content\n style={{\n padding: 0,\n background: 'var(--color-bg-2)',\n display: 'flex',\n flexDirection: 'column',\n minHeight: 'calc(100vh - 60px)',\n }}\n >\n <div style={{ padding: '12px 20px 0' }}>\n <Breadcrumb>\n {breadcrumbs.map((c, i) =>\n c.path ? (\n <Breadcrumb.Item key={`${c.label}-${i}`}>\n <a\n onClick={(e) => {\n e.preventDefault()\n if (c.path) navigate(c.path)\n }}\n href={c.path}\n style={{ color: 'var(--color-text-2)' }}\n >\n {c.label}\n </a>\n </Breadcrumb.Item>\n ) : (\n <Breadcrumb.Item key={`${c.label}-${i}`}>{c.label}</Breadcrumb.Item>\n ),\n )}\n </Breadcrumb>\n </div>\n\n <div style={{ padding: '16px 20px 24px', flex: 1 }}>\n <Outlet />\n </div>\n </Content>\n </ArcoLayout>\n </ArcoLayout>\n )\n}\n\n// Surface the known-routes set for tests / dev tools.\nexport { ROUTE_META, PIN_DASHBOARD_KEY }\n","/**\n * RouteErrorBoundary — defense-in-depth for lazy route rendering.\n *\n * Wraps the lazy page tree so that an uncaught render throw OR a failed lazy\n * chunk load (stale/404 bundle after a fresh build) degrades to a friendly\n * \"加载失败,请刷新\" panel instead of a blank white screen.\n *\n * This is a class component because React error boundaries can only be\n * expressed as classes (getDerivedStateFromError / componentDidCatch). Arco is\n * used for the fallback UI — no prototype Tailwind.\n */\nimport { Component, type ErrorInfo, type ReactNode } from 'react'\n\nimport Result from '@arco-design/web-react/es/Result'\nimport Button from '@arco-design/web-react/es/Button'\n\ninterface Props {\n children: ReactNode\n}\n\ninterface State {\n hasError: boolean\n error: Error | null\n}\n\nexport default class RouteErrorBoundary extends Component<Props, State> {\n state: State = { hasError: false, error: null }\n\n static getDerivedStateFromError(error: Error): State {\n return { hasError: true, error }\n }\n\n componentDidCatch(error: Error, info: ErrorInfo): void {\n // Surface to the console so the failure isn't silent; no telemetry backend.\n // eslint-disable-next-line no-console\n console.error('[RouteErrorBoundary] route render failed:', error, info)\n }\n\n handleReload = (): void => {\n // A failed lazy chunk almost always means a stale bundle; a hard reload\n // re-fetches the current index.html + its chunk graph.\n window.location.reload()\n }\n\n render(): ReactNode {\n if (this.state.hasError) {\n return (\n <div style={{ padding: 16 }}>\n <Result\n status=\"error\"\n title=\"页面加载失败\"\n subTitle={\n this.state.error?.message ||\n '资源加载异常,可能是版本已更新。请刷新页面重试。'\n }\n extra={\n <Button type=\"primary\" onClick={this.handleReload}>\n 刷新页面\n </Button>\n }\n />\n </div>\n )\n }\n return this.props.children\n }\n}\n","import { lazy, Suspense, type ReactNode } from 'react'\nimport { Routes, Route, Navigate } from 'react-router-dom'\nimport Layout from './components/Layout'\nimport RouteErrorBoundary from './components/RouteErrorBoundary'\n\n// ── Arco Pro 重设计 IA (decision 29688066) ────────────────────────────────────\n// 分组 11 视图 + 各整页详情路由。Phase 4c 收尾:所有视图均已是真实页,旧\n// 遗留页 / 旧 IA 回退跳转 / Phase 0 占位组件已全部删除(core-belief\n// 「不留 deprecated wrapper」;旧外链不兜底重定向)。\n//\n// 路由前缀分组:\n// /workplace 工作台 (Phase 1)\n// /tasks 任务列表 (Phase 2a — 暂复用现有 TasksHubPage)\n// /tasks/:taskId 任务详情整页 (Phase 2a)\n// /ai/kb /ai/kb/:name KB 命中 / 详情 (Phase 2b)\n// /ai/skills /ai/skills/:id Skill 调用 / 详情 (Phase 2b)\n// /ai/agents /ai/agents/:name Agent 委托/详情 (Phase 2b)\n// /ai/distill 蒸馏列表 (Phase 2c)\n// /ai/distill/run 执行蒸馏向导 (Phase 2c)\n// /ai/distill/:topicId 蒸馏详情 (Phase 2c)\n// /decisions /decisions/:id 决策 / 详情整页 (Phase 3)\n// /issues /issues/:id 问题 / 详情整页 (Phase 3)\n// /system/daemon Daemon (Phase 4 — 暂复用 DaemonHealthPage)\n// /system/diagnostics 诊断 (Phase 4 — 暂复用 DiagnosticsPage)\n// /system/settings 设置 (Phase 4)\n\n// 工作台 (Phase 1, decision 29688066)。\nconst WorkplacePage = lazy(() => import('./pages/WorkplacePage'))\n// 任务详情整页 (Phase 2a, decision 29688066)。\nconst TaskDetailPage = lazy(() => import('./pages/TaskDetailPage'))\n// AI 资源 · KB 命中列表 + 详情 (Phase 2b, decision 29688066)。\nconst KbHitsPage = lazy(() => import('./pages/ai/KbHitsPage'))\nconst KbDetailPage = lazy(() => import('./pages/ai/KbDetailPage'))\n// AI 资源 · Skill 调用列表 + 详情 (Phase 2c, decision 29688066)。\nconst SkillsPage = lazy(() => import('./pages/ai/SkillsPage'))\nconst SkillDetailPage = lazy(() => import('./pages/ai/SkillDetailPage'))\n// AI 资源 · Agent 委托列表 + 详情 (Phase 2d, decision 29688066)。\nconst AgentsPage = lazy(() => import('./pages/ai/AgentsPage'))\nconst AgentDetailPage = lazy(() => import('./pages/ai/AgentDetailPage'))\n// AI 资源 · 蒸馏列表 + 详情 (Phase 2e, decision 29688066)。\n// 执行向导 /ai/distill/run (Phase 2f) — 接真实 init/run + SSE 流。\nconst DistillPage = lazy(() => import('./pages/ai/DistillPage'))\nconst DistillDetailPage = lazy(() => import('./pages/ai/DistillDetailPage'))\nconst DistillRunPage = lazy(() => import('./pages/ai/DistillRunPage'))\n// AI 资源 · Agent 进化向导 /ai/agents/:name/distill (Q1 闭环, decision 568a8c53)。\nconst AgentDistillRunPage = lazy(() => import('./pages/ai/AgentDistillRunPage'))\n// 治理 · 决策列表 + 详情整页 (Phase 3a, decision 29688066)。\nconst DecisionsPage = lazy(() => import('./pages/DecisionsPage'))\nconst DecisionDetailPage = lazy(() => import('./pages/DecisionDetailPage'))\n// 治理 · 问题列表 + 详情整页 (Phase 3b, decision 29688066)。\n// 前端 merge 三源(/api/violations + /api/tasks failed + /api/drift/report),零新后端。\nconst IssuesPage = lazy(() => import('./pages/IssuesPage'))\nconst IssueDetailPage = lazy(() => import('./pages/IssueDetailPage'))\n// 任务列表 + 系统页(Daemon / 诊断,视觉对齐在 Phase 4b 落地)。\nconst TasksHubPage = lazy(() => import('./pages/TasksHubPage'))\nconst DaemonHealthPage = lazy(() => import('./pages/DaemonHealthPage'))\nconst DiagnosticsPage = lazy(() => import('./pages/DiagnosticsPage'))\n// 系统 · 设置可写 (Phase 4a, decision 29688066)。\n// 读 GET /api/config、写 POST /api/config(白名单 + 校验 + needsRestart)。\nconst SettingsPage = lazy(() => import('./pages/SettingsPage'))\nconst NotFound = lazy(() => import('./components/NotFound'))\n\nfunction PageFallback() {\n return (\n <div className=\"flex items-center justify-center h-full py-16\">\n <div className=\"flex items-center gap-3 text-sm text-gray-500\">\n <div className=\"w-4 h-4 border-2 border-gray-300 border-t-blue-500 rounded-full animate-spin\" />\n 加载中...\n </div>\n </div>\n )\n}\n\n/**\n * Wrap a lazy page in the shared Suspense fallback + an error boundary.\n *\n * The Suspense boundary is MANDATORY for every `lazy()` element: a lazy\n * component suspends on first render (before its chunk loads), and with no\n * enclosing <Suspense> React throws an uncaught error → blank white screen on\n * first open (the chunk is cached on subsequent visits, masking the bug). The\n * RouteErrorBoundary additionally catches a failed chunk fetch (stale/404\n * bundle) and degrades to a \"刷新页面\" panel instead of white-screening.\n *\n * Do NOT mount a lazy() route element bare (without <Lazy>) — see\n * tests/unit/web/app-lazy-routes-contract.test.ts which locks this invariant.\n */\nfunction Lazy({ children }: { children: ReactNode }) {\n return (\n <RouteErrorBoundary>\n <Suspense fallback={<PageFallback />}>{children}</Suspense>\n </RouteErrorBoundary>\n )\n}\n\nexport default function App() {\n return (\n <Routes>\n <Route path=\"/\" element={<Layout />}>\n {/* index → /workplace (新默认) */}\n <Route index element={<Navigate to=\"/workplace\" replace />} />\n\n {/* ── 工作台 (Phase 1) ────────────────────────────────────────── */}\n <Route path=\"workplace\" element={<Lazy><WorkplacePage /></Lazy>} />\n\n {/* ── 任务 ─────────────────────────────────────────────────────\n TasksHubPage 列表(保留窗口级 KPI 聚合);任务详情整页化已在\n Phase 2a 落地,点行进 /tasks/:taskId。 */}\n <Route path=\"tasks\" element={<Lazy><TasksHubPage /></Lazy>} />\n <Route path=\"tasks/:taskId\" element={<Lazy><TaskDetailPage /></Lazy>} />\n\n {/* ── AI 资源四页 (Phase 2b/2c) ─────────────────────────────────── */}\n <Route path=\"ai/kb\" element={<Lazy><KbHitsPage /></Lazy>} />\n <Route path=\"ai/kb/:name\" element={<Lazy><KbDetailPage /></Lazy>} />\n <Route path=\"ai/skills\" element={<Lazy><SkillsPage /></Lazy>} />\n <Route path=\"ai/skills/:id\" element={<Lazy><SkillDetailPage /></Lazy>} />\n <Route path=\"ai/agents\" element={<Lazy><AgentsPage /></Lazy>} />\n <Route path=\"ai/agents/:name\" element={<Lazy><AgentDetailPage /></Lazy>} />\n <Route path=\"ai/agents/:name/distill\" element={<Lazy><AgentDistillRunPage /></Lazy>} />\n <Route path=\"ai/distill\" element={<Lazy><DistillPage /></Lazy>} />\n {/* /run 必须排在 /:topicId 之前以正确匹配向导路由(Phase 2f 接真实 init/run + SSE) */}\n <Route path=\"ai/distill/run\" element={<Lazy><DistillRunPage /></Lazy>} />\n <Route path=\"ai/distill/:topicId\" element={<Lazy><DistillDetailPage /></Lazy>} />\n\n {/* ── 治理两页 (Phase 3) ──────────────────────────────────────────\n 决策(列表 + 整页详情)已在 Phase 3a 落地(接 /api/decisions[/:id]);\n 问题(列表 + 整页详情)已在 Phase 3b 落地(前端 merge 三源,零新后端)。 */}\n <Route path=\"decisions\" element={<Lazy><DecisionsPage /></Lazy>} />\n <Route path=\"decisions/:id\" element={<Lazy><DecisionDetailPage /></Lazy>} />\n <Route path=\"issues\" element={<Lazy><IssuesPage /></Lazy>} />\n <Route path=\"issues/:id\" element={<Lazy><IssueDetailPage /></Lazy>} />\n\n {/* ── 系统三页 ──────────────────────────────────────────────────\n Phase 0 暂复用现有 Daemon/Diagnostics 页(视觉对齐在 Phase 4b);\n 设置已在 Phase 4a 落地为可写(接 GET/POST /api/config)。 */}\n <Route path=\"system/daemon\" element={<Lazy><DaemonHealthPage /></Lazy>} />\n <Route path=\"system/diagnostics\" element={<Lazy><DiagnosticsPage /></Lazy>} />\n <Route path=\"system/settings\" element={<Lazy><SettingsPage /></Lazy>} />\n\n {/* === catch-all 404 === */}\n <Route path=\"*\" element={<Lazy><NotFound /></Lazy>} />\n </Route>\n </Routes>\n )\n}\n","import { createContext, useContext, useState, useCallback, ReactNode } from 'react'\nimport { CheckCircle, XCircle, AlertCircle, Info, X } from 'lucide-react'\nimport clsx from 'clsx'\n\ntype ToastType = 'success' | 'error' | 'warning' | 'info'\n\ninterface Toast {\n id: number\n type: ToastType\n message: string\n}\n\ninterface ToastContextValue {\n show: (type: ToastType, message: string) => void\n success: (message: string) => void\n error: (message: string) => void\n warning: (message: string) => void\n info: (message: string) => void\n}\n\nconst ToastContext = createContext<ToastContextValue | null>(null)\n\nexport function useToast() {\n const ctx = useContext(ToastContext)\n if (!ctx) throw new Error('useToast must be used within ToastProvider')\n return ctx\n}\n\nlet nextId = 1\n\nexport function ToastProvider({ children }: { children: ReactNode }) {\n const [toasts, setToasts] = useState<Toast[]>([])\n\n const remove = useCallback((id: number) => {\n setToasts(prev => prev.filter(t => t.id !== id))\n }, [])\n\n const show = useCallback((type: ToastType, message: string) => {\n const id = nextId++\n setToasts(prev => [...prev, { id, type, message }])\n setTimeout(() => remove(id), 4000)\n }, [remove])\n\n const value: ToastContextValue = {\n show,\n success: (msg) => show('success', msg),\n error: (msg) => show('error', msg),\n warning: (msg) => show('warning', msg),\n info: (msg) => show('info', msg),\n }\n\n return (\n <ToastContext.Provider value={value}>\n {children}\n <div className=\"fixed top-4 right-4 z-[9999] space-y-2 max-w-md\">\n {toasts.map(t => (\n <ToastItem key={t.id} toast={t} onClose={() => remove(t.id)} />\n ))}\n </div>\n </ToastContext.Provider>\n )\n}\n\nfunction ToastItem({ toast, onClose }: { toast: Toast; onClose: () => void }) {\n const icons = {\n success: <CheckCircle className=\"h-5 w-5 text-green-500\" />,\n error: <XCircle className=\"h-5 w-5 text-red-500\" />,\n warning: <AlertCircle className=\"h-5 w-5 text-yellow-500\" />,\n info: <Info className=\"h-5 w-5 text-blue-500\" />,\n }\n const borderColors = {\n success: 'border-green-200',\n error: 'border-red-200',\n warning: 'border-yellow-200',\n info: 'border-blue-200',\n }\n\n return (\n <div\n className={clsx(\n 'bg-white shadow-lg rounded-lg border px-4 py-3 flex items-start gap-3 animate-in slide-in-from-right',\n borderColors[toast.type]\n )}\n >\n {icons[toast.type]}\n <div className=\"flex-1 text-sm text-gray-800\">{toast.message}</div>\n <button onClick={onClose} className=\"text-gray-400 hover:text-gray-600\">\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n )\n}\n","import { createContext, useContext, useState, useCallback, ReactNode } from 'react'\nimport { AlertTriangle } from 'lucide-react'\n\ninterface ConfirmOptions {\n title: string\n message: string\n confirmText?: string\n cancelText?: string\n variant?: 'danger' | 'warning' | 'info'\n}\n\ninterface ConfirmContextValue {\n confirm: (options: ConfirmOptions) => Promise<boolean>\n}\n\nconst ConfirmContext = createContext<ConfirmContextValue | null>(null)\n\nexport function useConfirm() {\n const ctx = useContext(ConfirmContext)\n if (!ctx) throw new Error('useConfirm must be used within ConfirmProvider')\n return ctx.confirm\n}\n\nexport function ConfirmProvider({ children }: { children: ReactNode }) {\n const [state, setState] = useState<{\n open: boolean\n options: ConfirmOptions | null\n resolve: ((value: boolean) => void) | null\n }>({ open: false, options: null, resolve: null })\n\n const confirm = useCallback((options: ConfirmOptions): Promise<boolean> => {\n return new Promise((resolve) => {\n setState({ open: true, options, resolve })\n })\n }, [])\n\n const handleClose = (result: boolean) => {\n if (state.resolve) state.resolve(result)\n setState({ open: false, options: null, resolve: null })\n }\n\n const variant = state.options?.variant || 'danger'\n const iconColor = {\n danger: 'text-red-600',\n warning: 'text-yellow-600',\n info: 'text-blue-600',\n }[variant]\n const btnColor = {\n danger: 'bg-red-600 hover:bg-red-700',\n warning: 'bg-yellow-600 hover:bg-yellow-700',\n info: 'bg-indigo-600 hover:bg-indigo-700',\n }[variant]\n\n return (\n <ConfirmContext.Provider value={{ confirm }}>\n {children}\n {state.open && state.options && (\n <div className=\"fixed inset-0 z-[9999] flex items-center justify-center\">\n <div\n className=\"absolute inset-0 bg-black bg-opacity-50\"\n onClick={() => handleClose(false)}\n />\n <div className=\"relative bg-white rounded-lg shadow-xl max-w-md w-full mx-4 p-6\">\n <div className=\"flex items-start gap-4\">\n <div className={`flex-shrink-0 ${iconColor}`}>\n <AlertTriangle className=\"h-6 w-6\" />\n </div>\n <div className=\"flex-1\">\n <h3 className=\"text-lg font-semibold text-gray-900 mb-2\">\n {state.options.title}\n </h3>\n <p className=\"text-sm text-gray-600 whitespace-pre-wrap\">\n {state.options.message}\n </p>\n </div>\n </div>\n <div className=\"flex justify-end gap-2 mt-6\">\n <button\n onClick={() => handleClose(false)}\n className=\"px-4 py-2 text-sm text-gray-700 bg-white border border-gray-300 rounded hover:bg-gray-50\"\n >\n {state.options.cancelText || '取消'}\n </button>\n <button\n onClick={() => handleClose(true)}\n className={`px-4 py-2 text-sm text-white rounded ${btnColor}`}\n >\n {state.options.confirmText || '确定'}\n </button>\n </div>\n </div>\n </div>\n )}\n </ConfirmContext.Provider>\n )\n}\n","import React from 'react'\nimport ReactDOM from 'react-dom/client'\nimport { BrowserRouter } from 'react-router-dom'\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query'\nimport { ConfigProvider } from '@arco-design/web-react'\nimport zhCN from '@arco-design/web-react/es/locale/zh-CN'\nimport App from './App'\nimport { ToastProvider } from './components/Toast'\nimport { ConfirmProvider } from './components/Confirm'\nimport { TimeWindowProvider } from './lib/time-window'\nimport { ProjectProvider } from './lib/project'\n\n// Apply theme attribute to <body> before first paint to avoid light/dark flash.\nimport './lib/theme'\n\n// Style load order matters — see ./index.css header.\nimport '@arco-design/web-react/dist/css/arco.css'\nimport './styles/arco-override.css'\nimport './styles/arco-tweaks.css'\nimport './index.css'\n\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n refetchOnWindowFocus: false,\n retry: 1,\n // Perf: cache-first for route switches. 60s staleTime means revisiting\n // /health or /tasks within a minute reuses cached data (0ms backend wait).\n // 5min gcTime keeps inactive query cache around for navigation patterns.\n staleTime: 60_000,\n gcTime: 5 * 60_000,\n },\n },\n})\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n <React.StrictMode>\n <QueryClientProvider client={queryClient}>\n <ConfigProvider locale={zhCN}>\n <ToastProvider>\n <ConfirmProvider>\n <TimeWindowProvider>\n <ProjectProvider>\n <BrowserRouter>\n <App />\n </BrowserRouter>\n </ProjectProvider>\n </TimeWindowProvider>\n </ConfirmProvider>\n </ToastProvider>\n </ConfigProvider>\n </QueryClientProvider>\n </React.StrictMode>,\n)\n"],"file":"assets/index-DileOOE4.js"}
|