diff --git a/backend/app/routers/tools.py b/backend/app/routers/tools.py
new file mode 100644
index 0000000..dec271a
--- /dev/null
+++ b/backend/app/routers/tools.py
@@ -0,0 +1,348 @@
+"""Tools API Router
+
+聚合两套工具体系的元数据:
+1. 注册层 (app/tools/) - YAML manifest 定义
+2. Agent 层 (app/agents/tools/) - @tool 装饰器定义
+"""
+
+import re
+import importlib
+
+from fastapi import APIRouter, Depends
+
+from app.routers.auth import get_current_user
+from app.models.user import User
+from app.schemas.tools import (
+ ToolsResponse,
+ ToolCategory,
+ ToolSubgroup,
+ ToolInfo,
+ ToolCommand,
+ ToolStats,
+ ToolSummary,
+)
+
+router = APIRouter(prefix="/api/tools", tags=["Tools"])
+
+# ============================================================
+# 辅助函数
+# ============================================================
+
+
+def _parse_command_from_docstring(docstring: str) -> dict:
+ """从函数的 docstring 解析参数信息"""
+ params = {"type": "object", "properties": {}, "required": []}
+ if not docstring:
+ return params
+
+ # 简单解析 Args: 段落
+ args_match = re.search(
+ r"Args:\s*(.*?)(?=\n\s*(?:Returns?|Raises?)|$", docstring, re.DOTALL | re.IGNORECASE
+ )
+ if args_match:
+ args_section = args_match.group(1)
+ # 匹配形如 "arg_name (type): description" 的行
+ for line in args_section.strip().split("\n"):
+ line = line.strip()
+ if not line:
+ continue
+ # 匹配: "name (type): description" 或 "name: description"
+ m = re.match(r"(\w+)\s*(?:\(\s*(\w+)\s*\))?\s*:", line)
+ if m:
+ param_name = m.group(1)
+ params["properties"][param_name] = {"type": "string", "description": line}
+ params["required"].append(param_name)
+
+ return params
+
+
+def _build_agent_tools() -> list[ToolInfo]:
+ """扫描 app/agents/tools/ 目录,内省 @tool 装饰器"""
+ tools: list[ToolInfo] = []
+
+ # 分类映射:文件名 -> (分类名, 子分类名)
+ category_map = {
+ "search": ("Agent层", "知识检索"),
+ "schedule": ("Agent层", "日程管理"),
+ "task": ("Agent层", "任务管理"),
+ "forum": ("Agent层", "论坛功能"),
+ "time_reasoning": ("Agent层", "时间推理"),
+ "builtins/file_tools": ("Agent层", "文件工具"),
+ "builtins/system_tools": ("Agent层", "系统命令"),
+ "builtins/dev_tools": ("Agent层", "开发工具"),
+ "builtins/collaboration_tools": ("Agent层", "协作工具"),
+ }
+
+ # 工具名称 -> 中文显示名
+ display_names = {
+ "search_knowledge": "知识库搜索",
+ "get_knowledge_graph_context": "知识图谱查询",
+ "build_knowledge_graph": "构建知识图谱",
+ "hybrid_search": "混合搜索",
+ "web_search": "联网搜索",
+ "get_schedule_day": "获取日程",
+ "create_todo": "创建待办",
+ "create_schedule_task": "创建日程任务",
+ "create_reminder": "创建提醒",
+ "create_goal": "创建目标",
+ "get_tasks": "获取任务列表",
+ "create_task": "创建任务",
+ "update_task_status": "更新任务状态",
+ "get_forum_posts": "获取论坛帖子",
+ "create_forum_post": "发布论坛帖子",
+ "scan_forum_for_instructions": "扫描论坛指令",
+ "resolve_time_expression": "解析时间表达式",
+ "glob": "文件路径匹配",
+ "grep": "文件内容搜索",
+ "read_file": "读取文件",
+ "write_file": "写入文件",
+ "bash": "Bash命令",
+ "powershell": "PowerShell命令",
+ "git": "Git操作",
+ "lsp_tools": "LSP代码导航",
+ "team_agent": "团队Agent通信",
+ "task_broadcast": "任务广播",
+ }
+
+ # 工具描述
+ descriptions = {
+ "search_knowledge": "搜索用户的私人知识库,返回最相关的文档片段",
+ "get_knowledge_graph_context": "获取用户知识图谱的上下文信息",
+ "build_knowledge_graph": "从文档构建/更新知识图谱",
+ "hybrid_search": "混合搜索,结合向量语义检索和关键词匹配",
+ "web_search": "通过 SearxNG 搜索外部网页信息",
+ "get_schedule_day": "获取指定日期的 todo/task/reminder/goal 聚合信息",
+ "create_todo": "创建指定日期的待办",
+ "create_schedule_task": "创建任务,支持优先级和截止日期",
+ "create_reminder": "创建提醒,支持自然语言时间",
+ "create_goal": "创建指定日期的目标",
+ "get_tasks": "获取用户当前的任务列表",
+ "create_task": "创建新任务",
+ "update_task_status": "更新任务状态",
+ "get_forum_posts": "获取论坛帖子列表",
+ "create_forum_post": "在论坛发布新帖子",
+ "scan_forum_for_instructions": "扫描论坛中的指令类帖子",
+ "resolve_time_expression": "解析中文自然语言时间表达",
+ "glob": "使用 glob 模式查找文件路径",
+ "grep": "在文件中搜索匹配的文本行",
+ "read_file": "读取文件内容",
+ "write_file": "写入文件内容",
+ "bash": "执行 Bash 命令",
+ "powershell": "执行 PowerShell 命令",
+ "git": "执行 Git 命令",
+ "lsp_tools": "LSP 代码导航和查找引用",
+ "team_agent": "向团队 Agent 发送消息或请求协作",
+ "task_broadcast": "向多个 Agent 广播任务",
+ }
+
+ # 需要扫描的模块
+ modules_to_scan = [
+ ("app.agents.tools.search", "search"),
+ ("app.agents.tools.schedule", "schedule"),
+ ("app.agents.tools.task", "task"),
+ ("app.agents.tools.forum", "forum"),
+ ("app.agents.tools.time_reasoning", "time_reasoning"),
+ ("app.agents.tools.builtins.file_tools", "builtins/file_tools"),
+ ("app.agents.tools.builtins.system_tools", "builtins/system_tools"),
+ ("app.agents.tools.builtins.dev_tools", "builtins/dev_tools"),
+ ("app.agents.tools.builtins.collaboration_tools", "builtins/collaboration_tools"),
+ ]
+
+ for module_name, category_key in modules_to_scan:
+ try:
+ mod = importlib.import_module(module_name)
+ except ImportError:
+ continue
+
+ # 扫描模块中所有 @tool 装饰的函数
+ for attr_name in dir(mod):
+ if attr_name.startswith("_"):
+ continue
+ attr = getattr(mod, attr_name)
+ # 检查是否是 langchain @tool 装饰的对象
+ if hasattr(attr, "name") and hasattr(attr, "description"):
+ tool_name = attr.name
+ tool_desc = attr.description or ""
+ # 清理 docstring 中的参数说明用于显示
+ display_desc = re.sub(r"\s*Args:\s*.*", "", tool_desc, flags=re.DOTALL).strip()
+ display_desc = re.sub(
+ r"\s*Returns?:\s*.*", "", display_desc, flags=re.DOTALL
+ ).strip()
+
+ # 获取 category 和 subcategory
+ cat_info = category_map.get(category_key, ("Agent层", category_key))
+ category, subcategory = cat_info[0], cat_info[1]
+
+ # 获取参数 schema
+ params_schema = getattr(attr, "args_schema", None)
+ parameters = {}
+ if params_schema:
+ try:
+ if hasattr(params_schema, "model_json_schema"):
+ parameters = params_schema.model_json_schema()
+ elif hasattr(params_schema, "schema"):
+ parameters = params_schema.schema()
+ except Exception:
+ pass
+
+ tool_info = ToolInfo(
+ name=tool_name,
+ display_name=display_names.get(tool_name, tool_name),
+ description=descriptions.get(tool_name, display_desc or tool_desc),
+ category=category,
+ subcategory=subcategory,
+ source="agent",
+ source_file=module_name,
+ tags=[],
+ enabled=True,
+ commands=[
+ ToolCommand(
+ name=tool_name,
+ description=tool_desc or display_desc,
+ parameters=parameters,
+ )
+ ],
+ stats=ToolStats(),
+ )
+ tools.append(tool_info)
+
+ return tools
+
+
+def _build_manifest_tools() -> list[ToolInfo]:
+ """从 YAML manifest 构建工具信息"""
+ tools: list[ToolInfo] = []
+
+ # manifest 文件 -> 分类映射
+ manifest_map = {
+ "file_operator": (
+ "注册层",
+ "文件操作",
+ [
+ ToolCommand(name="read_file", description="读取指定路径的文件内容"),
+ ToolCommand(name="write_file", description="将内容写入文件"),
+ ToolCommand(name="list_directory", description="列出目录内容"),
+ ToolCommand(name="search_files", description="递归搜索匹配模式的文件"),
+ ],
+ ),
+ "task_manager": (
+ "注册层",
+ "任务管理",
+ [
+ ToolCommand(name="create_task", description="创建新任务"),
+ ToolCommand(name="list_tasks", description="列出任务"),
+ ToolCommand(name="get_task", description="获取任务详情"),
+ ToolCommand(name="complete_task", description="标记任务完成"),
+ ToolCommand(name="fail_task", description="标记任务失败"),
+ ],
+ ),
+ "web_fetch": (
+ "注册层",
+ "网页抓取",
+ [
+ ToolCommand(name="fetch", description="抓取网页内容"),
+ ToolCommand(name="screenshot", description="截取网页截图"),
+ ],
+ ),
+ "web_search": (
+ "注册层",
+ "联网搜索",
+ [
+ ToolCommand(name="search", description="执行语义级搜索"),
+ ToolCommand(name="deep_search", description="深度搜索,带摘要生成"),
+ ],
+ ),
+ }
+
+ manifest_descriptions = {
+ "file_operator": "强大的文件系统操作工具,支持读写、搜索、下载等功能",
+ "task_manager": "任务创建、查询、更新和状态管理",
+ "web_fetch": "网页内容抓取工具,支持 HTML 解析、截图等功能",
+ "web_search": "语义级并发搜索引擎,支持多源搜索和结果聚合",
+ }
+
+ for tool_name, (category, subcategory, commands) in manifest_map.items():
+ tool_info = ToolInfo(
+ name=tool_name,
+ display_name=subcategory,
+ description=manifest_descriptions.get(tool_name, ""),
+ category=category,
+ subcategory=subcategory,
+ source="manifest",
+ source_file=f"app/tools/manifests/{tool_name}.yaml",
+ tags=[],
+ enabled=True,
+ commands=commands,
+ stats=ToolStats(),
+ )
+ tools.append(tool_info)
+
+ return tools
+
+
+# ============================================================
+# 路由
+# ============================================================
+
+
+@router.get("", response_model=ToolsResponse)
+async def list_tools(
+ current_user: User = Depends(get_current_user),
+):
+ """获取所有内置工具列表(只读)"""
+ # 构建工具列表
+ manifest_tools = _build_manifest_tools()
+ agent_tools = _build_agent_tools()
+
+ all_tools = manifest_tools + agent_tools
+
+ # 按 category 和 subcategory 分组
+ category_map: dict[str, dict[str, list[ToolInfo]]] = {
+ "注册层": {},
+ "Agent层": {},
+ }
+
+ for tool in all_tools:
+ cat = tool.category
+ subcat = tool.subcategory
+ if cat not in category_map:
+ category_map[cat] = {}
+ if subcat not in category_map[cat]:
+ category_map[cat][subcat] = []
+ category_map[cat][subcat].append(tool)
+
+ # 构建响应
+ categories = []
+ for cat_name, subgroups_dict in category_map.items():
+ if not subgroups_dict:
+ continue
+ subgroups = []
+ for subcat_name, tools_list in subgroups_dict.items():
+ subgroups.append(
+ ToolSubgroup(
+ name=subcat_name,
+ display_name=subcat_name,
+ tools=tools_list,
+ )
+ )
+ categories.append(
+ ToolCategory(
+ name=cat_name,
+ display_name=cat_name,
+ subgroups=subgroups,
+ )
+ )
+
+ # 计算摘要
+ total_commands = sum(len(t.commands) for t in all_tools)
+ active_commands = sum(len(t.commands) for t in all_tools if t.enabled)
+
+ summary = ToolSummary(
+ total_commands=total_commands,
+ active_commands=active_commands,
+ total_tools=len(all_tools),
+ manifest_tools=len(manifest_tools),
+ agent_tools=len(agent_tools),
+ )
+
+ return ToolsResponse(categories=categories, summary=summary)
diff --git a/backend/app/schemas/tools.py b/backend/app/schemas/tools.py
new file mode 100644
index 0000000..9f6adb0
--- /dev/null
+++ b/backend/app/schemas/tools.py
@@ -0,0 +1,76 @@
+"""Tools API Schemas"""
+
+from pydantic import BaseModel
+from typing import Optional
+
+
+class ToolCommand(BaseModel):
+ """单个工具命令"""
+
+ name: str
+ description: str
+ parameters: dict = {}
+
+
+class ToolStats(BaseModel):
+ """工具调用统计"""
+
+ call_count: int = 0
+ error_count: int = 0
+ total_duration_ms: int = 0
+ avg_duration_ms: int = 0
+ error_rate: float = 0.0
+
+
+class ToolInfo(BaseModel):
+ """工具完整信息"""
+
+ name: str
+ display_name: str
+ description: str
+ category: str # 中文分类名
+ subcategory: str = "" # 子分类
+ source: str # "manifest" | "agent"
+ source_file: str = "" # 来源文件路径
+ tags: list[str] = []
+ enabled: bool = True
+ commands: list[ToolCommand] = []
+ stats: Optional[ToolStats] = None
+ config: dict = {} # 配置参数(只读)
+
+
+class ToolCategory(BaseModel):
+ """工具分类"""
+
+ name: str # 大分类:注册层 / Agent层
+ display_name: str # 中文显示名
+ subgroups: list["ToolSubgroup"] = []
+
+
+class ToolSubgroup(BaseModel):
+ """工具子分类"""
+
+ name: str # 子分类名
+ display_name: str # 中文显示名
+ tools: list[ToolInfo] = []
+
+
+class ToolSummary(BaseModel):
+ """工具统计摘要"""
+
+ total_commands: int = 0
+ active_commands: int = 0
+ total_tools: int = 0
+ manifest_tools: int = 0
+ agent_tools: int = 0
+
+
+class ToolsResponse(BaseModel):
+ """GET /api/tools 响应"""
+
+ categories: list[ToolCategory]
+ summary: ToolSummary
+
+
+# 更新前向引用
+ToolCategory.model_rebuild()
diff --git a/development-doc/plan/temple-update/README.md b/development-doc/plan/temple-update/README.md
new file mode 100644
index 0000000..a54c75f
--- /dev/null
+++ b/development-doc/plan/temple-update/README.md
@@ -0,0 +1,165 @@
+# 智慧神殿(Temple)升级计划索引
+
+本目录用于存放智慧神殿(Temple)页面的升级规划文档。
+
+## 文档说明
+
+| 文件 | 说明 |
+|------|------|
+| `README.md` | 总览、阶段关系、实施顺序、当前状态 |
+| `phase-0-current-state.md` | 当前现状、问题、目标架构 |
+| `phase-1-tools-api.md` | 后端 Tools API 开发 |
+| `phase-2-tools-frontend.md` | Tools Tab 前端实现 |
+| `phase-3-skills-integration.md` | Skills Tab 复用集成 |
+| `checklist.md` | 执行清单 |
+
+## 推荐阅读顺序
+
+1. 先读 `README.md`(本文)
+2. 再读 `phase-0-current-state.md`
+3. 再按顺序阅读 phase 1 ~ 3
+4. 参考 `checklist.md` 进行任务追踪
+
+---
+
+## 当前总体状态(2026-04-08)
+
+| Phase | 当前状态 | 说明 |
+|------|------|------|
+| Phase 0 | 已完成 | 现状梳理完毕,本文档 |
+| Phase 1 | 待开始 | 后端 Tools API 开发 |
+| Phase 2 | 待开始 | 前端 Tools Tab 实现 |
+| Phase 3 | 待开始 | Skills Tab 复用集成 |
+
+---
+
+## 总体升级原则
+
+1. **Tools 只读不做编辑** - 系统内置工具不允许手动修改,防止配置破坏
+2. **Skills 以 DB 为 source of truth** - UI 操作 DB,后端自动生成 `.md` 文件,用户不直接碰代码
+3. **复用现有 Skills 页面** - 已有完整 CRUD,改动成本最低
+4. **MCP 暂不纳入** - 当前仅为概念性能力包,后期独立需求
+5. **样式沿用现有体系** - 复用 `chatPage.css` 的深色终端风格 + `jarvis-*` CSS 变量
+
+---
+
+## 阶段关系图
+
+```
+Phase 0 ──────────────────────────────────────────────────────────────┐
+│ 现状与目标 │
+│ - Temple 页面现状分析 │
+│ - Tools 系统梳理 │
+│ - Skills 系统梳理 │
+│ - 设计决策 │
+│ 状态:已完成 │
+└────────────────────────────────────────────────────────────────────┘
+ │
+ ▼
+Phase 1 ──────────────────────────────────────────────────────────────┐
+│ 后端 Tools API │
+│ - GET /api/tools 接口开发 │
+│ - ToolRegistry 聚合所有工具 │
+│ - 聚合两套工具体系元数据 │
+│ │
+│ 核心文件: app/routers/tools.py │
+│ 依赖: 无 │
+│ 工作量: 1 天 │
+└────────────────────────────────────────────────────────────────────┘
+ │
+ ▼
+Phase 2 ──────────────────────────────────────────────────────────────┐
+│ 前端 Tools Tab │
+│ - useTemple.ts composable │
+│ - Tools 分类树实现 │
+│ - 工具详情面板 │
+│ - Metrics Strip 统计行 │
+│ │
+│ 核心文件: frontend/src/pages/temple/ │
+│ 依赖: Phase 1 │
+│ 工作量: 2 天 │
+└────────────────────────────────────────────────────────────────────┘
+ │
+ ▼
+Phase 3 ──────────────────────────────────────────────────────────────┐
+│ Skills Tab 复用集成 │
+│ - 确认现有 Skills 页面功能完整 │
+│ - 与 Temple 页面 Tab 切换联动 │
+│ - 样式一致性检查 │
+│ │
+│ 核心文件: frontend/src/pages/temple/, frontend/src/pages/skills/ │
+│ 依赖: Phase 2 │
+│ 工作量: 0.5 天 │
+└────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## 两套 Tools 体系梳理
+
+### 注册层工具(`app/tools/`)
+
+| 工具 | Manifest | 命令数 |
+|------|---------|--------|
+| `file_operator` | `manifests/file_operator.yaml` | 4 |
+| `task_manager` | `manifests/task_manager.yaml` | 5 |
+| `web_fetch` | `manifests/web_fetch.yaml` | 2 |
+| `web_search` | `manifests/web_search.yaml` | 2 |
+
+### Agent 内置层工具(`app/agents/tools/`)
+
+| 类别 | 工具数 | 来源文件 |
+|------|--------|---------|
+| 文件操作 | 4 | `builtins/file_tools.py` |
+| 系统命令 | 2 | `builtins/system_tools.py` |
+| 开发工具 | 2 | `builtins/dev_tools.py` |
+| 协作工具 | 2 | `builtins/collaboration_tools.py` |
+| 知识检索 | 5 | `search.py` |
+| 日程管理 | 5 | `schedule.py` |
+| 任务管理 | 3 | `task.py` |
+| 论坛功能 | 3 | `forum.py` |
+| 时间推理 | 1 | `time_reasoning.py` |
+
+**合计约 34 个工具命令**
+
+---
+
+## 设计决策记录
+
+| 决策 | 原因 |
+|------|------|
+| Tools 只读不做编辑 | 系统内置工具不允许用户手动修改,防止配置破坏 |
+| 不引入 MCP 管理 | 当前 MCP 仅为概念性能力包,无实际 server 连接需求,后期独立需求 |
+| Skills 以 DB 为 source of truth | UI 操作 DB,后端同步生成 .md 文件,用户不直接碰代码 |
+| 复用现有 Skills 页面 | 已有完整 CRUD,改动成本最低 |
+| 按工具来源分类 | 与代码结构对应,用户可追溯工具定义位置 |
+
+---
+
+## 文件变更追踪
+
+| Phase | 新增文件 | 修改文件 |
+|-------|---------|---------|
+| Phase 1 | `app/routers/tools.py`, `app/schemas/tools.py` | `app/main.py`(注册路由) |
+| Phase 2 | `frontend/src/pages/temple/index.vue`, `templePage.css`, `composables/useTemple.ts`, `frontend/src/api/tools.ts` | `frontend/src/pages/temple/index.vue`(重写占位页) |
+| Phase 3 | 无 | `frontend/src/pages/temple/index.vue`(Tab 切换逻辑) |
+
+---
+
+## 与其他 Phase 的关系
+
+| 相关模块 | 协作内容 |
+|---------|---------|
+| Skills Registry (agent-update Phase 9) | Skills 的 DB 层由 `/api/skills` 提供,文件层由 SkillRegistry 管理 |
+| Tool System (tool-update T.1-T.4) | Temple 展示的 Tools 元数据来自 tool-update 建立的 manifest 系统 |
+
+---
+
+## 总工作量
+
+| Phase | 工作量 |
+|-------|--------|
+| Phase 1 | 1 天 |
+| Phase 2 | 2 天 |
+| Phase 3 | 0.5 天 |
+| **总计** | **3.5 天** |
diff --git a/development-doc/plan/temple-update/checklist.md b/development-doc/plan/temple-update/checklist.md
new file mode 100644
index 0000000..bd76683
--- /dev/null
+++ b/development-doc/plan/temple-update/checklist.md
@@ -0,0 +1,60 @@
+# 智慧神殿(Temple)执行清单
+
+> 更新日期:2026-04-08
+> 总工作量:3.5 天
+
+---
+
+## Phase 1:后端 Tools API
+
+| 序号 | 任务 | 状态 | 备注 |
+|------|------|------|------|
+| 1.1 | 创建 `app/schemas/tools.py`,定义 Pydantic Schema | 待开始 | |
+| 1.2 | 创建 `app/routers/tools.py`,实现 `GET /api/tools` | 待开始 | |
+| 1.3 | 实现 ToolRegistry 工具元数据聚合 | 待开始 | 复用 `list_all()` |
+| 1.4 | 实现 Agent 层工具扫描(内省 `@tool` 装饰器) | 待开始 | 扫描 `app/agents/tools/` |
+| 1.5 | 实现分类分组逻辑(注册层 / Agent 层) | 待开始 | |
+| 1.6 | 在 `app/main.py` 注册路由 | 待开始 | |
+| 1.7 | 本地测试 `GET /api/tools` 返回正确数据 | 待开始 | |
+
+---
+
+## Phase 2:前端 Tools Tab
+
+| 序号 | 任务 | 状态 | 备注 |
+|------|------|------|------|
+| 2.1 | 创建 `frontend/src/api/tools.ts` API 客户端 | 待开始 | |
+| 2.2 | 创建 `frontend/src/pages/temple/composables/useTemple.ts` | 待开始 | |
+| 2.3 | 实现 Tab 切换器组件 | 待开始 | Tools / Skills 切换 |
+| 2.4 | 实现 Metrics Strip 统计行 | 待开始 | |
+| 2.5 | 实现分类树组件(两极结构) | 待开始 | |
+| 2.6 | 实现工具列表(无选中时) | 待开始 | 卡片形式 |
+| 2.7 | 实现工具详情面板 | 待开始 | 含 Commands 列表 |
+| 2.8 | 创建 `templePage.css` 样式 | 待开始 | 复用 jarvis-* 变量 |
+| 2.9 | 重写 `frontend/src/pages/temple/index.vue` | 待开始 | 替换占位符 |
+| 2.10 | 联调后端 API,数据正确渲染 | 待开始 | |
+
+---
+
+## Phase 3:Skills Tab 复用集成
+
+| 序号 | 任务 | 状态 | 备注 |
+|------|------|------|------|
+| 3.1 | 将 Skills 页面集成到 Temple Skills Tab | 待开始 | 推荐方案 A(条件渲染) |
+| 3.2 | Tab 切换逻辑实现 | 待开始 | |
+| 3.3 | Skills CRUD 功能验证 | 待开始 | 创建/编辑/删除/启用/禁用 |
+| 3.4 | Skills Modal 和 Drawer 交互验证 | 待开始 | |
+| 3.5 | Skills Tab 下 Metrics Strip 切换指标 | 待开始 | 显示 Skills 指标 |
+| 3.6 | Tab 切换状态保持验证 | 待开始 | 不丢失选中状态 |
+
+---
+
+## 验收标准
+
+- [ ] `GET /api/tools` 返回 200,响应结构正确
+- [ ] Temple 页面加载无报错
+- [ ] Tools Tab 显示所有工具分类
+- [ ] 点击工具有详情(Commands 列表完整)
+- [ ] Skills Tab 下 Skills CRUD 全部正常
+- [ ] 样式与 Jarvis 整体风格一致
+- [ ] 无前端 console.error
diff --git a/development-doc/plan/temple-update/phase-0-current-state.md b/development-doc/plan/temple-update/phase-0-current-state.md
new file mode 100644
index 0000000..936ae10
--- /dev/null
+++ b/development-doc/plan/temple-update/phase-0-current-state.md
@@ -0,0 +1,171 @@
+# Phase 0:智慧神殿现状与目标
+
+日期:2026-04-08
+状态:已完成
+
+---
+
+## 1. 本阶段目的
+
+本文件用于统一背景认知,明确:
+
+- Temple 页面当前处于什么状态
+- 主要短板是什么
+- 为什么要升级
+- 升级后的目标形态是什么
+
+---
+
+## 2. 当前 Temple 页面状态
+
+### 2.1 现有实现
+
+`frontend/src/pages/temple/index.vue` 是一个**空白占位页**:
+
+```vue
+
+
+
+
+
+```
+
+### 2.2 触发入口
+
+聊天输入框上方三个按钮之一(`◈`),跳转到 `/temple`:
+
+```html
+
+
+
+
+
+
+```
+
+---
+
+## 3. 当前系统现状
+
+### 3.1 Tools 系统(两套并存)
+
+#### A. 工具注册层(`app/tools/`)
+
+已建立 manifest 驱动的工具注册体系:
+
+```
+app/tools/
+├── manifests/ # YAML manifest 定义
+│ ├── file_operator.yaml # 4 commands: read_file, write_file, list_directory, search_files
+│ ├── task_manager.yaml # 5 commands: create_task, list_tasks, get_task, complete_task, fail_task
+│ ├── web_fetch.yaml # 2 commands: fetch, screenshot
+│ └── web_search.yaml # 2 commands: search, deep_search
+├── registry.py # ToolRegistry 动态注册中心
+├── implementations/ # 工具 Python 实现
+├── permissions.py # 权限控制
+├── hooks/ # Hook 系统(审计日志、安全扫描、危险确认)
+└── schemas/ # Pydantic Schema
+```
+
+#### B. Agent 工具层(`app/agents/tools/`)
+
+LangChain `@tool` 装饰器定义的 Agent 可用工具:
+
+| 类别 | 工具 | 源文件 |
+|------|------|--------|
+| 文件操作 | `glob`, `grep`, `read_file`, `write_file` | `builtins/file_tools.py` |
+| 系统命令 | `bash`, `powershell` | `builtins/system_tools.py` |
+| 开发工具 | `git`, `lsp_tools` | `builtins/dev_tools.py` |
+| 协作工具 | `team_agent`, `task_broadcast` | `builtins/collaboration_tools.py` |
+| 知识检索 | `search_knowledge`, `get_knowledge_graph_context`, `build_knowledge_graph`, `hybrid_search`, `web_search` | `search.py` |
+| 日程管理 | `get_schedule_day`, `create_todo`, `create_schedule_task`, `create_reminder`, `create_goal` | `schedule.py` |
+| 任务管理 | `get_tasks`, `create_task`, `update_task_status` | `task.py` |
+| 论坛功能 | `get_forum_posts`, `create_forum_post`, `scan_forum_for_instructions` | `forum.py` |
+| 时间推理 | `resolve_time_expression` | `time_reasoning.py` |
+
+### 3.2 Skills 系统
+
+#### A. DB 层
+
+已有完整 CRUD:
+
+- 路由:`/api/skills`
+- 字段:`name`, `description`, `instructions`, `agent_type`, `tools`, `visibility`, `is_builtin`, `is_active`
+- Agent types:`general`, `schedule_planner`, `executor`, `librarian`, `analyst`
+- Visibility:`private`, `team`, `market`
+
+#### B. 文件层
+
+`SkillRegistry` 加载 `.md` 文件供 Agent 运行时使用。
+
+加载器:
+- `MCPSkillLoader` - MCP 能力包加载
+- `LocalSkillLoader` - 本地 `.md` 文件加载
+- `PluginLoader` - 插件式加载
+
+### 3.3 当前问题
+
+| 问题 | 影响 |
+|------|------|
+| Temple 页面是空白占位页 | 三个按钮入口之一完全无功能 |
+| Tools 无统一展示入口 | 用户无法看到系统有哪些可用工具 |
+| Tools 散落在两套体系 | manifest 层 + agent 层,用户无感知 |
+| Skills 页面独立在 `/skills` | 工具和技能没有统一管理入口 |
+
+---
+
+## 4. 目标架构
+
+```
+┌─────────────────────────────────────────────────────────────┐
+│ /temple │
+│ ┌──────────────────────────────────────────────────────┐ │
+│ │ [◈ 智慧神殿] [Tools] [Skills] │ │
+│ └──────────────────────────────────────────────────────┘ │
+│ ┌──────────────────────────────────────────────────────┐ │
+│ │ TOTAL: 30 ACTIVE: 28 AGENTS: 5 (Metrics) │ │
+│ └──────────────────────────────────────────────────────┘ │
+│ │
+│ ┌────────────────┐ ┌─────────────────────────────────┐ │
+│ │ [分类树] │ │ [工具详情] │ │
+│ │ │ │ │ │
+│ │ ▼ 注册层 │ │ file_operator │ │
+│ │ 文件操作 │ │ 描述: 强大的文件系统操作工具 │ │
+│ │ 任务管理 │ │ 命令: 4 个 │ │
+│ │ ▼ Agent层 │ │ 调用: 1,234 次 错误率: 0.2% │ │
+│ │ 知识检索 │ │ │ │
+│ │ 日程管理 │ │ [Commands] │ │
+│ │ 任务管理 │ │ • read_file │ │
+│ │ 论坛功能 │ │ • write_file │ │
+│ │ 时间推理 │ │ • list_directory │ │
+│ └────────────────┘ └─────────────────────────────────┘ │
+└─────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## 5. 本阶段产出要求
+
+- [x] 团队对 Temple 当前状态和目标方向达成一致
+- [x] Tools 系统两套并存的现状已梳理清楚
+- [x] Skills 系统现有架构已梳理清楚
+- [x] 后续 phase 文档能够在这个认知基础上展开
diff --git a/development-doc/plan/temple-update/phase-1-tools-api.md b/development-doc/plan/temple-update/phase-1-tools-api.md
new file mode 100644
index 0000000..f2f4c30
--- /dev/null
+++ b/development-doc/plan/temple-update/phase-1-tools-api.md
@@ -0,0 +1,135 @@
+# Phase 1:后端 Tools API 开发
+
+日期:2026-04-08
+状态:待开始
+
+---
+
+## 1. 本阶段目的
+
+开发 `GET /api/tools` 接口,聚合两套工具体系的元数据,为前端 Tools Tab 提供数据源。
+
+---
+
+## 2. 核心文件
+
+| 文件 | 作用 |
+|------|------|
+| `app/routers/tools.py` | 新建,Tools 路由 |
+| `app/schemas/tools.py` | 新建,Tools API Pydantic Schema |
+
+---
+
+## 3. API 设计
+
+### 3.1 接口
+
+```
+GET /api/tools
+```
+
+### 3.2 响应结构
+
+```python
+class ToolCommand(BaseModel):
+ name: str
+ description: str
+ parameters: dict # JSON Schema
+
+class ToolStats(BaseModel):
+ call_count: int
+ error_count: int
+ total_duration_ms: int
+ avg_duration_ms: int
+ error_rate: float
+
+class ToolCategory(BaseModel):
+ name: str # 显示用中文分类名
+ source: str # "manifest" | "agent"
+ tools: list[ToolInfo]
+
+class ToolInfo(BaseModel):
+ name: str
+ display_name: str
+ description: str
+ category: str
+ tags: list[str]
+ enabled: bool
+ source: str # "manifest" | "agent"
+ commands: list[ToolCommand]
+ stats: ToolStats | None
+
+class ToolsResponse(BaseModel):
+ categories: list[ToolCategory]
+ summary: dict:
+ total: int
+ active: int
+ by_source: dict
+```
+
+### 3.3 分类结构
+
+按工具来源分为两大类:
+
+**注册层(source: "manifest")**
+
+| Category Name | 来源 |
+|--------------|------|
+| `文件操作` | `manifests/file_operator.yaml` |
+| `任务管理` | `manifests/task_manager.yaml` |
+| `网页抓取` | `manifests/web_fetch.yaml` |
+| `联网搜索` | `manifests/web_search.yaml` |
+
+**Agent 层(source: "agent")**
+
+| Category Name | 来源 |
+|--------------|------|
+| `文件工具` | `builtins/file_tools.py` |
+| `系统命令` | `builtins/system_tools.py` |
+| `开发工具` | `builtins/dev_tools.py` |
+| `协作工具` | `builtins/collaboration_tools.py` |
+| `知识检索` | `search.py` |
+| `日程管理` | `schedule.py` |
+| `任务管理` | `task.py` |
+| `论坛功能` | `forum.py` |
+| `时间推理` | `time_reasoning.py` |
+
+---
+
+## 4. 实现逻辑
+
+### 4.1 数据聚合流程
+
+```
+1. 从 ToolRegistry.list_all() 获取注册层工具元数据
+2. 扫描 app/agents/tools/ 下所有 @tool 装饰器,获取 Agent 层工具
+3. 合并两套数据,按 category 分组
+4. 调用 ToolRegistry.get_stats() 获取统计数据
+5. 返回聚合后的 categories + summary
+```
+
+### 4.2 Agent 层工具扫描
+
+通过内省 `app/agents/tools/` 目录下所有 `@tool` 装饰的函数,提取:
+
+- `__name__` → tool name
+- `__doc__` → description
+- `__annotations__` → parameters schema
+
+### 4.3 注册路由
+
+在 `app/main.py` 中注册新路由:
+
+```python
+from app.routers import tools as tools_router
+app.include_router(tools_router.router, prefix="/api", tags=["tools"])
+```
+
+---
+
+## 5. 产出要求
+
+- [x] `GET /api/tools` 接口可调用,返回完整工具列表
+- [x] 两套工具体系元数据正确聚合
+- [x] 统计数据(调用次数、错误率)正确返回
+- [x] 按 category 分组,source 字段区分来源
diff --git a/development-doc/plan/temple-update/phase-2-tools-frontend.md b/development-doc/plan/temple-update/phase-2-tools-frontend.md
new file mode 100644
index 0000000..6c138ef
--- /dev/null
+++ b/development-doc/plan/temple-update/phase-2-tools-frontend.md
@@ -0,0 +1,167 @@
+# Phase 2:前端 Tools Tab 实现
+
+日期:2026-04-08
+状态:待开始
+
+---
+
+## 1. 本阶段目的
+
+实现 Temple 页面的 Tools Tab,包括分类树 + 详情面板 + Metrics Strip。
+
+---
+
+## 2. 核心文件
+
+| 文件 | 作用 |
+|------|------|
+| `frontend/src/api/tools.ts` | 新建,Tools API 客户端 |
+| `frontend/src/pages/temple/composables/useTemple.ts` | 新建,Tab/Skills 逻辑 |
+| `frontend/src/pages/temple/index.vue` | 重写主页面(替换占位符) |
+| `frontend/src/pages/temple/templePage.css` | 新建,样式 |
+
+---
+
+## 3. 页面布局
+
+```
+┌─────────────────────────────────────────────────────────────┐
+│ [◈ 智慧神殿] [Tools] [Skills] ← Tab 切换器 │
+├─────────────────────────────────────────────────────────────┤
+│ TOTAL: 30 │ ACTIVE: 28 │ AGENTS: 5 ← Metrics Strip │
+├──────────────────────────┬──────────────────────────────────┤
+│ │ │
+│ [分类树] │ [工具详情] │
+│ │ │
+│ ▼ 注册层 │ file_operator │
+│ 文件操作 │ ──────────── │
+│ 任务管理 │ 描述: 强大的文件系统操作工具 │
+│ 网页抓取 │ 命令: 4 个 │
+│ 联网搜索 │ 标签: file, system, essential │
+│ ▼ Agent层 │ 状态: 启用 │
+│ 文件工具 │ 调用: 1,234 次 │
+│ 系统命令 │ 错误率: 0.2% │
+│ 开发工具 │ 平均耗时: 150ms │
+│ 协作工具 │ │
+│ 知识检索 │ [Commands] │
+│ 日程管理 │ ─────────────────────────── │
+│ 任务管理 │ read_file │
+│ 论坛功能 │ ─────────────────────────── │
+│ 时间推理 │ write_file │
+│ │ ─────────────────────────── │
+│ │ list_directory │
+│ │ ─────────────────────────── │
+│ │ search_files │
+└──────────────────────────┴──────────────────────────────────┘
+```
+
+---
+
+## 4. 组件说明
+
+### 4.1 Tab 切换器
+
+两个 Tab:`Tools` | `Skills`
+- `Tools` → 本 phase 实现
+- `Skills` → Phase 3(复用现有页面)
+
+### 4.2 Metrics Strip
+
+三个统计指标卡片:
+
+| 指标 | 说明 |
+|------|------|
+| `TOTAL` | 系统工具总数(所有工具的 commands 总数) |
+| `ACTIVE` | 启用中的工具数 |
+| `AGENTS` | 工具绑定的 Agent 类型数(固定 5) |
+
+### 4.3 分类树
+
+- 两级结构:大类(注册层 / Agent 层)→ 具体分类
+- 点击分类 → 右侧显示该分类下的工具列表
+- 点击工具 → 右侧显示工具详情
+
+### 4.4 工具详情面板
+
+当无工具选中时:显示分类下的工具列表(卡片形式)
+当有工具选中时:显示工具详情
+
+详情内容:
+- **Name / Display Name**
+- **Description**
+- **Category / Tags**
+- **Enabled status**
+- **Stats**: call_count, error_rate, avg_duration_ms
+- **Commands**: 每个 command 的 name + description(只读)
+
+---
+
+## 5. useTemple.ts 接口设计
+
+```typescript
+// useTemple.ts
+export function useTemple() {
+ // State
+ const activeTab = ref<'tools' | 'skills'>('tools')
+ const categories = ref([])
+ const selectedCategory = ref(null)
+ const selectedTool = ref(null)
+ const loading = ref(false)
+
+ // Computed
+ const summary = computed(() => { ... })
+ const currentCategoryTools = computed(() => { ... })
+
+ // Actions
+ async function fetchTools() { ... }
+ function selectCategory(name: string) { ... }
+ function selectTool(tool: ToolInfo) { ... }
+
+ return {
+ activeTab,
+ categories,
+ selectedCategory,
+ selectedTool,
+ loading,
+ summary,
+ currentCategoryTools,
+ fetchTools,
+ selectCategory,
+ selectTool,
+ }
+}
+```
+
+---
+
+## 6. 样式规范
+
+沿用 Jarvis 现有风格:
+
+```css
+/* templePage.css */
+.temple-page {
+ /* 复用 jarvis-* CSS 变量 */
+ background: var(--bg-primary);
+ color: var(--text-primary);
+}
+
+.metric-card {
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+}
+
+.category-tree {
+ /* 深色终端风格 */
+}
+```
+
+---
+
+## 7. 产出要求
+
+- [x] Tab 切换器正常切换 Tools / Skills
+- [x] Metrics Strip 正确显示统计数据
+- [x] 分类树正确渲染,展开/收起正常
+- [x] 点击工具有详情面板,Commands 列表完整
+- [x] 样式与 Jarvis 整体风格一致
diff --git a/development-doc/plan/temple-update/phase-3-skills-integration.md b/development-doc/plan/temple-update/phase-3-skills-integration.md
new file mode 100644
index 0000000..2e3b4ac
--- /dev/null
+++ b/development-doc/plan/temple-update/phase-3-skills-integration.md
@@ -0,0 +1,88 @@
+# Phase 3:Skills Tab 复用集成
+
+日期:2026-04-08
+状态:待开始
+
+---
+
+## 1. 本阶段目的
+
+将现有的 `/skills` 页面完整嵌入 Temple 页面的 Skills Tab,实现统一入口。
+
+---
+
+## 2. 核心文件
+
+| 文件 | 作用 |
+|------|------|
+| `frontend/src/pages/skills/index.vue` | 已有,Skills 完整页面 |
+| `frontend/src/pages/skills/composables/useSkillsPage.ts` | 已有,Skills 逻辑 |
+| `frontend/src/api/skill.ts` | 已有,Skills API 客户端 |
+
+---
+
+## 3. 集成方式
+
+### 3.1 方案选择
+
+**方案 A(推荐):Tab 内条件渲染**
+
+在 `Temple/index.vue` 中使用 `v-if` 切换:
+
+```vue
+
+
+
+```
+
+优点:单一页面,状态共享简单
+缺点:Skills 页面较大,代码集中
+
+**方案 B:路由嵌套**
+
+```vue
+// Temple/index.vue
+
+```
+
+在 `skills/` 路由加 `parent: temple`
+
+优点:页面分离,代码清晰
+缺点:需要改路由配置
+
+**推荐方案 A**,改动最小,Skills 页面代码以内联形式放入 Temple。
+
+### 3.2 Tab 切换逻辑
+
+```typescript
+function switchTab(tab: 'tools' | 'skills') {
+ activeTab.value = tab
+ if (tab === 'skills') {
+ // Skills 页面初始化(如果需要)
+ }
+}
+```
+
+---
+
+## 4. 样式调整
+
+Skills 页面样式独立在 `skillsPage.css`,切换 Tab 时保留其样式上下文。
+
+---
+
+## 5. 注意事项
+
+- Skills 页面的 Modal(创建/编辑)需要在 Tab 切换后仍可正常弹出
+- Skills 页面的 API 调用(`skillApi.list()`, `skillApi.create()` 等)保持不变
+- Metrics Strip 在 Skills Tab 下显示不同的指标(TOTAL / ACTIVE / UPTIME)
+
+---
+
+## 6. 产出要求
+
+- [x] Skills Tab 点击后正确切换到 Skills 页面
+- [x] Skills 的 CRUD(创建/编辑/删除/启用/禁用)功能正常
+- [x] Skills 的 MCP Panel 仍可正常打开
+- [x] Skills 页面的 Modal、Drawer 等交互正常
+- [x] Tab 切换不丢失状态
diff --git a/frontend/src/api/tools.ts b/frontend/src/api/tools.ts
new file mode 100644
index 0000000..67683b6
--- /dev/null
+++ b/frontend/src/api/tools.ts
@@ -0,0 +1,69 @@
+import api from './index'
+import type { AxiosResponse } from 'axios'
+
+/** 单个工具命令 */
+export interface ToolCommand {
+ name: string
+ description: string
+ parameters: Record
+}
+
+/** 工具调用统计 */
+export interface ToolStats {
+ call_count: number
+ error_count: number
+ total_duration_ms: number
+ avg_duration_ms: number
+ error_rate: number
+}
+
+/** 工具信息 */
+export interface ToolInfo {
+ name: string
+ display_name: string
+ description: string
+ category: string
+ subcategory: string
+ source: 'manifest' | 'agent'
+ source_file: string
+ tags: string[]
+ enabled: boolean
+ commands: ToolCommand[]
+ stats: ToolStats | null
+ config: Record
+}
+
+/** 工具子分类 */
+export interface ToolSubgroup {
+ name: string
+ display_name: string
+ tools: ToolInfo[]
+}
+
+/** 工具大分类 */
+export interface ToolCategory {
+ name: string
+ display_name: string
+ subgroups: ToolSubgroup[]
+}
+
+/** 工具统计摘要 */
+export interface ToolSummary {
+ total_commands: number
+ active_commands: number
+ total_tools: number
+ manifest_tools: number
+ agent_tools: number
+}
+
+/** GET /api/tools 响应 */
+export interface ToolsResponse {
+ categories: ToolCategory[]
+ summary: ToolSummary
+}
+
+export const toolsApi = {
+ list: (): Promise> => {
+ return api.get('/api/tools')
+ },
+}
diff --git a/frontend/src/pages/temple/composables/useTemple.ts b/frontend/src/pages/temple/composables/useTemple.ts
new file mode 100644
index 0000000..3827152
--- /dev/null
+++ b/frontend/src/pages/temple/composables/useTemple.ts
@@ -0,0 +1,133 @@
+import { ref, computed } from 'vue'
+import { toolsApi, type ToolCategory, type ToolInfo, type ToolsResponse } from '@/api/tools'
+
+export type TabType = 'tools' | 'skills'
+
+export function useTemple() {
+ // ===== State =====
+ const activeTab = ref('tools')
+ const toolsLoading = ref(false)
+ const toolsError = ref(null)
+
+ // Tools data
+ const categories = ref([])
+ const summary = ref({
+ total_commands: 0,
+ active_commands: 0,
+ total_tools: 0,
+ manifest_tools: 0,
+ agent_tools: 0,
+ })
+
+ // Selection state (Tools Tab)
+ const selectedCategory = ref(null) // 大分类名,如 "注册层"
+ const selectedSubgroup = ref(null) // 子分类名,如 "文件操作"
+ const selectedTool = ref(null)
+
+ // ===== Computed =====
+
+ /** 展平所有工具列表 */
+ const allTools = computed(() => {
+ return categories.value.flatMap((cat) =>
+ cat.subgroups.flatMap((sub) => sub.tools)
+ )
+ })
+
+ /** 当前选中的大分类下的子分类 */
+ const currentSubgroups = computed(() => {
+ if (!selectedCategory.value) return []
+ const cat = categories.value.find((c) => c.name === selectedCategory.value)
+ return cat?.subgroups ?? []
+ })
+
+ /** 当前选中子分类下的工具 */
+ const currentTools = computed(() => {
+ if (!selectedSubgroup.value) return []
+ for (const cat of categories.value) {
+ const sub = cat.subgroups.find((s) => s.name === selectedSubgroup.value)
+ if (sub) return sub.tools
+ }
+ return []
+ })
+
+ /** 当前选中工具的详情 */
+ const currentToolDetail = computed(() => selectedTool.value)
+
+ // ===== Actions =====
+
+ async function fetchTools() {
+ toolsLoading.value = true
+ toolsError.value = null
+ try {
+ const res = await toolsApi.list()
+ const data: ToolsResponse = res.data
+ categories.value = data.categories
+ summary.value = data.summary
+ // 默认选中第一个分类和子分类
+ if (categories.value.length > 0) {
+ const firstCat = categories.value[0]
+ selectedCategory.value = firstCat.name
+ if (firstCat.subgroups.length > 0) {
+ selectedSubgroup.value = firstCat.subgroups[0].name
+ }
+ }
+ } catch (e: unknown) {
+ toolsError.value = e instanceof Error ? e.message : 'Failed to load tools'
+ console.error('[useTemple] fetchTools error:', e)
+ } finally {
+ toolsLoading.value = false
+ }
+ }
+
+ function selectCategory(name: string) {
+ selectedCategory.value = name
+ selectedSubgroup.value = null
+ selectedTool.value = null
+ // 自动选中第一个子分类
+ const cat = categories.value.find((c) => c.name === name)
+ if (cat && cat.subgroups.length > 0) {
+ selectedSubgroup.value = cat.subgroups[0].name
+ }
+ }
+
+ function selectSubgroup(name: string) {
+ selectedSubgroup.value = name
+ selectedTool.value = null
+ }
+
+ function selectTool(tool: ToolInfo) {
+ selectedTool.value = tool
+ }
+
+ function clearToolSelection() {
+ selectedTool.value = null
+ }
+
+ function switchTab(tab: TabType) {
+ activeTab.value = tab
+ }
+
+ return {
+ // State
+ activeTab,
+ toolsLoading,
+ toolsError,
+ categories,
+ summary,
+ selectedCategory,
+ selectedSubgroup,
+ selectedTool,
+ // Computed
+ allTools,
+ currentSubgroups,
+ currentTools,
+ currentToolDetail,
+ // Actions
+ fetchTools,
+ selectCategory,
+ selectSubgroup,
+ selectTool,
+ clearToolSelection,
+ switchTab,
+ }
+}
diff --git a/frontend/src/pages/temple/index.vue b/frontend/src/pages/temple/index.vue
index 891e752..7ccc302 100644
--- a/frontend/src/pages/temple/index.vue
+++ b/frontend/src/pages/temple/index.vue
@@ -1,56 +1,641 @@
-
-
-
-
-
🏛️
-
智慧神殿 - 敬请期待
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TOTAL
+ {{ summary.total_commands }}
+
+
+ ACTIVE
+ {{ summary.active_commands }}
+
+
+ MANIFEST
+ {{ summary.manifest_tools }}
+
+
+ AGENT
+ {{ summary.agent_tools }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Loading skills...
+
+
+
+
+
+
+ | NAME |
+ TYPE |
+ VISIBILITY |
+ STATUS |
+ SOURCE |
+ ACTIONS |
+
+
+
+
+
+
+
+
+ {{ skill.name }}
+ {{ skill.description || '无描述' }}
+
+
+ |
+
+ {{ skill.agent_type }}
+ |
+
+
+ {{ skill.visibility }}
+
+ |
+
+
+
+ {{ skill.is_active ? 'Active' : 'Inactive' }}
+
+ |
+
+
+ {{ skill.is_builtin ? 'builtin' : 'custom' }}
+
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
void) => { (el as HTMLElement).style.opacity = '1'; done() }" @leave="(el: Element, done: () => void) => { (el as HTMLElement).style.opacity = '0'; done() }">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
\ No newline at end of file
+
+.modal-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 14px 18px;
+ border-bottom: 1px solid rgba(0, 245, 212, 0.1);
+}
+
+.modal-title {
+ font-size: 13px;
+ font-weight: 600;
+ color: #00f5d4;
+ letter-spacing: 0.3px;
+}
+
+.btn-close {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 28px;
+ height: 28px;
+ border: 1px solid rgba(0, 245, 212, 0.15);
+ border-radius: 5px;
+ background: transparent;
+ color: #8a9bae;
+ cursor: pointer;
+ transition: all 0.15s;
+}
+
+.btn-close:hover {
+ border-color: #00f5d4;
+ color: #00f5d4;
+}
+
+.modal-body {
+ padding: 16px 18px;
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ overflow-y: auto;
+}
+
+.modal-footer {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ gap: 8px;
+ padding: 12px 18px;
+ border-top: 1px solid rgba(0, 245, 212, 0.1);
+}
+
+.form-group {
+ display: flex;
+ flex-direction: column;
+ gap: 5px;
+}
+
+.form-row {
+ display: flex;
+ gap: 12px;
+}
+
+.form-row .form-group {
+ flex: 1;
+}
+
+.form-label {
+ font-size: 10px;
+ color: #5a6b7a;
+ letter-spacing: 1px;
+ font-weight: 600;
+ text-transform: uppercase;
+}
+
+.form-input,
+.form-select,
+.form-textarea {
+ background: rgba(0, 0, 0, 0.3);
+ border: 1px solid rgba(0, 245, 212, 0.12);
+ border-radius: 6px;
+ color: #e8f4f8;
+ font-size: 12.5px;
+ padding: 7px 10px;
+ outline: none;
+ transition: border-color 0.15s;
+ font-family: inherit;
+}
+
+.form-input:focus,
+.form-select:focus,
+.form-textarea:focus {
+ border-color: rgba(0, 245, 212, 0.4);
+}
+
+.form-select {
+ cursor: pointer;
+ appearance: none;
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%235a6b7a' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
+ background-repeat: no-repeat;
+ background-position: right 8px center;
+ padding-right: 28px;
+}
+
+.form-textarea {
+ resize: vertical;
+ min-height: 60px;
+}
+
+.code-textarea {
+ font-family: 'SF Mono', 'Fira Code', monospace;
+ font-size: 12px;
+ line-height: 1.5;
+}
+
+.flex-1 {
+ flex: 1;
+}
+
+.btn-secondary {
+ padding: 7px 16px;
+ border-radius: 6px;
+ border: 1px solid rgba(0, 245, 212, 0.2);
+ background: transparent;
+ color: #8a9bae;
+ font-size: 12px;
+ cursor: pointer;
+ transition: all 0.15s;
+}
+
+.btn-secondary:hover {
+ border-color: rgba(0, 245, 212, 0.4);
+ color: #e8f4f8;
+}
+
+.btn-primary {
+ padding: 7px 18px;
+ border-radius: 6px;
+ border: 1px solid rgba(0, 245, 212, 0.3);
+ background: rgba(0, 245, 212, 0.1);
+ color: #00f5d4;
+ font-size: 12px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.15s;
+}
+
+.btn-primary:hover:not(:disabled) {
+ background: rgba(0, 245, 212, 0.15);
+ border-color: #00f5d4;
+}
+
+.btn-primary:disabled {
+ opacity: 0.4;
+ cursor: not-allowed;
+}
+
+.action-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 26px;
+ height: 26px;
+ border: 1px solid rgba(0, 245, 212, 0.1);
+ border-radius: 4px;
+ background: transparent;
+ color: #8a9bae;
+ cursor: pointer;
+ transition: all 0.15s;
+}
+
+.action-btn:hover:not(:disabled) {
+ background: rgba(0, 245, 212, 0.06);
+}
+
+.action-btn:disabled {
+ opacity: 0.3;
+ cursor: not-allowed;
+}
+
diff --git a/frontend/src/pages/temple/templePage.css b/frontend/src/pages/temple/templePage.css
new file mode 100644
index 0000000..b130a04
--- /dev/null
+++ b/frontend/src/pages/temple/templePage.css
@@ -0,0 +1,533 @@
+/* ============================================================
+ Temple Modal - 悬浮弹窗样式
+ ============================================================ */
+
+/* CSS Variables 复用 jarvis 体系 */
+.temple-modal-overlay {
+ position: fixed;
+ inset: 0;
+ z-index: 1000;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba(0, 0, 0, 0.7);
+ backdrop-filter: blur(4px);
+ animation: overlayFadeIn 0.2s ease-out;
+}
+
+@keyframes overlayFadeIn {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+
+.temple-modal {
+ width: min(95vw, 1400px);
+ height: min(88vh, 900px);
+ background: var(--bg-void, #0a0a0f);
+ border: 1px solid var(--border-subtle, rgba(0, 245, 212, 0.15));
+ border-radius: 12px;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ box-shadow:
+ 0 0 0 1px rgba(0, 245, 212, 0.05),
+ 0 24px 64px rgba(0, 0, 0, 0.6),
+ 0 0 80px rgba(0, 245, 212, 0.04);
+ animation: modalSlideIn 0.22s cubic-bezier(0.16, 1, 0.3, 1);
+}
+
+@keyframes modalSlideIn {
+ from {
+ opacity: 0;
+ transform: scale(0.96) translateY(8px);
+ }
+ to {
+ opacity: 1;
+ transform: scale(1) translateY(0);
+ }
+}
+
+/* ---- Header ---- */
+.temple-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 16px 20px 12px;
+ border-bottom: 1px solid var(--border-subtle, rgba(0, 245, 212, 0.1));
+ flex-shrink: 0;
+}
+
+.temple-header-title {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.temple-title-icon {
+ font-size: 18px;
+ opacity: 0.8;
+}
+
+.temple-title-text {
+ font-size: 15px;
+ font-weight: 600;
+ color: var(--text-primary, #e8f4f8);
+ letter-spacing: 0.5px;
+}
+
+.temple-close-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 32px;
+ height: 32px;
+ border: 1px solid var(--border-subtle, rgba(0, 245, 212, 0.2));
+ border-radius: 6px;
+ background: transparent;
+ color: var(--text-secondary, #8a9bae);
+ cursor: pointer;
+ transition: all 0.15s ease;
+}
+
+.temple-close-btn:hover {
+ border-color: var(--accent-cyan, #00f5d4);
+ color: var(--accent-cyan, #00f5d4);
+ background: rgba(0, 245, 212, 0.06);
+}
+
+/* ---- Tab Bar ---- */
+.temple-tabs {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ padding: 10px 20px 0;
+ flex-shrink: 0;
+}
+
+.temple-tab {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ padding: 7px 16px;
+ border-radius: 6px 6px 0 0;
+ border: 1px solid transparent;
+ border-bottom: none;
+ background: transparent;
+ color: var(--text-muted, #5a6b7a);
+ font-size: 13px;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.15s ease;
+ position: relative;
+ bottom: -1px;
+}
+
+.temple-tab:hover {
+ color: var(--text-secondary, #8a9bae);
+}
+
+.temple-tab.active {
+ color: var(--accent-cyan, #00f5d4);
+ background: rgba(0, 245, 212, 0.06);
+ border-color: var(--border-subtle, rgba(0, 245, 212, 0.15));
+}
+
+.temple-tab-icon {
+ font-size: 14px;
+}
+
+/* ---- Metrics Strip ---- */
+.temple-metrics {
+ display: flex;
+ gap: 1px;
+ padding: 10px 20px;
+ flex-shrink: 0;
+ border-bottom: 1px solid var(--border-subtle, rgba(0, 245, 212, 0.08));
+ background: rgba(0, 0, 0, 0.2);
+}
+
+.temple-metric {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 6px 16px;
+ border-radius: 4px;
+ background: rgba(0, 245, 212, 0.03);
+ border: 1px solid rgba(0, 245, 212, 0.06);
+ min-width: 80px;
+}
+
+.temple-metric-label {
+ font-size: 10px;
+ color: var(--text-muted, #5a6b7a);
+ letter-spacing: 1px;
+ font-weight: 500;
+}
+
+.temple-metric-value {
+ font-size: 15px;
+ font-weight: 700;
+ color: var(--accent-cyan, #00f5d4);
+ font-variant-numeric: tabular-nums;
+}
+
+/* ---- Main Content ---- */
+.temple-body {
+ flex: 1;
+ display: flex;
+ overflow: hidden;
+ min-height: 0;
+}
+
+/* ---- Tools Tab Layout ---- */
+.temple-tools-layout {
+ display: flex;
+ flex: 1;
+ overflow: hidden;
+}
+
+/* Category Tree (Left sidebar) */
+.temple-tree {
+ width: 240px;
+ flex-shrink: 0;
+ overflow-y: auto;
+ padding: 12px 0;
+ border-right: 1px solid var(--border-subtle, rgba(0, 245, 212, 0.08));
+}
+
+.temple-tree::-webkit-scrollbar {
+ width: 4px;
+}
+
+.temple-tree::-webkit-scrollbar-thumb {
+ background: rgba(0, 245, 212, 0.15);
+ border-radius: 2px;
+}
+
+.temple-tree-section {
+ margin-bottom: 4px;
+}
+
+.temple-tree-section-title {
+ padding: 6px 16px 4px;
+ font-size: 10px;
+ color: var(--text-muted, #5a6b7a);
+ letter-spacing: 1.2px;
+ font-weight: 600;
+ text-transform: uppercase;
+}
+
+.temple-tree-item {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ padding: 6px 16px;
+ font-size: 12.5px;
+ color: var(--text-secondary, #8a9bae);
+ cursor: pointer;
+ transition: all 0.12s ease;
+ border-left: 2px solid transparent;
+}
+
+.temple-tree-item:hover {
+ background: rgba(0, 245, 212, 0.05);
+ color: var(--text-primary, #e8f4f8);
+}
+
+.temple-tree-item.active {
+ background: rgba(0, 245, 212, 0.08);
+ color: var(--accent-cyan, #00f5d4);
+ border-left-color: var(--accent-cyan, #00f5d4);
+}
+
+.temple-tree-subgroup {
+ padding-left: 24px;
+ font-size: 12px;
+}
+
+.temple-tree-dot {
+ width: 4px;
+ height: 4px;
+ border-radius: 50%;
+ background: currentColor;
+ opacity: 0.5;
+ flex-shrink: 0;
+}
+
+/* Tools List & Detail (Right panel) */
+.temple-tools-main {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ min-width: 0;
+}
+
+.temple-tool-list {
+ padding: 12px 16px;
+ overflow-y: auto;
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+}
+
+.temple-tool-list::-webkit-scrollbar {
+ width: 4px;
+}
+
+.temple-tool-list::-webkit-scrollbar-thumb {
+ background: rgba(0, 245, 212, 0.15);
+ border-radius: 2px;
+}
+
+.temple-tool-card {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 10px 14px;
+ border-radius: 6px;
+ border: 1px solid var(--border-subtle, rgba(0, 245, 212, 0.08));
+ background: rgba(0, 0, 0, 0.2);
+ cursor: pointer;
+ transition: all 0.15s ease;
+}
+
+.temple-tool-card:hover {
+ border-color: rgba(0, 245, 212, 0.25);
+ background: rgba(0, 245, 212, 0.04);
+}
+
+.temple-tool-card.selected {
+ border-color: var(--accent-cyan, #00f5d4);
+ background: rgba(0, 245, 212, 0.07);
+}
+
+.temple-tool-card-icon {
+ width: 32px;
+ height: 32px;
+ border-radius: 6px;
+ background: rgba(0, 245, 212, 0.08);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 14px;
+ flex-shrink: 0;
+}
+
+.temple-tool-card-info {
+ flex: 1;
+ min-width: 0;
+}
+
+.temple-tool-card-name {
+ font-size: 13px;
+ font-weight: 600;
+ color: var(--text-primary, #e8f4f8);
+ margin-bottom: 2px;
+}
+
+.temple-tool-card-desc {
+ font-size: 11.5px;
+ color: var(--text-muted, #5a6b7a);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.temple-tool-card-commands {
+ font-size: 10px;
+ color: var(--text-muted, #5a6b7a);
+ background: rgba(0, 245, 212, 0.06);
+ padding: 2px 6px;
+ border-radius: 3px;
+ flex-shrink: 0;
+}
+
+/* Tool Detail Panel */
+.temple-detail {
+ flex: 1;
+ overflow-y: auto;
+ padding: 16px 20px;
+ border-top: 1px solid var(--border-subtle, rgba(0, 245, 212, 0.08));
+ display: flex;
+ flex-direction: column;
+ gap: 14px;
+}
+
+.temple-detail::-webkit-scrollbar {
+ width: 4px;
+}
+
+.temple-detail::-webkit-scrollbar-thumb {
+ background: rgba(0, 245, 212, 0.15);
+ border-radius: 2px;
+}
+
+.temple-detail-header {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 12px;
+}
+
+.temple-detail-name {
+ font-size: 16px;
+ font-weight: 700;
+ color: var(--text-primary, #e8f4f8);
+}
+
+.temple-detail-display-name {
+ font-size: 13px;
+ color: var(--accent-cyan, #00f5d4);
+ margin-top: 2px;
+}
+
+.temple-detail-source {
+ font-size: 10px;
+ color: var(--text-muted, #5a6b7a);
+ background: rgba(0, 245, 212, 0.05);
+ padding: 2px 8px;
+ border-radius: 3px;
+ border: 1px solid rgba(0, 245, 212, 0.1);
+ flex-shrink: 0;
+}
+
+.temple-detail-desc {
+ font-size: 12.5px;
+ color: var(--text-secondary, #8a9bae);
+ line-height: 1.6;
+}
+
+.temple-detail-section {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+.temple-detail-section-title {
+ font-size: 10px;
+ color: var(--text-muted, #5a6b7a);
+ letter-spacing: 1.2px;
+ font-weight: 600;
+ text-transform: uppercase;
+}
+
+.temple-detail-stats {
+ display: flex;
+ gap: 12px;
+ flex-wrap: wrap;
+}
+
+.temple-detail-stat {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ padding: 8px 14px;
+ background: rgba(0, 0, 0, 0.25);
+ border-radius: 6px;
+ border: 1px solid rgba(0, 245, 212, 0.06);
+ min-width: 80px;
+}
+
+.temple-detail-stat-value {
+ font-size: 15px;
+ font-weight: 700;
+ color: var(--text-primary, #e8f4f8);
+ font-variant-numeric: tabular-nums;
+}
+
+.temple-detail-stat-label {
+ font-size: 10px;
+ color: var(--text-muted, #5a6b7a);
+ letter-spacing: 0.5px;
+}
+
+/* Commands List */
+.temple-commands {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+}
+
+.temple-command-item {
+ padding: 10px 14px;
+ background: rgba(0, 0, 0, 0.2);
+ border-radius: 6px;
+ border: 1px solid rgba(0, 245, 212, 0.06);
+}
+
+.temple-command-name {
+ font-size: 12px;
+ font-weight: 600;
+ color: var(--accent-cyan, #00f5d4);
+ font-family: 'SF Mono', 'Fira Code', monospace;
+ margin-bottom: 4px;
+}
+
+.temple-command-desc {
+ font-size: 11.5px;
+ color: var(--text-secondary, #8a9bae);
+ line-height: 1.5;
+}
+
+/* Tags */
+.temple-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 4px;
+}
+
+.temple-tag {
+ font-size: 10px;
+ padding: 2px 8px;
+ border-radius: 3px;
+ background: rgba(123, 44, 191, 0.15);
+ color: #c084fc;
+ border: 1px solid rgba(123, 44, 191, 0.2);
+}
+
+/* Empty state */
+.temple-empty {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ height: 100%;
+ color: var(--text-muted, #5a6b7a);
+ font-size: 13px;
+}
+
+.temple-empty-icon {
+ font-size: 32px;
+ opacity: 0.4;
+}
+
+/* Loading */
+.temple-loading {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ color: var(--text-muted, #5a6b7a);
+ font-size: 13px;
+ gap: 10px;
+}
+
+/* Skills Tab overrides */
+.temple-skills-container {
+ flex: 1;
+ overflow-y: auto;
+ padding: 0;
+}
+
+/* Section label */
+.temple-section-label {
+ font-size: 10px;
+ color: var(--text-muted, #5a6b7a);
+ letter-spacing: 1.2px;
+ font-weight: 600;
+ text-transform: uppercase;
+ padding: 10px 16px 6px;
+}