foxclaw 0.1.2 → 0.1.3
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/index.js +1 -8
- package/package.json +1 -1
- package/python/.env.example +8 -0
- package/python/.github/workflows/ci.yml +47 -2
- package/python/CHANGELOG.md +57 -0
- package/python/CHANGELOG_CN.md +57 -0
- package/python/README.md +11 -2
- package/python/README_CN.md +32 -20
- package/python/bench/bm25_audit.py +1 -14
- package/python/bench/bm25_regression.py +0 -1
- package/python/bench/bm25_stress.py +0 -4
- package/python/bench/cd_audit.py +0 -23
- package/python/bench/chaos.py +6 -8
- package/python/bench/e2e_real_models.py +0 -1
- package/python/bench/llm_retry_test.py +2 -9
- package/python/bench/load_test.py +5 -8
- package/python/bench/vector_ivf_upgrade.py +1 -7
- package/python/docs/RELEASE.md +4 -3
- package/python/docs/RUN_CN.md +2 -2
- package/python/evals/governance/cases.py +0 -37
- package/python/evals/governance/run_evals.py +5 -37
- package/python/examples/governance_middleware_demo.py +1 -6
- package/python/examples/langgraph_governance_demo.py +7 -11
- package/python/foxclaw/__init__.py +34 -152
- package/python/foxclaw/agents/base.py +65 -136
- package/python/foxclaw/agents/impl/_helpers.py +2 -10
- package/python/foxclaw/agents/impl/finance.py +4 -21
- package/python/foxclaw/agents/impl/office.py +7 -24
- package/python/foxclaw/agents/impl/supervisor.py +12 -79
- package/python/foxclaw/agents/mixins/_context.py +0 -23
- package/python/foxclaw/agents/mixins/augment.py +10 -16
- package/python/foxclaw/agents/mixins/llm.py +7 -6
- package/python/foxclaw/agents/mixins/memory.py +7 -1
- package/python/foxclaw/agents/mixins/preference.py +58 -8
- package/python/foxclaw/agents/mixins/prompt.py +0 -6
- package/python/foxclaw/agents/mixins/skillbox.py +6 -6
- package/python/foxclaw/agents/mixins/tool_exec.py +16 -42
- package/python/foxclaw/api/__init__.py +18 -77
- package/python/foxclaw/api/_state.py +43 -0
- package/python/foxclaw/api/{app.py → bootstrap.py} +5 -32
- package/python/foxclaw/api/middleware.py +5 -28
- package/python/foxclaw/api/routes/ahs.py +60 -73
- package/python/foxclaw/api/routes/attachments.py +5 -6
- package/python/foxclaw/api/routes/browser.py +7 -11
- package/python/foxclaw/api/routes/domain.py +18 -26
- package/python/foxclaw/api/routes/knowledge.py +3 -21
- package/python/foxclaw/api/routes/llm_admin.py +21 -33
- package/python/foxclaw/api/routes/memory.py +28 -12
- package/python/foxclaw/api/routes/orchestration.py +3 -5
- package/python/foxclaw/api/routes/recovery.py +4 -3
- package/python/foxclaw/api/routes/review.py +2 -11
- package/python/foxclaw/api/routes/search.py +3 -7
- package/python/foxclaw/api/routes/system.py +33 -49
- package/python/foxclaw/api/routes/task.py +31 -49
- package/python/foxclaw/api/routes/ws.py +2 -6
- package/python/foxclaw/api/spine.py +1 -4
- package/python/foxclaw/browser/action/action_executor.py +1 -5
- package/python/foxclaw/browser/action/action_types.py +0 -1
- package/python/foxclaw/browser/action/url_policy.py +1 -5
- package/python/foxclaw/browser/adapter/web_adapter.py +1 -1
- package/python/foxclaw/browser/driver/playwright_driver.py +20 -16
- package/python/foxclaw/browser/perception/dom_extractor.py +0 -1
- package/python/foxclaw/browser/perception/element_indexer.py +1 -2
- package/python/foxclaw/browser/service.py +7 -11
- package/python/foxclaw/capability/embedding_service.py +4 -6
- package/python/foxclaw/channels/__init__.py +9 -11
- package/python/foxclaw/channels/discord.py +4 -13
- package/python/foxclaw/channels/dispatcher.py +2 -27
- package/python/foxclaw/channels/feishu.py +10 -20
- package/python/foxclaw/channels/openclaw_bridge.py +4 -9
- package/python/foxclaw/channels/signing.py +9 -9
- package/python/foxclaw/channels/telegram.py +3 -4
- package/python/foxclaw/channels/weixin.py +7 -17
- package/python/foxclaw/cli.py +42 -13
- package/python/foxclaw/cognitive/reasoner.py +9 -10
- package/python/foxclaw/cognitive/state.py +18 -24
- package/python/foxclaw/core/audit_chain.py +1 -3
- package/python/foxclaw/core/audit_sink.py +3 -3
- package/python/foxclaw/core/compaction.py +8 -26
- package/python/foxclaw/core/config.py +2 -2
- package/python/foxclaw/core/confirm_nonce.py +6 -12
- package/python/foxclaw/core/envfile.py +2 -2
- package/python/foxclaw/core/failure_policy.py +17 -26
- package/python/foxclaw/core/gateway.py +6 -10
- package/python/foxclaw/core/governance_audit.py +3 -7
- package/python/foxclaw/core/idempotency.py +15 -22
- package/python/foxclaw/core/injection_guard.py +10 -29
- package/python/foxclaw/core/memory_adapter.py +30 -57
- package/python/foxclaw/core/metrics.py +4 -5
- package/python/foxclaw/core/model_router.py +36 -148
- package/python/foxclaw/core/paths.py +1 -1
- package/python/foxclaw/core/recovery.py +21 -34
- package/python/foxclaw/core/scheduler.py +23 -26
- package/python/foxclaw/core/secrets.py +0 -3
- package/python/foxclaw/core/sessions.py +4 -6
- package/python/foxclaw/core/settings.py +16 -32
- package/python/foxclaw/core/shared_write.py +11 -23
- package/python/foxclaw/core/steering_queue.py +12 -11
- package/python/foxclaw/core/system_bus.py +1 -1
- package/python/foxclaw/core/thought_chain.py +30 -32
- package/python/foxclaw/core/token_meter.py +9 -13
- package/python/foxclaw/core/tools.py +4 -12
- package/python/foxclaw/core/tracing.py +25 -40
- package/python/foxclaw/core/truth_pipeline.py +5 -9
- package/python/foxclaw/core/update_check.py +149 -0
- package/python/foxclaw/core/vec_recall_adapter.py +11 -37
- package/python/foxclaw/core/verify.py +6 -14
- package/python/foxclaw/core/web_search.py +4 -28
- package/python/foxclaw/finance/evidence.py +14 -18
- package/python/foxclaw/finance/fx.py +1 -3
- package/python/foxclaw/finance/graph.py +9 -18
- package/python/foxclaw/finance/models.py +20 -24
- package/python/foxclaw/finance/nlparse.py +12 -72
- package/python/foxclaw/finance/policy.py +8 -36
- package/python/foxclaw/finance/reasoner.py +3 -11
- package/python/foxclaw/finance/reasoning.py +13 -34
- package/python/foxclaw/finance/reconcile.py +5 -10
- package/python/foxclaw/finance/runtime.py +19 -46
- package/python/foxclaw/governance/middleware.py +13 -21
- package/python/foxclaw/harness/_base.py +2 -8
- package/python/foxclaw/harness/_policy.py +19 -38
- package/python/foxclaw/harness/drift.py +1 -13
- package/python/foxclaw/harness/event_bus.py +2 -5
- package/python/foxclaw/harness/harness.py +9 -97
- package/python/foxclaw/harness/loop_detection.py +11 -18
- package/python/foxclaw/itinerary/amap_client.py +2 -5
- package/python/foxclaw/itinerary/models.py +7 -7
- package/python/foxclaw/itinerary/reasoner.py +1 -6
- package/python/foxclaw/itinerary/reasoning.py +15 -21
- package/python/foxclaw/itinerary/runtime.py +8 -12
- package/python/foxclaw/kernel/capabilities.py +5 -6
- package/python/foxclaw/kernel/policy_gate.py +4 -10
- package/python/foxclaw/kernel/process_manager.py +17 -36
- package/python/foxclaw/kernel/scheduler.py +3 -9
- package/python/foxclaw/kernel/sentinel.py +13 -23
- package/python/foxclaw/kernel/sentinel_client.py +12 -15
- package/python/foxclaw/kernel/spine.py +9 -9
- package/python/foxclaw/knowledge/__init__.py +4 -20
- package/python/foxclaw/knowledge/truth_crystallizer.py +5 -8
- package/python/foxclaw/learning/knowledge_graph.py +4 -9
- package/python/foxclaw/learning/models.py +13 -13
- package/python/foxclaw/learning/reasoner.py +1 -4
- package/python/foxclaw/learning/runtime.py +19 -31
- package/python/foxclaw/learning/spaced_repetition.py +2 -7
- package/python/foxclaw/mcp_server.py +2 -3
- package/python/foxclaw/orchestration/__init__.py +16 -33
- package/python/foxclaw/pipeline/cognitive_pipeline.py +45 -97
- package/python/foxclaw/pipeline/stage_meta.py +21 -0
- package/python/foxclaw/pipeline/supervisor_stages.py +13 -42
- package/python/foxclaw/planning/llm_planner.py +3 -3
- package/python/foxclaw/planning/planner.py +6 -11
- package/python/foxclaw/search/agent_port.py +7 -11
- package/python/foxclaw/search/evidence.py +0 -4
- package/python/foxclaw/search/internal_search.py +3 -5
- package/python/foxclaw/search/models.py +11 -13
- package/python/foxclaw/search/planner.py +3 -3
- package/python/foxclaw/search/retriever.py +1 -1
- package/python/foxclaw/search/runtime.py +1 -8
- package/python/foxclaw/skills/__init__.py +46 -100
- package/python/foxclaw/skills/archive.py +111 -0
- package/python/foxclaw/skills/fetch.py +226 -0
- package/python/foxclaw/skills/hooks_spec.py +21 -25
- package/python/foxclaw/skills/install_cmd.py +216 -0
- package/python/foxclaw/skills/lifecycle.py +16 -42
- package/python/foxclaw/skills/markdown_skill.py +10 -9
- package/python/foxclaw/skills/mcp_client.py +5 -11
- package/python/foxclaw/skills/mcp_store.py +0 -3
- package/python/foxclaw/skills/permission.py +13 -48
- package/python/foxclaw/skills/pipeline.py +21 -53
- package/python/foxclaw/skills/policy.py +4 -10
- package/python/foxclaw/skills/review.py +3 -3
- package/python/frontend/deck/auth.js +0 -7
- package/python/frontend/deck/chat_model_picker.js +0 -54
- package/python/frontend/deck/domain.js +0 -20
- package/python/frontend/deck/main.js +0 -144
- package/python/frontend/deck/markdown.js +0 -4
- package/python/frontend/deck/settings.js +1 -18
- package/python/frontend/deck/state.js +0 -1
- package/python/frontend/deck/util.js +0 -2
- package/python/frontend/deck/visuals.js +0 -22
- package/python/frontend/planet/planet.js +0 -201
- package/python/frontend/v3/assets/index-CQSBdxk4.js +34 -0
- package/python/frontend/v3/assets/index-D5nIsjms.css +1 -0
- package/python/frontend/v3/index.html +3 -3
- package/python/frontend/widget_runtime.js +0 -43
- package/python/frontend/widgets.js +0 -57
- package/python/frontend_src/index.html +1 -1
- package/python/frontend_src/package-lock.json +2 -2
- package/python/frontend_src/package.json +1 -1
- package/python/frontend_src/src/App.vue +3 -7
- package/python/frontend_src/src/api.js +0 -7
- package/python/frontend_src/src/components/ChatDock.vue +27 -39
- package/python/frontend_src/src/components/DocViewer.vue +0 -9
- package/python/frontend_src/src/components/Inspector.vue +0 -6
- package/python/frontend_src/src/components/LeftRail.vue +60 -39
- package/python/frontend_src/src/components/MenuPopover.vue +9 -11
- package/python/frontend_src/src/components/MessageStream.vue +18 -30
- package/python/frontend_src/src/components/ModelPicker.vue +0 -5
- package/python/frontend_src/src/components/QuickIngest.vue +0 -6
- package/python/frontend_src/src/components/Stage.vue +71 -25
- package/python/frontend_src/src/components/ToolMenu.vue +0 -3
- package/python/frontend_src/src/components/TopBar.vue +38 -10
- package/python/frontend_src/src/components/panels/ActivityPanel.vue +0 -2
- package/python/frontend_src/src/components/panels/AgentsPanel.vue +2 -5
- package/python/frontend_src/src/components/panels/KnowledgePanel.vue +0 -16
- package/python/frontend_src/src/components/panels/MemoryPanel.vue +0 -1
- package/python/frontend_src/src/components/panels/PanelBox.vue +6 -7
- package/python/frontend_src/src/components/panels/ReviewPanel.vue +0 -16
- package/python/frontend_src/src/components/panels/SettingsPanel.vue +142 -38
- package/python/frontend_src/src/components/panels/TasksPanel.vue +0 -1
- package/python/frontend_src/src/components/panels/ToolsPanel.vue +125 -19
- package/python/frontend_src/src/lib/fmt.js +0 -4
- package/python/frontend_src/src/lib/i18n.js +53 -0
- package/python/frontend_src/src/lib/locales/en.js +173 -0
- package/python/frontend_src/src/lib/locales/zh.js +174 -0
- package/python/frontend_src/src/lib/md.js +0 -14
- package/python/frontend_src/src/main.js +2 -0
- package/python/frontend_src/src/stores/app.js +17 -32
- package/python/frontend_src/src/stores/chat.js +0 -34
- package/python/frontend_src/src/stores/model.js +0 -8
- package/python/frontend_src/src/stores/panels.js +0 -41
- package/python/frontend_src/src/stores/profile.js +31 -0
- package/python/frontend_src/src/stores/system.js +25 -0
- package/python/frontend_src/vite.config.js +0 -7
- package/python/pyproject.toml +6 -3
- package/python/requirements.txt +311 -0
- package/python/tests/conftest.py +0 -22
- package/python/tests/run_all.py +3 -66
- package/python/tests/test_agent_lifecycle.py +4 -38
- package/python/tests/test_ahs_p2.py +4 -25
- package/python/tests/test_anthropic_tools.py +1 -15
- package/python/tests/test_api.py +19 -9
- package/python/tests/test_api_auth.py +1 -5
- package/python/tests/test_attachments.py +9 -25
- package/python/tests/test_audit_chain.py +2 -7
- package/python/tests/test_audit_sink.py +0 -6
- package/python/tests/test_browser.py +2 -6
- package/python/tests/test_browser_request_guard.py +0 -4
- package/python/tests/test_capabilities.py +0 -6
- package/python/tests/test_channel_signing.py +2 -9
- package/python/tests/test_channels.py +1 -11
- package/python/tests/test_config_layering.py +0 -4
- package/python/tests/test_confirm_nonce.py +1 -12
- package/python/tests/test_context_compaction_wiring.py +1 -7
- package/python/tests/test_dispatch.py +0 -6
- package/python/tests/test_domain_evals.py +11 -80
- package/python/tests/test_domain_import.py +0 -6
- package/python/tests/test_domain_reasoners.py +0 -14
- package/python/tests/test_e2e.py +0 -17
- package/python/tests/test_emb_cache.py +7 -17
- package/python/tests/test_embedding_singleton.py +1 -3
- package/python/tests/test_evals_smoke.py +0 -24
- package/python/tests/test_event_spine.py +10 -18
- package/python/tests/test_evidence_semantic.py +1 -14
- package/python/tests/test_evidence_sse.py +3 -6
- package/python/tests/test_file_ingest.py +0 -11
- package/python/tests/test_finance.py +0 -9
- package/python/tests/test_finance_ledger.py +5 -12
- package/python/tests/test_finance_persist.py +8 -12
- package/python/tests/test_gateway.py +3 -22
- package/python/tests/test_governance.py +5 -52
- package/python/tests/test_governance_audit.py +4 -39
- package/python/tests/test_governance_middleware.py +1 -7
- package/python/tests/test_hkc.py +6 -24
- package/python/tests/test_hkc_index_build_manager.py +0 -33
- package/python/tests/test_hkc_manifest_reuse.py +4 -27
- package/python/tests/test_hkc_search_event_sync.py +3 -54
- package/python/tests/test_import_path_guard.py +0 -6
- package/python/tests/test_injection_guard.py +18 -36
- package/python/tests/test_integration.py +5 -29
- package/python/tests/test_itinerary.py +0 -3
- package/python/tests/test_kee_semantic.py +0 -5
- package/python/tests/test_kernel.py +1 -11
- package/python/tests/test_learning.py +3 -12
- package/python/tests/test_llm_admin.py +4 -19
- package/python/tests/test_llm_planner.py +1 -23
- package/python/tests/test_markdown_skills.py +3 -14
- package/python/tests/test_markdown_skills_openclaw.py +4 -9
- package/python/tests/test_mcp_connectors.py +3 -15
- package/python/tests/test_mcp_guardian_discovery.py +2 -6
- package/python/tests/test_mcp_no_memory.py +3 -3
- package/python/tests/test_mcp_policy_gate.py +0 -1
- package/python/tests/test_mcp_server.py +6 -9
- package/python/tests/test_memory_recall.py +1 -4
- package/python/tests/test_metrics.py +0 -8
- package/python/tests/test_multi_chain.py +1 -13
- package/python/tests/test_multimodal.py +5 -18
- package/python/tests/test_negotiation.py +3 -13
- package/python/tests/test_orchestration.py +1 -11
- package/python/tests/test_orchestration_decoupled.py +0 -6
- package/python/tests/test_p3_p5_hardening.py +3 -17
- package/python/tests/test_parallel_dispatch.py +4 -12
- package/python/tests/test_pipeline.py +17 -58
- package/python/tests/test_plan_visible.py +4 -4
- package/python/tests/test_planner.py +0 -7
- package/python/tests/test_policy_gate.py +2 -3
- package/python/tests/test_profile.py +67 -0
- package/python/tests/test_readme_claims.py +163 -0
- package/python/tests/test_reasoner.py +2 -17
- package/python/tests/test_release_check.py +2 -13
- package/python/tests/test_resume_checkpoint.py +7 -15
- package/python/tests/test_routing.py +2 -12
- package/python/tests/test_scheduler.py +7 -10
- package/python/tests/test_search.py +1 -11
- package/python/tests/test_secrets.py +4 -10
- package/python/tests/test_semantic.py +1 -10
- package/python/tests/test_sessions.py +3 -4
- package/python/tests/test_settings.py +2 -18
- package/python/tests/test_shadow_learning.py +3 -43
- package/python/tests/test_shared_write.py +0 -7
- package/python/tests/test_skill_taint_gate.py +1 -10
- package/python/tests/test_skills.py +2 -18
- package/python/tests/test_skills_fetch.py +282 -0
- package/python/tests/test_stats_and_events.py +2 -5
- package/python/tests/test_streaming.py +2 -7
- package/python/tests/test_supervisor_pipeline.py +4 -5
- package/python/tests/test_supervisor_triage.py +4 -10
- package/python/tests/test_taint.py +2 -7
- package/python/tests/test_task_stream.py +1 -12
- package/python/tests/test_thinking_sse.py +0 -1
- package/python/tests/test_tool_center.py +1 -17
- package/python/tests/test_tool_parallel.py +2 -2
- package/python/tests/test_tool_params.py +1 -5
- package/python/tests/test_tool_use.py +0 -13
- package/python/tests/test_toplevel_concurrency.py +3 -4
- package/python/tests/test_tracing.py +7 -41
- package/python/tests/test_truth_crystallizer.py +4 -6
- package/python/tests/test_truth_flow.py +2 -7
- package/python/tests/test_update_check.py +95 -0
- package/python/tests/test_verify_evidence.py +8 -21
- package/python/tests/test_version_sync.py +35 -6
- package/python/tests/test_web_trigger.py +0 -17
- package/python/tools/check_faiss_type.py +0 -1
- package/python/tools/check_log.ps1 +0 -8
- package/python/tools/mypy_baseline.txt +12 -4
- package/python/tools/mypy_ratchet.py +52 -6
- package/python/tools/pack.py +0 -5
- package/python/tools/release_check.py +7 -7
- package/python/tools/restart_foxclaw.ps1 +5 -8
- package/python/tools/shared_write_audit.py +1 -15
- package/python/tools/size_check.py +1 -1
- package/python/tools/strip_comments.py +228 -0
- package/python/frontend/v3/assets/index-BD7VPbMV.js +0 -33
- package/python/frontend/v3/assets/index-CAvnYWGH.css +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.topbar[data-v-c3cf2a1d]{display:flex;align-items:center;gap:10px;padding:0 16px;background:#ffffff80;-webkit-backdrop-filter:blur(18px) saturate(160%);backdrop-filter:blur(18px) saturate(160%);border-bottom:1px solid var(--line-soft)}.brand[data-v-c3cf2a1d]{display:flex;align-items:center;gap:9px}.logo[data-v-c3cf2a1d]{width:28px;height:28px;border-radius:9px;display:grid;place-items:center;background:var(--green);color:#fff;font-weight:800;font-size:15px;box-shadow:0 4px 12px #1a9d5f52}.brand h1[data-v-c3cf2a1d]{font-size:15px;font-weight:700;letter-spacing:-.01em}.ver[data-v-c3cf2a1d]{font-size:11px;font-weight:600;color:var(--dim);padding:2px 7px;border-radius:var(--r-pill);background:#ffffffb3;border:1px solid var(--line)}.upd[data-v-c3cf2a1d]{display:grid;place-items:center;width:18px;height:18px;margin-left:-3px;border-radius:50%;font-size:11px;font-weight:700;line-height:1;color:var(--amber);background:#d69e2e1f;border:1px solid rgba(214,158,46,.35)}.upd[data-v-c3cf2a1d]:hover{background:#d69e2e33}.spacer[data-v-c3cf2a1d]{flex:1}.stat[data-v-c3cf2a1d]{display:flex;align-items:center;gap:6px;font-size:12.5px;color:var(--dim)}.stat .val[data-v-c3cf2a1d]{font-weight:700;color:var(--ink)}.stat .val.ok[data-v-c3cf2a1d]{color:var(--green)}.stat .val.bad[data-v-c3cf2a1d]{color:var(--amber)}.stat .val.dim[data-v-c3cf2a1d]{color:var(--dim)}.tbtn[data-v-c3cf2a1d]{font-size:12.5px;font-weight:600;color:var(--ink);padding:6px 11px;border-radius:var(--r-sm);border:1px solid var(--line);background:#ffffffb3;transition:color .15s,background .15s}.tbtn[data-v-c3cf2a1d]:hover{color:var(--ink);background:#fff}.tbtn.on[data-v-c3cf2a1d]{color:var(--green);background:#fff;border-color:#1a9d5f52}.nav-pop[data-v-28d78e1a]{position:fixed;z-index:var(--z-menu);width:214px;max-height:min(64vh,420px);display:flex;flex-direction:column;border-radius:var(--r-mid);background:#ffffffe0;-webkit-backdrop-filter:blur(24px) saturate(180%);backdrop-filter:blur(24px) saturate(180%);border:1px solid rgba(255,255,255,.9);box-shadow:var(--sh-pop);overflow:hidden;animation:pop-in-28d78e1a .16s ease}@keyframes pop-in-28d78e1a{0%{opacity:0;transform:translateY(-6px) scale(.985)}}.pop-head[data-v-28d78e1a]{display:flex;align-items:center;justify-content:space-between;padding:9px 11px;flex-shrink:0;font-size:11px;font-weight:700;letter-spacing:.06em;color:var(--faint);text-transform:uppercase;border-bottom:1px solid var(--line-soft)}.pop-head .x[data-v-28d78e1a]{cursor:pointer;font-size:11px;color:var(--faint);padding:2px 4px}.pop-head .x[data-v-28d78e1a]:hover{color:var(--ink)}.pop-body[data-v-28d78e1a]{padding:6px;overflow-y:auto}.pop-sec[data-v-28d78e1a]{padding:9px 6px 5px;font-size:11px;font-weight:700;letter-spacing:.08em;color:var(--dim);text-transform:uppercase}.pop-item[data-v-28d78e1a]{width:100%;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:8px 9px;border-radius:var(--r-sm);transition:background .14s}.pop-item .lbl[data-v-28d78e1a]{font-size:13px;font-weight:600;color:var(--ink)}.pop-item .tag[data-v-28d78e1a]{font-size:11px;font-weight:600;color:var(--dim)}.pop-item[data-v-28d78e1a]:hover{background:var(--surface-2)}.pop-item.on[data-v-28d78e1a]{background:var(--accent-soft)}.pop-item.on .lbl[data-v-28d78e1a]{color:var(--accent);font-weight:600}.rail-left[data-v-310e54b3]{padding:12px;gap:10px}.new-sess[data-v-310e54b3]{display:flex;align-items:center;justify-content:center;gap:6px;padding:9px 12px;flex-shrink:0;font-size:13px;font-weight:600;color:var(--green);background:#1a9d5f1a;border-radius:var(--r-sm);transition:background .16s,transform .1s}.new-sess[data-v-310e54b3]:hover{background:#1a9d5f2b}.new-sess[data-v-310e54b3]:active{transform:scale(.985)}.rail-nav[data-v-310e54b3]{display:flex;flex-direction:column;gap:2px;flex-shrink:0}.rail-row[data-v-310e54b3]{position:relative;display:flex;align-items:center}.rail-item[data-v-310e54b3]{flex:1;min-width:0;display:flex;align-items:center;gap:9px;padding:7px 9px;border-radius:var(--r-sm);border:1px solid transparent;transition:background .14s,border-color .14s}.rail-item .ic[data-v-310e54b3]{width:15px;height:15px;display:grid;place-items:center;color:var(--dim);flex-shrink:0}.rail-item .ic svg[data-v-310e54b3]{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}.rail-item b[data-v-310e54b3]{flex:1;min-width:0;text-align:left;font-size:13px;font-weight:600;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rail-row:hover .rail-item[data-v-310e54b3]{background:#fff9}.rail-row.on .rail-item[data-v-310e54b3]{background:#ffffffeb;border-color:var(--line);box-shadow:0 1px 2px #17201a0d}.rail-row.on .rail-item .ic[data-v-310e54b3]{color:var(--green)}.rail-row.on .rail-item b[data-v-310e54b3]{font-weight:600}.rail-row.sub .rail-item[data-v-310e54b3]{background:#ffffff80}.rail-row.sub .rail-item .ic[data-v-310e54b3]{color:var(--green)}.beta[data-v-310e54b3]{flex-shrink:0;font-size:10px;font-weight:700;letter-spacing:.08em;color:var(--amber);padding:2px 5px;border-radius:4px;background:#c774001f}.rail-acts[data-v-310e54b3]{position:absolute;right:5px;top:50%;transform:translateY(-50%);display:flex;gap:2px;padding-left:14px;background:linear-gradient(90deg,#fff0,#fffffff0 34%);opacity:0;transition:opacity .13s;pointer-events:none}.rail-row:hover .rail-acts[data-v-310e54b3],.rail-acts[data-v-310e54b3]:focus-within{opacity:1;pointer-events:auto}.act[data-v-310e54b3]{width:21px;height:21px;display:grid;place-items:center;border-radius:6px;color:var(--dim);transition:background .13s,color .13s}.act svg[data-v-310e54b3]{width:13px;height:13px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}.act[data-v-310e54b3]:hover{background:#1a9d5f1f;color:var(--green)}.cur[data-v-310e54b3]{font-size:11.5px;color:var(--dim);flex-shrink:0}.caret[data-v-310e54b3]{font-size:10.5px;color:var(--dim);transition:transform .18s;flex-shrink:0}.caret.open[data-v-310e54b3]{transform:rotate(180deg)}.sec-head[data-v-310e54b3]{display:flex;align-items:center;justify-content:space-between;padding:2px 4px 0;font-size:11px;font-weight:700;letter-spacing:.06em;color:var(--dim);text-transform:uppercase;flex-shrink:0}.sec-head em[data-v-310e54b3]{font-size:11px;font-weight:700;color:var(--ink);padding:2px 7px;border-radius:var(--r-pill);background:#ffffffdb;border:1px solid var(--line)}.ns-list[data-v-310e54b3]{display:flex;flex-direction:column;gap:3px;flex:1;margin:0 -4px;padding:0 4px}.rail-foot[data-v-310e54b3]{flex-shrink:0;margin-top:2px;padding-top:8px;border-top:1px solid var(--line)}.ns-row[data-v-310e54b3]{position:relative;display:flex;align-items:center;border-radius:var(--r-sm);border:1px solid transparent;transition:background .14s,border-color .14s}.ns-row[data-v-310e54b3]:hover{background:#ffffffa8}.ns-row.on[data-v-310e54b3]{background:#ffffffeb;border-color:var(--line);box-shadow:0 1px 2px #17201a0d}.ns-item[data-v-310e54b3]{flex:1;min-width:0;text-align:left;display:flex;flex-direction:column;gap:2px;padding:8px 10px}.ns-item b[data-v-310e54b3]{font-size:13px;font-weight:600;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ns-item span[data-v-310e54b3]{font-size:11.5px;color:var(--dim)}.ns-acts[data-v-310e54b3]{position:absolute;right:4px;top:50%;transform:translateY(-50%);display:flex;gap:2px;padding-left:16px;background:linear-gradient(90deg,#fff0,#fffffff5 36%);opacity:0;pointer-events:none;transition:opacity .13s}.ns-row:hover .ns-acts[data-v-310e54b3],.ns-acts[data-v-310e54b3]:focus-within{opacity:1;pointer-events:auto}.act.del[data-v-310e54b3]:hover{background:#b4443a1f;color:#b4443a}.ns-edit[data-v-310e54b3]{width:100%;padding:7px 9px;font-size:12.5px;color:var(--ink);background:#fff;border:1px solid var(--green);border-radius:var(--r-sm);outline:none}.cli[data-v-045bb22d]{flex:1;min-width:0;display:flex;flex-direction:column;margin:8px;border-radius:var(--r-mid);overflow:hidden;background:var(--cli-bg);border:1px solid rgba(255,255,255,.06);box-shadow:0 18px 44px #0b0f0a57}.term-bar[data-v-045bb22d]{display:flex;align-items:center;gap:6px;flex-shrink:0;padding:9px 12px;background:var(--cli-bg-2);border-bottom:1px solid var(--cli-line)}.tl[data-v-045bb22d]{width:9px;height:9px;border-radius:50%;background:#ffffff24}.tl[data-v-045bb22d]:first-child{background:#ff685c9e}.tl[data-v-045bb22d]:nth-child(2){background:#e2c07a9e}.tl[data-v-045bb22d]:nth-child(3){background:#7fe08c94}.term-bar .path[data-v-045bb22d]{margin-left:8px;font-family:var(--mono);font-size:11.5px;color:var(--cli-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.term-bar .lang[data-v-045bb22d]{margin-left:auto;flex-shrink:0;font-family:var(--mono);font-size:11px;font-weight:700;letter-spacing:.06em;color:var(--cli-bg);background:var(--cli-acc);padding:2px 8px;border-radius:var(--r-pill)}.term-body[data-v-045bb22d]{flex:1;overflow:auto;padding:10px 0 16px;font-family:var(--mono);font-size:12.5px;line-height:1.72}.term-body[data-v-045bb22d]::-webkit-scrollbar-thumb{background:#ffffff29}.row[data-v-045bb22d]{display:flex;white-space:pre}.row[data-v-045bb22d]:hover{background:#ffffff09}.no[data-v-045bb22d]{flex-shrink:0;width:48px;text-align:right;padding-right:14px;color:#ffffff6b;user-select:none}.code[data-v-045bb22d]{color:var(--cli-ink);padding-right:24px}.read[data-v-045bb22d]{flex:1;overflow-y:auto;padding:34px 8px 60px}.read-head[data-v-045bb22d],.read-body[data-v-045bb22d]{max-width:68ch;margin:0 auto}.read-head[data-v-045bb22d]{padding:0 20px 18px;border-bottom:1px solid var(--line-soft)}.read-head h2[data-v-045bb22d]{font-family:var(--serif);font-size:23px;font-weight:600;letter-spacing:-.01em;line-height:1.4}.read-meta[data-v-045bb22d]{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:8px;font-size:11.5px;color:var(--dim)}.read-meta code[data-v-045bb22d]{font-family:var(--mono);font-size:11.5px;color:var(--ink)}.read-body[data-v-045bb22d]{padding:20px 20px 0}.read-body[data-v-045bb22d] p{font-family:var(--serif);font-size:15px;line-height:1.92;color:#24302a;margin-bottom:15px;text-align:justify}.read-body[data-v-045bb22d] h3,.read-body[data-v-045bb22d] h4,.read-body[data-v-045bb22d] h5{font-family:var(--serif);color:var(--ink);line-height:1.5;margin:22px 0 8px}.read-body[data-v-045bb22d] h3{font-size:18px;font-weight:650}.read-body[data-v-045bb22d] h4{font-size:15.5px;font-weight:600}.read-body[data-v-045bb22d] h5{font-size:12px;font-weight:700;letter-spacing:.06em;color:var(--dim);text-transform:uppercase}.read-body[data-v-045bb22d] ul{margin:0 0 15px;padding-left:18px}.read-body[data-v-045bb22d] li{font-family:var(--serif);font-size:14.5px;line-height:1.85;color:#24302a;margin-bottom:5px}.read-body[data-v-045bb22d] li::marker{color:var(--faint)}.read-body[data-v-045bb22d] blockquote{margin:0 0 15px;padding:8px 14px;border-left:2px solid var(--line);font-family:var(--serif);font-size:14px;line-height:1.85;color:var(--dim)}.read-body[data-v-045bb22d] hr{margin:20px 0;border:0;border-top:1px solid var(--line-soft)}.read-body[data-v-045bb22d] strong{font-weight:650;color:#16201b}.read-body[data-v-045bb22d] code{font-family:var(--mono);font-size:12px;padding:1px 5px;border-radius:4px;background:#1a9d5f17;color:var(--green)}.read-body[data-v-045bb22d] a{color:var(--green);border-bottom:1px solid rgba(26,157,95,.3)}.read-body[data-v-045bb22d] ol{margin:0 0 15px;padding-left:20px}.read-body[data-v-045bb22d] h2{font-family:var(--serif);font-size:20px;font-weight:650;line-height:1.5;color:var(--ink);margin:26px 0 10px}.read-body[data-v-045bb22d] pre{margin:0 0 15px;padding:11px 13px;background:var(--cli-bg);border-radius:var(--r-sm);overflow-x:auto}.read-body[data-v-045bb22d] pre code{padding:0;background:none;color:var(--cli-ink);font-size:12px;line-height:1.72}.read-body[data-v-045bb22d] table{width:100%;border-collapse:collapse;margin:0 0 15px}.read-body[data-v-045bb22d] th,.read-body[data-v-045bb22d] td{padding:6px 10px;border-bottom:1px solid var(--line-soft);font-size:13px;text-align:left;vertical-align:top}.read-body[data-v-045bb22d] th{font-size:11.5px;font-weight:600;color:var(--dim)}.ms[data-v-efc12ae7]{flex:1;min-height:0;overflow-y:auto}.ms-in[data-v-efc12ae7]{max-width:780px;margin:0 auto;padding:18px 22px 26px;display:flex;flex-direction:column;gap:20px}.msg.user[data-v-efc12ae7]{display:flex;justify-content:flex-end}.u-body[data-v-efc12ae7]{max-width:78%;display:flex;flex-direction:column;align-items:flex-end;gap:5px}.u-atts[data-v-efc12ae7]{display:flex;gap:5px;flex-wrap:wrap;justify-content:flex-end}.u-att[data-v-efc12ae7]{font-size:11.5px;padding:3px 9px;border-radius:var(--r-pill);color:var(--ink);background:#ffffffe6;border:1px solid var(--line)}.u-text[data-v-efc12ae7]{padding:9px 14px;border-radius:14px 14px 4px;font-size:13.5px;line-height:1.65;color:var(--ink);background:linear-gradient(180deg,#fff,#f2f8ee);border:1px solid var(--line-soft);box-shadow:0 1px 2px #17201a0d;white-space:pre-wrap;word-break:break-word}.u-time[data-v-efc12ae7]{font-size:11px;color:var(--faint);font-family:var(--mono)}.a-body[data-v-efc12ae7]{display:flex;flex-direction:column;gap:9px}.a-head[data-v-efc12ae7]{display:flex;align-items:center;gap:7px;font-size:11.5px;color:var(--dim)}.avatar[data-v-efc12ae7]{width:7px;height:7px;border-radius:50%;background:var(--green);box-shadow:0 0 6px #1a9d5f80}.avatar.live[data-v-efc12ae7]{animation:pulse-efc12ae7 1.1s ease-in-out infinite}@keyframes pulse-efc12ae7{50%{opacity:.35;transform:scale(.8)}}.who[data-v-efc12ae7]{font-weight:700;color:var(--ink)}.a-head .stage[data-v-efc12ae7]{padding:2px 8px;border-radius:var(--r-pill);background:#1a9d5f1f;color:var(--green);font-family:var(--mono);font-size:10.5px;font-weight:600}.a-head .live-tag[data-v-efc12ae7]{color:var(--green);font-size:10.5px;font-weight:600}.a-time[data-v-efc12ae7]{margin-left:auto;font-family:var(--mono)}.a-text[data-v-efc12ae7]{font-size:13.5px;line-height:1.8;color:var(--ink);word-break:break-word;white-space:pre-wrap}.a-text[data-v-efc12ae7] pre,.a-text[data-v-efc12ae7] pre code{white-space:pre}.a-text.waiting[data-v-efc12ae7]{color:var(--faint)}.a-text[data-v-efc12ae7] p{margin:0 0 8px}.a-text[data-v-efc12ae7] p:last-child{margin-bottom:0}.a-text[data-v-efc12ae7] h2,.a-text[data-v-efc12ae7] h3,.a-text[data-v-efc12ae7] h4,.a-text[data-v-efc12ae7] h5{font-family:var(--serif);color:var(--ink);line-height:1.5;margin:14px 0 6px}.a-text[data-v-efc12ae7] h2{font-size:16.5px;font-weight:650}.a-text[data-v-efc12ae7] h3{font-size:15px;font-weight:650}.a-text[data-v-efc12ae7] h4,.a-text[data-v-efc12ae7] h5{font-size:13.5px;font-weight:650}.a-text[data-v-efc12ae7] ul,.a-text[data-v-efc12ae7] ol{margin:0 0 8px;padding-left:20px}.a-text[data-v-efc12ae7] li{margin-bottom:3px}.a-text[data-v-efc12ae7] li::marker{color:var(--faint)}.a-text[data-v-efc12ae7] blockquote{margin:0 0 8px;padding:3px 10px;border-left:2px solid var(--line);color:var(--dim)}.a-text[data-v-efc12ae7] hr{margin:12px 0;border:0;border-top:1px solid var(--line-soft)}.a-text[data-v-efc12ae7] strong{font-weight:650;color:var(--ink)}.a-text[data-v-efc12ae7] del{color:var(--faint)}.a-text[data-v-efc12ae7] code{font-family:var(--mono);font-size:12px;padding:1px 5px;border-radius:4px;background:#1a9d5f17;color:var(--green);white-space:pre-wrap}.a-text[data-v-efc12ae7] pre{margin:8px 0;padding:10px 12px;background:#17211c;border-radius:var(--r-sm);overflow-x:auto}.a-text[data-v-efc12ae7] pre code{padding:0;background:none;color:#dfe9e2;font-size:12px;line-height:1.7;white-space:pre}.a-text[data-v-efc12ae7] table{display:block;overflow-x:auto;border-collapse:collapse;margin:8px 0;font-size:12.5px}.a-text[data-v-efc12ae7] th,.a-text[data-v-efc12ae7] td{padding:4px 9px;border-bottom:1px solid var(--line-soft);text-align:left;vertical-align:top}.a-text[data-v-efc12ae7] th{color:var(--dim);font-size:11.5px}.a-text[data-v-efc12ae7] a{color:var(--green);border-bottom:1px solid rgba(26,157,95,.3)}.a-text.streaming[data-v-efc12ae7]>:last-child:after{content:"";display:inline-block;width:6px;height:13px;margin-left:3px;vertical-align:-2px;background:var(--green);animation:blink-efc12ae7 1s step-end infinite}@keyframes blink-efc12ae7{50%{opacity:0}}.dots[data-v-efc12ae7]{animation:blink-efc12ae7 1.2s step-end infinite;letter-spacing:2px}.fold[data-v-efc12ae7]{border-radius:var(--r-sm);background:#f1f4efb3;border:1px solid var(--line-soft);overflow:hidden}.fold summary[data-v-efc12ae7]{display:flex;align-items:center;gap:7px;padding:7px 11px;cursor:pointer;font-size:12px;font-weight:600;color:var(--ink);list-style:none}.fold summary[data-v-efc12ae7]::-webkit-details-marker{display:none}.fold summary[data-v-efc12ae7]:before{content:"▸";font-size:10px;color:var(--dim)}.fold[open] summary[data-v-efc12ae7]:before{content:"▾"}.fold summary em[data-v-efc12ae7]{font-style:normal;font-family:var(--mono);font-size:10.5px;color:var(--dim)}.fold-body[data-v-efc12ae7]{margin:0;padding:2px 12px 10px;font-size:11.5px;line-height:1.7;color:var(--dim);white-space:pre-wrap;word-break:break-word;max-height:280px;overflow-y:auto}.fold-body ol[data-v-efc12ae7]{margin:0;padding-left:18px}.fold.think .fold-body[data-v-efc12ae7]{font-family:var(--mono);font-size:11px}.fold.ev .fold-body[data-v-efc12ae7]{padding-bottom:8px}.ev-row[data-v-efc12ae7]{display:flex;align-items:baseline;gap:7px;padding:3px 0;flex-wrap:wrap}.ev-row b[data-v-efc12ae7]{font-size:12px;font-weight:700;color:var(--ink)}.ev-st[data-v-efc12ae7]{font-family:var(--mono);font-size:10.5px;color:var(--dim)}.ev-dot[data-v-efc12ae7]{width:5px;height:5px;border-radius:50%;background:var(--amber);flex-shrink:0}.ev-dot.verified[data-v-efc12ae7]{background:var(--green)}.ev-dot.failed[data-v-efc12ae7]{background:var(--red)}.ev-link[data-v-efc12ae7],.ev-file[data-v-efc12ae7]{font-size:11.5px;color:var(--accent);text-decoration:none}.ev-file[data-v-efc12ae7]{color:var(--dim)}.ev-link[data-v-efc12ae7]:hover{text-decoration:underline}.sres[data-v-efc12ae7]{border-radius:var(--r-sm);background:#ffffffbf;border:1px solid var(--line-soft);overflow:hidden}.sres-h[data-v-efc12ae7]{display:flex;align-items:center;gap:10px;padding:7px 11px;border-bottom:1px solid var(--line-soft);font-size:10.5px;color:var(--dim);font-family:var(--mono)}.sres-h .sroute[data-v-efc12ae7]{padding:2px 7px;border-radius:var(--r-pill);color:var(--green);background:#1a9d5f1f;font-weight:700}.srow[data-v-efc12ae7]{display:flex;align-items:baseline;gap:8px;padding:6px 10px;border-bottom:1px solid rgba(23,32,26,.04)}.srow[data-v-efc12ae7]:last-child{border-bottom:0}.ssrc[data-v-efc12ae7]{flex-shrink:0;font-size:10.5px;font-weight:600;padding:2px 6px;border-radius:4px;color:var(--dim);background:var(--surface-2)}.ssrc.knowledge[data-v-efc12ae7]{color:var(--green);background:#1a9d5f1f}.ssrc.web[data-v-efc12ae7]{color:var(--accent);background:#0a84ff1f}.srow p[data-v-efc12ae7]{flex:1;min-width:0;font-size:12px;line-height:1.6;color:var(--ink);word-break:break-word}.srow em[data-v-efc12ae7]{font-style:normal;font-family:var(--mono);font-size:10.5px;color:var(--dim)}.notice[data-v-efc12ae7]{padding:6px 10px;border-radius:var(--r-sm);font-size:11.5px;color:var(--amber);background:#c88c2817}.a-acts[data-v-efc12ae7]{display:flex;gap:6px;opacity:0;transition:opacity .13s}.msg:hover .a-acts[data-v-efc12ae7],.a-acts[data-v-efc12ae7]:focus-within{opacity:1}.mini[data-v-efc12ae7]{font-size:11.5px;padding:3px 10px;border-radius:var(--r-pill);color:var(--dim);background:#ffffffdb;border:1px solid var(--line);transition:color .13s,border-color .13s,background .13s}.mini[data-v-efc12ae7]:hover{color:var(--green);background:#fff;border-color:#1a9d5f59}@media(hover:none){.a-acts[data-v-efc12ae7]{opacity:1}}.err[data-v-efc12ae7]{padding:7px 10px;border-radius:var(--r-sm);font-size:11.5px;color:var(--red);background:#e5484d12;border:1px solid rgba(229,72,77,.16);white-space:pre-wrap}.panel[data-v-a7fcdff6]{flex:1;min-width:0;min-height:0;display:flex;flex-direction:column}.ph[data-v-a7fcdff6]{display:flex;align-items:center;gap:10px;flex-shrink:0;padding:11px 16px 10px;border-bottom:1px solid var(--line-soft)}.tt[data-v-a7fcdff6]{display:flex;align-items:baseline;gap:8px;min-width:0}.tt h2[data-v-a7fcdff6]{font-size:13.5px;font-weight:650;letter-spacing:-.01em;color:var(--ink)}.rf[data-v-a7fcdff6]{margin-left:auto;flex-shrink:0;padding:5px 11px;border-radius:var(--r-pill);font-size:11.5px;font-weight:600;color:var(--ink);background:#ffffffdb;border:1px solid var(--line);transition:color .14s,background .14s,border-color .14s}.rf[data-v-a7fcdff6]:hover{color:var(--green);background:#fff;border-color:#1a9d5f59}.rf.spin[data-v-a7fcdff6]{color:var(--dim)}.pb[data-v-a7fcdff6]{flex:1;padding:14px 16px 18px}.pn-row.static[data-v-cdbea439]:hover{background:transparent}.id[data-v-828bb5bf]{font-family:var(--mono);font-size:11px;font-style:normal;color:var(--dim);margin-left:4px}.det[data-v-828bb5bf]{margin:2px 0 8px 10px;padding:8px 12px;border-left:2px solid var(--line)}.kv[data-v-828bb5bf]{display:flex;justify-content:space-between;gap:12px;padding:4px 0;font-size:12px;color:var(--dim)}.kv b[data-v-828bb5bf]{font-weight:600;color:var(--ink);font-family:var(--mono);font-size:11.5px;text-align:right}.sw[data-v-5b252a48]{flex-shrink:0;padding:4px 10px;border-radius:var(--r-pill);font-size:11px;font-family:var(--mono);background:var(--surface-2);color:var(--faint);border:1px solid transparent}.sw.on[data-v-5b252a48]{background:#1a9d5f1f;color:var(--green)}.sw[data-v-5b252a48]:disabled{opacity:.5}.mbtn[data-v-5b252a48]{flex-shrink:0;padding:4px 10px;border-radius:var(--r-pill);font-size:11px;font-family:var(--mono);color:var(--dim);background:#fffc;border:1px solid var(--line-soft);transition:color .13s,border-color .13s,background .13s}.mbtn[data-v-5b252a48]:hover{color:var(--green);border-color:#1a9d5f59;background:#fff}.mbtn.on[data-v-5b252a48]{color:var(--green);background:#1a9d5f1a;border-color:#1a9d5f66}.mbtn.danger[data-v-5b252a48]:hover{color:var(--red);border-color:#e5484d59}.mbtn[data-v-5b252a48]:disabled{opacity:.5}.tk-form[data-v-5b252a48],.tk-test[data-v-5b252a48]{margin:4px 0 6px;padding:11px 12px;border-radius:var(--r-mid);background:#ffffffdb;border:1px solid var(--line-soft)}.tk-test[data-v-5b252a48]{display:flex;flex-direction:column;gap:7px}.tk-test .f span em[data-v-5b252a48]{font-style:normal;font-weight:600;font-family:var(--mono);font-size:11px;color:var(--dim)}.frow[data-v-5b252a48]{display:flex;gap:8px}.frow .f[data-v-5b252a48]{flex:1 1 0;min-width:0}.frow .f.grow[data-v-5b252a48]{flex:2 1 0}.frow .f.narrow[data-v-5b252a48]{flex:0 1 104px}.f[data-v-5b252a48]{display:block;margin-bottom:7px}.f>span[data-v-5b252a48]{display:block;margin-bottom:3px;font-size:11px;color:var(--faint)}.f input[data-v-5b252a48],.f select[data-v-5b252a48],.f textarea[data-v-5b252a48]{display:block;width:100%;padding:5px 8px;border-radius:6px;font-family:inherit;font-size:12.5px;color:var(--ink);background:#17201a0a;border:1px solid transparent;outline:none;transition:border-color .14s,background .14s}.f textarea[data-v-5b252a48]{resize:vertical;line-height:1.6}.f input[data-v-5b252a48]:focus,.f select[data-v-5b252a48]:focus,.f textarea[data-v-5b252a48]:focus{border-color:var(--line);background:#fff}.f input[data-v-5b252a48]::placeholder,.f textarea[data-v-5b252a48]::placeholder{color:var(--dim)}.f input[type=file][data-v-5b252a48]{padding:4px 6px;font-size:11.5px;color:var(--dim)}.chk[data-v-5b252a48]{display:flex;align-items:center;gap:6px;margin-bottom:6px;font-size:12px;color:var(--dim)}.chk input[data-v-5b252a48]{accent-color:var(--green)}.fbar[data-v-5b252a48]{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:3px}.go[data-v-5b252a48]{flex-shrink:0;padding:6px 15px;border-radius:var(--r-pill);font-size:12.5px;font-weight:600;color:#fff;background:var(--green);transition:opacity .15s,transform .12s}.go[data-v-5b252a48]:hover:not(:disabled){opacity:.9}.go[data-v-5b252a48]:active:not(:disabled){transform:scale(.97)}.go[data-v-5b252a48]:disabled{background:#17201a1f;color:var(--faint)}.go.warn[data-v-5b252a48]{background:var(--amber)}.tip[data-v-5b252a48]{flex:1 1 auto;min-width:0;font-size:11.5px;color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tip.dim[data-v-5b252a48]{color:var(--faint)}.tip.ok[data-v-5b252a48]{color:var(--green)}.tip.bad[data-v-5b252a48]{color:var(--red);white-space:normal}.tk-res[data-v-5b252a48]{margin-top:4px;padding:8px 10px;border-radius:var(--r-sm);background:#17201a08;border:1px solid var(--line-soft)}.tk-res .r-h[data-v-5b252a48]{display:flex;gap:6px;font-size:12px;color:var(--dim)}.tk-res .r-h b[data-v-5b252a48]{font-family:var(--mono);font-size:11.5px;color:var(--ink)}.tk-res.bad .r-h b[data-v-5b252a48]{color:var(--amber)}.tk-res pre[data-v-5b252a48]{margin:6px 0 0;max-height:220px;overflow:auto;font-family:var(--mono);font-size:11.5px;line-height:1.6;color:var(--dim);white-space:pre-wrap;word-break:break-word}.pn-note.meta[data-v-5b252a48]{margin-top:6px}.pn-note.meta.bad[data-v-5b252a48]{color:var(--red)}.acts[data-v-1a916225]{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.btn[data-v-1a916225]{padding:7px 13px;border-radius:var(--r-sm);font-size:11.5px;color:var(--green);font-weight:600;background:#1a9d5f1a;border:1px solid rgba(26,157,95,.16)}.btn[data-v-1a916225]:hover{background:#1a9d5f29}.hint[data-v-1a916225]{font-size:11.5px;color:var(--dim)}.kb-in[data-v-11ecf8c3]{margin-bottom:14px;border-radius:var(--r-mid);background:#ffffffe6;border:1px solid rgba(26,157,95,.16);overflow:hidden;transition:border-color .15s,box-shadow .15s}.kb-in[data-v-11ecf8c3]:focus-within{border-color:#1a9d5f61;box-shadow:0 2px 12px #1a9d5f14}.kb-in textarea[data-v-11ecf8c3]{display:block;width:100%;padding:11px 12px 6px;font-family:var(--sans);font-size:13px;line-height:1.7;color:var(--ink);background:transparent;border:0;outline:none;resize:vertical;min-height:62px}.kb-in textarea[data-v-11ecf8c3]::placeholder{color:var(--dim)}.kb-bar[data-v-11ecf8c3]{display:flex;align-items:center;gap:6px;padding:6px 8px 8px 12px;border-top:1px solid var(--line-soft)}.kb-bar input[data-v-11ecf8c3]{padding:4px 8px;border-radius:6px;font-size:11.5px;color:var(--ink);background:#17201a0a;border:1px solid transparent;outline:none}.kb-bar input[data-v-11ecf8c3]:focus{border-color:var(--line);background:#fff}.kb-bar input[data-v-11ecf8c3]::placeholder{color:var(--dim)}.f-title[data-v-11ecf8c3]{flex:1 1 110px;max-width:190px;min-width:0}.f-domain[data-v-11ecf8c3]{flex:0 1 96px;min-width:60px}.tip[data-v-11ecf8c3]{flex:1 1 auto;min-width:0;font-size:11.5px;color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tip.dim[data-v-11ecf8c3]{color:var(--faint)}.tip.ok[data-v-11ecf8c3]{color:var(--green)}.tip.bad[data-v-11ecf8c3]{color:var(--red)}.go[data-v-11ecf8c3]{flex-shrink:0;padding:6px 15px;border-radius:var(--r-pill);font-size:11.5px;font-weight:600;color:#fff;background:var(--green);transition:opacity .15s,transform .12s}.go[data-v-11ecf8c3]:hover:not(:disabled){opacity:.9}.go[data-v-11ecf8c3]:active:not(:disabled){transform:scale(.97)}.go[data-v-11ecf8c3]:disabled{background:#17201a12;color:var(--dim);border:1px solid var(--line-soft)}.meta[data-v-11ecf8c3]{margin-top:8px}.sec-gap[data-v-11ecf8c3]{margin-top:14px}.pn-note.meta.bad[data-v-11ecf8c3]{color:var(--red)}.kb-find[data-v-11ecf8c3]{display:flex;align-items:center;gap:6px;margin-bottom:8px}.kb-find input[data-v-11ecf8c3]{flex:1 1 auto;min-width:0;padding:7px 10px;border-radius:var(--r-sm);font-size:12.5px;color:var(--ink);background:#ffffffe6;border:1px solid var(--line-soft);outline:none;transition:border-color .15s}.kb-find input[data-v-11ecf8c3]:focus{border-color:#1a9d5f73}.kb-find input[data-v-11ecf8c3]::placeholder{color:var(--dim)}.kb-find select[data-v-11ecf8c3]{padding:6px 8px;border-radius:var(--r-sm);font-size:12px;font-weight:600;color:var(--ink);background:#ffffffe6;border:1px solid var(--line);outline:none}.kb-find .go[data-v-11ecf8c3]{padding:6px 13px}.kb-hits[data-v-11ecf8c3]{display:flex;flex-direction:column;gap:2px}.kb-hit[data-v-11ecf8c3]{display:flex;align-items:center;gap:8px;width:100%;padding:7px 9px;border-radius:var(--r-sm);text-align:left;transition:background .13s}.kb-hit[data-v-11ecf8c3]:hover{background:#ffffffbf}.kb-hit .m[data-v-11ecf8c3]{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.kb-hit .m b[data-v-11ecf8c3]{font-size:13px;font-weight:600;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kb-hit .m .s[data-v-11ecf8c3]{font-size:11.5px;color:var(--dim)}.kb-hit .r[data-v-11ecf8c3]{flex-shrink:0;font-size:11.5px;color:var(--dim);font-variant-numeric:tabular-nums}.pn-chips.gap[data-v-11ecf8c3]{margin-top:8px}.kb-ab[data-v-11ecf8c3]{margin-top:10px;padding:10px 12px;border-radius:var(--r-mid);background:#ffffffdb;border:1px solid var(--line-soft)}.kb-ab-h[data-v-11ecf8c3]{display:flex;align-items:baseline;gap:6px;font-size:13px;font-weight:600;color:var(--ink);margin-bottom:5px}.kb-ab-h .v[data-v-11ecf8c3]{font-size:11.5px;font-weight:600;color:var(--dim)}.rv-grid[data-v-1a353dab]{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);gap:22px;align-items:start}@container (max-width: 820px){.rv-grid[data-v-1a353dab]{grid-template-columns:minmax(0,1fr);gap:20px}}.card[data-v-1a353dab]{padding:16px 18px 18px;border-radius:var(--r-md);background:#ffffffdb;border:1px solid var(--line-soft);box-shadow:0 1px 3px #17201a0a}.ct[data-v-1a353dab]{display:flex;align-items:center;gap:8px;margin-bottom:10px}.ct .dim[data-v-1a353dab]{font-size:11.5px;color:var(--dim)}.pn-tag.new[data-v-1a353dab]{background:#1a9d5f1f;color:var(--green)}.card h3[data-v-1a353dab]{font-family:var(--serif);font-size:17px;line-height:1.62;font-weight:600;color:var(--ink);margin-bottom:12px}.sum[data-v-1a353dab]{font-size:13px;line-height:1.8;color:var(--dim);margin-bottom:10px}.src[data-v-1a353dab]{font-size:12px;line-height:1.85;color:var(--dim);padding:9px 12px;border-left:2px solid var(--line);background:#17201a06;margin-bottom:14px;white-space:pre-wrap}.hint[data-v-1a353dab]{font-size:12px;color:var(--dim);margin:4px 0 14px;line-height:1.7}.err[data-v-1a353dab]{margin-top:10px;font-size:11px;color:#b4453c}.act[data-v-1a353dab]{display:inline-block;padding:8px 18px;border-radius:var(--r-pill);font-size:12px;font-weight:600;color:#fff;background:var(--green);transition:opacity .15s}.act[data-v-1a353dab]:hover{opacity:.9}.grades[data-v-1a353dab]{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:7px}.g[data-v-1a353dab]{display:flex;flex-direction:column;align-items:center;gap:2px;padding:9px 4px 8px;border-radius:var(--r-sm);font-size:12px;font-weight:600;color:var(--ink);background:#ffffffe6;border:1px solid var(--line-soft);transition:border-color .14s,background .14s,color .14s}.g span[data-v-1a353dab]{font-size:11px;font-weight:500;color:var(--dim)}.g[data-v-1a353dab]:hover{border-color:#1a9d5f6b;background:#1a9d5f0f}.g0[data-v-1a353dab]:hover{border-color:#b4453c6b;background:#b4453c0f}.done[data-v-1a353dab],.idle[data-v-1a353dab]{padding:14px 2px}.done b[data-v-1a353dab]{font-size:13px}.done p[data-v-1a353dab],.idle p[data-v-1a353dab]{font-size:12px;line-height:1.8;color:var(--dim);margin:6px 0 14px}.idle b[data-v-1a353dab]{color:var(--ink)}.curve[data-v-1a353dab]{display:block;width:100%;height:130px;overflow:visible}.curve .ref[data-v-1a353dab]{stroke:#17201a1f;stroke-width:1;stroke-dasharray:3 3;vector-effect:non-scaling-stroke}.curve .line[data-v-1a353dab]{fill:none;stroke:var(--green);stroke-width:1.8;vector-effect:non-scaling-stroke}.curve .dot[data-v-1a353dab]{fill:var(--green);stroke:#fff;stroke-width:1.5;vector-effect:non-scaling-stroke}.axis[data-v-1a353dab]{display:flex;justify-content:space-between;align-items:baseline;margin-top:5px;font-size:11px;font-weight:600;color:var(--dim)}.axis .dim[data-v-1a353dab]{font-family:var(--mono);font-size:11px}.note[data-v-1a353dab]{margin-top:8px;font-size:11.5px;line-height:1.75;color:var(--dim)}.note.warn[data-v-1a353dab]{padding:7px 9px;border-radius:var(--r-sm);background:#c48a1a12;border-left:2px solid rgba(196,138,26,.45);color:#8a6a24}.load[data-v-1a353dab]{display:flex;align-items:flex-end;gap:6px;padding:8px 2px 0}.load .bar[data-v-1a353dab]{flex:1;display:flex;flex-direction:column;align-items:center;gap:3px;min-width:0}.load i[data-v-1a353dab]{display:block;width:100%;max-width:26px;border-radius:2px 2px 0 0;background:#1a9d5f8c}.load i.zero[data-v-1a353dab]{background:#17201a24}.load span[data-v-1a353dab]{font-size:10.5px;color:var(--dim)}.load em[data-v-1a353dab]{font-style:normal;font-family:var(--mono);font-size:10.5px;font-weight:600;color:var(--ink)}.sec-gap[data-v-6518b64e]{margin-top:14px}.del[data-v-6518b64e]{flex-shrink:0;padding:4px 10px;border-radius:var(--r-pill);font-size:11px;font-weight:600;color:var(--dim);background:var(--surface-2);border:1px solid var(--line-soft)}.del[data-v-6518b64e]:hover{color:var(--red);background:#e5484d1a}.del[data-v-6518b64e]:disabled{opacity:.5}.card[data-v-01d0339a]{border-radius:var(--r-mid);background:#ffffffd1;border:1px solid var(--line-soft);box-shadow:0 1px 2px #17201a0a;padding:4px 6px 6px;margin-bottom:12px}.grp[data-v-01d0339a]{padding:8px 8px 6px;font-size:11px;font-weight:700;letter-spacing:.08em;color:var(--dim);text-transform:uppercase}.row[data-v-01d0339a]{width:100%;display:flex;align-items:center;gap:10px;padding:8px;border-radius:var(--r-sm);text-align:left;transition:background .14s}.row[data-v-01d0339a]:hover{background:#ffffffe6}.row.static[data-v-01d0339a]:hover{background:transparent}.row .ic[data-v-01d0339a]{width:22px;height:22px;display:grid;place-items:center;color:var(--dim);flex-shrink:0}.row .ic svg[data-v-01d0339a]{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}.row .m[data-v-01d0339a]{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.row .m b[data-v-01d0339a]{font-size:13px;font-weight:600;color:var(--ink)}.row .m span[data-v-01d0339a]{font-size:11.5px;color:var(--dim)}.hint[data-v-01d0339a]{display:flex;align-items:center;gap:5px;font-size:12px;font-weight:600;color:var(--dim);flex-shrink:0}.hint .dot[data-v-01d0339a]{width:7px;height:7px;border-radius:50%}.chev[data-v-01d0339a]{color:var(--dim);font-size:13px;flex-shrink:0;transition:transform .16s}.chev.open[data-v-01d0339a]{transform:rotate(90deg)}.seg[data-v-01d0339a]{display:flex;gap:2px;padding:2px;border-radius:var(--r-sm);background:#17201a0d;flex-shrink:0}.seg button[data-v-01d0339a]{padding:4px 10px;border-radius:7px;font-size:11.5px;color:var(--dim);transition:background .15s,color .15s}.seg button.on[data-v-01d0339a]{background:#fff;color:var(--ink);font-weight:600;box-shadow:0 1px 2px #17201a12}.sub[data-v-01d0339a]{margin:2px 8px 6px 40px;padding:4px;border-left:1px solid var(--line-soft)}.opt[data-v-01d0339a]{width:100%;display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:7px;text-align:left;transition:background .13s}.opt[data-v-01d0339a]:hover{background:#ffffffe6}.opt.on[data-v-01d0339a]{background:#1a9d5f17}.opt .dot[data-v-01d0339a]{width:7px;height:7px;border-radius:50%;flex-shrink:0}.opt .m[data-v-01d0339a]{flex:1;min-width:0;display:flex;align-items:baseline;gap:7px}.opt .m b[data-v-01d0339a]{font-size:12.5px;font-weight:600;color:var(--ink)}.opt .m span[data-v-01d0339a]{font-size:11.5px;color:var(--dim);font-family:var(--mono)}.tip[data-v-01d0339a]{padding:4px 8px 2px;font-size:11.5px;line-height:1.6;color:var(--dim)}.tip.err[data-v-01d0339a]{color:var(--red)}.nick-edit[data-v-01d0339a]{display:flex;align-items:center;gap:6px;padding:4px 8px 2px}.nick-in[data-v-01d0339a]{flex:1;min-width:0;padding:5px 8px;border-radius:7px;font-size:12.5px;color:var(--ink);background:#fff;border:1px solid var(--line)}.nick-in[data-v-01d0339a]:focus{outline:none;border-color:#1a9d5f80}.nick-save[data-v-01d0339a]{flex-shrink:0;padding:5px 11px;border-radius:7px;font-size:12px;font-weight:600;color:#fff;background:var(--green)}.nick-save[data-v-01d0339a]:disabled{opacity:.45}.kv[data-v-01d0339a]{display:flex;align-items:center;gap:10px;padding:4px 8px}.kv kbd[data-v-01d0339a]{min-width:92px;flex-shrink:0;font-family:var(--mono);font-size:11.5px;font-weight:600;color:var(--ink);padding:2px 6px;border-radius:5px;background:#17201a0d}.kv span[data-v-01d0339a]{font-size:11.5px;color:var(--dim)}.foot[data-v-01d0339a]{display:flex;align-items:center;justify-content:space-between;margin-top:2px;padding:10px 4px 2px;border-top:1px solid var(--line-soft)}.foot .mono[data-v-01d0339a]{font-family:var(--mono);font-size:11.5px;color:var(--dim)}.foot .dev[data-v-01d0339a]{font-size:12px;color:var(--faint)}.stage[data-v-31f35103]{display:flex;flex-direction:column;min-height:0}.tabs[data-v-31f35103]{display:flex;align-items:center;gap:4px;padding:8px 10px 0;flex-shrink:0;overflow-x:auto}.tab[data-v-31f35103]{display:flex;align-items:center;gap:6px;padding:6px 11px;border-radius:var(--r-sm) var(--r-sm) 0 0;font-size:12px;color:var(--dim);border:1px solid transparent;border-bottom:0;white-space:nowrap}.tab[data-v-31f35103]:hover{color:var(--ink);background:#ffffff80}.tab.on[data-v-31f35103]{color:var(--ink);font-weight:600;background:#ffffffdb;border-color:var(--line-soft)}.tab.doc[data-v-31f35103]{max-width:260px}.tab.doc .t[data-v-31f35103]{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tab.doc .x[data-v-31f35103]{font-size:11px;color:var(--dim)}.tab.doc .x[data-v-31f35103]:hover{color:var(--red)}.stage-body[data-v-31f35103]{flex:1;min-height:0;margin:0 8px 8px;border-radius:0 var(--r-mid) var(--r-mid) var(--r-mid);background:var(--mid-panel);border:1px solid rgba(26,157,95,.1);overflow:hidden;display:flex}.stage-body.bare[data-v-31f35103]{margin-top:8px;border-radius:var(--r-mid)}.core[data-v-31f35103]{flex:1;min-height:0;display:flex;flex-direction:column}.core-empty[data-v-31f35103]{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:18px;position:relative;padding:24px 18px;overflow-y:auto}.core-cap[data-v-31f35103]{font-size:12.5px;color:var(--dim);line-height:1.7;text-align:center}.hero[data-v-31f35103]{text-align:center}.hero-t[data-v-31f35103]{font-size:19px;font-weight:600;letter-spacing:-.02em;color:var(--ink);margin-bottom:6px}.ask-nick[data-v-31f35103]{display:flex;align-items:center;gap:8px;width:100%;max-width:420px;padding:9px 11px;border-radius:var(--r-sm);background:#1a9d5f0f;border:1px solid rgba(26,157,95,.22)}.an-q[data-v-31f35103]{font-size:12.5px;font-weight:600;color:var(--ink);flex-shrink:0}.an-in[data-v-31f35103]{flex:1;min-width:56px;padding:5px 8px;border-radius:7px;font-size:12.5px;color:var(--ink);background:#fff;border:1px solid var(--line)}.an-in[data-v-31f35103]:focus{outline:none;border-color:#1a9d5f80}.an-ok[data-v-31f35103]{flex-shrink:0;padding:5px 10px;border-radius:7px;font-size:12px;font-weight:600;color:#fff;background:var(--green)}.an-ok[data-v-31f35103]:disabled{opacity:.45;cursor:default}.an-skip[data-v-31f35103]{flex-shrink:0;padding:4px 2px;font-size:11.5px;color:var(--dim)}.an-skip[data-v-31f35103]:hover{color:var(--ink)}.tries[data-v-31f35103]{display:flex;flex-direction:column;gap:6px;width:100%;max-width:420px}.try[data-v-31f35103]{display:flex;align-items:center;gap:8px;width:100%;padding:10px 13px;border-radius:var(--r-sm);font-size:12.5px;color:var(--ink);text-align:left;background:#ffffffd1;border:1px solid var(--line);transition:color .14s,border-color .14s,background .14s,transform .12s}.try[data-v-31f35103]:hover{color:var(--ink);background:#fff;border-color:#1a9d5f6b}.try[data-v-31f35103]:active{transform:scale(.99)}.try .arrow[data-v-31f35103]{font-size:12px;color:var(--green);flex-shrink:0}.resume[data-v-31f35103]{display:flex;align-items:center;gap:7px;max-width:420px;padding:7px 13px;border-radius:var(--r-pill);background:var(--surface-2);color:var(--dim);transition:background .14s,color .14s}.resume[data-v-31f35103]:hover{background:var(--surface-3);color:var(--ink)}.resume .rl[data-v-31f35103]{font-size:11px;font-weight:700;color:var(--dim);text-transform:uppercase;letter-spacing:.07em}.resume b[data-v-31f35103]{font-size:12px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.resume .rm[data-v-31f35103]{font-size:11px;color:var(--dim);flex-shrink:0}.recent[data-v-31f35103]{width:100%;max-width:420px}.recent .rh[data-v-31f35103]{margin-bottom:5px;font-size:11px;font-weight:700;letter-spacing:.08em;color:var(--dim);text-transform:uppercase}.rk-list[data-v-31f35103]{display:flex;flex-wrap:wrap;gap:5px}.rk[data-v-31f35103]{max-width:190px;padding:5px 10px;border-radius:var(--r-pill);font-size:11.5px;color:var(--ink);background:#fffc;border:1px solid var(--line);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:color .13s,border-color .13s,background .13s}.rk[data-v-31f35103]:hover{color:var(--green);background:#fff;border-color:#1a9d5f66}.cm[data-v-d6468d56]{position:absolute;left:8px;right:8px;bottom:calc(100% + 6px);z-index:40;max-height:264px;overflow-y:auto;padding:5px;border-radius:var(--r-mid);background:#fffffff0;-webkit-backdrop-filter:blur(24px) saturate(180%);backdrop-filter:blur(24px) saturate(180%);border:1px solid rgba(255,255,255,.9);box-shadow:var(--sh-pop);animation:cm-in-d6468d56 .13s ease}@keyframes cm-in-d6468d56{0%{opacity:0;transform:translateY(4px)}}.cm-h[data-v-d6468d56]{padding:4px 7px 5px;font-size:11px;font-weight:700;letter-spacing:.07em;color:var(--dim);text-transform:uppercase}.cm-it[data-v-d6468d56]{width:100%;display:flex;align-items:baseline;gap:8px;padding:7px 9px;border-radius:var(--r-sm);text-align:left}.cm-it.on[data-v-d6468d56]{background:var(--surface-2)}.cm-it b[data-v-d6468d56]{font-size:12.5px;font-weight:700;font-family:var(--mono);flex-shrink:0;color:var(--ink)}.cm-it span[data-v-d6468d56]{flex:1;min-width:0;font-size:12px;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cm-it em[data-v-d6468d56]{font-style:normal;font-size:10.5px;font-weight:600;color:var(--dim);padding:2px 6px;border-radius:var(--r-pill);background:var(--surface-2)}.cm-empty[data-v-d6468d56]{padding:10px 8px;font-size:12px;color:var(--dim)}.cm-f[data-v-d6468d56]{padding:7px 8px 3px;margin-top:3px;border-top:1px solid var(--line-soft);font-size:11px;color:var(--dim);font-family:var(--mono)}.mp[data-v-1c7db88f]{position:relative;flex-shrink:0}.pill[data-v-1c7db88f]{display:flex;align-items:center;gap:5px;padding:5px 9px;border-radius:var(--r-pill);font-size:12px;font-weight:600;color:var(--ink);background:var(--surface-2);max-width:150px;transition:background .15s,color .15s}.pill[data-v-1c7db88f]:hover,.pill.on[data-v-1c7db88f]{background:var(--surface-3);color:var(--ink)}.pill .dot[data-v-1c7db88f]{width:5px;height:5px;border-radius:50%;flex-shrink:0}.pill .nm[data-v-1c7db88f]{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pill .caret[data-v-1c7db88f]{font-size:10px;color:var(--dim)}.pop[data-v-1c7db88f]{position:absolute;left:0;bottom:calc(100% + 8px);z-index:var(--z-menu);width:272px;max-height:54vh;display:flex;flex-direction:column;padding:6px;border-radius:var(--r-mid);background:#ffffffeb;-webkit-backdrop-filter:blur(24px) saturate(180%);backdrop-filter:blur(24px) saturate(180%);border:1px solid rgba(255,255,255,.9);box-shadow:var(--sh-pop);overflow-y:auto;animation:mp-in-1c7db88f .15s ease}@keyframes mp-in-1c7db88f{0%{opacity:0;transform:translateY(5px)}}.it[data-v-1c7db88f]{width:100%;display:flex;align-items:center;gap:8px;padding:6px 7px;border-radius:var(--r-sm);text-align:left;transition:background .13s}.it[data-v-1c7db88f]:hover{background:var(--surface-2)}.it.on[data-v-1c7db88f]{background:var(--accent-soft)}.it.dis[data-v-1c7db88f]{opacity:.55}.it .dot[data-v-1c7db88f]{width:6px;height:6px;border-radius:50%;flex-shrink:0}.it .tx[data-v-1c7db88f]{display:flex;flex-direction:column;gap:1px;flex:1;min-width:0}.it .tx b[data-v-1c7db88f]{font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.it .tx span[data-v-1c7db88f]{font-size:11px;color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.it .tx.plain[data-v-1c7db88f]{background:none;padding:0}.tg[data-v-1c7db88f]{flex-shrink:0;font-size:10.5px;font-weight:600;padding:2px 6px;border-radius:var(--r-pill);color:var(--accent);background:#1a9d5f21}.tg.warn[data-v-1c7db88f]{color:var(--amber);background:#c88c2821}.it .x[data-v-1c7db88f]{flex-shrink:0;font-size:11px;color:var(--dim);padding:2px 4px}.it .x[data-v-1c7db88f]:hover{color:var(--red)}button.x[data-v-1c7db88f]{background:none;border:0;font-family:inherit;cursor:pointer}button.x[data-v-1c7db88f]:hover:not(:disabled){color:var(--accent)}button.x[data-v-1c7db88f]:disabled{opacity:.4;cursor:default}.tres[data-v-1c7db88f]{margin-top:5px;padding:7px 9px;border-radius:var(--r-sm);font-size:11.5px;line-height:1.55;color:var(--dim);background:var(--surface-2);overflow-wrap:anywhere}.tres.ok[data-v-1c7db88f]{color:var(--green);background:#1a9d5f14}.tres.err[data-v-1c7db88f]{color:var(--red);background:#e5484d12}.sep[data-v-1c7db88f]{padding:9px 7px 4px;font-size:11px;font-weight:700;letter-spacing:.08em;color:var(--dim);text-transform:uppercase}.empty[data-v-1c7db88f]{padding:10px 7px;font-size:12px;color:var(--dim)}.foot[data-v-1c7db88f]{position:sticky;bottom:-6px;display:flex;gap:5px;padding:6px 4px 4px;margin-top:5px;border-top:1px solid var(--line-soft);background:#fffffff5;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.fbtn[data-v-1c7db88f]{flex:1;padding:7px;border-radius:var(--r-sm);font-size:12px;font-weight:600;color:var(--dim);background:var(--surface-2)}.fbtn[data-v-1c7db88f]:hover{color:var(--ink);background:var(--surface-3)}.form[data-v-1c7db88f]{display:flex;flex-direction:column;gap:6px;padding:4px}.fhead[data-v-1c7db88f]{display:flex;align-items:center;justify-content:space-between;font-size:12.5px;font-weight:700;padding:2px 3px 4px}.fhead .x[data-v-1c7db88f]{cursor:pointer;color:var(--dim);font-size:12px}.form label[data-v-1c7db88f]{display:flex;flex-direction:column;gap:3px;font-size:11.5px;font-weight:600;color:var(--dim)}.form input[data-v-1c7db88f]{padding:6px 8px;border-radius:7px;font-size:12px;background:#fff;border:1px solid var(--line)}.form input[data-v-1c7db88f]:focus{border-color:#1a9d5f73}.form input[data-v-1c7db88f]:disabled{color:var(--faint);background:var(--surface-2)}.submit[data-v-1c7db88f]{margin-top:3px;padding:7px;border-radius:var(--r-sm);font-size:12px;font-weight:600;color:#fff;background:var(--green)}.submit[data-v-1c7db88f]:disabled{opacity:.6}.tm[data-v-28d25609]{position:relative;flex-shrink:0}.plus[data-v-28d25609]{width:28px;height:28px;border-radius:50%;display:grid;place-items:center;font-size:15px;color:var(--dim);background:var(--surface-2);transition:color .15s,background .15s}.plus[data-v-28d25609]:hover,.plus.on[data-v-28d25609]{color:var(--ink);background:var(--surface-3)}.pop[data-v-28d25609]{position:absolute;left:0;bottom:calc(100% + 8px);z-index:var(--z-menu);width:250px;max-height:54vh;display:flex;flex-direction:column;padding:6px;border-radius:var(--r-mid);background:#ffffffeb;-webkit-backdrop-filter:blur(24px) saturate(180%);backdrop-filter:blur(24px) saturate(180%);border:1px solid rgba(255,255,255,.9);box-shadow:var(--sh-pop);overflow-y:auto;animation:tm-in-28d25609 .15s ease}@keyframes tm-in-28d25609{0%{opacity:0;transform:translateY(5px)}}.sec[data-v-28d25609]{padding:6px 7px 4px;font-size:11px;font-weight:700;letter-spacing:.08em;color:var(--dim);text-transform:uppercase}.it[data-v-28d25609]{width:100%;display:flex;align-items:center;gap:9px;padding:8px;border-radius:var(--r-sm);text-align:left;transition:background .13s}.it[data-v-28d25609]:hover{background:var(--surface-2)}.it .ic[data-v-28d25609]{font-size:14px;width:16px;text-align:center;flex-shrink:0}.it .tx[data-v-28d25609]{display:flex;flex-direction:column;gap:2px}.it .tx b[data-v-28d25609]{font-size:13px;font-weight:600}.it .tx span[data-v-28d25609]{font-size:11px;color:var(--dim)}.foot[data-v-28d25609]{margin-top:4px;padding:7px 7px 3px;border-top:1px solid var(--line-soft);font-size:11px;color:var(--dim);font-family:var(--mono)}.dock[data-v-371234e7]{padding:0 8px 8px;position:relative}.dock-in[data-v-371234e7]{position:relative;width:min(736px,calc(100% - 44px));margin:0 auto}.chips[data-v-371234e7]{display:flex;gap:6px;flex-wrap:wrap;padding:0 2px 7px}.chip[data-v-371234e7]{display:flex;align-items:center;gap:6px;padding:5px 9px;border-radius:var(--r-pill);font-size:11.5px;background:#ffffffe6;border:1px solid var(--line);box-shadow:0 1px 2px #17201a0a;max-width:220px}.chip .cn[data-v-371234e7]{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ink)}.chip .cs[data-v-371234e7]{font-family:var(--mono);font-size:10.5px;color:var(--dim);flex-shrink:0}.chip .cx[data-v-371234e7]{cursor:pointer;font-size:11px;color:var(--dim);padding:0 2px;flex-shrink:0}.chip .cx[data-v-371234e7]:hover{color:var(--red)}.chip.img[data-v-371234e7]{padding:3px 5px}.chip.img img[data-v-371234e7]{width:22px;height:22px;border-radius:5px;object-fit:cover}.chip.ing[data-v-371234e7]{border-color:#1a9d5f4d}.chip.ing.error[data-v-371234e7]{border-color:#c83c3c57}.chip.ing .bar[data-v-371234e7]{width:44px;height:3px;border-radius:2px;overflow:hidden;background:#17201a1a;flex-shrink:0}.chip.ing .bar i[data-v-371234e7]{display:block;height:100%;background:var(--green);transition:width .3s}.chip.ing.error .bar i[data-v-371234e7]{background:var(--red)}.wrap[data-v-371234e7]{display:flex;align-items:flex-end;gap:8px;padding:7px 9px;background:#ffffffe6;border:1px solid var(--line-soft);border-radius:var(--r-mid);box-shadow:var(--sh-card);transition:border-color .15s,box-shadow .15s}.wrap[data-v-371234e7]:focus-within{border-color:#1a9d5f66;box-shadow:0 0 0 3px #1a9d5f14,var(--sh-card)}textarea[data-v-371234e7]{flex:1;min-width:0;font-size:13.5px;line-height:1.6;padding:5px 2px;border:0;background:none;resize:none;overflow-y:auto;max-height:340px;transition:height .14s ease}textarea[data-v-371234e7]:focus{outline:none}textarea[data-v-371234e7]::placeholder{color:var(--dim);opacity:1}.send[data-v-371234e7]{width:30px;height:30px;border-radius:50%;flex-shrink:0;display:grid;place-items:center;font-size:12px;color:#fff;background:var(--green);box-shadow:0 4px 12px #1a9d5f4d;transition:transform .1s,filter .15s,background .15s}.send[data-v-371234e7]:hover{filter:brightness(1.06)}.send[data-v-371234e7]:active{transform:scale(.94)}.send.stop[data-v-371234e7]{background:var(--red);box-shadow:0 4px 12px #e5484d47;font-size:10px}.toast[data-v-371234e7]{position:absolute;left:50%;bottom:62px;transform:translate(-50%);padding:7px 13px;border-radius:var(--r-pill);font-size:11.5px;color:var(--cli-ink);background:#11160feb;box-shadow:var(--sh-pop);white-space:nowrap;max-width:82vw;overflow:hidden;text-overflow:ellipsis;z-index:30}.fade-enter-active[data-v-371234e7],.fade-leave-active[data-v-371234e7]{transition:opacity .18s}.fade-enter-from[data-v-371234e7],.fade-leave-to[data-v-371234e7]{opacity:0}.qi[data-v-6cdbc607]{padding:0 0 10px;margin-bottom:14px;border-bottom:1px solid var(--line-soft)}.qi-h[data-v-6cdbc607]{display:flex;align-items:baseline;gap:6px;margin-bottom:7px;font-size:11px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--dim)}.qi-h em[data-v-6cdbc607]{font-style:normal;font-weight:500;letter-spacing:0;text-transform:none;font-size:11px;color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.qi-ta[data-v-6cdbc607]{display:block;width:100%;box-sizing:border-box;resize:vertical;min-height:46px;max-height:140px;padding:7px 9px;border-radius:var(--r-sm);font-family:var(--sans);font-size:12.5px;line-height:1.6;color:var(--ink);background:#fff;border:1px solid var(--line);transition:border-color .15s}.qi-ta[data-v-6cdbc607]::placeholder{color:var(--dim)}.qi-ta[data-v-6cdbc607]:focus{outline:none;border-color:#1a9d5f6b}.qi-b[data-v-6cdbc607]{display:flex;gap:6px;margin-top:6px}.qi-title[data-v-6cdbc607]{flex:1 1 auto;min-width:0;padding:5px 8px;border-radius:var(--r-pill);font-size:11.5px;color:var(--ink);background:#ffffffdb;border:1px solid var(--line)}.qi-title[data-v-6cdbc607]::placeholder{color:var(--dim)}.qi-title[data-v-6cdbc607]:focus{outline:none;border-color:#1a9d5f59}.qi-go[data-v-6cdbc607]{flex-shrink:0;padding:6px 13px;border-radius:var(--r-pill);font-size:11.5px;font-weight:600;color:#fff;background:var(--green);border:1px solid var(--green);transition:opacity .15s}.qi-go[data-v-6cdbc607]:disabled{background:#17201a12;color:var(--dim);border-color:var(--line)}.qi-msg[data-v-6cdbc607]{margin-top:6px;font-size:11px;line-height:1.5}.qi-msg.ok[data-v-6cdbc607]{color:var(--green)}.qi-msg.busy[data-v-6cdbc607]{color:var(--dim)}.qi-msg.err[data-v-6cdbc607]{color:#b4453c}.rail-right[data-v-6327fda1]{padding:0}.head[data-v-6327fda1]{display:flex;align-items:center;gap:8px;flex-shrink:0;padding:10px 12px 9px;border-bottom:1px solid var(--line-soft)}.seg[data-v-6327fda1]{display:flex;gap:2px;padding:2px;border-radius:var(--r-sm);background:#4032200e}.seg button[data-v-6327fda1]{display:flex;align-items:center;gap:4px;padding:4px 11px;border-radius:7px;font-size:11.5px;color:var(--dim);transition:background .15s,color .15s}.seg button.on[data-v-6327fda1]{background:#fff;color:var(--ink);font-weight:600;box-shadow:0 1px 2px #40322017}.seg .pip[data-v-6327fda1]{width:5px;height:5px;border-radius:50%;background:var(--green)}.collapse[data-v-6327fda1]{margin-left:auto;font-size:13px;color:var(--faint);padding:2px 5px}.collapse[data-v-6327fda1]:hover{color:var(--ink)}.body[data-v-6327fda1]{flex:1;padding:12px}.sec[data-v-6327fda1]{margin-bottom:20px}.sec-h[data-v-6327fda1]{display:flex;align-items:center;justify-content:space-between;font-size:11.5px;font-weight:700;letter-spacing:.07em;color:var(--dim);text-transform:uppercase;margin-bottom:8px}.sec-h em[data-v-6327fda1]{font-family:var(--mono);font-size:11.5px;font-weight:700;color:var(--ink)}.kpi[data-v-6327fda1]{display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-bottom:8px}.kpi div[data-v-6327fda1]{padding:8px 9px;border-radius:var(--r-sm);background:#ffffffe6;border:1px solid var(--line)}.kpi b[data-v-6327fda1]{display:block;font-size:16px;font-weight:700;letter-spacing:-.01em;color:var(--w-ink)}.kpi span[data-v-6327fda1]{font-size:11.5px;font-weight:500;color:var(--w-dim)}.go[data-v-6327fda1]{width:100%;padding:8px;border-radius:var(--r-sm);font-size:12px;font-weight:600;color:#fff;background:var(--green);transition:opacity .15s}.go[data-v-6327fda1]:disabled{color:var(--w-dim);background:#40322012;font-weight:600;border:1px solid var(--line-soft)}.go[data-v-6327fda1]:not(:disabled):hover{opacity:.9}.sub-h[data-v-6327fda1]{display:flex;justify-content:space-between;padding:5px 2px 6px;font-size:11px;font-weight:600;color:var(--w-dim)}.sub-h em[data-v-6327fda1]{font-style:normal;font-family:var(--mono)}.row[data-v-6327fda1]{width:100%;text-align:left;display:flex;flex-direction:column;gap:2px;padding:8px 9px;border-radius:var(--r-sm);margin-bottom:2px;transition:background .14s}.row[data-v-6327fda1]:hover{background:#ffffffbf}.row b[data-v-6327fda1]{font-size:13px;font-weight:600;color:var(--w-ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.row span[data-v-6327fda1]{font-size:11.5px;color:var(--w-dim)}.more[data-v-6327fda1]{width:100%;display:flex;align-items:center;justify-content:center;gap:6px;margin-top:4px;padding:7px 9px;border-radius:var(--r-sm);font-size:12px;font-weight:600;color:var(--w-dim);border:1px dashed var(--line);transition:color .15s,border-color .15s,background .15s}.more[data-v-6327fda1]:hover{color:var(--green);border-color:#1a9d5f52;background:#1a9d5f0d}.bars[data-v-6327fda1]{display:flex;flex-direction:column;gap:2px}.bars i[data-v-6327fda1]{display:block;width:10px;height:1.5px;border-radius:1px;background:currentColor;opacity:.75}.doc-head[data-v-6327fda1]{padding:0 4px 12px;border-bottom:1px solid var(--line-soft);margin-bottom:12px}.kind[data-v-6327fda1]{display:inline-block;margin-bottom:7px;padding:3px 8px;border-radius:var(--r-pill);font-family:var(--mono);font-size:11px;font-weight:700;letter-spacing:.08em}.kind.code[data-v-6327fda1]{background:var(--cli-bg);color:var(--cli-acc)}.kind.text[data-v-6327fda1]{background:var(--surface-2);color:var(--w-ink)}.doc-head h3[data-v-6327fda1]{font-size:15px;font-weight:650;line-height:1.45;color:var(--w-ink)}.path[data-v-6327fda1]{display:block;margin-top:6px;font-family:var(--mono);font-size:11px;color:var(--w-dim);word-break:break-all}.meta[data-v-6327fda1]{margin-top:5px;font-size:11.5px;color:var(--w-dim)}.out-line[data-v-6327fda1]{display:flex;gap:7px;padding:6px 7px;border-radius:7px;font-size:12px;color:var(--w-ink);line-height:1.55}.out-line[data-v-6327fda1]:hover{background:#ffffffb3;color:var(--w-ink)}.out-line .n[data-v-6327fda1]{font-family:var(--mono);font-size:10.5px;color:var(--w-dim);padding-top:2px}.acts[data-v-6327fda1]{padding-top:6px}.acts button[data-v-6327fda1]{width:100%;padding:8px;border-radius:var(--r-sm);font-size:12.5px;font-weight:600;color:var(--w-ink);background:#fffc;border:1px solid var(--line)}.acts button[data-v-6327fda1]:hover{color:var(--ink);background:#fff}:root{--g-left: #d7e8d0;--g-mid: #eef7e8;--g-right: #f8f3e9;--band: linear-gradient(100deg, var(--g-left) 0%, var(--g-mid) 46%, var(--g-right) 100%);--veil-left: rgba(255, 255, 255, .28);--veil-mid: rgba(236, 246, 228, .9);--veil-right: rgba(251, 247, 239, .92);--mid-panel: rgba(238, 247, 232, .95);--right-panel: #fbf7ef;--ink: #17201a;--dim: #3f4c42;--faint: #65716a;--line: rgba(23, 32, 26, .1);--line-soft: rgba(23, 32, 26, .06);--w-ink: #211d17;--w-dim: #4a4237;--w-faint: #776d5c;--w-line: rgba(64, 50, 32, .12);--w-line-soft: rgba(64, 50, 32, .06);--w-surface-2: #f3ede1;--w-surface-3: #e9e1d2;--accent: #0a84ff;--accent-soft: rgba(10, 132, 255, .1);--green: #1a9d5f;--amber: #c77400;--red: #e5484d;--surface: #ffffff;--surface-2: #f1f4ef;--surface-3: #e4eae2;--r-card: 20px;--r-mid: 14px;--r-sm: 10px;--r-pill: 999px;--sh-card: 0 1px 2px rgba(23, 32, 26, .04), 0 10px 26px rgba(23, 32, 26, .07);--sh-pop: 0 14px 40px rgba(23, 32, 26, .18), 0 2px 10px rgba(23, 32, 26, .08);--gap: 14px;--pad: 14px;--cli-bg: #11160f;--cli-bg-2: #0b0f0a;--cli-ink: #d9e6d2;--cli-dim: #849480;--cli-line: rgba(255, 255, 255, .07);--cli-acc: #7fe08c;--cli-warn: #e2c07a;--font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;--mono: ui-monospace, SFMono-Regular, "JetBrains Mono", "Cascadia Code", Consolas, monospace;--serif: "Songti SC", "Noto Serif SC", Georgia, serif;--z-menu: 100;--z-top: 500}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}html,body,#app{height:100%}body{font-family:var(--font);color:var(--ink);background:var(--g-right);-webkit-font-smoothing:antialiased;overflow:hidden}button{font-family:inherit;border:0;background:none;color:inherit;cursor:pointer}input,textarea{font-family:inherit;border:0;background:none;color:inherit;outline:none}em{font-style:normal}.app{height:100vh;display:grid;grid-template-rows:56px 1fr;min-height:0}.workspace{--rail-w: 344px;display:grid;grid-template-columns:296px minmax(0,1fr) var(--rail-w);gap:var(--gap);padding:var(--pad);min-height:0;background:var(--band);transition:grid-template-columns .24s ease}.workspace.is-collapsed{--rail-w: 0px}.col{position:relative;display:flex;flex-direction:column;min-height:0;min-width:0;border-radius:var(--r-card);border:1px solid rgba(255,255,255,.55);background:var(--veil-left);-webkit-backdrop-filter:blur(16px) saturate(150%);backdrop-filter:blur(16px) saturate(150%);box-shadow:var(--sh-card);overflow:hidden}.col--mid{background:var(--veil-mid)}.col--right{background:var(--right-panel);--ink: var(--w-ink);--dim: var(--w-dim);--faint: var(--w-faint);--line: var(--w-line);--line-soft: var(--w-line-soft);--surface-2: var(--w-surface-2);--surface-3: var(--w-surface-3);transition:opacity .18s ease}.col--right .scroll::-webkit-scrollbar-thumb{background:#40322029}.workspace.is-collapsed .col--right{opacity:0;pointer-events:none}.mid{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(0,1fr) auto}.scroll{overflow-y:auto;overscroll-behavior:contain;min-height:0}.scroll::-webkit-scrollbar{width:8px;height:8px}.scroll::-webkit-scrollbar-thumb{background:#17201a24;border-radius:99px}.scroll::-webkit-scrollbar-track{background:transparent}.empty{padding:28px 12px;text-align:center;font-size:12.5px;color:var(--faint);line-height:1.7}.dot{width:6px;height:6px;border-radius:50%;background:var(--green);flex-shrink:0}.rail-handle{position:fixed;right:0;top:50%;transform:translateY(-50%);z-index:var(--z-menu);padding:16px 6px;font-size:11px;letter-spacing:.04em;color:var(--dim);background:#ffffffdb;border:1px solid var(--line);border-right:0;border-radius:12px 0 0 12px;box-shadow:var(--sh-card);writing-mode:vertical-rl}.rail-handle:hover{color:var(--ink)}@media(prefers-reduced-motion:reduce){.workspace,.col--right{transition:none}}@media(max-width:1180px){.workspace{grid-template-columns:248px minmax(0,1fr)}.col--right{position:fixed;top:calc(56px + var(--pad));right:var(--pad);bottom:var(--pad);width:344px;z-index:60;box-shadow:var(--sh-pop);transition:transform .2s ease,opacity .18s ease}.workspace.is-collapsed .col--right{transform:translate(calc(100% + var(--pad)))}}.rail-scrim{position:fixed;inset:56px 0 0;z-index:59;background:#17201a29}.pn-sec{margin-bottom:18px}.pn-sec:last-child{margin-bottom:0}.pn-h{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;font-size:11.5px;font-weight:700;letter-spacing:.07em;color:var(--dim);text-transform:uppercase}.pn-h em{font-style:normal;font-family:var(--mono);font-size:11.5px;font-weight:700;color:var(--ink);text-transform:none}.pn-kpi{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:16px}.pn-kpi>div{flex:1 1 104px;padding:10px 11px;border-radius:var(--r-sm);background:#ffffffc7;border:1px solid var(--line-soft)}.pn-kpi b{display:block;font-size:18px;font-weight:650;letter-spacing:-.02em;line-height:1.25}.pn-kpi span{font-size:11.5px;font-weight:500;color:var(--dim)}.pn-row{width:100%;text-align:left;display:flex;align-items:center;gap:10px;padding:9px 10px;border-radius:var(--r-sm);border:1px solid transparent;transition:background .14s,border-color .14s}.pn-row+.pn-row{margin-top:2px}.pn-row:hover{background:#ffffffb8}.pn-row.clickable:hover{border-color:var(--line);background:#fff}.pn-row .m{flex:1;min-width:0}.pn-row b{display:block;font-size:13.5px;font-weight:600;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pn-row span.s{display:block;margin-top:2px;font-size:11.5px;color:var(--dim)}.pn-row .r{flex-shrink:0;font-family:var(--mono);font-size:11.5px;color:var(--dim)}.pn-tag{display:inline-block;flex-shrink:0;padding:3px 8px;border-radius:var(--r-pill);font-family:var(--mono);font-size:11px;letter-spacing:.04em;background:var(--surface-2);color:var(--dim)}.pn-tag.green{background:#1a9d5f1f;color:var(--green)}.pn-tag.amber{background:#c7740021;color:var(--amber)}.pn-tag.red{background:#e5484d1f;color:var(--red)}.pn-chips{display:flex;flex-wrap:wrap;gap:6px}.pn-chip{padding:5px 10px;border-radius:var(--r-pill);font-family:var(--mono);font-size:11.5px;color:var(--dim);background:#ffffffc7;border:1px solid var(--line-soft);transition:color .13s,border-color .13s,background .13s}button.pn-chip:hover{color:var(--green);background:#fff;border-color:#1a9d5f59}button.pn-chip.on{color:var(--green);background:#1a9d5f1a;border-color:#1a9d5f66}.pn-chip.warn{color:var(--amber);background:#c7740017;border-color:#c774003d}.pn-empty{padding:16px 12px;border-radius:var(--r-sm);font-size:12px;line-height:1.7;color:var(--dim);background:#fff9;border:1px dashed var(--line)}.pn-st{padding:14px 4px;font-size:12px;color:var(--dim)}.pn-st.err{color:var(--amber)}.pn-cols{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:18px;align-items:start}.panel>.pb{container-type:inline-size}@container (max-width: 660px){.pn-cols{grid-template-columns:minmax(0,1fr);gap:0}}@container (max-width: 300px){.pn-row{flex-wrap:wrap;row-gap:6px}.pn-row .m{flex:1 1 100%}.pn-h{flex-wrap:wrap;gap:6px}.pn-kpi>div{flex:1 1 76px}}.pn-note{font-size:11.5px;line-height:1.65;color:var(--dim);padding:8px 10px;border-radius:var(--r-sm);background:#fff9;border:1px solid var(--line-soft)}.pn-note code{font-family:var(--mono);font-size:11px;color:var(--ink);word-break:break-all}
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>Foxclaw
|
|
6
|
+
<title>Foxclaw</title>
|
|
7
7
|
<!-- 内联 SVG 图标:不新增静态文件,也避免浏览器探 /favicon.ico 报 404 -->
|
|
8
8
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><rect width='32' height='32' rx='9' fill='%23179d5f'/><circle cx='16' cy='16' r='6.5' fill='%23f4fbf0'/></svg>" />
|
|
9
|
-
<script type="module" crossorigin src="/v3/assets/index-
|
|
10
|
-
<link rel="stylesheet" crossorigin href="/v3/assets/index-
|
|
9
|
+
<script type="module" crossorigin src="/v3/assets/index-CQSBdxk4.js"></script>
|
|
10
|
+
<link rel="stylesheet" crossorigin href="/v3/assets/index-D5nIsjms.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
|
13
13
|
<div id="app"></div>
|
|
@@ -1,39 +1,16 @@
|
|
|
1
|
-
/* ════════════════════════════════════════════════════════════
|
|
2
|
-
FOXCLAW DECK — Widget Runtime
|
|
3
|
-
可插拔 widget 系统。新模块只需 registerWidget() 一次。
|
|
4
|
-
════════════════════════════════════════════════════════════ */
|
|
5
1
|
|
|
6
2
|
const WidgetRuntime = (() => {
|
|
7
3
|
|
|
8
|
-
// ── 注册表:定义有哪些 widget 类型 ──
|
|
9
4
|
const registry = new Map();
|
|
10
5
|
|
|
11
|
-
// ── 实例:当前布局中存在的 widget ──
|
|
12
|
-
// { instanceId, widgetId, column, order }
|
|
13
6
|
let instances = [];
|
|
14
7
|
|
|
15
|
-
// ── 事件订阅:widgetId -> Set<eventType> ──
|
|
16
8
|
const eventSubs = new Map();
|
|
17
9
|
|
|
18
|
-
// ── 共享上下文,所有 widget 都能访问 ──
|
|
19
10
|
let ctx = {};
|
|
20
11
|
|
|
21
|
-
// ── DOM 列引用 ──
|
|
22
12
|
const columns = {};
|
|
23
13
|
|
|
24
|
-
/* ───────────────────────────────────────────
|
|
25
|
-
注册一个 widget 类型
|
|
26
|
-
spec = {
|
|
27
|
-
id, title, icon,
|
|
28
|
-
defaultColumn: 'left'|'center'|'right',
|
|
29
|
-
size: {minH, maxH, flex},
|
|
30
|
-
events: ['harness_block', ...], // 关心的事件类型
|
|
31
|
-
render(el, ctx, instance), // 渲染主体
|
|
32
|
-
onEvent(evt, el, ctx), // 收到订阅事件
|
|
33
|
-
onAgentChange(agentId, el, ctx), // 激活 Agent 变化
|
|
34
|
-
refresh(el, ctx, agentId), // 数据刷新
|
|
35
|
-
}
|
|
36
|
-
─────────────────────────────────────────── */
|
|
37
14
|
function register(spec) {
|
|
38
15
|
if (!spec.id) throw new Error('widget 必须有 id');
|
|
39
16
|
registry.set(spec.id, {
|
|
@@ -46,14 +23,12 @@ const WidgetRuntime = (() => {
|
|
|
46
23
|
refresh: null,
|
|
47
24
|
...spec,
|
|
48
25
|
});
|
|
49
|
-
// 建立事件订阅索引
|
|
50
26
|
(spec.events || []).forEach(ev => {
|
|
51
27
|
if (!eventSubs.has(ev)) eventSubs.set(ev, new Set());
|
|
52
28
|
eventSubs.get(ev).add(spec.id);
|
|
53
29
|
});
|
|
54
30
|
}
|
|
55
31
|
|
|
56
|
-
/* 初始化:绑定列容器 + 共享上下文 */
|
|
57
32
|
function init(columnEls, sharedCtx) {
|
|
58
33
|
columns.left = columnEls.left;
|
|
59
34
|
columns.center = columnEls.center;
|
|
@@ -61,7 +36,6 @@ const WidgetRuntime = (() => {
|
|
|
61
36
|
ctx = sharedCtx || {};
|
|
62
37
|
}
|
|
63
38
|
|
|
64
|
-
/* 设置布局(从默认或 localStorage 恢复) */
|
|
65
39
|
function setLayout(layout) {
|
|
66
40
|
instances = layout.map((item, i) => ({
|
|
67
41
|
instanceId: item.instanceId || `inst_${item.widgetId}_${i}`,
|
|
@@ -72,7 +46,6 @@ const WidgetRuntime = (() => {
|
|
|
72
46
|
renderAll();
|
|
73
47
|
}
|
|
74
48
|
|
|
75
|
-
/* 默认布局:每个注册的 widget 放进它的 defaultColumn */
|
|
76
49
|
function defaultLayout() {
|
|
77
50
|
return [...registry.values()].map((spec, i) => ({
|
|
78
51
|
instanceId: `inst_${spec.id}`,
|
|
@@ -82,7 +55,6 @@ const WidgetRuntime = (() => {
|
|
|
82
55
|
}));
|
|
83
56
|
}
|
|
84
57
|
|
|
85
|
-
/* 渲染全部实例 */
|
|
86
58
|
function renderAll() {
|
|
87
59
|
Object.values(columns).forEach(col => { if (col) col.innerHTML = ''; });
|
|
88
60
|
const byCol = { left: [], center: [], right: [] };
|
|
@@ -96,7 +68,6 @@ const WidgetRuntime = (() => {
|
|
|
96
68
|
});
|
|
97
69
|
}
|
|
98
70
|
|
|
99
|
-
/* 挂载单个 widget 到 DOM */
|
|
100
71
|
function mountWidget(inst, colName) {
|
|
101
72
|
const spec = registry.get(inst.widgetId);
|
|
102
73
|
if (!spec) return;
|
|
@@ -127,26 +98,22 @@ const WidgetRuntime = (() => {
|
|
|
127
98
|
inst._el = panel;
|
|
128
99
|
inst._body = body;
|
|
129
100
|
|
|
130
|
-
// 移除按钮
|
|
131
101
|
panel.querySelector('.ph-remove').onclick = (e) => {
|
|
132
102
|
e.stopPropagation();
|
|
133
103
|
removeInstance(inst.instanceId);
|
|
134
104
|
};
|
|
135
105
|
|
|
136
|
-
// 调用 widget 自己的渲染
|
|
137
106
|
try {
|
|
138
107
|
spec.render(body, ctx, inst);
|
|
139
108
|
} catch (err) {
|
|
140
109
|
body.innerHTML = `<div class="empty">渲染错误: ${err.message}</div>`;
|
|
141
110
|
}
|
|
142
111
|
|
|
143
|
-
// 首次同步当前 Agent
|
|
144
112
|
if (spec.onAgentChange && ctx.activeAgent) {
|
|
145
113
|
try { spec.onAgentChange(ctx.activeAgent, body, ctx); } catch {}
|
|
146
114
|
}
|
|
147
115
|
}
|
|
148
116
|
|
|
149
|
-
/* 事件分发:把事件发给所有订阅的 widget 实例 */
|
|
150
117
|
function dispatch(eventType, payload) {
|
|
151
118
|
const subscribers = eventSubs.get(eventType);
|
|
152
119
|
if (!subscribers) return;
|
|
@@ -159,7 +126,6 @@ const WidgetRuntime = (() => {
|
|
|
159
126
|
});
|
|
160
127
|
}
|
|
161
128
|
|
|
162
|
-
/* 通知所有 widget:激活 Agent 变了 */
|
|
163
129
|
function notifyAgentChange(agentId) {
|
|
164
130
|
ctx.activeAgent = agentId;
|
|
165
131
|
instances.forEach(inst => {
|
|
@@ -170,7 +136,6 @@ const WidgetRuntime = (() => {
|
|
|
170
136
|
});
|
|
171
137
|
}
|
|
172
138
|
|
|
173
|
-
/* 刷新所有 widget 的数据 */
|
|
174
139
|
function refreshAll(agentId) {
|
|
175
140
|
instances.forEach(inst => {
|
|
176
141
|
const spec = registry.get(inst.widgetId);
|
|
@@ -180,7 +145,6 @@ const WidgetRuntime = (() => {
|
|
|
180
145
|
});
|
|
181
146
|
}
|
|
182
147
|
|
|
183
|
-
/* 设置某个实例的 head status 文本 */
|
|
184
148
|
function setStatus(instanceId, text) {
|
|
185
149
|
const inst = instances.find(i => i.instanceId === instanceId);
|
|
186
150
|
if (inst && inst._el) {
|
|
@@ -189,7 +153,6 @@ const WidgetRuntime = (() => {
|
|
|
189
153
|
}
|
|
190
154
|
}
|
|
191
155
|
|
|
192
|
-
/* ── 增删实例 ── */
|
|
193
156
|
function addInstance(widgetId, column) {
|
|
194
157
|
const spec = registry.get(widgetId);
|
|
195
158
|
if (!spec) return;
|
|
@@ -214,7 +177,6 @@ const WidgetRuntime = (() => {
|
|
|
214
177
|
saveLayout();
|
|
215
178
|
}
|
|
216
179
|
|
|
217
|
-
/* ── 拖拽:重排实例 ── */
|
|
218
180
|
function captureLayoutFromDOM() {
|
|
219
181
|
const newInstances = [];
|
|
220
182
|
['left', 'center', 'right'].forEach(colName => {
|
|
@@ -239,7 +201,6 @@ const WidgetRuntime = (() => {
|
|
|
239
201
|
saveLayout();
|
|
240
202
|
}
|
|
241
203
|
|
|
242
|
-
/* ── 持久化 ── */
|
|
243
204
|
function saveLayout() {
|
|
244
205
|
try {
|
|
245
206
|
const layout = instances.map(i => ({
|
|
@@ -256,7 +217,6 @@ const WidgetRuntime = (() => {
|
|
|
256
217
|
try {
|
|
257
218
|
const saved = JSON.parse(localStorage.getItem('foxclaw_widget_layout'));
|
|
258
219
|
if (saved && saved.length) {
|
|
259
|
-
// 过滤掉已不存在的 widget 类型
|
|
260
220
|
const valid = saved.filter(i => registry.has(i.widgetId));
|
|
261
221
|
if (valid.length) { setLayout(valid); return true; }
|
|
262
222
|
}
|
|
@@ -264,7 +224,6 @@ const WidgetRuntime = (() => {
|
|
|
264
224
|
return false;
|
|
265
225
|
}
|
|
266
226
|
|
|
267
|
-
/* ── 编辑模式:显示/隐藏移除按钮 ── */
|
|
268
227
|
function setEditMode(on) {
|
|
269
228
|
instances.forEach(inst => {
|
|
270
229
|
if (!inst._el) return;
|
|
@@ -273,7 +232,6 @@ const WidgetRuntime = (() => {
|
|
|
273
232
|
});
|
|
274
233
|
}
|
|
275
234
|
|
|
276
|
-
/* ── 面板库:列出未激活的 widget 供添加 ── */
|
|
277
235
|
function getLibrary() {
|
|
278
236
|
return [...registry.values()].map(spec => ({
|
|
279
237
|
id: spec.id,
|
|
@@ -283,7 +241,6 @@ const WidgetRuntime = (() => {
|
|
|
283
241
|
}));
|
|
284
242
|
}
|
|
285
243
|
|
|
286
|
-
/* 公开 API */
|
|
287
244
|
return {
|
|
288
245
|
register, init, setLayout, defaultLayout, renderAll,
|
|
289
246
|
dispatch, notifyAgentChange, refreshAll, setStatus,
|
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
/* ════════════════════════════════════════════════════════════
|
|
2
|
-
FOXCLAW DECK — Widget Definitions
|
|
3
|
-
每个 widget 是一个 registerWidget() 注册。
|
|
4
|
-
新增模块只需在这里加一个 register block。
|
|
5
|
-
════════════════════════════════════════════════════════════ */
|
|
6
1
|
|
|
7
|
-
/* 共享工具(由主文件注入到 ctx) */
|
|
8
2
|
function _esc(s){return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\n/g,'<br>');}
|
|
9
3
|
function _statusColor(s){return{PASS:'#1dffa6',WARN:'#ffb347',BLOCK:'#ff4060',BASELINE:'#b066ff',PENDING:'#3a4d68'}[s]||'#1de9ff';}
|
|
10
4
|
|
|
11
|
-
/* ─────────────────────────────────────────────
|
|
12
|
-
WIDGET 1: AGENT 编队 (roster)
|
|
13
|
-
───────────────────────────────────────────── */
|
|
14
5
|
WidgetRuntime.register({
|
|
15
6
|
id: 'roster',
|
|
16
7
|
title: 'AGENT 编队',
|
|
@@ -44,9 +35,6 @@ WidgetRuntime.register({
|
|
|
44
35
|
},
|
|
45
36
|
});
|
|
46
37
|
|
|
47
|
-
/* ─────────────────────────────────────────────
|
|
48
|
-
WIDGET 2: 任务流 (tasks)
|
|
49
|
-
───────────────────────────────────────────── */
|
|
50
38
|
WidgetRuntime.register({
|
|
51
39
|
id: 'tasks',
|
|
52
40
|
title: '任务流',
|
|
@@ -59,9 +47,6 @@ WidgetRuntime.register({
|
|
|
59
47
|
},
|
|
60
48
|
});
|
|
61
49
|
|
|
62
|
-
/* ─────────────────────────────────────────────
|
|
63
|
-
WIDGET 3: 中央核心 (core) — 激活 Agent
|
|
64
|
-
───────────────────────────────────────────── */
|
|
65
50
|
WidgetRuntime.register({
|
|
66
51
|
id: 'core',
|
|
67
52
|
title: '中央核心 · 激活单元',
|
|
@@ -94,7 +79,6 @@ WidgetRuntime.register({
|
|
|
94
79
|
</div>
|
|
95
80
|
<div class="chat-log" data-role="chat-log"></div>
|
|
96
81
|
</div>`;
|
|
97
|
-
// orbit ticks
|
|
98
82
|
const tick = el.querySelector('[data-role="orbit-tick"]');
|
|
99
83
|
let h=''; for(let i=0;i<24;i++)h+=`<span style="transform:translateX(-50%) rotate(${i*15}deg)"></span>`;
|
|
100
84
|
tick.innerHTML=h;
|
|
@@ -111,9 +95,6 @@ WidgetRuntime.register({
|
|
|
111
95
|
},
|
|
112
96
|
});
|
|
113
97
|
|
|
114
|
-
/* ─────────────────────────────────────────────
|
|
115
|
-
WIDGET 4: HARNESS 遥测 (harness)
|
|
116
|
-
───────────────────────────────────────────── */
|
|
117
98
|
WidgetRuntime.register({
|
|
118
99
|
id: 'harness',
|
|
119
100
|
title: 'HARNESS 遥测',
|
|
@@ -150,14 +131,10 @@ WidgetRuntime.register({
|
|
|
150
131
|
ctx.loadHarnessInto(el, agentId);
|
|
151
132
|
},
|
|
152
133
|
onEvent(evt, el, ctx) {
|
|
153
|
-
// policy 更新或校准完成时立即刷新
|
|
154
134
|
ctx.loadHarnessInto(el, ctx.activeAgent);
|
|
155
135
|
},
|
|
156
136
|
});
|
|
157
137
|
|
|
158
|
-
/* ─────────────────────────────────────────────
|
|
159
|
-
WIDGET 5: 推理链 STREAM (thoughtchain)
|
|
160
|
-
───────────────────────────────────────────── */
|
|
161
138
|
WidgetRuntime.register({
|
|
162
139
|
id: 'thoughtchain',
|
|
163
140
|
title: '推理链 STREAM',
|
|
@@ -175,9 +152,6 @@ WidgetRuntime.register({
|
|
|
175
152
|
},
|
|
176
153
|
});
|
|
177
154
|
|
|
178
|
-
/* ─────────────────────────────────────────────
|
|
179
|
-
WIDGET 6: 事件流 LIVE (events)
|
|
180
|
-
───────────────────────────────────────────── */
|
|
181
155
|
WidgetRuntime.register({
|
|
182
156
|
id: 'events',
|
|
183
157
|
title: '事件流 · LIVE',
|
|
@@ -206,10 +180,6 @@ WidgetRuntime.register({
|
|
|
206
180
|
},
|
|
207
181
|
});
|
|
208
182
|
|
|
209
|
-
/* ─────────────────────────────────────────────
|
|
210
|
-
WIDGET 7: 协同 DAG (dag) — 多 Agent 星舰控制流
|
|
211
|
-
命令 → 主管分发 → 子 Agent → Harness 关卡 → 记忆汇聚
|
|
212
|
-
───────────────────────────────────────────── */
|
|
213
183
|
WidgetRuntime.register({
|
|
214
184
|
id: 'dag',
|
|
215
185
|
title: '协同 DAG · 控制流',
|
|
@@ -243,7 +213,6 @@ WidgetRuntime.register({
|
|
|
243
213
|
},
|
|
244
214
|
});
|
|
245
215
|
|
|
246
|
-
/* DAG 拓扑定义 */
|
|
247
216
|
const _DAG_NODES = {
|
|
248
217
|
command: { x: 60, y: 115, label: '指令', icon: '❯', kind: 'entry', color: '#1de9ff' },
|
|
249
218
|
supervisor: { x: 180, y: 115, label: '主管', icon: '🏢', kind: 'hub', color: '#1de9ff' },
|
|
@@ -265,7 +234,6 @@ function _dagBuild(el, ctx) {
|
|
|
265
234
|
const edgesG = el.querySelector('[data-role="dag-edges"]');
|
|
266
235
|
const nodesG = el.querySelector('[data-role="dag-nodes"]');
|
|
267
236
|
|
|
268
|
-
// edges
|
|
269
237
|
edgesG.innerHTML = _DAG_EDGES.map(([from, to], i) => {
|
|
270
238
|
const a = _DAG_NODES[from], b = _DAG_NODES[to];
|
|
271
239
|
const curve = (from === 'memory' && to === 'supervisor')
|
|
@@ -275,7 +243,6 @@ function _dagBuild(el, ctx) {
|
|
|
275
243
|
fill="none" stroke="#1a2942" stroke-width="1.5" marker-end="url(#dagArrow)"/>`;
|
|
276
244
|
}).join('');
|
|
277
245
|
|
|
278
|
-
// nodes
|
|
279
246
|
nodesG.innerHTML = Object.entries(_DAG_NODES).map(([id, n]) => {
|
|
280
247
|
const r = n.kind === 'hub' ? 17 : n.kind === 'gate' ? 16 : 14;
|
|
281
248
|
const shape = n.kind === 'gate'
|
|
@@ -301,7 +268,6 @@ function _dagSetActive(el, agentId) {
|
|
|
301
268
|
el.querySelectorAll('.dag-node').forEach(g => {
|
|
302
269
|
g.classList.toggle('dag-dim', false);
|
|
303
270
|
});
|
|
304
|
-
// highlight active agent path: command→supervisor→agent→harness→memory
|
|
305
271
|
const path = ['command','supervisor', agentId, 'harness','memory'];
|
|
306
272
|
el.querySelectorAll('.dag-node').forEach(g => {
|
|
307
273
|
const id = g.dataset.nodeG;
|
|
@@ -353,7 +319,6 @@ function _dagFlashGate(el, color) {
|
|
|
353
319
|
const gate = el.querySelector('[data-node="harness"]');
|
|
354
320
|
if (!gate) return;
|
|
355
321
|
const g = gate.closest('.dag-node') || gate;
|
|
356
|
-
// 注入一次性 keyframes(如未注入)
|
|
357
322
|
if (!document.getElementById('dag-flash-style')) {
|
|
358
323
|
const st = document.createElement('style');
|
|
359
324
|
st.id = 'dag-flash-style';
|
|
@@ -371,7 +336,6 @@ function _dagFlashGate(el, color) {
|
|
|
371
336
|
gate.classList.remove('dag-gate-flash');
|
|
372
337
|
void gate.offsetWidth; // 强制重排,允许动画重放
|
|
373
338
|
gate.classList.add('dag-gate-flash');
|
|
374
|
-
// 同时让 HARNESS 文字标签也闪一下
|
|
375
339
|
const label = el.querySelector('.dag-node[data-node-g="harness"] .dag-label');
|
|
376
340
|
if (label) { label.style.fill = color; label.style.fontWeight = '700'; }
|
|
377
341
|
setTimeout(() => {
|
|
@@ -381,11 +345,6 @@ function _dagFlashGate(el, color) {
|
|
|
381
345
|
}, 1200);
|
|
382
346
|
}
|
|
383
347
|
|
|
384
|
-
/* ─────────────────────────────────────────────
|
|
385
|
-
WIDGET 8: 执行终端 (terminal) — Shell 执行流
|
|
386
|
-
命令回显 · 记忆检索 · 推理 · 工具调用 · Harness 校验
|
|
387
|
-
带打字机流式效果,营造 "AI 正在工作" 的真实感
|
|
388
|
-
───────────────────────────────────────────── */
|
|
389
348
|
WidgetRuntime.register({
|
|
390
349
|
id: 'terminal',
|
|
391
350
|
title: '执行终端 · SHELL',
|
|
@@ -464,14 +423,9 @@ function _termWrite(el, text, type = 'out', stream = false) {
|
|
|
464
423
|
txtEl.textContent = text;
|
|
465
424
|
}
|
|
466
425
|
out.scrollTop = out.scrollHeight;
|
|
467
|
-
// 限制行数
|
|
468
426
|
while (out.children.length > 80) out.firstChild?.remove();
|
|
469
427
|
}
|
|
470
428
|
|
|
471
|
-
/* ─────────────────────────────────────────────
|
|
472
|
-
WIDGET 9: AI 浏览器 (browser) — 网页操作可视化
|
|
473
|
-
模拟 Agent 浏览网页:地址栏 · 加载流 · 操作高亮(点击/输入/滚动)
|
|
474
|
-
───────────────────────────────────────────── */
|
|
475
429
|
WidgetRuntime.register({
|
|
476
430
|
id: 'browser',
|
|
477
431
|
title: 'AI 浏览器 · BROWSE',
|
|
@@ -507,14 +461,12 @@ function _brzNavigate(el, url, actions) {
|
|
|
507
461
|
statusEl.textContent = 'LOADING';
|
|
508
462
|
statusEl.className = 'brz-status loading';
|
|
509
463
|
|
|
510
|
-
// 进度条动画
|
|
511
464
|
progEl.style.width = '0%';
|
|
512
465
|
progEl.style.opacity = '1';
|
|
513
466
|
setTimeout(() => progEl.style.width = '70%', 80);
|
|
514
467
|
setTimeout(() => { progEl.style.width = '100%'; }, 700);
|
|
515
468
|
setTimeout(() => { progEl.style.opacity = '0'; statusEl.textContent = 'LOADED'; statusEl.className = 'brz-status loaded'; }, 950);
|
|
516
469
|
|
|
517
|
-
// 渲染一个抽象的"网页骨架" + 操作高亮
|
|
518
470
|
vp.innerHTML = `
|
|
519
471
|
<div class="brz-page">
|
|
520
472
|
<div class="brz-skel brz-skel-title"></div>
|
|
@@ -531,7 +483,6 @@ function _brzNavigate(el, url, actions) {
|
|
|
531
483
|
<div class="brz-cursor" data-role="brz-cursor">➤</div>
|
|
532
484
|
</div>`;
|
|
533
485
|
|
|
534
|
-
// AI 操作序列高亮
|
|
535
486
|
const acts = actions || [
|
|
536
487
|
{ type: 'scan', label: '解析页面结构', x: 50, y: 20 },
|
|
537
488
|
{ type: 'click', label: '点击主内容区', x: 30, y: 45 },
|
|
@@ -548,7 +499,6 @@ function _brzNavigate(el, url, actions) {
|
|
|
548
499
|
cursor.style.top = a.y + '%';
|
|
549
500
|
cursor.setAttribute('data-label', a.label);
|
|
550
501
|
cursor.className = `brz-cursor act-${a.type}`;
|
|
551
|
-
// 涟漪
|
|
552
502
|
const ripple = document.createElement('div');
|
|
553
503
|
ripple.className = 'brz-ripple';
|
|
554
504
|
ripple.style.left = a.x + '%';
|
|
@@ -561,11 +511,6 @@ function _brzNavigate(el, url, actions) {
|
|
|
561
511
|
setTimeout(runAct, 1000);
|
|
562
512
|
}
|
|
563
513
|
|
|
564
|
-
/* ─────────────────────────────────────────────
|
|
565
|
-
WIDGET 10: 语音输入 (voice) — 麦克风波形 + 语音识别
|
|
566
|
-
Web Audio API 真实波形 + 浏览器原生 SpeechRecognition
|
|
567
|
-
识别结果可直接作为指令传输给激活 Agent
|
|
568
|
-
───────────────────────────────────────────── */
|
|
569
514
|
WidgetRuntime.register({
|
|
570
515
|
id: 'voice',
|
|
571
516
|
title: '语音输入 · VOICE',
|
|
@@ -600,7 +545,6 @@ function _voiceInit(el, ctx) {
|
|
|
600
545
|
let audioCtx = null, analyser = null, dataArr = null, rafId = null, stream = null;
|
|
601
546
|
let recognition = null, recognizing = false, finalText = '';
|
|
602
547
|
|
|
603
|
-
// 语音识别(浏览器原生)
|
|
604
548
|
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
|
|
605
549
|
if (SR) {
|
|
606
550
|
recognition = new SR();
|
|
@@ -685,7 +629,6 @@ function _voiceInit(el, ctx) {
|
|
|
685
629
|
const text = transcriptEl.textContent.trim();
|
|
686
630
|
if (!text || text === '聆听中...') return;
|
|
687
631
|
stopMic();
|
|
688
|
-
// 把识别结果填入控制台并传输
|
|
689
632
|
const input = document.getElementById('consoleInput');
|
|
690
633
|
if (input) { input.value = text; }
|
|
691
634
|
if (typeof transmit === 'function') transmit();
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>Foxclaw
|
|
6
|
+
<title>Foxclaw</title>
|
|
7
7
|
<!-- 内联 SVG 图标:不新增静态文件,也避免浏览器探 /favicon.ico 报 404 -->
|
|
8
8
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><rect width='32' height='32' rx='9' fill='%23179d5f'/><circle cx='16' cy='16' r='6.5' fill='%23f4fbf0'/></svg>" />
|
|
9
9
|
</head>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "foxclaw-deck-next",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "foxclaw-deck-next",
|
|
9
|
-
"version": "
|
|
9
|
+
"version": "0.1.2",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"vue": "^3.5.13"
|
|
12
12
|
},
|
|
@@ -7,10 +7,8 @@ import Inspector from './components/Inspector.vue'
|
|
|
7
7
|
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
|
8
8
|
import { state, setModule } from './stores/app.js'
|
|
9
9
|
import { bootChat } from './stores/chat.js'
|
|
10
|
+
import { t } from './lib/i18n.js'
|
|
10
11
|
|
|
11
|
-
/* 窄窗断点与 base.css 的 @media (max-width: 1180px) 是同一个数:
|
|
12
|
-
到这条线以下右栏变成抽屉(见 base.css),这里负责「变窄时自动收起」。
|
|
13
|
-
否则 900px 窗口里三栏并存,中栏只剩 252px,输入框被 + / 模型胶囊挤到 115px。 */
|
|
14
12
|
const NARROW = 1180
|
|
15
13
|
const narrow = ref(false)
|
|
16
14
|
|
|
@@ -21,7 +19,6 @@ function syncNarrow() {
|
|
|
21
19
|
if (n) state.railOpen = false
|
|
22
20
|
}
|
|
23
21
|
|
|
24
|
-
/* 恢复上次会话历史(后端落盘) */
|
|
25
22
|
onMounted(() => {
|
|
26
23
|
bootChat()
|
|
27
24
|
narrow.value = window.innerWidth < NARROW
|
|
@@ -34,7 +31,6 @@ onBeforeUnmount(() => {
|
|
|
34
31
|
window.removeEventListener('resize', syncNarrow)
|
|
35
32
|
})
|
|
36
33
|
|
|
37
|
-
/* Ctrl+, 打开设置(顶栏 ⚙ 旁边写的那个键位)。输入框里也生效 —— 它是全局入口 */
|
|
38
34
|
function onKey(e) {
|
|
39
35
|
if (e.ctrlKey && (e.key === ',' || e.code === 'Comma')) {
|
|
40
36
|
e.preventDefault()
|
|
@@ -55,8 +51,8 @@ function onKey(e) {
|
|
|
55
51
|
<Inspector />
|
|
56
52
|
</div>
|
|
57
53
|
<div v-if="narrow && state.railOpen" class="rail-scrim" @click="state.railOpen = false" />
|
|
58
|
-
<button v-if="!state.railOpen" class="rail-handle" title="
|
|
59
|
-
|
|
54
|
+
<button v-if="!state.railOpen" class="rail-handle" :title="t('app.expandInspector')" @click="state.railOpen = true">
|
|
55
|
+
{{ t('app.inspector') }}
|
|
60
56
|
</button>
|
|
61
57
|
</div>
|
|
62
58
|
</template>
|