diff --git a/apps/demo/src/App.tsx b/apps/demo/src/App.tsx
index 09a25f04..41368c03 100644
--- a/apps/demo/src/App.tsx
+++ b/apps/demo/src/App.tsx
@@ -1,11 +1,5 @@
-import { useLocation } from "react-router-dom";
-
-import { DesignSystemShell } from "./app/design-system-shell";
import { FullScreenApp } from "./app/full-screen-app";
-import { isFullScreenPath } from "./app/route-matches";
export default function App() {
- const location = useLocation();
-
- return isFullScreenPath(location.pathname) ? : ;
+ return ;
}
diff --git a/apps/demo/src/app/design-system-shell.tsx b/apps/demo/src/app/design-system-shell.tsx
deleted file mode 100644
index fcf50f01..00000000
--- a/apps/demo/src/app/design-system-shell.tsx
+++ /dev/null
@@ -1,193 +0,0 @@
-import {
- GitHubIcon,
- NavigationMenu,
- NavigationMenuButton,
- NavigationMenuItem,
- NavigationMenuLabel,
- NavigationMenuList,
- NexuLogoIcon,
- Sidebar,
- SidebarContent,
- SidebarFooter,
- SidebarHeader,
-} from "@nexu-design/ui-web";
-import {
- ChevronUp,
- CircleHelp,
- Clock,
- Globe,
- Monitor,
- PanelLeft,
- PanelLeftClose,
- Play,
- Route as RouteIcon,
- Sparkles,
- Users,
- Wrench,
-} from "lucide-react";
-import { useState } from "react";
-import { NavLink, Navigate, Route, Routes, useLocation } from "react-router-dom";
-
-import { CommentSystem } from "../components/CommentSystem";
-import { ProductRouteElements } from "./routes/product-routes";
-
-const PRODUCT_NAV = [
- { to: "/demo", label: "Product Demo", icon: Play },
- { to: "/journey", label: "User Journey", icon: RouteIcon },
- { to: "/app/sessions", label: "Sessions", icon: Monitor },
- { to: "/app/team", label: "团队协作", icon: Users },
- { to: "/app/clone", label: "分身搭建", icon: Wrench },
- { to: "/app/automation", label: "Automation", icon: Clock },
- { to: "/app/skills", label: "Skills", icon: Sparkles },
-];
-
-function NavSection({
- title,
- items,
- collapsed,
-}: {
- title: string;
- items: typeof PRODUCT_NAV;
- collapsed: boolean;
-}) {
- const location = useLocation();
-
- const isSelected = (to: string) =>
- location.pathname === to || location.pathname.startsWith(`${to}/`);
-
- return (
-
- {!collapsed && {title}}
-
- {items.map(({ to, label, icon: Icon }) => (
-
-
-
-
- {!collapsed && label}
-
-
-
- ))}
-
-
- );
-}
-
-export function DesignSystemShell() {
- const [collapsed, setCollapsed] = useState(false);
-
- return (
- <>
-
-
- {collapsed ? (
-
-
-
- ) : (
-
-
-
-
-
- )}
-
-
-
-
-
-
-
- {!collapsed && (
-
- )}
-
-
- {collapsed ? (
-
- ) : (
-
- )}
-
-
-
-
-
- {ProductRouteElements()}
- } />
- } />
-
-
-
-
- >
- );
-}
diff --git a/apps/demo/src/app/route-matches.ts b/apps/demo/src/app/route-matches.ts
deleted file mode 100644
index f4d65b58..00000000
--- a/apps/demo/src/app/route-matches.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-const fullScreenExactPaths = new Set([
- "/openclaw/workspace",
- "/openclaw/welcome",
- "/openclaw/invite",
- "/openclaw/onboarding",
- "/openclaw/whatsapp-qr",
- "/openclaw/privacy",
- "/openclaw/terms",
- "/openclaw/channels",
- "/openclaw/pricing",
- "/openclaw/usage",
- "/openclaw/rewards",
- "/openclaw/changelog",
-]);
-
-export function isFullScreenPath(pathname: string) {
- return (
- fullScreenExactPaths.has(pathname) ||
- pathname.startsWith("/openclaw/auth") ||
- pathname.startsWith("/openclaw/changelog/") ||
- pathname.startsWith("/openclaw/skill/") ||
- pathname.startsWith("/openclaw/growth-demo")
- );
-}
diff --git a/apps/demo/src/app/routes/product-routes.tsx b/apps/demo/src/app/routes/product-routes.tsx
deleted file mode 100644
index ed2d3fd6..00000000
--- a/apps/demo/src/app/routes/product-routes.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import { Navigate, Route } from "react-router-dom";
-
-import JourneyPage from "../../pages/journey/JourneyPage";
-import AutomationPage from "../../pages/product/AutomationPage";
-import CloneBuilderPage from "../../pages/product/CloneBuilderPage";
-import ProductDemoPage from "../../pages/product/ProductDemoPage";
-import ProductLayout from "../../pages/product/ProductLayout";
-import SessionsPage from "../../pages/product/SessionsPage";
-import SkillsPage from "../../pages/product/SkillsPage";
-import TeamPage from "../../pages/product/TeamPage";
-
-export function ProductRouteElements() {
- return (
- <>
- } />
- } />
- } />
-
-
-
- }
- />
-
-
-
- }
- />
-
-
-
- }
- />
-
-
-
- }
- />
-
-
-
- }
- />
- >
- );
-}
diff --git a/apps/demo/src/pages/LandingParts.tsx b/apps/demo/src/pages/LandingParts.tsx
deleted file mode 100644
index e6b26607..00000000
--- a/apps/demo/src/pages/LandingParts.tsx
+++ /dev/null
@@ -1,168 +0,0 @@
-import {
- Collapsible,
- CollapsibleContent,
- CollapsibleTrigger,
- ConversationMessage,
-} from "@nexu-design/ui-web";
-import { CheckCircle2, ChevronDown, type LucideIcon } from "lucide-react";
-import { type ReactNode, useState } from "react";
-
-export function ChatMsg({
- from,
- name,
- children,
-}: {
- from: "clone" | "user" | "other";
- name?: string;
- children: ReactNode;
-}) {
- if (from === "user") {
- return (
-
-
- {children}
-
-
- );
- }
- return (
-
-
- {from === "clone" ? "😊" : (name?.[0] ?? "?")}
-
- }
- bubbleClassName="bg-surface-2 px-3 py-2 text-[13px]"
- meta={name && from === "other" ? name : undefined}
- >
- {children}
-
-
- );
-}
-
-export function ChatWindow({
- title,
- badge,
- children,
-}: {
- title: string;
- badge?: string;
- children: ReactNode;
-}) {
- return (
-
-
-
- 😊
-
-
{title}
- {badge && (
-
- {badge}
-
- )}
-
-
-
{children}
-
- );
-}
-
-export function ChatDivider({ text }: { text: string }) {
- return —— {text} ——
;
-}
-
-export function ScenarioSection({
- tag,
- tagIcon: Icon,
- title,
- desc,
- features,
- chatContent,
- reverse,
-}: {
- tag: string;
- tagIcon: LucideIcon;
- title: string;
- desc: string;
- features: string[];
- chatContent: ReactNode;
- reverse?: boolean;
-}) {
- const textBlock = (
-
-
- {tag}
-
-
{title}
-
{desc}
-
- {features.map((f) => (
-
- {f}
-
- ))}
-
-
- );
-
- const first = reverse ? chatContent : textBlock;
- const second = reverse ? textBlock : chatContent;
-
- return (
-
- );
-}
-
-export function SectionHeading({
- tag,
- title,
- desc,
-}: {
- tag?: string;
- title: string;
- desc?: string;
-}) {
- return (
-
- {tag && (
-
- {tag}
-
- )}
-
{title}
- {desc && (
-
{desc}
- )}
-
- );
-}
-
-export function FAQItem({ q, a }: { q: string; a: string }) {
- const [open, setOpen] = useState(false);
- return (
-
-
- {q}
-
-
-
- {a}
-
-
- );
-}
diff --git a/apps/demo/src/pages/LandingPreview.tsx b/apps/demo/src/pages/LandingPreview.tsx
deleted file mode 100644
index 2e8258b3..00000000
--- a/apps/demo/src/pages/LandingPreview.tsx
+++ /dev/null
@@ -1,1105 +0,0 @@
-import { Button } from "@nexu-design/ui-web";
-import {
- ArrowRight,
- BarChart3,
- Brain,
- Check,
- Crown,
- GitPullRequest,
- MessageSquare,
- Rss,
- Send,
- Shield,
- Sparkles,
- Star,
- Target,
- UserPlus,
- Users,
- X,
- Zap,
-} from "lucide-react";
-import {
- ChatDivider,
- ChatMsg,
- ChatWindow,
- FAQItem,
- ScenarioSection,
- SectionHeading,
-} from "./LandingParts";
-import ChatCardGroup from "./product/ChatCards";
-import type { ChatCard } from "./product/sessionsData";
-
-const LANDING_CARDS: Record = {
- scenario1a: [
- {
- type: "skill",
- title: "深度调研",
- status: "success",
- body: "✓ 检索 23 篇文章 + 5 个竞品官网\n✓ 生成竞品分析报告",
- path: "skills/web-research/SKILL.md",
- meta: "耗时 15s · 自动调用",
- },
- ],
- scenario1b: [
- {
- type: "file",
- title: "竞品分析报告",
- status: "success",
- body: "8,200 字 · 3 个关键发现\n记忆壁垒 · IM 入口 · 团队协作",
- path: "artifacts/research/竞品分析.md",
- diff: { added: 128, removed: 0 },
- actions: [{ label: "打开编辑", primary: true }],
- },
- {
- type: "memory",
- title: "记住了 3 个关键结论",
- status: "success",
- body: "记忆壁垒是核心 · IM 优于独立 App · 团队协作驱动付费",
- meta: "记忆 +3 · 自动归档",
- },
- ],
- scenario1c: [
- {
- type: "file",
- title: "产品方案 v1",
- status: "success",
- body: "基于竞品分析 + 你的 12 条历史偏好\n自动引用了之前的决策记录",
- path: "artifacts/prds/产品方案.md",
- diff: { added: 86, removed: 0 },
- actions: [{ label: "打开编辑", primary: true }, { label: "分享" }],
- },
- ],
- scenario2a: [
- {
- type: "skill",
- title: "竞品监控",
- status: "success",
- body: "✓ 能力已激活\n✓ 监控 Linear / Notion / Cursor",
- path: "skills/competitor-watch/SKILL.md",
- actions: [{ label: "查看配置" }],
- },
- {
- type: "automation",
- title: "每日竞品扫描",
- status: "success",
- body: "⏰ cron: 每天 09:00\n有更新推送飞书 + 保存分析报告",
- path: "automation/competitor-scan.yaml",
- meta: "下次触发:明天 09:00",
- actions: [{ label: "测试执行" }],
- },
- ],
- scenario2b: [
- {
- type: "automation",
- title: "每周 Sprint 回顾",
- status: "success",
- body: "⏰ cron: 每周五 18:00\n自动汇总本周产出 + 推送到群",
- path: "automation/weekly-review.yaml",
- meta: "2 个自动任务已上线",
- actions: [{ label: "查看全部", primary: true }],
- },
- ],
- scenario3a: [
- {
- type: "automation",
- title: "📊 今日战况复盘",
- status: "success",
- body: "✅ 完成 12 个任务,写了 3 份文档\n🧠 新记住 5 件事,默契度 → 78%",
- meta: "自动推送 · 每天 21:00",
- },
- {
- type: "skill",
- title: "⚡ 竞品监控发现",
- status: "warning",
- body: "Notion 发布了 AI 新功能\n分析报告已准备好",
- actions: [{ label: "查看分析", primary: true }],
- },
- {
- type: "memory",
- title: "🔔 记忆冲突提醒",
- status: "warning",
- body: "发现 3 条记忆有矛盾,需要你来定夺",
- actions: [{ label: "处理", primary: true }],
- },
- ],
- scenario3b: [
- {
- type: "file",
- title: "Notion AI 新功能分析",
- status: "success",
- body: "Notion 采用嵌入式 AI 方案\n对我们的启示:记忆 + 能力组合是差异化优势",
- path: "artifacts/research/notion-ai-update.md",
- diff: { added: 42, removed: 0 },
- actions: [{ label: "打开", primary: true }],
- },
- ],
- scenario4a: [
- {
- type: "memory",
- title: "已记住",
- status: "success",
- body: '"搜索结果页加相关推荐"\n归入产品想法 · 标签:搜索优化',
- path: "memory/ideas/search-recommendations.md",
- meta: "记忆 +1 · 默契度 +0.5%",
- },
- ],
- scenario4b: [
- {
- type: "file",
- title: "搜索优化方案",
- status: "success",
- body: "混合搜索 + 相关推荐\n参考了你过去 17 条相关记忆",
- path: "artifacts/prds/search-optimization.md",
- diff: { added: 64, removed: 0 },
- actions: [{ label: "打开编辑", primary: true }],
- },
- {
- type: "memory",
- title: "默契度提升",
- status: "success",
- body: "记忆关联命中 · 默契度 +1% → 79%",
- meta: "跨越 2 个月的记忆关联",
- },
- ],
-};
-
-export default function LandingPreview() {
- return (
-
- {/* ───── Nav ───── */}
-
-
- {/* ───── Hero ───── */}
-
-
-
-
-
-
- People quit. Clones don't.
-
-
- 为你的龙虾打造一间赛博办公室 — 世界首个人与分身共存的办公协作网络
-
-
-
- 每个人有一个分身 — 记住你说过的每句话,帮你做事,和团队协作。
-
- 人走了,分身留下,知识永不流失。
-
-
-
-
-
-
- ✓ 免费开始
- ✓ 无需信用卡
- ✓ 邀请同事立减 50%
-
-
-
-
- {/* ───── Logo / Trust Bar ───── */}
-
-
-
- 已有数万知识工作者在使用
-
-
- {["ByteBuilder", "NextStudio", "锐思科技", "CloudStack", "DataPulse", "创见设计"].map(
- (name) => (
-
- {name}
-
- ),
- )}
-
-
-
-
- {/* ───── Pain → Solution ───── */}
-
-
-
- {[
- {
- before: "每次用 AI 都要重新解释背景",
- after: "分身记住你说过的一切,新人继承分身第一天就有前任的判断力",
- },
- {
- before: "AI 只能等你问,不会主动帮忙",
- after: "分身主动推送日报、代问进度、自动站会 — 人与分身共存",
- },
- {
- before: "想做一件事要切换 5 个工具",
- after: "一句话告诉分身,它调用技能帮你搞定 — 人做决策,分身做执行",
- },
- {
- before: "灵感和决策散落在各处",
- after: "所有记忆、文档、资料都帮你整理好",
- },
- {
- before: "每个 AI 工具都是单点,无法串联",
- after: "数千种能力自由组合,自动任务全天运转",
- },
- {
- before: "对话结束后什么也没留下",
- after: "每次对话都帮你沉淀文档、记忆和知识",
- },
- ].map((p) => (
-
- ))}
-
-
-
-
-
- {/* ───── Your Clone's Workspace ───── */}
-
-
-
-
-
你的分身空间
- {[
- {
- icon: "🧬",
- name: "身份档案",
- desc: "性格、角色、头像、声音…… 分身了解你是谁",
- },
- {
- icon: "👥",
- name: "联系人",
- desc: "你的同事、朋友、客户…… 分身记得每个人",
- },
- {
- icon: "🧠",
- name: "记忆库",
- desc: "223 条记忆 — 你说过的想法、决策、偏好全都记住",
- },
- {
- icon: "📁",
- name: "文档和产出",
- desc: "报告、方案、设计稿、表格…… 分身帮你整理归档",
- },
- {
- icon: "📚",
- name: "知识库",
- desc: "参考资料、竞品信息、行业报告…… 随时调用",
- },
- {
- icon: "💬",
- name: "对话记录",
- desc: "每次聊天的完整记录和上传的资料",
- },
- {
- icon: "⚡",
- name: "自动任务",
- desc: "定时日报、竞品监控、周报…… 分身自动执行",
- },
- {
- icon: "🔧",
- name: "能力清单",
- desc: "数千种能力 — 写报告、做分析、跑数据……",
- },
- ].map((item) => (
-
- {item.icon}
- {item.name}
- — {item.desc}
-
- ))}
-
-
-
-
-
支持任意内容:文档 · 表格 · 设计稿 · 图片 · 音视频 · PDF
-
-
-
-
-
-
-
- {/* ───── Scenario 1: Just Tell It ───── */}
-
- 帮我做一份 AI 赛道的竞品分析
- 收到,让我帮你搞定 📂
-
-
-
- 报告完成 ✅ 8,200 字,3 个关键发现
-
-
-
- 不错,基于这个写一份产品方案
-
-
-
-
- }
- />
-
-
-
- {/* ───── Scenario 2: Abilities & Auto Tasks ───── */}
-
- 帮我设一个竞品监控,每天自动跑
- 好的,帮你设置 ⚡
-
-
-
- 再加一个每周五自动生成周报
-
-
-
-
- }
- />
-
-
-
- {/* ───── Scenario 3: Daily Updates ───── */}
-
-
-
-
- 展开竞品分析看看
-
-
-
-
- }
- />
-
-
-
- {/* ───── Scenario 4: Memory & Growth ───── */}
-
- 对了,搜索结果页可以加个相关推荐
-
-
-
-
-
- 主人,你 2 个月前提过"搜索加相关推荐"。这周刚好在做搜索优化,要不要一起做了?
-
- 我都忘了!好,帮我写个方案
-
-
-
-
- }
- />
-
-
-
- {/* ───── Scenario 5: Team Collaboration & Virality ───── */}
-
- @分身 帮我问下李四 Gateway 进度
-
- 已替你询问李四的分身 🤝
-
-
-
- → 你的分身 → 李四的分身 → 自动获取进度
-
-
-
- 李四反馈:Gateway 重构完成 65%,卡在第三方 SDK 适配,预计延迟 2 天。
-
-
- 已自动更新 Sprint 状态 ✅
-
-
- 这个分身太方便了,我也想要一个!
-
-
- ✨ 欢迎加入!
-
- 王五,点击下方链接 3 分钟激活你的专属分身 👇
-
- refly.ai/invite/team-abc123
-
-
- }
- />
-
-
-
- {/* ───── Agent-Native Workspace ───── */}
-
-
-
- {/* Invite Flow */}
-
-
- {[
- {
- step: "1",
- icon: UserPlus,
- title: "邀请同事",
- desc: "发送链接或在群里 @分身邀请",
- color: "text-info",
- },
- {
- step: "2",
- icon: Sparkles,
- title: "3 分钟激活",
- desc: "同事在 IM 里完成 onboarding",
- color: "text-clone",
- },
- {
- step: "3",
- icon: GitPullRequest,
- title: "分身互联",
- desc: "分身之间自动建立协作通道",
- color: "text-success",
- },
- {
- step: "4",
- icon: Zap,
- title: "效率飞轮",
- desc: "团队越大,每个分身越强",
- color: "text-warning",
- },
- ].map((s, i) => (
-
- {i < 3 && (
-
- )}
-
-
-
-
{s.title}
-
{s.desc}
-
- ))}
-
-
-
- {/* Team capabilities grid */}
-
- {[
- {
- icon: Target,
- title: "OKR + Sprint 联动",
- desc: "团队目标自动拆解到每个人的分身,Sprint 进度实时汇总。不用开会就能掌握全局。",
- badge: "自动追踪",
- },
- {
- icon: Send,
- title: "分身代理沟通",
- desc: '"帮我问李四进度" — 你的分身自动找李四的分身,结果直接返回。不打扰同事,不等回复。',
- badge: "零等待",
- },
- {
- icon: BarChart3,
- title: "团队 Insights",
- desc: '自然语言查询团队数据:"Sprint 3 有什么风险?" — 分身分析所有人的任务和进度,给出建议。',
- badge: "AI 分析",
- },
- {
- icon: Shield,
- title: "共享知识库",
- desc: "团队记忆自动沉淀:决策、方案、竞品情报。新人入职,分身一读就懂团队上下文。",
- badge: "壁垒沉淀",
- },
- {
- icon: Rss,
- title: "IM 卡片协作",
- desc: "所有操作以交互式卡片出现在群聊中:审批、对齐、报告、提醒。在聊天里完成一切。",
- badge: "飞书/Slack",
- },
- {
- icon: Crown,
- title: "裂变增长",
- desc: "群聊里每张卡片都是入口。同事看到你的分身在干活 → 点击 → 3 分钟获得自己的分身。",
- badge: "k-factor >1",
- },
- ].map((item) => (
-
-
-
-
-
-
- {item.badge}
-
-
-
{item.title}
-
{item.desc}
-
- ))}
-
-
- {/* Team invite CTA */}
-
-
-
- 带上你的团队,一起 10x
-
-
- 邀请 3 位同事加入,每人免费获得 Pro 版 30 天体验
-
-
-
-
-
-
-
-
- {/* ───── How it works ───── */}
-
-
-
- {[
- {
- step: "01",
- title: "加个好友",
- desc: "在飞书/Slack 里添加机器人,或直接打开网页版。30 秒搞定。",
- },
- {
- step: "02",
- title: "聊几句就上岗",
- desc: "分身会问你几个问题——做什么工作、喜欢什么风格。不是填表,是聊天。3 分钟搞定。",
- },
- {
- step: "03",
- title: "越用越懂你",
- desc: "记住你的一切、主动帮你干活、每天看它做了什么。用得越久越离不开。",
- },
- ].map((s, i) => (
-
- {i < 2 && (
-
- )}
-
{s.step}
-
{s.title}
-
{s.desc}
-
- ))}
-
-
-
-
-
- {/* ───── Killer Numbers ───── */}
-
-
- {[
- { num: "数千+", label: "种能力", sub: "产品/研发/运营/设计全覆盖" },
- {
- num: "5",
- label: "个平台",
- sub: "飞书 · Slack · 网页 · WhatsApp · API",
- },
- { num: "10x", label: "团队效率", sub: "分身代理沟通 + 自动对齐" },
- { num: "82%", label: "续费率", sub: "用了 30 天的团队都不想停" },
- ].map((n) => (
-
-
- {n.num}
-
-
{n.label}
-
{n.sub}
-
- ))}
-
-
-
-
-
- {/* ───── Comparison ───── */}
-
-
-
-
-
-
- | 能力 |
- nexu |
- ChatGPT |
-
- Notion AI
- |
-
- Coze/扣子
- |
-
-
-
- {(
- [
- ["记得住,越用越懂你", true, "shallow", false, "shallow"],
- ["有自己的知识库和工作空间", true, false, false, false],
- ["数千种能力,自由组合", true, "plugin", "limited", true],
- ["自动任务(定时 + 条件触发)", true, false, false, true],
- ["每日动态 + 主动提醒", true, false, false, "limited"],
- ["住在飞书/Slack 里直接用", true, false, false, true],
- ["团队群协作,天然传播", true, false, "limited", "limited"],
- ["等级 + 默契度成长体系", true, false, false, false],
- ["3 分钟上手", true, true, false, false],
- ] as [
- string,
- boolean | string,
- boolean | string,
- boolean | string,
- boolean | string,
- ][]
- ).map(([feature, refly, chatgpt, notion, coze]) => (
-
- | {feature as string} |
- {[
- ["Refly", refly],
- ["ChatGPT", chatgpt],
- ["Notion", notion],
- ["Coze", coze],
- ].map(([name, val]) => (
-
- {val === true ? (
-
- ) : val === false ? (
-
- ) : (
-
- {{
- shallow: "浅层",
- plugin: "需插件",
- limited: "有限",
- }[val as string] ?? val}
-
- )}
- |
- ))}
-
- ))}
-
-
-
-
-
-
-
- {/* ───── Social Proof ───── */}
-
-
-
- {[
- {
- quote:
- "我的分身记得我 3 个月前随口说的一个想法,上周竟然主动提醒我可以做了。太神了。",
- who: "独立开发者",
- title: "@IndieHacker",
- days: 87,
- },
- {
- quote:
- "每天打开看分身昨晚做了什么,比刷朋友圈有意义。竞品监控已经帮我发现了两次重要机会。",
- who: "产品经理",
- title: "PM @ SaaS",
- days: 62,
- },
- {
- quote: "让分身帮我写产品方案,它先做了竞品调研再写。比实习生靠谱。",
- who: "创业公司 CEO",
- title: "CEO & Founder",
- days: 45,
- },
- {
- quote:
- "团队 5 个人,每人一个分身,开会前它已经帮我汇总了所有人的进度。群里一发,大家都想加。",
- who: "技术负责人",
- title: "Tech Lead",
- days: 93,
- },
- {
- quote: "做了一个客户跟进的自动任务,现在每周自动提醒我跟进,一个客户都不漏。",
- who: "销售负责人",
- title: "Sales",
- days: 38,
- },
- {
- quote: "分身里已经有 500 多条记忆了。默契度 82%,它比我自己还了解我的偏好。",
- who: "自由设计师",
- title: "Freelancer",
- days: 186,
- },
- ].map((t) => (
-
-
- {[1, 2, 3, 4, 5].map((s) => (
-
- ))}
-
-
"{t.quote}"
-
-
- {t.who[0]}
-
-
-
{t.who}
-
- {t.title} · 使用 {t.days} 天
-
-
-
-
- ))}
-
-
-
-
-
- {/* ───── FAQ ───── */}
-
-
-
-
- {/* ───── Pricing ───── */}
-
-
-
- {[
- {
- name: "基础版",
- price: "免费",
- sub: "",
- items: ["分身上岗", "500 能量/月", "3 种能力", "基础记忆", "每日动态"],
- cta: "免费开始",
- hl: false,
- },
- {
- name: "专业版",
- price: "¥29",
- sub: "/月",
- items: [
- "分身全力以赴",
- "5,000 能量/月",
- "无限能力 + 自定义",
- "完整记忆 + 成长体系",
- "自动任务",
- "飞书深度整合",
- "主动提醒",
- "优先模型",
- ],
- cta: "解锁完整分身",
- hl: true,
- },
- {
- name: "团队版",
- price: "¥19",
- sub: "/人/月",
- items: ["专业版全部", "团队共享知识库", "分身间协作", "团队管理后台", "群聊协作"],
- cta: "团队一起用",
- hl: false,
- },
- ].map((p) => (
-
- {p.hl && (
-
- 推荐
-
- )}
-
{p.name}
-
-
- {p.price}
-
- {p.sub}
-
-
- {p.items.map((item) => (
-
- ✓ {item}
-
- ))}
-
-
-
- ))}
-
-
- 还可以单独购买能量包:¥10 = 1,000 能量
-
-
-
- {/* ───── Final CTA ───── */}
-
-
-
-
- 给你的龙虾一间赛博办公室
-
-
- 免费开始,3 分钟上手。员工会辞职,分身不会。
-
-
-
- {["😊", "🤝", "😄", "💻", "🎨", "🚀", "✨"].map((emoji) => (
-
- {emoji}
-
- ))}
-
-
12,000+ 团队 · 89,536 人已加入
-
-
-
- {/* ───── Footer ───── */}
-
-
- );
-}
diff --git a/apps/demo/src/pages/journey/JourneyPage.tsx b/apps/demo/src/pages/journey/JourneyPage.tsx
deleted file mode 100644
index afeb7cd2..00000000
--- a/apps/demo/src/pages/journey/JourneyPage.tsx
+++ /dev/null
@@ -1,182 +0,0 @@
-import { Button, Stepper, StepperItem, StepperSeparator } from "@nexu-design/ui-web";
-import {
- ArrowLeft,
- ArrowRight,
- Crown,
- Eye,
- Globe,
- Link2,
- MessageSquare,
- Monitor,
- User,
- Users,
- X,
- Zap,
-} from "lucide-react";
-import { useCallback, useEffect, useState } from "react";
-import { useNavigate } from "react-router-dom";
-import StepAutomation from "./StepAutomation";
-import StepClone from "./StepClone";
-import StepIM from "./StepIM";
-import StepLanding from "./StepLanding";
-import StepOnboarding from "./StepOnboarding";
-import StepPreview from "./StepPreview";
-import StepSession from "./StepSession";
-import StepTeam from "./StepTeam";
-import StepUpgrade from "./StepUpgrade";
-
-const STEPS = [
- { id: "landing", label: "Landing Page", icon: Globe, desc: "龙虾的赛博办公室" },
- { id: "onboarding", label: "Onboarding", icon: MessageSquare, desc: "分身初始化" },
- { id: "clone", label: "分身入口", icon: User, desc: "产品主界面" },
- { id: "session", label: "Session", icon: Monitor, desc: "对话交互" },
- { id: "automation", label: "Automation & Skills", icon: Zap, desc: "自动化 + 能力" },
- { id: "team", label: "团队协作", icon: Users, desc: "人与分身共存的办公协作网络" },
- { id: "im", label: "IM 接入", icon: Link2, desc: "飞书 / Slack" },
- { id: "preview", label: "接入预览", icon: Eye, desc: "最终效果" },
- { id: "upgrade", label: "解锁超能力", icon: Crown, desc: "升级 + 邀请团队" },
-] as const;
-
-const STEP_COMPONENTS = [
- StepLanding,
- StepOnboarding,
- StepClone,
- StepSession,
- StepAutomation,
- StepTeam,
- StepIM,
- StepPreview,
- StepUpgrade,
-];
-
-export default function JourneyPage() {
- const [currentStep, setCurrentStep] = useState(0);
- const [direction, setDirection] = useState<"next" | "prev">("next");
- const [animating, setAnimating] = useState(false);
- const navigate = useNavigate();
-
- const goTo = useCallback(
- (idx: number, dir: "next" | "prev") => {
- if (animating || idx < 0 || idx >= STEPS.length) return;
- setDirection(dir);
- setAnimating(true);
- setTimeout(() => {
- setCurrentStep(idx);
- setAnimating(false);
- }, 250);
- },
- [animating],
- );
-
- const next = useCallback(() => goTo(currentStep + 1, "next"), [currentStep, goTo]);
- const prev = useCallback(() => goTo(currentStep - 1, "prev"), [currentStep, goTo]);
-
- useEffect(() => {
- const handler = (e: KeyboardEvent) => {
- if (e.key === "ArrowRight" || e.key === "ArrowDown") next();
- if (e.key === "ArrowLeft" || e.key === "ArrowUp") prev();
- if (e.key === "Escape") navigate("/overview");
- };
- window.addEventListener("keydown", handler);
- return () => window.removeEventListener("keydown", handler);
- }, [next, prev, navigate]);
-
- const StepComponent = STEP_COMPONENTS[currentStep];
- const isFirst = currentStep === 0;
- const isLast = currentStep === STEPS.length - 1;
-
- return (
-
- {/* Top bar */}
-
-
- {/* Step content */}
-
-
-
-
- {/* Bottom nav */}
-
-
- );
-}
diff --git a/apps/demo/src/pages/journey/StepAutomation.tsx b/apps/demo/src/pages/journey/StepAutomation.tsx
deleted file mode 100644
index 240b3685..00000000
--- a/apps/demo/src/pages/journey/StepAutomation.tsx
+++ /dev/null
@@ -1,458 +0,0 @@
-import { Button } from "@nexu-design/ui-web";
-import {
- BarChart3,
- Bell,
- Brain,
- Calendar,
- CheckCircle,
- Clock,
- Code,
- Download,
- FileText,
- Mail,
- MessageSquare,
- MoreHorizontal,
- Pause,
- Plus,
- Search,
- Shield,
- Sparkles,
- Star,
- ToggleRight,
- TrendingUp,
- Users,
- Wrench,
- Zap,
-} from "lucide-react";
-import { useState } from "react";
-import ChatCardGroup from "../product/ChatCards";
-import type { ChatCard } from "../product/sessionsData";
-
-type View = "automation" | "skills";
-
-const TEMPLATES = [
- { name: "每日邮件摘要", icon: Mail, color: "bg-info-subtle text-info" },
- { name: "竞品监测", icon: Search, color: "bg-clone/10 text-clone" },
- { name: "周五回顾", icon: BarChart3, color: "bg-success-subtle text-success" },
- { name: "安全自审", icon: Shield, color: "bg-danger-subtle text-danger" },
- { name: "增长日报", icon: TrendingUp, color: "bg-warning-subtle text-warning" },
- { name: "灵感方案", icon: Sparkles, color: "bg-clone/10 text-clone" },
-];
-
-const TASKS = [
- {
- name: "今日战况复盘",
- cron: "每天 22:00",
- icon: Brain,
- enabled: true,
- lastRun: "今天 22:00",
- stats: "扫荡 7,660 条 · 评论 21 次",
- },
- { name: "早间日报", cron: "每天 08:30", icon: Calendar, enabled: true, lastRun: "今天 08:30" },
- {
- name: "Action Item 检查",
- cron: "每天 3 次",
- icon: CheckCircle,
- enabled: true,
- lastRun: "今天 15:00",
- stats: "检查 7 项 · 已完成 3",
- },
- { name: "记忆周报", cron: "每周日 20:00", icon: Brain, enabled: true, lastRun: "上周日" },
- { name: "TODO 提醒", cron: "每天 10:00/15:00", icon: Bell, enabled: true, lastRun: "今天 10:00" },
- { name: "联系人扫描", cron: "每周一 09:00", icon: Users, enabled: true, lastRun: "上周一" },
-];
-
-const PROACTIVE_RULES = [
- { name: "灵感关联", trigger: "用户记录新想法时", example: '"3 天前说的 X 跟这个想法很像"' },
- { name: "截止日预警", trigger: "待办距截止 < 24h", example: '"数据库迁移今天到期"' },
- { name: "上下文衔接", trigger: "新对话开始时", example: '"昨天的 PRD 还没完成,要继续吗?"' },
- { name: "知识沉淀", trigger: "对话中出现重要决策", example: "自动保存 PostgreSQL 选型决策" },
- { name: "对方承诺追踪", trigger: "会议中对方承诺行动项", example: '"王浩今天的 demo 还没更新"' },
-];
-
-const SKILLS = [
- {
- name: "Memory & Notes",
- desc: "自动记忆管理,知识沉淀",
- icon: FileText,
- installed: true,
- installs: "12.4k",
- },
- {
- name: "Task Manager",
- desc: "待办创建、追踪、提醒",
- icon: BarChart3,
- installed: true,
- installs: "11.2k",
- },
- {
- name: "Web Research",
- desc: "联网搜索 + 信息整理",
- icon: Search,
- installed: true,
- installs: "10.1k",
- },
- {
- name: "Code Automation",
- desc: "代码生成、PR、自动化",
- icon: Code,
- installed: true,
- installs: "8.3k",
- },
- {
- name: "Daily Digest",
- desc: "每日日程 + 待办汇总",
- icon: FileText,
- installed: true,
- installs: "9.8k",
- },
-];
-
-const RECOMMENDED = [
- {
- name: "Contact Intelligence",
- desc: "联系人健康评分 + 关系管理",
- icon: Users,
- installs: "7.2k",
- },
- { name: "Advisory Board", desc: "多 Agent 辩论 → 综合建议", icon: Brain, installs: "3.8k" },
- { name: "PRD Generator", desc: "需求文档生成与迭代", icon: FileText, installs: "6.7k" },
- { name: "Security Auditor", desc: "多视角安全审查 + 告警", icon: Shield, installs: "3.2k" },
-];
-
-const AUTOMATION_CARD_EXAMPLES: ChatCard[] = [
- {
- type: "automation",
- title: "今日战况复盘",
- status: "running",
- body: "正在扫描 7,660 条对话和 21 份文档...",
- path: "automation/daily-digest.yaml",
- meta: "定时触发 · 每天 22:00",
- },
- {
- type: "file",
- title: "日报已生成",
- status: "success",
- body: "完成 12 个任务 · 3 份文档 · 5 条新记忆",
- path: "artifacts/reports/daily-report-0223.md",
- diff: { added: 89, removed: 0 },
- actions: [{ label: "查看日报", primary: true }, { label: "推送飞书" }],
- },
-];
-
-const SKILL_CARD_EXAMPLE: ChatCard[] = [
- {
- type: "skill",
- title: "Web Research",
- status: "success",
- body: "联网搜索 + 信息整理 · 已安装",
- meta: "10.1k 安装 · 官方认证",
- actions: [{ label: "配置", primary: true }, { label: "查看文档" }],
- },
-];
-
-export default function StepAutomation() {
- const [view, setView] = useState("automation");
-
- return (
-
- {/* View toggle */}
-
-
-
-
-
- {view === "automation" ? (
-
- {/* Stats */}
-
- {[
- { label: "活跃任务", value: "8", icon: Clock, color: "text-info" },
- { label: "主动规则", value: "7", icon: Brain, color: "text-clone" },
- { label: "今日触发", value: "14", icon: Zap, color: "text-success" },
- { label: "成功率", value: "96%", icon: CheckCircle, color: "text-success" },
- ].map((s) => (
-
-
-
{s.value}
-
{s.label}
-
- ))}
-
-
- {/* Templates */}
-
-
-
-
- Start with a template
-
-
-
- {TEMPLATES.map((t) => (
-
- ))}
-
-
-
- {/* Active tasks */}
-
-
-
-
- Active automations
-
-
- {TASKS.length}
-
-
-
- {TASKS.map((task) => (
-
-
-
-
-
-
- {task.name}
-
- {task.cron}
-
-
-
- 上次运行:{task.lastRun}
-
- {task.stats && (
-
- {task.stats}
-
- )}
-
-
-
- ))}
-
-
-
- {/* Proactive rules */}
-
-
-
- Proactive Rules
-
-
- {PROACTIVE_RULES.map((rule) => (
-
-
-
-
- {rule.name}
- · {rule.trigger}
-
-
- {rule.example}
-
-
-
-
- ))}
-
-
-
- {/* Card preview — what automation outputs look like */}
-
-
-
-
- Session 中的卡片产出
-
-
- 预览
-
-
-
-
-
- 😊
-
-
- 分身执行自动化后产出卡片 →
-
-
-
-
-
-
- ) : (
-
- {/* Installed */}
-
-
Skills
-
- Give your clone superpowers — teach it new skills.
-
-
-
-
- Installed {SKILLS.length}
-
- Featured
-
- Explore 12
-
-
-
-
- {SKILLS.map((s) => (
-
-
-
-
-
-
- {s.name}
-
-
-
{s.desc}
-
-
- {s.installs}
-
-
- ))}
-
-
-
- {/* Recommended */}
-
-
-
-
- Recommended for you
-
-
-
- {RECOMMENDED.map((s) => (
-
- ))}
-
-
-
- {/* Skill card preview */}
-
-
-
-
- Session 中的技能卡片
-
-
- 预览
-
-
-
-
-
-
-
- {/* Builder tools */}
-
-
-
-
-
- )}
-
- );
-}
diff --git a/apps/demo/src/pages/journey/StepClone.tsx b/apps/demo/src/pages/journey/StepClone.tsx
deleted file mode 100644
index eb210057..00000000
--- a/apps/demo/src/pages/journey/StepClone.tsx
+++ /dev/null
@@ -1,579 +0,0 @@
-import { Button } from "@nexu-design/ui-web";
-import {
- Activity,
- Brain,
- ChevronRight,
- Database,
- FileText,
- Globe,
- MessageSquare,
- Pencil,
- Phone,
- Plus,
- Rss,
- Send,
- Shield,
- Wrench,
-} from "lucide-react";
-import { useState } from "react";
-import ChatCardGroup from "../product/ChatCards";
-import type { ChatCard } from "../product/sessionsData";
-
-const SOUL_FILES = [
- { label: "角色", value: "全栈工程师 · 产品经理" },
- { label: "领域", value: "Web 开发 · AI 应用 · SaaS" },
- { label: "沟通", value: "简洁直接 · 技术术语用英文" },
- { label: "习惯", value: "晚上效率高 · 先做难的 · 迭代快" },
-];
-
-const WORLDVIEW = [
- { icon: "🎯", label: "产品哲学", value: "用户体验 > 功能数量" },
- { icon: "⚡", label: "技术观", value: "实用主义,先跑起来再优化" },
- { icon: "🧭", label: "决策原则", value: '"这让分身更懂用户了吗?"' },
-];
-
-type FeedItemType = "automation" | "session" | "skill" | "memory" | "proactive" | "team";
-
-const FEED_ITEMS: {
- type: FeedItemType;
- icon: string;
- title: string;
- desc: string;
- time: string;
- files?: number;
- memories?: number;
-}[] = [
- {
- type: "proactive",
- icon: "📊",
- title: "今日战况复盘已生成",
- desc: "完成 12 个任务,生成 3 份文档,新增 5 条记忆",
- time: "22:00",
- files: 3,
- memories: 5,
- },
- {
- type: "team",
- icon: "🤝",
- title: "张三的分身查询了你的任务进度",
- desc: "分身已自动回复 Gateway 重构时间线",
- time: "14:30",
- },
- {
- type: "automation",
- icon: "⚡",
- title: "竞品监控触发 — Notion 发布 AI 更新",
- desc: "已自动生成竞品分析摘要并存入 artifacts",
- time: "18:30",
- files: 1,
- },
- {
- type: "session",
- icon: "💬",
- title: "注册流程优化方案完成",
- desc: "基于 OAuth 选型,生成完整 PRD + 流程图",
- time: "16:45",
- files: 2,
- memories: 1,
- },
- {
- type: "memory",
- icon: "🧠",
- title: "记忆整理完成 — 发现 3 条冲突",
- desc: "自动整理本周 23 条记忆,建议确认 3 条变更",
- time: "14:00",
- memories: 23,
- },
-];
-
-const FEED_TYPE_STYLES: Record = {
- automation: "bg-blue-500/10 text-blue-600",
- session: "bg-emerald-500/10 text-emerald-600",
- skill: "bg-purple-500/10 text-purple-600",
- memory: "bg-amber-500/10 text-amber-600",
- proactive: "bg-orange-500/10 text-orange-600",
- team: "bg-cyan-500/10 text-cyan-600",
-};
-
-// Sample ChatCards to preview how feed items appear as cards in sessions
-const FEED_CARD_PREVIEWS: ChatCard[] = [
- {
- type: "automation",
- title: "今日战况复盘",
- status: "success",
- body: "✓ 扫描 3 个活跃 Session\n✓ 生成日报并推送到飞书群",
- path: "artifacts/reports/daily-digest-0221.md",
- meta: "cron: 每天 22:00",
- },
- {
- type: "collaboration",
- title: "李四分身回复:Gateway 进度",
- status: "success",
- body: "整体进度:15%\nAPI 路由层已完成,中间件迁移进行中",
- path: "contacts/李四-后端.md",
- meta: "Proxy 回复 · 2 分钟",
- },
- {
- type: "file",
- title: "注册流程优化 PRD",
- status: "success",
- body: "方案 A:Google OAuth + 飞书扫码\n预计注册转化率提升 40%",
- path: "artifacts/prds/注册流程优化.md",
- diff: { added: 48, removed: 0 },
- },
-];
-
-const CHANNELS_NATIVE = [
- {
- name: "Email",
- icon: "📧",
- status: "connected",
- desc: "tom@refly.ai · IMAP 已配置",
- badge: "零安装",
- },
- {
- name: "SMS",
- icon: "💬",
- status: "connected",
- desc: "+86 138****7890 · Twilio",
- badge: "零安装",
- },
- {
- name: "WhatsApp",
- icon: "📱",
- status: "pending",
- desc: "待绑定手机号",
- badge: "零安装",
- },
-];
-
-const CHANNELS_IM = [
- {
- name: "飞书",
- icon: "🐦",
- status: "connected",
- desc: "Bot 已上线 · 主渠道",
- },
- {
- name: "Slack",
- icon: "💼",
- status: "connected",
- desc: "OAuth 已授权 · 3 个 Channel",
- },
- { name: "Telegram", icon: "✈️", status: "pending", desc: "待配置 Bot Token" },
- { name: "Discord", icon: "🎮", status: "off", desc: "即将支持" },
- { name: "企业微信", icon: "🏢", status: "off", desc: "即将支持" },
-];
-
-const MEMORY_CATEGORIES = [
- { id: "ideas", label: "想法", icon: "💡", count: 31 },
- { id: "tone", label: "口吻", icon: "🗣️", count: 8 },
- { id: "preferences", label: "喜好", icon: "⭐", count: 24 },
- { id: "habits", label: "习惯", icon: "🔄", count: 15 },
- { id: "status", label: "近况", icon: "📍", count: 12 },
- { id: "goals", label: "目标", icon: "🎯", count: 18 },
- { id: "worldview", label: "世界观", icon: "🌏", count: 9 },
- { id: "decisions", label: "决策", icon: "⚖️", count: 18 },
- { id: "facts", label: "事实", icon: "📎", count: 67 },
-];
-
-const MEMORY_SAMPLE = [
- { category: "ideas", content: 'AI 视为"赛博合伙人"的协作理念', icon: "💡" },
- {
- category: "decisions",
- content: "PostgreSQL + TypeORM 替代 MongoDB",
- icon: "⚖️",
- },
- {
- category: "preferences",
- content: "喜欢运动,乒乓球和跑步,影视达人",
- icon: "⭐",
- },
-];
-
-type TabId = "feeds" | "channels" | "memory";
-
-export default function StepClone() {
- const [activeTab, setActiveTab] = useState("feeds");
-
- const TABS: { id: TabId; label: string; icon: typeof Rss }[] = [
- { id: "feeds", label: "Feeds", icon: Rss },
- { id: "channels", label: "Channels", icon: MessageSquare },
- { id: "memory", label: "Memory", icon: Database },
- ];
-
- return (
-
-
-
分身搭建
-
- 配置你的数字分身 — 所有信息存储在分身的大脑中,越用越懂你
-
-
-
-
- {/* Left: PersonaPanel (condensed, product-aligned) */}
-
-
-
-
我的分身
-
全栈工程师
-
-
-
-
-
-
-
-
- {[
- { v: "1,770", l: "轮次" },
- { v: "162", l: "文件" },
- { v: "223", l: "记忆" },
- { v: "6", l: "联系人" },
- ].map((s) => (
-
- ))}
-
-
-
-
-
-
- 人设特质
-
-
-
- {SOUL_FILES.map((f) => (
-
-
- {f.label}
-
-
- {f.value}
-
-
-
- ))}
-
-
-
-
-
-
-
- 世界观
-
-
-
- {WORLDVIEW.map((w) => (
-
-
{w.icon}
-
-
{w.label}
-
{w.value}
-
-
- ))}
-
-
-
-
- {/* Right: Tab-based content */}
-
-
- {TABS.map((t) => (
-
- ))}
-
-
- {activeTab === "feeds" && (
- <>
-
-
-
-
-
-
-
- 7 文件
-
-
-
-
- 14 记忆
-
-
-
-
- {FEED_ITEMS.map((item) => (
-
-
-
{item.icon}
-
-
-
- {item.type}
-
- {item.time}
-
-
{item.title}
-
{item.desc}
-
- {item.files != null && (
-
- {item.files}
-
- )}
- {item.memories != null && (
-
- {item.memories}
-
- )}
-
- 查看详情
-
-
-
-
-
- ))}
-
-
-
-
- Feed 中的活动会以卡片形式出现在 Session 中:
-
-
-
-
-
- >
- )}
-
- {activeTab === "channels" && (
-
-
-
-
- 无需下载 App — 发消息即可启动分身
-
-
- {CHANNELS_NATIVE.map((ch) => (
-
-
{ch.icon}
-
-
-
- {ch.name}
-
- {ch.badge && (
-
- {ch.badge}
-
- )}
-
-
{ch.desc}
-
- {ch.status === "connected" && (
-
- 已连接
-
- )}
- {ch.status === "pending" && (
-
- 配置
-
- )}
-
- ))}
-
-
-
-
-
-
- {CHANNELS_IM.map((ch) => (
-
-
{ch.icon}
-
- {ch.name}
- {ch.desc}
-
- {ch.status === "connected" && (
-
- 已连接
-
- )}
- {ch.status === "pending" && (
-
- 配置
-
- )}
- {ch.status === "off" && (
-
即将支持
- )}
-
- ))}
-
-
-
-
-
- )}
-
- {activeTab === "memory" && (
-
-
- {MEMORY_CATEGORIES.map((cat) => (
-
- ))}
-
-
-
- {MEMORY_SAMPLE.map((m) => (
-
-
- {m.icon}
-
- {MEMORY_CATEGORIES.find((c) => c.id === m.category)?.label}
-
-
-
- {m.content}
-
-
- ))}
-
-
-
-
- )}
-
-
-
- );
-}
diff --git a/apps/demo/src/pages/journey/StepIM.tsx b/apps/demo/src/pages/journey/StepIM.tsx
deleted file mode 100644
index a968f632..00000000
--- a/apps/demo/src/pages/journey/StepIM.tsx
+++ /dev/null
@@ -1,425 +0,0 @@
-import { Button } from "@nexu-design/ui-web";
-import {
- Check,
- CheckCircle,
- Globe,
- Link2,
- MessageSquare,
- Phone,
- Plus,
- RefreshCw,
- Settings,
- Sparkles,
-} from "lucide-react";
-import ChatCardGroup from "../product/ChatCards";
-import type { ChatCard } from "../product/sessionsData";
-
-type ChannelCategory = "native" | "im";
-
-interface Channel {
- name: string;
- icon: string;
- status: "connected" | "pending" | "coming";
- desc: string;
- badge: string | null;
- category: ChannelCategory;
- stats: {
- rounds: number;
- files: number;
- memories: number;
- contacts: number;
- } | null;
- recent?: { type: string; label: string; time: string }[];
- highlight?: string;
- steps?: string[];
- stepsDone?: number;
-}
-
-const NATIVE_CHANNELS: Channel[] = [
- {
- name: "Email",
- icon: "📧",
- status: "connected",
- desc: "tom@refly.ai · IMAP/SMTP 已配置",
- badge: "零安装",
- category: "native",
- stats: { rounds: 342, files: 28, memories: 45, contacts: 8 },
- recent: [
- {
- type: "file",
- label: "分身回复了投资人 Alex 的 follow-up",
- time: "1 小时前",
- },
- { type: "memory", label: "从邮件中提取了合作意向备忘", time: "3 小时前" },
- ],
- highlight: "发邮件给分身 = 启动一个 Session。附件自动存入 artifacts,关键信息记入 memory。",
- },
- {
- name: "SMS / iMessage",
- icon: "💬",
- status: "connected",
- desc: "+86 138****7890 · Twilio 接入",
- badge: "零安装",
- category: "native",
- stats: { rounds: 87, files: 5, memories: 23, contacts: 3 },
- recent: [
- {
- type: "memory",
- label: "短信指令:帮我查下明天的日程",
- time: "30 分钟前",
- },
- { type: "file", label: "分身回复了日程摘要", time: "30 分钟前" },
- ],
- highlight: "给分身发短信,随时随地发指令。无需打开任何 App,最原生的交互方式。",
- },
- {
- name: "WhatsApp",
- icon: "📱",
- status: "pending",
- desc: "待绑定手机号 · Meta API",
- badge: "零安装",
- category: "native",
- stats: null,
- recent: [],
- highlight: "全球 20 亿用户的即时通讯。给分身的 WhatsApp 号发消息就能开始工作。",
- },
-];
-
-const IM_CHANNELS: Channel[] = [
- {
- name: "飞书",
- icon: "🐦",
- status: "connected",
- desc: "Bot 已上线 · WebSocket 活跃",
- badge: "主渠道",
- category: "im",
- stats: { rounds: 1247, files: 89, memories: 156, contacts: 5 },
- recent: [
- { type: "memory", label: "记录了 OAuth 选型决策", time: "20 分钟前" },
- { type: "file", label: "生成了注册流程 PRD", time: "2 小时前" },
- ],
- steps: ["创建飞书机器人", "填写 App ID + Secret", "选择权限范围", "部署完成"],
- stepsDone: 4,
- },
- {
- name: "Slack",
- icon: "💼",
- status: "connected",
- desc: "OAuth 已授权 · 3 个 Channel",
- badge: null,
- category: "im",
- stats: { rounds: 523, files: 34, memories: 67, contacts: 3 },
- recent: [{ type: "file", label: "更新了竞品分析报告", time: "昨天" }],
- steps: ["安装 Slack App", "OAuth 授权", "选择 Channel", "部署完成"],
- stepsDone: 4,
- },
- {
- name: "Telegram",
- icon: "✈️",
- status: "pending",
- desc: "待配置 Bot Token",
- badge: null,
- category: "im",
- stats: null,
- recent: [],
- steps: ["创建 Telegram Bot", "填写 Bot Token", "设置 Webhook", "部署完成"],
- stepsDone: 0,
- },
- {
- name: "Discord",
- icon: "🎮",
- status: "coming",
- desc: "即将支持",
- badge: "敬请期待",
- category: "im",
- stats: null,
- recent: [],
- steps: [],
- stepsDone: 0,
- },
- {
- name: "企业微信",
- icon: "🏢",
- status: "coming",
- desc: "即将支持",
- badge: "敬请期待",
- category: "im",
- stats: null,
- recent: [],
- steps: [],
- stepsDone: 0,
- },
-];
-
-// Sample card for email/SMS session preview
-const EMAIL_SESSION_CARDS: ChatCard[] = [
- {
- type: "file",
- title: "投资人 Alex follow-up 回复",
- status: "success",
- body: "已根据你的记忆起草回复,附上最新产品进展和 demo 链接。",
- path: "artifacts/emails/investor-alex-followup.md",
- meta: "来自 Email · 1 小时前",
- actions: [{ label: "查看邮件", primary: true }],
- },
-];
-
-function StatBadge({
- icon,
- label,
- value,
-}: {
- icon: string;
- label: string;
- value: number;
-}) {
- return (
-
- {icon}
- {value.toLocaleString()}
- {label}
-
- );
-}
-
-function ChannelCard({ ch }: { ch: Channel }) {
- return (
-
-
-
- {ch.icon}
-
-
-
- {ch.name}
- {ch.badge && (
-
- {ch.badge}
-
- )}
-
-
{ch.desc}
-
-
- {ch.status === "connected" && (
-
- 已连接
-
- )}
- {ch.status === "pending" && (
-
- )}
- {ch.status === "coming" && 即将支持}
-
-
-
- {/* Native channel highlight */}
- {ch.highlight && (
-
- )}
-
- {ch.stats && (
-
-
-
-
-
-
-
- {ch.recent && ch.recent.length > 0 && (
-
- {ch.recent.map((r) => (
-
- {r.type === "memory" ? "🧠" : "📄"}
- {r.label}
- {r.time}
-
- ))}
-
- )}
-
- )}
-
- {ch.status === "pending" && ch.steps && ch.steps.length > 0 && (
-
-
-
配置步骤
-
- {ch.steps.map((step, i) => (
-
- {i < (ch.stepsDone ?? 0) ? (
-
- ) : (
-
- )}
-
- {step}
-
-
- ))}
-
-
-
-
- )}
-
- );
-}
-
-export default function StepIM() {
- return (
-
-
-
接入 IM / 飞书
-
- 让分身住在你常用的工具里 — 在哪都能用,记忆跨平台同步
-
-
-
- {/* Integration flow diagram */}
-
-
- 接入流程(以飞书为例)
-
-
- {["创建机器人", "配置权限", "填写凭证", "测试连接", "上线运行"].map((step, i) => (
-
-
-
- {i < 4 ? : i + 1}
-
-
- {step}
-
-
- {i < 4 &&
}
-
- ))}
-
-
-
- 飞书已连接
-
- · Bot 名称:Refly 分身 · WebSocket 活跃 · 延迟 < 200ms
-
-
-
-
- {/* Native channels section */}
-
-
-
- 无需下载任何 App — 每个手机都有短信和邮件。发一条消息就能启动分身工作。
-
-
- {NATIVE_CHANNELS.map((ch) => (
-
- ))}
-
-
-
- {/* IM platforms section */}
-
-
-
-
-
-
IM 平台
-
团队协作 · 群聊 · 卡片交互
-
-
- {IM_CHANNELS.map((ch) => (
-
- ))}
-
-
-
- {/* Card preview: session from email/SMS */}
-
-
-
-
- {/* Key features */}
-
- {[
- {
- icon: RefreshCw,
- label: "跨平台同步",
- desc: "飞书说的话,网页也记得",
- },
- { icon: Globe, label: "多端同时在线", desc: "网页 + IM 同时使用" },
- {
- icon: MessageSquare,
- label: "群聊协作",
- desc: "在群里帮你汇总进度",
- },
- { icon: Phone, label: "零安装接入", desc: "邮件/短信 发一条即启动" },
- ].map((f) => (
-
-
-
{f.label}
-
{f.desc}
-
- ))}
-
-
- );
-}
diff --git a/apps/demo/src/pages/journey/StepLanding.tsx b/apps/demo/src/pages/journey/StepLanding.tsx
deleted file mode 100644
index 3604d6a3..00000000
--- a/apps/demo/src/pages/journey/StepLanding.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import LandingPreview from "../LandingPreview";
-
-export default function StepLanding() {
- return ;
-}
diff --git a/apps/demo/src/pages/journey/StepOnboarding.tsx b/apps/demo/src/pages/journey/StepOnboarding.tsx
deleted file mode 100644
index b75abae1..00000000
--- a/apps/demo/src/pages/journey/StepOnboarding.tsx
+++ /dev/null
@@ -1,598 +0,0 @@
-import { Button } from "@nexu-design/ui-web";
-import {
- ArrowRight,
- Brain,
- Check,
- CheckCircle,
- ChevronRight,
- Database,
- Globe,
- Link2,
- MessageSquare,
- RefreshCw,
- Send,
- Shield,
- Sparkles,
- Upload,
- UserPlus,
- Users,
- Wrench,
-} from "lucide-react";
-import { useState } from "react";
-import ChatCardGroup from "../product/ChatCards";
-import type { ChatCard } from "../product/sessionsData";
-
-const STEPS = [
- { id: "persona", label: "基础人设", icon: Shield, status: "done" as const },
- { id: "worldview", label: "世界观", icon: Globe, status: "done" as const },
- { id: "memory", label: "记忆导入", icon: Database, status: "active" as const },
- { id: "integrations", label: "渠道授权", icon: Link2, status: "pending" as const },
- { id: "skills", label: "能力配置", icon: Sparkles, status: "pending" as const },
- { id: "knowledge", label: "知识库", icon: Brain, status: "pending" as const },
- { id: "team", label: "团队协作", icon: Users, status: "pending" as const },
-];
-
-interface ChatMsg {
- from: "clone" | "user" | "system";
- content: string;
- widget?: "integrations" | "skills" | "upload" | "progress" | "team";
-}
-
-const MESSAGES: ChatMsg[] = [
- { from: "system", content: "🎉 分身初始化 · 持续对话" },
- {
- from: "clone",
- content:
- "你好!我是你的数字分身 😊\n\n让我先了解你,这样我才能更好地帮你。我们可以随时聊,不用一次搞定 — 你说到哪儿算哪儿,之后随时回来补充。",
- },
- {
- from: "clone",
- content:
- "先来最基础的:\n\n1. 你希望我叫你什么?\n2. 你主要做什么工作?(角色/领域)\n3. 你希望我用什么风格跟你沟通?(正式/轻松/技术范/随意聊)",
- },
- {
- from: "user",
- content:
- "叫我 Tom,我是产品经理 + 技术合伙人,做 AI SaaS 方向。沟通风格要简洁直接,技术术语可以直接用英文。",
- },
- {
- from: "clone",
- content:
- "明白了 Tom 👋\n\n已记录:\n✅ 称呼:Tom\n✅ 角色:产品经理 + 技术合伙人\n✅ 领域:AI SaaS\n✅ 沟通风格:简洁直接 · 技术术语用英文\n\n接下来我想了解你的价值观和做事原则 — 这样我做决策时才不会跑偏。",
- },
- {
- from: "clone",
- content:
- '你做产品和技术决策时,有没有几条核心原则?\n比如"用户体验优先"、"先跑起来再说"、"不过度工程化"之类的。',
- },
- {
- from: "user",
- content:
- '有的:\n1. 用户体验 > 功能数量\n2. 实用主义,先跑起来再优化\n3. 判断标准是"这让分身更懂用户了吗?"\n4. 直说结论不说废话',
- },
- {
- from: "clone",
- content:
- '非常清晰 ✅ 已存入世界观:\n\n🎯 产品哲学:用户体验 > 功能数量\n⚡ 技术观:实用主义,先跑起来再优化\n🧭 决策标准:"这让分身更懂用户了吗?"\n💬 沟通准则:直说结论不说废话\n\n现在最关键的一步 — 让我获取你已有的记忆和内容。有几个方式可以快速导入:',
- },
- {
- from: "clone",
- content:
- "你可以:\n\n📎 **直接上传文件** — 简历、笔记、文档、项目资料等,我会自动提取关键信息\n\n🔗 **授权已有工具** — 连接你日常用的工具,我会从中学习你的习惯和偏好\n\n💬 **继续跟我聊** — 聊你最近在做的事、你的想法和计划,我边聊边记\n\n想先从哪个开始?",
- widget: "integrations",
- },
-];
-
-const ONBOARDING_CARDS: ChatCard[] = [
- {
- type: "memory",
- title: "人设特质已记录",
- status: "success",
- body: "角色:产品经理 + 技术合伙人\n领域:AI SaaS · 沟通风格:简洁直接",
- path: ".soul/identity.md",
- },
- {
- type: "memory",
- title: "世界观已存入",
- status: "success",
- body: "产品哲学:用户体验 > 功能数量\n技术观:实用主义 · 沟通准则:直说结论",
- path: ".soul/values.md",
- },
-];
-
-interface IntegrationItem {
- name: string;
- icon: string;
- desc: string;
- status: "connected" | "available" | "coming";
- importable: string;
-}
-
-const INTEGRATIONS: IntegrationItem[] = [
- {
- name: "飞书",
- icon: "🐦",
- desc: "消息、文档、日历、审批",
- status: "connected",
- importable: "1,247 条消息 · 89 文档",
- },
- {
- name: "Slack",
- icon: "💬",
- desc: "频道消息、DM、Threads",
- status: "connected",
- importable: "523 条消息 · 34 文档",
- },
- {
- name: "Notion",
- icon: "📝",
- desc: "页面、数据库、知识库",
- status: "available",
- importable: "导入 Notion 工作空间",
- },
- {
- name: "Gmail",
- icon: "📧",
- desc: "邮件内容、联系人",
- status: "available",
- importable: "扫描重要邮件和联系人",
- },
- {
- name: "GitHub",
- icon: "🐙",
- desc: "代码仓库、Issues、PR",
- status: "available",
- importable: "导入项目上下文",
- },
- {
- name: "Linear",
- icon: "🔵",
- desc: "Issues、Sprint、Roadmap",
- status: "available",
- importable: "同步项目进度",
- },
- {
- name: "n8n",
- icon: "⚡",
- desc: "自动化工作流",
- status: "available",
- importable: "导入现有工作流",
- },
- {
- name: "Google Calendar",
- icon: "📅",
- desc: "日程、会议",
- status: "available",
- importable: "同步日历和会议",
- },
- { name: "Figma", icon: "🎨", desc: "设计稿、评论", status: "coming", importable: "即将支持" },
- { name: "WeChat", icon: "💚", desc: "微信对话", status: "coming", importable: "即将支持" },
-];
-
-interface SkillOption {
- name: string;
- desc: string;
- icon: string;
- recommended: boolean;
- selected: boolean;
-}
-
-const SKILL_DEFAULTS: SkillOption[] = [
- { name: "记忆管理", desc: "自动记忆、知识沉淀", icon: "🧠", recommended: true, selected: true },
- { name: "任务管理", desc: "待办创建、追踪、提醒", icon: "✅", recommended: true, selected: true },
- { name: "每日汇报", desc: "晨间日报 + 日程提醒", icon: "📋", recommended: true, selected: true },
- { name: "联网搜索", desc: "实时搜索 + 信息整理", icon: "🔍", recommended: true, selected: true },
- { name: "代码助手", desc: "代码生成、PR、审查", icon: "💻", recommended: false, selected: false },
- { name: "文档写作", desc: "PRD、方案、报告生成", icon: "📄", recommended: false, selected: true },
- { name: "竞品监控", desc: "定期扫描竞品动态", icon: "📊", recommended: false, selected: false },
- {
- name: "会议纪要",
- desc: "录音转写 + Action Items",
- icon: "🎙️",
- recommended: false,
- selected: false,
- },
- { name: "邮件管理", desc: "邮件分类 + 摘要", icon: "📬", recommended: false, selected: false },
- { name: "社交媒体", desc: "内容发布 + 互动", icon: "📱", recommended: false, selected: false },
-];
-
-const INVITE_LIST = [
- { name: "张三", channel: "飞书", icon: "👨💻", status: "joined" as const },
- { name: "李四", channel: "飞书", icon: "🧑💻", status: "joined" as const },
- { name: "王五", channel: "Slack", icon: "👩🎨", status: "invited" as const },
- { name: "赵六", channel: "飞书", icon: "👩💼", status: "pending" as const },
-];
-
-function IntegrationsWidget() {
- const [expanded, setExpanded] = useState(false);
- const shown = expanded ? INTEGRATIONS : INTEGRATIONS.slice(0, 4);
-
- return (
-
-
- {shown.map((item) => (
-
-
- {item.icon}
- {item.name}
- {item.status === "connected" && (
-
- )}
- {item.status === "coming" && (
- 即将
- )}
-
-
{item.desc}
- {item.status === "connected" && (
-
- {item.importable}
-
- )}
- {item.status === "available" && (
-
- )}
-
- ))}
-
- {!expanded && INTEGRATIONS.length > 4 && (
-
- )}
-
- );
-}
-
-function SkillsWidget() {
- const [skills, setSkills] = useState(SKILL_DEFAULTS);
- const toggle = (name: string) => {
- setSkills((prev) => prev.map((s) => (s.name === name ? { ...s, selected: !s.selected } : s)));
- };
-
- return (
-
-
- {skills.map((s) => (
-
- ))}
-
-
- 已选 {skills.filter((s) => s.selected).length} 个能力 · 之后随时可在 Skills 页面调整
-
-
- );
-}
-
-function UploadWidget() {
- return (
-
-
-
拖拽文件到这里,或点击上传
-
- 支持 PDF、Word、Excel、Markdown、代码、图片、音视频等
-
-
- {["简历", "笔记", "项目文档", "会议录音"].map((tag) => (
-
- {tag}
-
- ))}
-
-
- );
-}
-
-function TeamSetupWidget() {
- const joined = INVITE_LIST.filter((m) => m.status === "joined").length;
-
- return (
-
-
-
- 团队成员
-
- {joined}/{INVITE_LIST.length} 已加入
-
-
-
- {INVITE_LIST.map((m) => (
-
- {m.icon}
- {m.name}
- {m.channel}
- {m.status === "joined" ? (
-
- ) : m.status === "invited" ? (
-
- 已邀请
-
- ) : (
-
- 待邀请
-
- )}
-
- ))}
-
-
-
-
-
🤖 团队分身网络
-
- 当团队成员加入后,你的分身可以:
-
-
- {[
- "📋 自动生成每日站会汇总",
- "🔍 代你查询其他成员任务进度",
- "⚠️ 检测依赖风险并主动发起对齐",
- "📊 生成团队 Sprint 报告",
- ].map((item) => (
-
- {item}
-
- ))}
-
-
-
- );
-}
-
-function ProgressWidget() {
- const items = [
- { label: "基础人设", done: true, detail: "称呼、角色、沟通风格" },
- { label: "世界观", done: true, detail: "4 条核心原则" },
- { label: "记忆导入", done: false, detail: "0 条记忆 · 0 文件" },
- { label: "渠道授权", done: false, detail: "2 已连接 · 8 可连接" },
- { label: "能力配置", done: false, detail: "4 个推荐能力" },
- { label: "知识库", done: false, detail: "等待导入" },
- { label: "团队协作", done: false, detail: "2/4 成员已加入" },
- ];
- const doneCount = items.filter((i) => i.done).length;
- const pct = Math.round((doneCount / items.length) * 100);
-
- return (
-
-
- 初始化进度
- {pct}%
-
-
-
- {items.map((item) => (
-
- {item.done ? (
-
- ) : (
-
- )}
-
- {item.label}
-
-
{item.detail}
-
- ))}
-
-
- );
-}
-
-// Active widget state to toggle inline widgets
-type ActiveWidget = "integrations" | "skills" | "upload" | "team" | "progress" | null;
-
-export default function StepOnboarding() {
- const [input, setInput] = useState("");
- const [activeWidget, setActiveWidget] = useState("integrations");
-
- return (
-
-
- {/* Header */}
-
-
- 😊
-
-
-
- 分身初始化
-
- 常驻对话
-
-
-
随时回来继续聊 · 越聊越懂你
-
-
-
- {/* Step indicator */}
-
-
- {STEPS.map((step, i) => (
-
-
- {step.status === "done" ? : }
- {step.label}
-
- {i < STEPS.length - 1 && (
-
- )}
-
- ))}
-
-
-
- {/* Chat */}
-
- {MESSAGES.map((msg) => (
-
- {msg.from === "system" ? (
-
- ) : msg.from === "user" ? (
-
- ) : (
-
-
- 😊
-
-
-
- {msg.content}
-
- {msg.widget === "integrations" && activeWidget === "integrations" && (
-
- )}
- {msg.widget === "integrations" && activeWidget === "skills" &&
}
- {msg.widget === "integrations" && activeWidget === "upload" &&
}
- {msg.widget === "integrations" && activeWidget === "team" && (
-
- )}
- {msg.widget === "integrations" && activeWidget === "progress" && (
-
- )}
-
-
- )}
-
- ))}
-
- {/* Memory cards */}
-
-
-
-
- {/* Quick actions */}
-
-
快捷操作:
- {[
- { label: "授权工具", icon: Link2, widget: "integrations" as const },
- { label: "上传文件", icon: Upload, widget: "upload" as const },
- { label: "选择能力", icon: Sparkles, widget: "skills" as const },
- { label: "邀请团队", icon: Users, widget: "team" as const },
- { label: "查看进度", icon: Wrench, widget: "progress" as const },
- ].map((action) => (
-
- ))}
-
-
-
- {/* Input area */}
-
-
-
-
-
- 这是一个持续对话 — 随时回来继续补充信息
-
-
-
-
-
-
- );
-}
diff --git a/apps/demo/src/pages/journey/StepPreview.tsx b/apps/demo/src/pages/journey/StepPreview.tsx
deleted file mode 100644
index 6fe3fd68..00000000
--- a/apps/demo/src/pages/journey/StepPreview.tsx
+++ /dev/null
@@ -1,250 +0,0 @@
-import { Bell, Brain, Check, Globe, MessageSquare, Sparkles, Star, Users, Zap } from "lucide-react";
-import ChatCardGroup from "../product/ChatCards";
-import type { ChatCard } from "../product/sessionsData";
-
-function FeishuMsg({
- from,
- name,
- avatar,
- children,
- time,
-}: {
- from: "user" | "clone" | "other";
- name?: string;
- avatar?: string;
- children: React.ReactNode;
- time?: string;
-}) {
- const isUser = from === "user";
- return (
-
-
- {avatar || (from === "clone" ? "😊" : "👤")}
-
-
- {name &&
{name}
}
-
- {children}
-
- {time &&
{time}
}
-
-
- );
-}
-
-const PREVIEW_CARDS: Record = {
- digest: [
- {
- type: "automation",
- title: "今日战况复盘",
- status: "success",
- body: "✅ 完成任务 12 个\n📄 生成文档 3 份\n🧠 新增记忆 5 条\n📈 对齐率 73% → 75%",
- path: "automation/daily-digest.yaml",
- actions: [{ label: "查看详情", primary: true }],
- },
- {
- type: "memory",
- title: "3 条记忆需确认",
- status: "warning",
- body: "发现矛盾记忆,需要你来定夺",
- path: "memory/conflicts/",
- actions: [{ label: "立即处理", primary: true }],
- },
- ],
- skill: [
- {
- type: "skill",
- title: "深度调研 · Web Research",
- status: "success",
- body: "检索 23 篇文章 + 5 个竞品",
- meta: "耗时 45s · 引用 23 篇",
- },
- {
- type: "file",
- title: "AI Agent 竞品分析报告",
- status: "success",
- body: "8,200 字 · 3 个关键发现:记忆壁垒、IM 入口、团队协作",
- path: "artifacts/research/ai-agent-market-2026.md",
- diff: { added: 389, removed: 0 },
- actions: [{ label: "查看报告", primary: true }],
- },
- {
- type: "automation",
- title: "竞品监控已创建",
- status: "success",
- body: "每天 09:00 自动检查竞品动态,有更新推送飞书",
- path: "automation/competitor-watch.yaml",
- },
- ],
- proactive: [
- {
- type: "automation",
- title: "截止日提醒",
- status: "warning",
- body: "数据库迁移 PR 今天到期。需要帮你拆解步骤吗?",
- actions: [{ label: "帮我拆解", primary: true }, { label: "延期" }],
- },
- {
- type: "memory",
- title: "灵感关联",
- status: "info",
- body: '你 3 天前说的"搜索加相关推荐"跟今天的优化方向很相关',
- meta: "根据 17 条相关记忆推荐",
- actions: [{ label: "合并处理", primary: true }],
- },
- ],
-};
-
-export default function StepPreview() {
- return (
-
-
-
接入效果预览
-
- 分身已上线,来看看它在各个场景中的表现
-
-
-
-
- {/* Feishu group chat */}
-
-
- 🐦
- 飞书 · 产品核心群
-
- 6 人
-
-
-
-
- @all 项目进度怎么样了?
-
-
- 我来帮 Tom 汇总 📊
-
-
✅ 前端登录 — 已完成(王浩)
-
🔄 接口对接 — 完成 60%(Tom)
-
⏳ 支付模块 — 明天开始(陈杰)
-
⚠️ 风险:接口对接需要等第三方升级
-
-
- 数据来自本周 12 次对话 + Linear
-
-
-
- 你这 AI 同事太强了……怎么弄的?
-
-
- 加个机器人,3 分钟搞定 😏
-
-
-
-
- {/* Daily digest card — using standardized ChatCards */}
-
-
- 📊
- 飞书 · 今日战况复盘
-
- 自动推送
-
-
-
-
-
- 😊
-
-
我的分身
-
BOT
-
22:00
-
-
-
-
-
- {/* Proactive alert — using standardized ChatCards */}
-
-
-
- 主动提醒
-
- Proactive
-
-
-
-
-
- 😊
-
-
我的分身
-
09:15 ~ 16:30
-
-
-
-
-
- {/* Skill execution in IM — with ChatCards */}
-
-
-
- IM 中使用 Skills
-
- Skills
-
-
-
-
- 帮我做一份 AI 赛道的竞品分析,然后设个每天自动监控
-
-
- 收到,开始调研 📂
-
-
-
-
-
-
-
-
- {/* Summary stats */}
-
-
完整用户旅程 — 已走完
-
- {[
- { icon: Globe, label: "Landing", status: "了解产品" },
- { icon: MessageSquare, label: "Onboarding", status: "初始化分身" },
- { icon: Users, label: "分身入口", status: "Feeds 动态" },
- { icon: Brain, label: "Session", status: "对话协作" },
- { icon: Zap, label: "Automation", status: "自动化 + Skills" },
- { icon: Star, label: "IM 接入", status: "飞书 / Slack" },
- { icon: Sparkles, label: "上线运行", status: "全天候工作" },
- ].map((s) => (
-
-
-
-
-
{s.label}
-
{s.status}
-
- ))}
-
-
-
- 分身已上岗,从此越用越懂你 🎉
-
-
- 记忆跨平台同步 · 自动任务全天运转 · 群聊协作天然传播
-
-
-
-
- );
-}
diff --git a/apps/demo/src/pages/journey/StepSession.tsx b/apps/demo/src/pages/journey/StepSession.tsx
deleted file mode 100644
index 970594b9..00000000
--- a/apps/demo/src/pages/journey/StepSession.tsx
+++ /dev/null
@@ -1,554 +0,0 @@
-import { Badge, Button, ConversationMessage, Input } from "@nexu-design/ui-web";
-import {
- BarChart3,
- Bookmark,
- ChevronRight,
- Clock,
- Eye,
- FileText,
- FolderOpen,
- Mic,
- MoreHorizontal,
- Paperclip,
- Plus,
- Search,
- Send,
- Sparkles,
- Terminal,
- Users,
- Wrench,
- X,
-} from "lucide-react";
-import { useState } from "react";
-import ChatCardGroup from "../product/ChatCards";
-import type { ChatCard } from "../product/sessionsData";
-
-const SESSIONS = [
- { id: 1, emoji: "📊", title: "竞品分析 · AI 赛道", time: "10 min", channel: "🌐", ops: 8 },
- { id: 2, emoji: "📝", title: "注册流程优化 PRD", time: "2h", channel: "🐦", ops: 12 },
- {
- id: 3,
- emoji: "🧠",
- title: "记忆整理 · 周复盘",
- time: "昨天",
- channel: "🌐",
- ops: 5,
- badge: "主动",
- },
- { id: 4, emoji: "💻", title: "OAuth 技术方案", time: "昨天", channel: "🐦", ops: 15 },
- { id: 5, emoji: "🔍", title: "Deep Research: Agent", time: "2天前", channel: "🌐", ops: 3 },
-];
-
-const QUICK_ACTIONS = [
- { label: "帮我写一份 PRD", icon: FileText, color: "text-emerald-400" },
- { label: "随手记一下...", icon: Bookmark, color: "text-violet-400" },
- { label: "帮我问李四进度", icon: Users, color: "text-cyan-400" },
- { label: "创建一个 automation", icon: Clock, color: "text-blue-400" },
- { label: "安装一个新 skill", icon: Wrench, color: "text-amber-400" },
- { label: "分析竞品", icon: BarChart3, color: "text-clone" },
-];
-
-const CAPABILITY_DOMAINS = [
- { domain: "📄 文件系统", accent: "border-l-emerald-500/40" },
- { domain: "🧠 记忆", accent: "border-l-violet-500/40" },
- { domain: "🔧 技能", accent: "border-l-amber-500/40" },
- { domain: "⏰ 自动化", accent: "border-l-blue-500/40" },
- { domain: "👥 团队协作", accent: "border-l-cyan-500/40" },
- { domain: "💰 升级", accent: "border-l-orange-500/40" },
-];
-
-const STEP_SESSION_CARDS: { research: ChatCard[]; output: ChatCard[] } = {
- research: [
- {
- type: "skill",
- title: "深度调研 · Web Research",
- status: "success",
- body: "检索 23 篇文章 + 5 个竞品,生成 8,200 字报告",
- meta: "耗时 45s · 引用 23 篇",
- },
- {
- type: "file",
- title: "AI Agent 赛道竞品分析",
- status: "success",
- body: "3 个关键发现:记忆壁垒、IM 入口、团队协作",
- path: "artifacts/research/ai-agent-market-2026.md",
- diff: { added: 389, removed: 0 },
- },
- ],
- output: [
- {
- type: "file",
- title: "AI Agent 产品方案",
- status: "success",
- body: "基于竞品分析 + 偏好生成完整 PRD",
- path: "artifacts/prds/ai-agent-product-plan.md",
- diff: { added: 156, removed: 0 },
- actions: [{ label: "打开文件", primary: true }],
- },
- {
- type: "memory",
- title: "Agent 定位决策",
- status: "success",
- body: "已记录:Agent Computer 定位 > 对话框",
- path: "memory/decisions/agent-positioning.md",
- },
- ],
-};
-
-const MESSAGES: {
- from: "user" | "clone";
- content: string | null;
- tool?: { name: string; icon: typeof Search };
- cards?: ChatCard[];
-}[] = [
- { from: "user", content: "帮我做一份 AI Agent 赛道的竞品分析" },
- { from: "clone", content: "收到,我来帮你搞 📂", tool: { name: "深度调研", icon: Search } },
- { from: "clone", content: null, cards: STEP_SESSION_CARDS.research },
- {
- from: "clone",
- content:
- "报告完成 ✅ 8,200 字,3 个关键发现:\n\n1. 记忆能力是核心壁垒\n2. IM 入口比独立 App 更好\n3. 团队协作是付费转化关键",
- },
- { from: "user", content: "不错,基于这个写一份产品方案" },
- { from: "clone", content: null, cards: STEP_SESSION_CARDS.output },
- {
- from: "clone",
- content: "已基于竞品分析 + 你之前的偏好生成产品方案 📄\n方案已保存到文档区,决策记录已更新。",
- },
-];
-
-const FILE_OPS = [
- {
- action: "CREATE",
- path: "artifacts/prds/ai-agent-product-plan.md",
- time: "刚刚",
- size: "3.2 KB",
- added: 156,
- },
- {
- action: "WRITE",
- path: "memory/decisions/agent-positioning.md",
- time: "1 分钟前",
- size: "1.1 KB",
- added: 42,
- removed: 5,
- },
- {
- action: "CREATE",
- path: "artifacts/research/ai-agent-market-2026.md",
- time: "3 分钟前",
- size: "12.8 KB",
- added: 389,
- },
- { action: "READ", path: "growth space/competitive/competitive-analysis.md", time: "5 分钟前" },
- { action: "READ", path: "memory/facts/market.md", time: "5 分钟前" },
-];
-
-const ACTION_STYLES: Record = {
- CREATE: { color: "text-success bg-success-subtle" },
- WRITE: { color: "text-clone bg-clone/10" },
- READ: { color: "text-info bg-info-subtle" },
- EXEC: { color: "text-warning bg-warning-subtle" },
-};
-
-function NewSessionViewCondensed({ onStartChat }: { onStartChat: (msg: string) => void }) {
- return (
-
-
- {/* Avatar + Greeting */}
-
- 😊
-
-
Good evening, Tom
-
- 你的主线入口 — 对话即操控一切
-
-
- {/* Quick action pills */}
-
- {QUICK_ACTIONS.map((t) => (
-
- ))}
-
-
- {/* Condensed 3x2 capability grid */}
-
-
-
- {CAPABILITY_DOMAINS.map((d) => (
-
- ))}
-
-
-
- {/* Scoped session hint */}
-
-
-
- 在其他页面你会看到 scoped sessions — 它们和这里一样是 Chat,但限定了特定的 Skills
- 和上下文:
-
-
- {[
- {
- label: "Team Insights",
- desc: "团队数据分析",
- color: "bg-cyan-500/10 text-cyan-400 border-cyan-500/20",
- },
- {
- label: "Sprint 分析",
- desc: "冲刺进度",
- color: "bg-blue-500/10 text-blue-400 border-blue-500/20",
- },
- {
- label: "OKR 对齐",
- desc: "目标跟踪",
- color: "bg-violet-500/10 text-violet-400 border-violet-500/20",
- },
- ].map((s) => (
-
- {s.label}
- · {s.desc}
-
- ))}
-
-
-
- {/* Footer hint */}
-
-
-
- 所有操作产出 6 种标准卡片:文件 · 记忆 · 技能 · 自动化 · 协作 · 升级 — 卡片可交互
-
-
-
-
- );
-}
-
-export default function StepSession() {
- const [activeSession, setActiveSession] = useState(null);
- const [previewOpen, setPreviewOpen] = useState(true);
- const [input, setInput] = useState("");
-
- const handleStartChat = (_msg: string) => {
- setActiveSession(1);
- };
-
- return (
-
- {/* Session list */}
-
-
-
-
-
-
-
-
-
-
-
- {SESSIONS.map((s) => {
- const isActive = activeSession === s.id;
- return (
-
- );
- })}
-
-
-
- {/* Main content: NewSessionView when no session, Chat when session active */}
- {activeSession === null ? (
-
- ) : (
-
-
-
-
- 📊
-
- 竞品分析 · AI 赛道
-
-
- 🌐 web
-
-
- 8 file ops
-
-
-
-
-
-
-
-
-
- {MESSAGES.map((msg) => (
-
- {msg.from === "clone" && (
-
- 😊
-
- )}
-
- {msg.cards && msg.cards.length > 0 &&
}
- {msg.tool && (
-
-
- {msg.tool.name}
- ✓
-
- )}
- {msg.content && (
-
- 😊
-
- ) : undefined
- }
- bubbleClassName={
- msg.from === "user"
- ? "bg-accent text-accent-fg text-[11px]"
- : "bg-surface-2 text-[11px]"
- }
- >
- {msg.content}
-
- )}
-
-
- ))}
-
-
- {/* Input */}
-
-
-
-
-
setInput(e.target.value)}
- placeholder="跟分身说点什么..."
- size="sm"
- className="border-0 bg-transparent shadow-none"
- />
-
-
-
-
-
-
- {/* Preview panel */}
- {previewOpen && (
-
-
-
-
-
- ai-agent-product-plan.md
-
-
- 新建
-
-
-
-
-
-
-
- ~/clone
-
- artifacts
-
- prds
-
-
-
-
- {`# AI Agent 赛道产品方案
-
-## 市场定位
-Agent Computer — 不是另一个对话框
-
-## 核心差异化
-1. 文件系统 = 持久记忆
-2. Skills = 可组合能力
-3. IM 入口 = 自然分发
-
-## 目标用户
-- 知识工作者 (PM/开发/运营)
-- 5-50 人团队
-- 已用过 ChatGPT 但不满足
-
-## 关键指标
-- D7 留存 > 40%
-- 月均 Sessions > 30
-- 团队裂变系数 > 1.5
-
-## 路线图
-Phase 1: 个人版 MVP
-Phase 2: 团队版 + IM 深度整合
-Phase 3: Skills 生态`}
-
-
- +156 lines
- 3.2 KB
-
-
-
- {/* File ops list */}
-
-
- 本次文件变更
-
-
- {FILE_OPS.map((op) => {
- const style = ACTION_STYLES[op.action];
- const name = op.path.split("/").pop();
- return (
-
-
-
- {op.action}
-
-
- {name}
-
-
-
-
- {op.path}
-
-
- {op.time}
-
-
- {op.added && (
-
- +{op.added}
- {op.removed && (
- -{op.removed}
- )}
- {op.size && {op.size}}
-
- )}
-
- );
- })}
-
-
-
- )}
-
- )}
-
- );
-}
diff --git a/apps/demo/src/pages/journey/StepTeam.tsx b/apps/demo/src/pages/journey/StepTeam.tsx
deleted file mode 100644
index 73e28653..00000000
--- a/apps/demo/src/pages/journey/StepTeam.tsx
+++ /dev/null
@@ -1,422 +0,0 @@
-import { Button, StatsBar } from "@nexu-design/ui-web";
-import {
- ArrowUp,
- BarChart3,
- Bot,
- CheckCircle,
- Circle,
- Clock,
- GitPullRequest,
- MessageSquare,
- Minus,
- Radio,
- Target,
- User,
- UserPlus,
- Users,
-} from "lucide-react";
-import { useState } from "react";
-import ChatCardGroup from "../product/ChatCards";
-import type { ChatCard } from "../product/sessionsData";
-
-const TEAM_MEMBERS = [
- { name: "张三", role: "前端工程师", avatar: "👨💻", level: 3, status: "online", alignment: 87 },
- { name: "李四", role: "后端工程师", avatar: "🧑💻", level: 2, status: "online", alignment: 73 },
- { name: "王五", role: "UI/UX 设计师", avatar: "👩🎨", level: 3, status: "busy", alignment: 91 },
- { name: "赵六", role: "产品经理", avatar: "👩💼", level: 4, status: "online", alignment: 95 },
-];
-
-const STATUS_COLOR: Record = {
- online: "bg-success",
- busy: "bg-warning",
- away: "bg-text-muted",
-};
-
-const TEAM_CARDS: Record = {
- standup: [
- {
- type: "collaboration",
- title: "团队站会 · Sprint 3",
- status: "success",
- body: "整体进度 58%\n张三:前端集成 + 测试 85%\n李四:Gateway 刚启动 ⚠️\n王五:设计稿 90% ✓",
- actions: [{ label: "📋 查看完整报告", primary: true }, { label: "💬 讨论" }],
- meta: "赵六的分身 · 09:05 自动生成",
- },
- ],
- proxy: [
- {
- type: "collaboration",
- title: "设计组 · 任务进度",
- status: "success",
- body: "设计稿 v2: 90%\n暗色主题: 100% ✅\n交互原型: 60%\n\n分身备注:周三下午可以评审交互原型",
- meta: "via 王五的分身 · 自动回复 · 无需打扰本人",
- viralCta: "💡 也让你的同事拥有分身 — 邀请有奖",
- },
- ],
- align: [
- {
- type: "collaboration",
- title: "对齐请求 · 高优先级",
- status: "warning",
- body: "前端集成依赖 Gateway 重构,可能延期 2 天\n🎯 建议:提前启动 Gateway 重构",
- actions: [{ label: "✅ 同意", primary: true }, { label: "❌ 拒绝" }, { label: "💬 回复" }],
- meta: "自动发起 · 基于任务依赖分析",
- },
- ],
-};
-
-// Simplified task data for journey preview
-const SIMPLE_TASKS = [
- {
- id: "TK-001",
- title: "Gateway 重构",
- status: "in_progress",
- priority: "high",
- assignee: "李四",
- executor: "agent",
- },
- {
- id: "TK-002",
- title: "前端集成接入",
- status: "todo",
- priority: "urgent",
- assignee: "张三",
- executor: "hybrid",
- },
- {
- id: "TK-003",
- title: "暗色主题设计稿",
- status: "done",
- priority: "medium",
- assignee: "王五",
- executor: "human",
- },
-];
-
-type TabId = "cards" | "alignments" | "tasks" | "okr" | "sprint" | "members";
-
-const TABS: { id: TabId; label: string; icon: typeof Radio }[] = [
- { id: "cards", label: "任务流", icon: Radio },
- { id: "alignments", label: "对齐请求", icon: GitPullRequest },
- { id: "tasks", label: "任务", icon: CheckCircle },
- { id: "okr", label: "OKR", icon: Target },
- { id: "sprint", label: "Sprint", icon: BarChart3 },
- { id: "members", label: "成员", icon: Users },
-];
-
-// ─── StatsBar ─────────────────────────────────────────────
-
-function TeamStatsBar() {
- const online = TEAM_MEMBERS.filter((m) => m.status === "online").length;
- const stats = [
- { id: "okr", label: "OKR 完成率", value: "86%", tone: "accent" as const },
- {
- id: "online",
- label: "分身在线",
- value: `${online}/${TEAM_MEMBERS.length}`,
- tone: "success" as const,
- },
- { id: "cards", label: "今日卡片", value: "5", tone: "accent" as const },
- { id: "alignments", label: "待对齐", value: "1", tone: "warning" as const },
- { id: "tasks", label: "活跃任务", value: "4", tone: "accent" as const },
- { id: "sprint", label: "Sprint 进度", value: "58%", tone: "info" as const },
- ];
-
- return ;
-}
-
-// ─── Simplified Task Card ─────────────────────────────────
-
-function SimpleTaskCard({
- task,
-}: {
- task: (typeof SIMPLE_TASKS)[number];
-}) {
- const statusConfig: Record = {
- todo: { icon: Circle, color: "text-info" },
- in_progress: { icon: Clock, color: "text-clone" },
- done: { icon: CheckCircle, color: "text-success" },
- };
- const priorityConfig: Record = {
- urgent: { icon: ArrowUp, color: "text-danger" },
- high: { icon: ArrowUp, color: "text-warning" },
- medium: { icon: Minus, color: "text-info" },
- };
- const executorConfig: Record = {
- human: { icon: User, color: "text-text-secondary" },
- agent: { icon: Bot, color: "text-clone" },
- hybrid: { icon: Users, color: "text-info" },
- };
- const status = statusConfig[task.status] ?? statusConfig.todo;
- const priority = priorityConfig[task.priority] ?? priorityConfig.medium;
- const executor = executorConfig[task.executor] ?? executorConfig.human;
- const StatusIcon = status.icon;
- const PriorityIcon = priority.icon;
- const ExecutorIcon = executor.icon;
-
- return (
-
-
-
{task.title}
-
- {task.assignee}
-
-
- {task.executor === "agent" ? "Agent" : task.executor === "hybrid" ? "人+Agent" : "人工"}
-
-
-
- );
-}
-
-// ─── TeamInsightsChat indicator (collapsed bar) ──────────────
-
-function ScopedSessionIndicator() {
- return (
-
-
-
- );
-}
-
-// ─── Main ──────────────────────────────────────────────────
-
-export default function StepTeam() {
- const [activeTab, setActiveTab] = useState("cards");
- const [cardTab, setCardTab] = useState<"standup" | "proxy" | "align">("standup");
-
- return (
-
-
-
团队协作 — 分身网络
-
- 当团队成员都有分身后,分身之间可以代替人交流、自动对齐、检测依赖风险。 所有交互通过 IM
- 卡片推送到飞书/Slack 群。
-
-
-
-
-
-
- {/* Tab bar */}
-
- {TABS.map((tab) => {
- const active = activeTab === tab.id;
- const Icon = tab.icon;
- return (
-
- );
- })}
-
-
- {/* Content area */}
-
- {/* Left: Team members panel */}
-
-
-
-
- 团队分身
- 3/4 在线
-
-
-
-
- {TEAM_MEMBERS.map((m) => (
-
-
-
-
- {m.name}
-
- Lv.{m.level}
-
-
-
{m.role}
-
-
-
- ))}
-
-
-
- {/* Right: Tab content */}
-
- {activeTab === "cards" && (
-
-
-
- IM 卡片流
-
-
- {[
- { id: "standup" as const, label: "📊 站会汇总" },
- { id: "proxy" as const, label: "🤝 分身代问" },
- { id: "align" as const, label: "⚠️ 对齐请求" },
- ].map((t) => (
-
- ))}
-
-
-
- {cardTab === "standup" ? "👩💼" : cardTab === "proxy" ? "😊" : "👨💻"}
-
-
- {cardTab === "standup"
- ? "赵六的分身"
- : cardTab === "proxy"
- ? "你的分身"
- : "张三的分身"}
-
-
BOT
-
- {cardTab === "standup" ? "09:05" : cardTab === "proxy" ? "10:30" : "14:00"}
-
-
-
-
- )}
-
- {activeTab === "tasks" && (
-
-
-
- 任务管理
-
-
- {SIMPLE_TASKS.map((t) => (
-
- ))}
-
-
- )}
-
- {activeTab === "alignments" && (
-
-
- 对齐请求
- — 待对齐卡片展示
-
- )}
-
- {activeTab === "okr" && (
-
-
- OKR
- — 目标与关键结果
-
- )}
-
- {activeTab === "sprint" && (
-
-
- Sprint
- — 迭代进度
-
- )}
-
- {activeTab === "members" && (
-
-
- 成员
- — 成员列表与详情
-
- )}
-
-
-
-
-
-
- {/* Core scenarios */}
-
-
核心场景
-
- {[
- {
- icon: "🤝",
- title: "分身代问",
- desc: "你的分身向其他成员的分身查询任务进度,自动回复,无需打扰本人。结果以 IM 卡片呈现。",
- tag: "P0 · Phase 4",
- },
- {
- icon: "📊",
- title: "站会自动化",
- desc: "每日自动汇总团队分身任务进度,生成站会 IM 卡片推送到群,包含风险提醒。",
- tag: "P0 · Phase 4",
- },
- {
- icon: "⚠️",
- title: "依赖感知与主动对齐",
- desc: "检测跨成员任务依赖风险,自动发起对齐请求卡片,一键确认调整排期。",
- tag: "P1 · Phase 5",
- },
- ].map((s) => (
-
-
- {s.icon}
- {s.title}
-
-
{s.desc}
-
- {s.tag}
-
-
- ))}
-
-
-
- );
-}
diff --git a/apps/demo/src/pages/journey/StepUpgrade.tsx b/apps/demo/src/pages/journey/StepUpgrade.tsx
deleted file mode 100644
index 7c1df8f5..00000000
--- a/apps/demo/src/pages/journey/StepUpgrade.tsx
+++ /dev/null
@@ -1,258 +0,0 @@
-import { Button } from "@nexu-design/ui-web";
-import {
- ArrowRight,
- BarChart3,
- Brain,
- Check,
- Crown,
- Gift,
- Rocket,
- Shield,
- Sparkles,
- UserPlus,
- Users,
- Zap,
-} from "lucide-react";
-
-const VALUE_ITEMS = [
- { icon: Brain, label: "无限记忆", free: "50 条", pro: "无限制", team: "无限制 + 共享" },
- { icon: Zap, label: "自动任务", free: "—", pro: "无限制", team: "无限制 + 团队联动" },
- {
- icon: Sparkles,
- label: "能力",
- free: "3 种",
- pro: "数千种 + 自定义",
- team: "数千种 + 团队共享",
- },
- {
- icon: BarChart3,
- label: "每日动态",
- free: "基础版",
- pro: "完整 + 主动提醒",
- team: "完整 + 团队 Insights",
- },
- { icon: Shield, label: "知识库", free: "10 MB", pro: "10 GB", team: "100 GB + 团队共享" },
- { icon: Users, label: "分身协作", free: "—", pro: "—", team: "分身间自动通信" },
-];
-
-const PLANS = [
- {
- name: "基础版",
- price: "免费",
- sub: "",
- desc: "入门体验分身能力",
- items: ["分身上岗", "500 能量/月", "3 种能力", "50 条记忆", "基础动态"],
- cta: "当前版本",
- highlight: false,
- disabled: true,
- },
- {
- name: "专业版",
- price: "¥29",
- sub: "/月",
- desc: "解锁完整分身潜力",
- items: [
- "5,000 能量/月",
- "无限能力 + 自定义",
- "完整记忆 + 成长体系",
- "自动任务 + 主动提醒",
- "飞书/Slack 深度整合",
- "优先模型",
- ],
- cta: "升级到专业版",
- highlight: true,
- disabled: false,
- },
- {
- name: "团队版",
- price: "¥19",
- sub: "/人/月",
- desc: "全团队 AI 协作网络",
- items: [
- "专业版全部能力",
- "团队共享知识库",
- "分身间自动协作",
- "OKR + Sprint 联动",
- "团队管理后台",
- "优先技术支持",
- ],
- cta: "邀请团队",
- highlight: false,
- disabled: false,
- },
-];
-
-const SUPERPOWERS = [
- { icon: "🧠", title: "记忆锁定", desc: "用了 30 天后,分身比你自己还懂你的偏好和工作习惯" },
- { icon: "⚡", title: "自动驾驶", desc: "竞品监控、日报周报、客户跟进 — 分身全天候自动运转" },
- { icon: "🤝", title: "团队网络", desc: "分身帮你问进度、对齐信息、汇总全局 — 不打扰同事" },
- { icon: "📈", title: "越用越强", desc: "每次对话都在学习你的风格,等级和默契度持续成长" },
-];
-
-export default function StepUpgrade() {
- return (
-
- {/* Header */}
-
-
- 解锁你的超能力
-
-
- 你已经体验了分身的基础能力
-
-
- 升级后,分身将进入全力以赴模式 — 无限记忆、自动任务、团队协作。
-
- 这不是付费墙,是你的超能力入口。
-
-
-
- {/* Value you've already built */}
-
-
-
-
- 你刚才体验的旅程已经为你创造了价值
-
-
-
- {SUPERPOWERS.map((s) => (
-
-
{s.icon}
-
{s.title}
-
{s.desc}
-
- ))}
-
-
-
- {/* Capability comparison table */}
-
-
-
- 能力对比 — 你值得拥有更多
-
-
-
-
-
- | 能力 |
- 基础版 |
-
-
- 专业版
-
- |
-
-
- 团队版
-
- |
-
-
-
- {VALUE_ITEMS.map((item) => (
-
- |
- {item.label}
- |
- {item.free} |
- {item.pro} |
- {item.team} |
-
- ))}
-
-
-
-
- {/* Pricing cards */}
-
- {PLANS.map((p) => (
-
- {p.highlight && (
-
- 推荐
-
- )}
-
{p.name}
-
{p.desc}
-
- {p.price}
- {p.sub}
-
-
- {p.items.map((item) => (
-
- {item}
-
- ))}
-
-
-
- ))}
-
-
- {/* Team invite incentive */}
-
-
-
-
-
-
-
- 邀请同事,一起解锁超能力
-
-
- 邀请 3 位同事加入,每人免费获得 Pro 版 30 天。你也会获得 30 天 Pro 延期。
-
- 团队越大,每个分身获得的共享知识越多,协作效率越高。
-
-
-
-
- 或直接在飞书/Slack 群里 @分身,说 "邀请 XXX"
-
-
-
-
-
-
- {/* Skip option */}
-
-
- 升级是可选的。基础版完全免费,随时可以升级。
-
-
- ✓ 不强制付费
- ✓ 随时升降级
- ✓ 数据不丢失
-
-
-
- );
-}
diff --git a/apps/demo/src/pages/product/AutomationPage.tsx b/apps/demo/src/pages/product/AutomationPage.tsx
deleted file mode 100644
index 5dd3d2c6..00000000
--- a/apps/demo/src/pages/product/AutomationPage.tsx
+++ /dev/null
@@ -1,1018 +0,0 @@
-import {
- Alert,
- AlertDescription,
- AlertTitle,
- Badge,
- Button,
- DetailPanel,
- DetailPanelCloseButton,
- DetailPanelContent,
- DetailPanelHeader,
- DetailPanelTitle,
- EntityCard,
- EntityCardContent,
- EntityCardDescription,
- EntityCardFooter,
- EntityCardHeader,
- EntityCardMedia,
- EntityCardMeta,
- EntityCardTitle,
- FollowUpInput,
- PageHeader,
- PanelFooter,
- PanelFooterActions,
- ScrollArea,
- StatCard,
- ToggleGroup,
- ToggleGroupItem,
-} from "@nexu-design/ui-web";
-import {
- AlertCircle,
- ArrowUpRight,
- BarChart3,
- Bell,
- Brain,
- Calendar,
- CheckCircle,
- Clock,
- Database,
- FileText,
- FolderOpen,
- Mail,
- MessageSquare,
- MoreHorizontal,
- Pause,
- Pencil,
- Play,
- Plus,
- Search,
- Shield,
- Sparkles,
- ToggleLeft,
- ToggleRight,
- TrendingUp,
- Users,
- Zap,
-} from "lucide-react";
-import type * as React from "react";
-import { useState } from "react";
-import { useNavigate } from "react-router-dom";
-
-import { useProductLayout } from "./ProductLayoutContext";
-
-type TabId = "schedules" | "proactive" | "logs";
-
-const AUTOMATION_TEMPLATES = [
- {
- name: "每日邮件摘要",
- desc: "汇总过去 24h 未读邮件,按发件人和优先级分类",
- icon: Mail,
- color: "bg-info-subtle text-info",
- },
- {
- name: "竞品监测",
- desc: "每周扫描竞品动态、产品更新、融资消息",
- icon: Search,
- color: "bg-clone/10 text-clone",
- },
- {
- name: "周五 Sprint 回顾",
- desc: "汇总本周完成 vs 计划任务,计算 velocity",
- icon: BarChart3,
- color: "bg-success-subtle text-success",
- },
- {
- name: "安全自审",
- desc: "每晚 AI 审查系统日志、权限配置、异常行为检测",
- icon: Shield,
- color: "bg-error-subtle text-error",
- },
- {
- name: "联系人健康扫描",
- desc: "每周扫描联系人,标记 >30 天未互动的关键人脉",
- icon: Users,
- color: "bg-role-ops/10 text-role-ops",
- },
- {
- name: "行动项追踪",
- desc: "每天 3 次检查 action items 完成情况,追踪对方承诺",
- icon: CheckCircle,
- color: "bg-success-subtle text-success",
- },
- {
- name: "知识库自动整理",
- desc: "新入库内容去重、合并、打标签、生成每周摘要",
- icon: Database,
- color: "bg-role-designer/10 text-role-designer",
- },
- {
- name: "增长指标日报",
- desc: "每日汇总核心指标:DAU、转化率、留存、社交互动",
- icon: TrendingUp,
- color: "bg-warning-subtle text-warning",
- },
- {
- name: "灵感 → 方案",
- desc: "新想法入库后自动搜索关联历史、评估可行性、生成方案",
- icon: Sparkles,
- color: "bg-clone/10 text-clone",
- },
-];
-
-const SCHEDULED_TASKS = [
- {
- id: 6,
- name: "今日战况复盘",
- cron: "每天 22:00",
- desc: "扫荡信息流,评论互动,筛选有价值内容,生成战况报告发送到飞书",
- channel: "飞书",
- enabled: true,
- lastRun: "今天 22:00",
- icon: Brain,
- isHighlight: true,
- stats: "今日:扫荡 7,660 条 · 评论 21 次 · 发现 3 个潜在目标",
- },
- {
- id: 1,
- name: "早间日报",
- cron: "每天 08:30",
- desc: "汇总日程、待办、紧急事项,发送到飞书",
- channel: "飞书",
- enabled: true,
- lastRun: "今天 08:30",
- icon: Calendar,
- },
- {
- id: 8,
- name: "Action Item 完成检查",
- cron: "每天 10:00 / 15:00 / 20:00",
- desc: "检查会议行动项完成情况,追踪对方承诺,未完成的主动提醒",
- channel: "飞书",
- enabled: true,
- lastRun: "今天 15:00",
- icon: CheckCircle,
- stats: "今日:检查 7 项 · 已完成 3 · 追踪对方 4 · 到期 1",
- },
- {
- id: 7,
- name: "记忆周报",
- cron: "每周日 20:00",
- desc: "复盘本周新增记忆、碎片聚合为结构化洞察、对齐率变化",
- channel: "飞书",
- enabled: true,
- lastRun: "上周日 20:00",
- icon: Database,
- stats: "本周:新增 23 条记忆 · 聚合 5 条碎片为洞察 · 对齐率 +3%",
- },
- {
- id: 2,
- name: "周五回顾",
- cron: "每周五 17:00",
- desc: "总结本周完成事项、未完成任务、下周规划",
- channel: "飞书",
- enabled: true,
- lastRun: "上周五 17:00",
- icon: FileText,
- },
- {
- id: 3,
- name: "TODO 提醒",
- cron: "每天 10:00 / 15:00",
- desc: "检查临期和过期的待办事项并提醒",
- channel: "飞书",
- enabled: true,
- lastRun: "今天 10:00",
- icon: Bell,
- },
- {
- id: 9,
- name: "联系人健康扫描",
- cron: "每周一 09:00",
- desc: "扫描联系人互动频率,标记 >30 天未联系的重要人脉,生成关系报告",
- channel: "飞书",
- enabled: true,
- lastRun: "上周一 09:00",
- icon: Users,
- stats: "上周:扫描 24 人 · 标记 6 人需关注 · 2 人流失风险",
- },
- {
- id: 10,
- name: "安全自审",
- cron: "每晚 03:00",
- desc: "AI 多视角审查系统运行日志、权限配置、异常行为检测,发现问题立即告警",
- channel: "飞书",
- enabled: true,
- lastRun: "今天 03:00",
- icon: Shield,
- },
- {
- id: 5,
- name: "邮件摘要",
- cron: "每 30 分钟(工作时段)",
- desc: "扫描未读邮件,过滤营销/冷推销,保留有价值对话并摘要",
- channel: "飞书",
- enabled: false,
- lastRun: "从未运行",
- icon: Mail,
- },
-];
-
-const PROACTIVE_RULES = [
- {
- id: 1,
- name: "灵感关联",
- trigger: "用户记录新想法时",
- action: "自动搜索相关历史记忆,发现关联并主动推送",
- enabled: true,
- example: '"你 3 天前说的 X 跟这个想法很像,要合并思考吗?"',
- },
- {
- id: 2,
- name: "截止日预警",
- trigger: "待办距截止 < 24h",
- action: "主动提醒用户并建议优先处理",
- enabled: true,
- example: '"数据库迁移今天到期,建议优先处理。需要帮你拆解步骤吗?"',
- },
- {
- id: 3,
- name: "上下文衔接",
- trigger: "新对话开始时",
- action: "自动加载最近相关记忆和未完成任务",
- enabled: true,
- example: '"你昨天让我帮你写的 PRD 还没完成,要继续吗?"',
- },
- {
- id: 4,
- name: "知识沉淀",
- trigger: "对话中出现重要决策",
- action: "自动提取并保存到记忆系统,更新分身认知",
- enabled: true,
- example: "自动保存:用户决定使用 PostgreSQL 替代 MongoDB",
- },
- {
- id: 5,
- name: "对方承诺追踪",
- trigger: "会议中对方承诺了行动项",
- action: '标记为"waiting on",到期未完成时提醒用户跟进',
- enabled: true,
- example: '"王浩承诺今天提交飞书扫码 demo,但还没更新。需要帮你发消息跟进吗?"',
- },
- {
- id: 6,
- name: "跨模块智能关联",
- trigger: "正在做 A 任务时,B 模块有相关信息",
- action: "主动插入关联信息,打通模块间数据",
- enabled: true,
- example: '"你在写定价方案,刘强上次聊过类似话题——他关注单位经济模型。"',
- },
- {
- id: 7,
- name: "自动化推荐",
- trigger: "用户重复做同一件事 3+ 次",
- action: "分身主动推荐自动化规则,用户一键确认",
- enabled: true,
- example: '"你每周一上午都在整理上周 Todo,要我帮你自动化吗?"',
- },
- {
- id: 8,
- name: "依赖风险检测",
- trigger: "团队成员任务进度变更时",
- action: "检测跨成员任务依赖风险,自动推送对齐请求卡片到 IM",
- enabled: true,
- example: '"张三的前端集成依赖李四的 Gateway,后者进度偏慢,建议提前对齐。"',
- },
- {
- id: 9,
- name: "站会自动化",
- trigger: "每日 09:00",
- action: "汇总团队分身任务进度,生成站会 IM 卡片推送到群",
- enabled: true,
- example: "自动生成 Sprint 3 进度 58%,风险项 1 个,推送到 #product-team",
- },
-];
-
-const ACTIVITY_LOGS = [
- { time: "08:30", type: "schedule", name: "早间日报", status: "success", detail: "已发送到飞书" },
- {
- time: "08:32",
- type: "proactive",
- name: "灵感关联",
- status: "success",
- detail: "发现 2 条相关记忆",
- },
- {
- time: "10:00",
- type: "schedule",
- name: "TODO 提醒",
- status: "success",
- detail: "提醒 3 条待办",
- },
- {
- time: "10:15",
- type: "proactive",
- name: "截止日预警",
- status: "warning",
- detail: "1 条任务今日到期",
- },
- {
- time: "11:30",
- type: "proactive",
- name: "知识沉淀",
- status: "success",
- detail: "自动保存 1 条决策",
- },
-];
-
-interface AutomationDetail {
- type: "schedule" | "proactive";
- id: number;
- name: string;
- icon: React.ElementType;
- enabled: boolean;
-}
-
-interface RunLog {
- time: string;
- status: "success" | "warning" | "error";
- summary: string;
-}
-
-interface ActivityLog {
- time: string;
- type: "schedule" | "proactive";
- name: string;
- status: RunLog["status"];
- detail: string;
-}
-
-function getCardActionProps(action: () => void) {
- return {
- role: "button" as const,
- tabIndex: 0,
- onClick: action,
- onKeyDown: (event: React.KeyboardEvent) => {
- if (event.key === "Enter" || event.key === " ") {
- event.preventDefault();
- action();
- }
- },
- };
-}
-
-function getLogStatusBadgeVariant(status: RunLog["status"]) {
- switch (status) {
- case "success":
- return "success";
- case "warning":
- return "warning";
- default:
- return "destructive";
- }
-}
-
-const AUTOMATION_RUN_LOGS: Record = {
- 6: [
- {
- time: "今天 22:00",
- status: "success",
- summary: "扫荡 7,660 条 · 评论 21 次 · 发现 3 个目标",
- },
- {
- time: "昨天 22:00",
- status: "success",
- summary: "扫荡 5,320 条 · 评论 15 次 · 发现 1 个目标",
- },
- {
- time: "前天 22:00",
- status: "success",
- summary: "扫荡 6,100 条 · 评论 18 次 · 发现 2 个目标",
- },
- {
- time: "2/18 22:00",
- status: "warning",
- summary: "扫荡 4,200 条 · 评论 12 次 · API 限流 1 次",
- },
- ],
- 1: [
- { time: "今天 08:30", status: "success", summary: "汇总 3 个日程 · 5 个待办 · 1 个紧急事项" },
- { time: "昨天 08:30", status: "success", summary: "汇总 2 个日程 · 3 个待办" },
- { time: "前天 08:30", status: "success", summary: "汇总 4 个日程 · 6 个待办 · 2 个紧急事项" },
- ],
- 8: [
- {
- time: "今天 15:00",
- status: "success",
- summary: "检查 7 项 · 已完成 3 · 追踪对方 4 · 王浩 demo 到期",
- },
- { time: "今天 10:00", status: "success", summary: "检查 7 项 · 已完成 1 · 新增对方承诺 2" },
- { time: "昨天 20:00", status: "warning", summary: "1 项过期:数据库 Schema 初稿(陈杰)" },
- ],
- 7: [
- {
- time: "上周日 20:00",
- status: "success",
- summary: "新增 23 条记忆 · 聚合 5 条碎片 · 默契度 +3%",
- },
- { time: "2/9 20:00", status: "success", summary: "新增 18 条记忆 · 合并 2 条 · 默契度 +2%" },
- ],
- 2: [
- { time: "上周五 17:00", status: "success", summary: "完成 15 / 18 任务 · 生成周报推送到飞书" },
- { time: "2/7 17:00", status: "success", summary: "完成 12 / 15 任务 · 生成周报推送到飞书" },
- ],
- 3: [
- { time: "今天 10:00", status: "success", summary: "提醒 3 条待办 · 1 条即将到期" },
- { time: "今天 15:00", status: "success", summary: "提醒 2 条待办" },
- { time: "昨天 10:00", status: "warning", summary: "1 条任务已过期:数据库迁移 PR Review" },
- ],
- 9: [
- {
- time: "上周一 09:00",
- status: "success",
- summary: "扫描 24 人 · 6 人需关注 · 2 人流失风险 · 已发提醒",
- },
- { time: "2/10 09:00", status: "success", summary: "扫描 22 人 · 3 人需关注 · 全部健康度正常" },
- ],
- 10: [
- {
- time: "今天 03:00",
- status: "success",
- summary: "审查 12 个 automation 日志 · 无异常 · 权限正常",
- },
- {
- time: "昨天 03:00",
- status: "success",
- summary: "审查完成 · 发现 1 条建议:优化 API 限流策略",
- },
- {
- time: "前天 03:00",
- status: "warning",
- summary: "检测到 1 个权限异常:邮件 skill 请求了写权限",
- },
- ],
-};
-
-const PROACTIVE_RUN_LOGS: Record = {
- 1: [
- { time: "今天 11:30", status: "success", summary: "发现 2 条相关记忆:搜索推荐 + 用户反馈" },
- { time: "昨天 14:20", status: "success", summary: "关联了 1 条历史决策:技术选型偏好" },
- ],
- 2: [
- { time: "今天 10:15", status: "warning", summary: "提醒:数据库迁移 PR 今日到期" },
- { time: "昨天 09:00", status: "success", summary: "提醒:竞品分析报告明天截止" },
- ],
- 4: [
- { time: "今天 11:30", status: "success", summary: "保存决策:使用 PostgreSQL + TypeORM" },
- { time: "昨天 16:00", status: "success", summary: "保存偏好:深色主题 + Linear 风格 UI" },
- ],
- 5: [
- {
- time: "今天 16:30",
- status: "warning",
- summary: "王浩承诺今天提交 demo,但截至 16:30 未更新",
- },
- { time: "昨天 10:00", status: "success", summary: "陈杰已提交 Schema 初稿,标记为已完成" },
- ],
- 6: [
- {
- time: "今天 14:20",
- status: "success",
- summary: "你在写定价方案时,关联了刘强上次讨论的单位经济模型",
- },
- {
- time: "昨天 16:00",
- status: "success",
- summary: "在竞品分析中,插入了知识库中 3 天前保存的 Cursor 资料",
- },
- ],
- 7: [
- {
- time: "今天 09:00",
- status: "success",
- summary: "检测到你本周 3 次手动整理 Todo,推荐自动化规则",
- },
- { time: "上周三", status: "success", summary: '推荐的"每日邮件摘要"已被确认并激活' },
- ],
-};
-
-function AutomationDetailPanel({ item, onClose }: { item: AutomationDetail; onClose: () => void }) {
- const navigate = useNavigate();
- const [followUp, setFollowUp] = useState("");
-
- const task = SCHEDULED_TASKS.find((t) => t.id === item.id);
- const rule = PROACTIVE_RULES.find((r) => r.id === item.id);
- const logs =
- item.type === "schedule"
- ? AUTOMATION_RUN_LOGS[item.id] || []
- : PROACTIVE_RUN_LOGS[item.id] || [];
-
- const handleFollowUp = () => {
- if (!followUp.trim()) return;
- navigate("/app/sessions");
- };
-
- return (
-
-
-
-
-
-
-
{item.name}
-
-
- {item.type === "schedule" ? "定时任务" : "主动规则"}
-
-
- {item.enabled ? "运行中" : "已暂停"}
-
-
-
-
-
-
-
-
- {/* Config info */}
-
- {task && (
-
-
-
- 频率
-
- {task.cron}
-
-
-
-
- 推送到
-
- {task.channel}
-
-
-
{task.desc}
-
- )}
- {rule && (
-
-
-
-
-
- 触发
-
- {rule.trigger}
-
-
-
-
- 动作
-
- {rule.action}
-
-
- {rule.example}
-
-
- )}
-
-
- {/* Run history */}
-
-
- {logs.length > 0 ? (
-
- {logs.map((log) => (
-
-
- {log.status === "success" ? (
-
- ) : log.status === "warning" ? (
-
- ) : (
-
- )}
-
-
-
-
- {log.status === "success"
- ? "成功"
- : log.status === "warning"
- ? "注意"
- : "失败"}
-
-
{log.time}
-
-
{log.summary}
-
-
- ))}
-
- ) : (
-
暂无运行记录
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
-
-function SchedulesTab({ onSelectItem }: { onSelectItem: (item: AutomationDetail) => void }) {
- const navigate = useNavigate();
-
- return (
-
- {/* Template grid */}
-
-
-
- Start with a template
-
-
- {AUTOMATION_TEMPLATES.map((t) => (
- navigate("/app/sessions"))}
- >
-
-
-
-
-
-
- {t.name}
-
- {t.desc}
-
-
-
-
- 使用模板
-
-
-
- ))}
-
-
-
- {/* Active automations */}
-
-
- Active automations
-
- {SCHEDULED_TASKS.filter((t) => t.enabled).length}
-
-
- {SCHEDULED_TASKS.map((task) => {
- const selectTask = () =>
- onSelectItem({
- type: "schedule",
- id: task.id,
- name: task.name,
- icon: task.icon,
- enabled: task.enabled,
- });
-
- return (
-
-
-
-
-
-
-
- {task.name}
-
- {task.cron}
-
-
- {task.enabled ? "运行中" : "已暂停"}
-
-
-
{task.desc}
-
-
- {task.channel}
-
- 上次运行:{task.lastRun}
-
-
-
-
- {task.stats && (
-
- {task.stats}
-
- )}
-
-
-
- {task.enabled ? (
-
- 暂停
-
- ) : (
-
- 启动
-
- )}
-
-
-
- 更多
-
-
-
-
- );
- })}
-
-
- );
-}
-
-function ProactiveTab({ onSelectItem }: { onSelectItem: (item: AutomationDetail) => void }) {
- return (
-
-
-
-
- 主动规则让分身不等你开口就主动帮你
- 。 分身会根据上下文触发规则,在合适的时机推送信息或执行操作。
-
-
-
- {PROACTIVE_RULES.map((rule) => {
- const selectRule = () =>
- onSelectItem({
- type: "proactive",
- id: rule.id,
- name: rule.name,
- icon: Zap,
- enabled: rule.enabled,
- });
-
- return (
-
-
-
-
-
-
-
-
-
- {rule.name}
-
-
- 主动规则
-
-
- {rule.enabled ? "启用中" : "已关闭"}
-
-
- {rule.enabled ? (
-
- ) : (
-
- )}
-
-
-
- 触发
-
- {rule.trigger}
-
-
-
-
- {rule.action}
-
- {rule.example}
-
-
-
- );
- })}
-
- );
-}
-
-function LogsTab() {
- return (
-
-
- 时间
- 类型
- 名称
- 状态
- 详情
-
- {(ACTIVITY_LOGS as ActivityLog[]).map((log) => (
-
-
{log.time}
-
-
- {log.type === "schedule" ? "定时" : "主动"}
-
-
-
{log.name}
-
-
-
- {log.status === "success" ? : }
- {log.status === "success" ? "成功" : log.status === "warning" ? "注意" : "失败"}
-
-
-
-
{log.detail}
-
- ))}
-
- );
-}
-
-const TABS_CONFIG = [
- { id: "schedules" as const, label: "定时任务", icon: Clock, count: 8 },
- { id: "proactive" as const, label: "Proactive", icon: Brain, count: 7 },
- { id: "logs" as const, label: "活动日志", icon: Zap, count: null },
-];
-
-export default function AutomationPage() {
- const [activeTab, setActiveTab] = useState("schedules");
- const [selectedItem, setSelectedItem] = useState(null);
- const { expandFileTree } = useProductLayout();
- const navigate = useNavigate();
-
- return (
-
-
-
-
-
- 设置自动任务,让分身帮你全天候工作。
-
- >
- }
- actions={
-
- }
- />
-
- {/* Stats */}
-
- {[
- { label: "活跃任务", value: "8", icon: Clock, tone: "info" as const },
- { label: "主动规则", value: "7", icon: Brain, tone: "accent" as const },
- { label: "今日触发", value: "14", icon: Zap, tone: "success" as const },
- {
- label: "成功率",
- value: "96%",
- icon: CheckCircle,
- tone: "success" as const,
- progress: 96,
- progressVariant: "success" as const,
- },
- ].map((s) => (
-
- ))}
-
-
- {/* Tabs */}
- {
- if (value) setActiveTab(value as TabId);
- }}
- variant="underline"
- aria-label="Automation views"
- className="mb-6"
- >
- {TABS_CONFIG.map((t) => (
-
-
- {t.label}
- {t.count && (
-
- {t.count}
-
- )}
-
- ))}
-
-
- {activeTab === "schedules" && }
- {activeTab === "proactive" && }
- {activeTab === "logs" && }
-
- {/* Bottom note */}
-
-
-
- 所有自动任务配置透明可查看,活动日志实时更新。
-
-
-
-
-
-
- {selectedItem && (
-
setSelectedItem(null)} />
- )}
-
- );
-}
diff --git a/apps/demo/src/pages/product/ChatCards.tsx b/apps/demo/src/pages/product/ChatCards.tsx
deleted file mode 100644
index 1aedd1d4..00000000
--- a/apps/demo/src/pages/product/ChatCards.tsx
+++ /dev/null
@@ -1,263 +0,0 @@
-import {
- Badge,
- Button,
- ConversationMessage,
- ConversationMessageStatusIcon,
-} from "@nexu-design/ui-web";
-import {
- ArrowUpRight,
- Brain,
- ChevronRight,
- Clock,
- Crown,
- FileText,
- Minus,
- Plus,
- Users,
- Wrench,
-} from "lucide-react";
-import type { CardStatus, CardType, ChatCard } from "./sessionsData";
-
-export type CardActionType = "openFile" | "navigate" | "showPricing";
-
-export interface CardAction {
- type: CardActionType;
- payload: string;
-}
-
-export interface ChatCardGroupProps {
- cards: ChatCard[];
- onCardAction?: (action: CardAction) => void;
- interactive?: boolean;
-}
-
-function resolveCardAction(card: ChatCard): CardAction | null {
- switch (card.type) {
- case "file":
- case "memory":
- return card.path ? { type: "openFile", payload: card.path } : null;
- case "skill":
- return { type: "navigate", payload: "/app/skills" };
- case "automation":
- return card.path
- ? { type: "openFile", payload: card.path }
- : { type: "navigate", payload: "/app/automation" };
- case "collaboration":
- return { type: "navigate", payload: "/app/team" };
- case "upgrade":
- return { type: "showPricing", payload: "" };
- default:
- return null;
- }
-}
-
-const CARD_CONFIG: Record<
- CardType,
- {
- icon: typeof FileText;
- label: string;
- accent: string;
- border: string;
- iconBg: string;
- }
-> = {
- file: {
- icon: FileText,
- label: "文件",
- accent: "text-emerald-400",
- border: "border-l-emerald-500/60",
- iconBg: "bg-emerald-500/10",
- },
- memory: {
- icon: Brain,
- label: "记忆",
- accent: "text-violet-400",
- border: "border-l-violet-500/60",
- iconBg: "bg-violet-500/10",
- },
- skill: {
- icon: Wrench,
- label: "技能",
- accent: "text-amber-400",
- border: "border-l-amber-500/60",
- iconBg: "bg-amber-500/10",
- },
- automation: {
- icon: Clock,
- label: "自动化",
- accent: "text-blue-400",
- border: "border-l-blue-500/60",
- iconBg: "bg-blue-500/10",
- },
- collaboration: {
- icon: Users,
- label: "协作",
- accent: "text-cyan-400",
- border: "border-l-cyan-500/60",
- iconBg: "bg-cyan-500/10",
- },
- upgrade: {
- icon: Crown,
- label: "升级",
- accent: "text-orange-400",
- border: "border-l-orange-500/60",
- iconBg: "bg-orange-500/10",
- },
-};
-
-const STATUS_CONFIG: Record = {
- success: { label: "完成", dot: "bg-emerald-400", bg: "bg-emerald-500/10 text-emerald-400" },
- running: {
- label: "执行中",
- dot: "bg-blue-400 animate-pulse",
- bg: "bg-blue-500/10 text-blue-400",
- },
- warning: { label: "注意", dot: "bg-amber-400", bg: "bg-amber-500/10 text-amber-400" },
- info: { label: "信息", dot: "bg-slate-400", bg: "bg-slate-500/10 text-slate-400" },
- locked: { label: "锁定", dot: "bg-orange-400", bg: "bg-orange-500/10 text-orange-400" },
-};
-
-function CardItem({
- card,
- onCardAction,
- interactive = false,
-}: {
- card: ChatCard;
- onCardAction?: (action: CardAction) => void;
- interactive?: boolean;
-}) {
- const cfg = CARD_CONFIG[card.type];
- const st = STATUS_CONFIG[card.status];
- const Icon = cfg.icon;
- const action = interactive ? resolveCardAction(card) : null;
-
- const handleClick = () => {
- if (action && onCardAction) onCardAction(action);
- };
-
- const handleActionBtn = (btn: { label: string; primary?: boolean }, e: React.MouseEvent) => {
- e.stopPropagation();
- if (!onCardAction) return;
- if (btn.primary && action) {
- onCardAction(action);
- } else if (card.type === "upgrade") {
- onCardAction({ type: "showPricing", payload: "" });
- } else if (action) {
- onCardAction(action);
- }
- };
-
- return (
-
-
-
- }
- className={interactive && action ? "cursor-pointer" : ""}
- bubbleClassName={`w-full border ${cfg.border} border-l-2 bg-surface-2/80 shadow-none ${
- interactive && action ? "group hover:bg-surface-2" : ""
- }`}
- meta={
-
-
{card.title}
-
-
- {st.label}
-
- {card.path && (
-
- ~/clone/{card.path}
-
-
- )}
-
- }
- >
-
-
- {card.body}
-
-
- {card.diff && (
-
-
-
- {card.diff.added}
-
- {card.diff.removed > 0 && (
-
-
- {card.diff.removed}
-
- )}
-
- )}
-
- {card.meta &&
{card.meta}
}
-
- {card.actions && card.actions.length > 0 && (
-
- {card.actions.map((btn) => (
-
- ))}
-
-
- )}
-
- {card.viralCta && (
-
-
-
- {card.viralCta}
-
-
- )}
-
-
- );
-}
-
-export default function ChatCardGroup({
- cards,
- onCardAction,
- interactive = false,
-}: ChatCardGroupProps) {
- return (
-
- {cards.map((card, index) => (
-
- ))}
-
- );
-}
diff --git a/apps/demo/src/pages/product/CloneBuilderPage.tsx b/apps/demo/src/pages/product/CloneBuilderPage.tsx
deleted file mode 100644
index b8faf860..00000000
--- a/apps/demo/src/pages/product/CloneBuilderPage.tsx
+++ /dev/null
@@ -1,1768 +0,0 @@
-import {
- Badge,
- Button,
- EntityCard,
- EntityCardContent,
- EntityCardDescription,
- EntityCardFooter,
- EntityCardHeader,
- EntityCardMedia,
- EntityCardMeta,
- EntityCardTitle,
- FilterPillTrigger,
- FilterPills,
- FilterPillsList,
- Input,
- PageHeader,
- Textarea,
- ToggleGroup,
- ToggleGroupItem,
-} from "@nexu-design/ui-web";
-import {
- Activity,
- ArrowUpRight,
- Brain,
- Check,
- ChevronRight,
- Database,
- FileText,
- FolderOpen,
- Globe,
- Mail,
- MessageSquare,
- Pencil,
- Phone,
- Plus,
- RefreshCw,
- Rss,
- Send,
- Shield,
- Sparkles,
- Users,
- Wrench,
- X,
-} from "lucide-react";
-import type React from "react";
-import { useEffect, useState } from "react";
-import { useNavigate, useSearchParams } from "react-router-dom";
-import OnboardingChat from "./OnboardingChat";
-import { useProductLayout } from "./ProductLayoutContext";
-
-const TABS = [
- { id: "feeds", label: "Feeds", icon: Rss },
- { id: "channels", label: "Channels", icon: MessageSquare },
- { id: "contacts", label: "Contacts", icon: Users },
- { id: "memory", label: "Memory", icon: Database },
- { id: "artifacts", label: "产物", icon: FileText },
- { id: "worldview", label: "世界观", icon: Globe },
-] as const;
-
-type TabId = (typeof TABS)[number]["id"];
-
-type ChannelCategory = "native" | "im";
-
-interface Channel {
- name: string;
- icon: string;
- status: "connected" | "pending" | "off";
- desc: string;
- badge: string | null;
- category: ChannelCategory;
- stats: { rounds: number; files: number; memories: number; contacts: number } | null;
- recent: { type: string; label: string; time: string }[];
- highlight?: string;
-}
-
-const CHANNELS: Channel[] = [
- // Native channels — zero install, every device has them
- {
- name: "Email",
- icon: "📧",
- status: "connected",
- desc: "tom@refly.ai · IMAP/SMTP 已配置",
- badge: "零安装",
- category: "native",
- stats: { rounds: 342, files: 28, memories: 45, contacts: 8 },
- recent: [
- { type: "file", label: "分身回复了投资人 Alex 的 follow-up", time: "1 小时前" },
- { type: "memory", label: "从邮件中提取了合作意向备忘", time: "3 小时前" },
- ],
- highlight: "发邮件给分身 = 启动一个 Session。附件自动存入 artifacts,关键信息记入 memory。",
- },
- {
- name: "SMS / iMessage",
- icon: "💬",
- status: "connected",
- desc: "+86 138****7890 · Twilio 接入",
- badge: "零安装",
- category: "native",
- stats: { rounds: 87, files: 5, memories: 23, contacts: 3 },
- recent: [
- { type: "memory", label: "短信指令:帮我查下明天的日程", time: "30 分钟前" },
- { type: "file", label: "分身回复了日程摘要", time: "30 分钟前" },
- ],
- highlight: "给分身发短信,随时随地发指令。无需打开任何 App,最原生的交互方式。",
- },
- {
- name: "WhatsApp",
- icon: "📱",
- status: "pending",
- desc: "待绑定手机号 · Meta API",
- badge: "零安装",
- category: "native",
- stats: null,
- recent: [],
- highlight: "全球 20 亿用户的即时通讯。给分身的 WhatsApp 号发消息就能开始工作。",
- },
- // IM platform channels
- {
- name: "飞书",
- icon: "🐦",
- status: "connected",
- desc: "Bot 已上线 · WebSocket 活跃",
- badge: "主渠道",
- category: "im",
- stats: { rounds: 1247, files: 89, memories: 156, contacts: 5 },
- recent: [
- { type: "memory", label: "记录了 OAuth 选型决策", time: "20 分钟前" },
- { type: "file", label: "生成了注册流程 PRD", time: "2 小时前" },
- ],
- },
- {
- name: "Slack",
- icon: "💼",
- status: "connected",
- desc: "OAuth 已授权 · 3 个 Channel",
- badge: null,
- category: "im",
- stats: { rounds: 523, files: 34, memories: 67, contacts: 3 },
- recent: [{ type: "file", label: "更新了竞品分析报告", time: "昨天" }],
- },
- {
- name: "Telegram",
- icon: "✈️",
- status: "pending",
- desc: "待配置 Bot Token",
- badge: null,
- category: "im",
- stats: null,
- recent: [],
- },
- {
- name: "Discord",
- icon: "🎮",
- status: "off",
- desc: "即将支持",
- badge: "敬请期待",
- category: "im",
- stats: null,
- recent: [],
- },
- {
- name: "企业微信",
- icon: "🏢",
- status: "off",
- desc: "即将支持",
- badge: "敬请期待",
- category: "im",
- stats: null,
- recent: [],
- },
-];
-
-const CONTACTS = [
- {
- name: "张明",
- role: "CTO",
- team: "Engineering",
- file: "contacts/张明-CTO.md",
- avatar: "👨💻",
- channel: "飞书",
- relation: "直属上级",
- notes: "偏好异步沟通,技术决策倾向稳定成熟方案,周三下午有固定 1on1",
- lastInteraction: "今天",
- },
- {
- name: "李薇",
- role: "Product Manager",
- team: "Product",
- file: "contacts/李薇-PM.md",
- avatar: "👩💼",
- channel: "飞书",
- relation: "核心协作",
- notes: "需求文档偏好 Notion 格式,喜欢用数据说话,每周一提交周报",
- lastInteraction: "2 小时前",
- },
- {
- name: "王浩",
- role: "前端工程师",
- team: "Engineering",
- file: "contacts/王浩-前端.md",
- avatar: "🧑💻",
- channel: "飞书",
- relation: "同组同事",
- notes: "React + TypeScript 专家,负责 Design System,代码审查很仔细",
- lastInteraction: "昨天",
- },
- {
- name: "刘芳",
- role: "UI/UX 设计师",
- team: "Design",
- file: "contacts/刘芳-设计.md",
- avatar: "👩🎨",
- channel: "Slack",
- relation: "跨组协作",
- notes: "偏好 Figma 评审,设计稿交付用 Notion,注重细节和动效",
- lastInteraction: "3 天前",
- },
- {
- name: "陈杰",
- role: "后端工程师",
- team: "Engineering",
- file: "contacts/陈杰-后端.md",
- avatar: "👨🔧",
- channel: "飞书",
- relation: "同组同事",
- notes: "NestJS + PostgreSQL 负责人,接口文档写得好,喜欢 TDD",
- lastInteraction: "昨天",
- },
- {
- name: "Alex Chen",
- role: "Investor / Advisor",
- team: "External",
- file: "contacts/alex-investor.md",
- avatar: "🤵",
- channel: "Email",
- relation: "投资人",
- notes: "关注 MAU 和 Retention 数据,每月一次 update,偏好英文沟通",
- lastInteraction: "1 周前",
- },
-];
-
-const CONTACT_GROUPS = [
- {
- name: "Product Team",
- file: "contacts/_groups/product-team.md",
- members: ["张明", "李薇", "王浩", "刘芳", "陈杰"],
- icon: "🏢",
- },
- {
- name: "Engineering",
- file: "contacts/_groups/engineering.md",
- members: ["张明", "王浩", "陈杰"],
- icon: "⚙️",
- },
- {
- name: "Founders & Investors",
- file: "contacts/_groups/founders.md",
- members: ["Alex Chen"],
- icon: "💼",
- },
-];
-
-const MEMORY_CATEGORIES = [
- { id: "all", label: "全部", icon: "📋", count: 223 },
- { id: "ideas", label: "想法", icon: "💡", count: 31 },
- { id: "tone", label: "口吻", icon: "🗣️", count: 8 },
- { id: "preferences", label: "喜好", icon: "⭐", count: 24 },
- { id: "habits", label: "习惯", icon: "🔄", count: 15 },
- { id: "status", label: "近况", icon: "📍", count: 12 },
- { id: "goals", label: "目标", icon: "🎯", count: 18 },
- { id: "worldview", label: "世界观", icon: "🌏", count: 9 },
- { id: "decisions", label: "决策", icon: "⚖️", count: 18 },
- { id: "facts", label: "事实", icon: "📎", count: 67 },
-];
-
-const MEMORY_ENTRIES = [
- {
- id: 1,
- category: "goals",
- content:
- "我是一名在上海的产品经理,其公司 refly.ai 正在构建基于 Openclaw 的数字员工基础设施,并刚完成了一轮顶级 VC 投资。",
- private: true,
- source: "conversation",
- time: "2 天前",
- },
- {
- id: 2,
- category: "ideas",
- content:
- '我认为当前很多人对 AI 的使用还停留在"电子宠物"阶段,但我更认同将 AI 视为"赛博合伙人"的协作理念。',
- private: false,
- source: "conversation",
- time: "3 天前",
- },
- {
- id: 3,
- category: "worldview",
- content:
- "AI 的关键在于其行动力,即 AI 不应只停留在思考层面,而必须能映射到现实世界,产生实际的连接和改变。",
- private: true,
- source: "extracted",
- time: "4 天前",
- },
- {
- id: 4,
- category: "preferences",
- content: "我喜欢运动,特别是乒乓球和跑步,同时也是一位影视达人。",
- private: true,
- source: "conversation",
- time: "5 天前",
- },
- {
- id: 5,
- category: "habits",
- content: "我的心态似乎比较好,即使有工作压力通常也不会影响睡眠。",
- private: true,
- source: "extracted",
- time: "5 天前",
- },
- {
- id: 6,
- category: "tone",
- content: "简洁直接,偏技术术语,喜欢用类比解释复杂概念,中文为主但技术词用英文。",
- private: false,
- source: "fine-tuned",
- time: "1 周前",
- },
- {
- id: 7,
- category: "decisions",
- content: "用户决定使用 PostgreSQL + TypeORM 替代 MongoDB,理由是关系型查询更适合多模块 JOIN。",
- private: false,
- source: "auto-extracted",
- time: "1 周前",
- },
- {
- id: 8,
- category: "status",
- content: "当前 Sprint 主要任务:注册流程优化、Design System 改版、记忆系统设计。",
- private: false,
- source: "proactive",
- time: "今天",
- },
- {
- id: 9,
- category: "ideas",
- content:
- "观察到中心化 Agent IM bot(如 Manus 在 Telegram 上的 Personal Agent)被封,开始思考去中心化产品形态的风险。",
- private: false,
- source: "conversation",
- time: "6 天前",
- },
- {
- id: 10,
- category: "goals",
- content: "我有提升自己的目标,积极招聘增长/商业化/产品人才,打造世界级产品。",
- private: true,
- source: "extracted",
- time: "1 周前",
- },
-];
-
-const MEMORY_CHANGELOG = [
- { action: "merge", desc: "合并了「我是 Openclaw 的用户」相关记忆", time: "1 天前" },
- {
- action: "extract",
- desc: "从 Tom 和 @biubiu暴雨 对话中提取了记忆点",
- source: "随便聊了聊",
- time: "2 天前",
- },
- {
- action: "extract",
- desc: "从 Tom 和 @就爱喝无糖 对话中提取了记忆点",
- source: "随便聊了聊",
- time: "3 天前",
- },
- { action: "merge", desc: "合并了「AI 的行动力」相关世界观记忆", time: "5 天前" },
- { action: "edit", desc: "Tom 编辑了一条记忆:口吻偏好", time: "6 天前" },
- { action: "extract", desc: "自动提取了 PostgreSQL 选型决策", source: "技术讨论", time: "1 周前" },
-];
-
-const ARTIFACT_FOLDERS = [
- {
- folder: "artifacts/prds/",
- count: 8,
- desc: "产品需求文档",
- files: ["注册流程优化.md", "onboarding-redesign.md", "onboarding-flowchart.svg"],
- },
- {
- folder: "artifacts/research/",
- count: 14,
- desc: "竞品分析、市场调研",
- files: ["竞品注册流程对比.md", "市场调研数据.xlsx", "用户访谈-20260218.mp4"],
- },
- {
- folder: "artifacts/code/",
- count: 5,
- desc: "Schema、代码片段、API",
- files: ["schema-design.sql", "oauth-callback.ts", "api-spec.json"],
- },
- {
- folder: "artifacts/designs/",
- count: 9,
- desc: "设计稿、Figma、UI 截图",
- files: ["landing-v2.figma", "hero-mockup.png", "onboarding-flow.svg", "brand-guide.pdf"],
- },
- {
- folder: "artifacts/reports/",
- count: 7,
- desc: "Sprint 回顾、周报、指标",
- files: ["sprint-review-w8.md", "monthly-metrics.xlsx", "investor-deck.pptx"],
- },
- {
- folder: "artifacts/media/",
- count: 6,
- desc: "产品 Demo、播客、素材",
- files: ["product-demo.mp4", "podcast-ep3.mp3", "logo-final.svg", "screenshot-feeds.png"],
- },
-];
-
-const SOUL_FILES = [
- { path: ".soul/identity.md", label: "角色", value: "全栈工程师", editable: true },
- { path: ".soul/persona.md", label: "领域", value: "Web 开发 · AI 应用 · SaaS", editable: true },
- {
- path: ".soul/persona.md",
- label: "沟通风格",
- value: "简洁直接 · 偏技术 · 喜欢用类比",
- editable: true,
- },
- { path: ".soul/persona.md", label: "语言", value: "中文为主 · 技术术语用英文", editable: true },
- {
- path: ".soul/persona.md",
- label: "工作习惯",
- value: "晚上效率高 · 喜欢先做难的 · 迭代速度快",
- editable: true,
- },
-];
-
-const WORLDVIEW_FILES = [
- {
- path: ".soul/values.md",
- label: "产品哲学",
- value: "用户体验 > 功能数量,简单 > 复杂",
- icon: "🎯",
- },
- {
- path: ".soul/worldview.md",
- label: "技术价值观",
- value: "实用主义,不过度工程化,先跑起来再优化",
- icon: "⚡",
- },
- {
- path: ".soul/worldview.md",
- label: "决策原则",
- value: '"这让分身更懂用户了吗?" — 是就做,不是就砍',
- icon: "🧭",
- },
- {
- path: ".soul/values.md",
- label: "沟通准则",
- value: "直说结论,不说废话,有代码就直接写",
- icon: "💬",
- },
- {
- path: ".soul/worldview.md",
- label: "优先级框架",
- value: "用户感知价值 > 技术优雅度 > 扩展性",
- icon: "📊",
- },
-];
-
-function ChannelStatBadge({ icon, label, value }: { icon: string; label: string; value: number }) {
- return (
-
- {icon}
- {value.toLocaleString()}
- {label}
-
- );
-}
-
-// --- Feed data types & mock data ---
-
-type FeedItemType = "automation" | "session" | "skill" | "memory" | "proactive" | "team";
-
-interface FeedItem {
- id: string;
- type: FeedItemType;
- title: string;
- desc: string;
- time: string;
- icon: string;
- tags: string[];
- link?: { label: string; to: string };
- files?: number;
- memories?: number;
-}
-
-const FEED_ITEMS: FeedItem[] = [
- {
- id: "f1",
- type: "proactive",
- icon: "📊",
- title: "今日战况复盘已生成",
- desc: "完成 12 个任务,生成 3 份文档,新增 5 条记忆。整体对齐率提升 2%。",
- time: "22:00",
- tags: ["每日复盘", "自动"],
- link: { label: "查看详情", to: "/app/sessions" },
- files: 3,
- memories: 5,
- },
- {
- id: "f9",
- type: "team",
- icon: "🤝",
- title: "张三的分身查询了你的任务进度",
- desc: "张三的前端集成需要确认你的 Gateway 重构时间线,分身已自动回复当前进度。",
- time: "14:30",
- tags: ["分身代问", "自动回复"],
- link: { label: "查看对话", to: "/app/team" },
- },
- {
- id: "f10",
- type: "team",
- icon: "📋",
- title: "站会汇总已推送到 #product-team",
- desc: "Sprint 3 进度 58%,1 个风险项:Gateway 重构进度偏慢。已推送 IM 卡片。",
- time: "09:05",
- tags: ["站会", "自动"],
- link: { label: "查看卡片", to: "/app/team" },
- files: 1,
- },
- {
- id: "f2",
- type: "automation",
- icon: "⚡",
- title: "竞品监控触发 — Notion 发布 AI 功能更新",
- desc: "检测到 Notion 发布 AI blocks 功能。已自动生成竞品分析摘要并存入 artifacts。",
- time: "18:30",
- tags: ["竞品监控", "触发"],
- link: { label: "查看分析", to: "/app/sessions" },
- files: 1,
- },
- {
- id: "f3",
- type: "session",
- icon: "💬",
- title: "注册流程优化方案完成",
- desc: "基于 OAuth 选型决策,生成完整 PRD,包含流程图和技术方案。",
- time: "16:45",
- tags: ["PRD", "主动对话"],
- link: { label: "继续对话", to: "/app/sessions" },
- files: 2,
- memories: 1,
- },
- {
- id: "f4",
- type: "skill",
- icon: "🔧",
- title: "Figma 设计稿导出 Skill 运行成功",
- desc: "自动导出 3 张设计稿为 PNG,并上传到 artifacts/designs/ 目录。",
- time: "15:20",
- tags: ["Skills", "Figma"],
- files: 3,
- },
- {
- id: "f5",
- type: "proactive",
- icon: "🧠",
- title: "记忆整理完成 — 发现 3 条冲突记忆",
- desc: "自动整理本周新增记忆 23 条,发现 3 条决策冲突,建议人工确认。",
- time: "14:00",
- tags: ["记忆维护", "自动"],
- link: { label: "查看冲突", to: "/app/clone?tab=memory" },
- memories: 23,
- },
- {
- id: "f6",
- type: "automation",
- icon: "📬",
- title: "飞书日报已发送",
- desc: "今日工作日报已自动汇总并推送到飞书群「产品核心群」。",
- time: "12:00",
- tags: ["飞书", "定时"],
- },
- {
- id: "f7",
- type: "session",
- icon: "🔍",
- title: "Deep Research: AI Agent 市场分析",
- desc: "基于 23 篇文献和 5 个竞品数据源,生成 8000 字分析报告。",
- time: "昨天 21:30",
- tags: ["调研", "深度"],
- link: { label: "阅读报告", to: "/app/sessions" },
- files: 1,
- memories: 4,
- },
- {
- id: "f8",
- type: "skill",
- icon: "🚀",
- title: "部署 Skill 执行完成",
- desc: "前端构建成功,已部署到 Vercel production 环境。构建耗时 42s。",
- time: "昨天 18:00",
- tags: ["CI/CD", "Vercel"],
- files: 1,
- },
-];
-
-const FEED_TYPE_STYLES: Record = {
- automation: { bg: "bg-blue-500/10", text: "text-blue-600", label: "Automation" },
- session: { bg: "bg-emerald-500/10", text: "text-emerald-600", label: "Session" },
- skill: { bg: "bg-purple-500/10", text: "text-purple-600", label: "Skill" },
- memory: { bg: "bg-amber-500/10", text: "text-amber-600", label: "Memory" },
- proactive: { bg: "bg-orange-500/10", text: "text-orange-600", label: "主动" },
- team: { bg: "bg-cyan-500/10", text: "text-cyan-600", label: "Team" },
-};
-
-interface FeedDetailMsg {
- from: "clone" | "system";
- content: string;
-}
-
-interface FeedFileOp {
- action: "create" | "write" | "read";
- path: string;
-}
-
-interface FeedDetail {
- messages: FeedDetailMsg[];
- fileOps: FeedFileOp[];
- sessionId?: string;
-}
-
-const FEED_DETAILS: Record = {
- f1: {
- messages: [
- { from: "system", content: "⏰ 定时任务 每日复盘 触发 22:00" },
- {
- from: "clone",
- content:
- "今日复盘报告已生成:\n\n✅ 完成任务 12 个\n📄 生成文档 3 份(PRD、竞品分析、迁移方案)\n🧠 新增记忆 5 条\n📈 对齐率 73% → 75% (+2%)\n\n亮点:注册优化 PRD 获得 PM 认可,竞品分析发现 Notion 关键差异点。",
- },
- {
- from: "clone",
- content:
- "建议明天优先推进:\n1. 数据库迁移 PR Review(陈杰待 review)\n2. Landing Page V2 设计稿定稿\n3. 竞品监控异常处理 — Notion 新功能跟进",
- },
- ],
- fileOps: [
- { action: "create", path: "artifacts/reports/daily-review-0221.md" },
- { action: "write", path: "memory/context/current-sprint.md" },
- { action: "write", path: ".soul/identity.md" },
- ],
- sessionId: "daily-review-0221",
- },
- f2: {
- messages: [
- { from: "system", content: "⚡ 竞品监控触发 — 检测到 Notion 产品更新" },
- {
- from: "clone",
- content:
- 'Notion 发布了 AI Blocks 功能更新:\n\n• 新增 AI 自动填充数据库属性\n• Inline AI 编辑增强(直接在文档内调整)\n• AI 模板市场扩展\n\n已自动更新竞品分析文档,关键发现:Notion 正在从"AI 助手"转向"AI 自动化"定位,与我们的 Agent Computer 有直接竞争。',
- },
- ],
- fileOps: [
- { action: "write", path: "knowledge/references/competitor-notion.md" },
- { action: "create", path: "artifacts/research/notion-ai-blocks-analysis.md" },
- ],
- sessionId: "competitor-notion-update",
- },
- f3: {
- messages: [
- {
- from: "clone",
- content:
- "注册流程优化方案已完成 ✅\n\n核心内容:\n• 方案 A:OAuth 优先(推荐)\n• 方案 B:飞书扫码\n• 包含完整流程图和技术方案\n• 预计注册转化率提升 40%",
- },
- {
- from: "clone",
- content:
- "已将 PRD 存入 artifacts/prds/,同时更新了 OAuth 选型决策记录。需要我展开某个部分吗?",
- },
- ],
- fileOps: [
- { action: "create", path: "artifacts/prds/注册流程优化.md" },
- { action: "write", path: "memory/decisions/auth-oauth.md" },
- ],
- sessionId: "registration-optimization",
- },
- f4: {
- messages: [
- { from: "system", content: "🔧 Skill 执行完成 — figma-export" },
- {
- from: "clone",
- content:
- "Figma 设计稿导出完成:\n\n• hero-mockup.png (380 KB)\n• onboarding-flow.svg (18 KB)\n• brand-guide.pdf (1.2 MB)\n\n已存入 artifacts/designs/ 目录。",
- },
- ],
- fileOps: [
- { action: "create", path: "artifacts/designs/hero-mockup.png" },
- { action: "create", path: "artifacts/designs/onboarding-flow.svg" },
- { action: "create", path: "artifacts/designs/brand-guide.pdf" },
- ],
- },
- f5: {
- messages: [
- { from: "system", content: "🧠 记忆维护任务执行 — 自动整理" },
- {
- from: "clone",
- content:
- '本周记忆整理完成:\n\n📊 新增 23 条记忆\n♻️ 合并重复 4 条\n⚠️ 发现 3 条冲突:\n\n1. 技术选型:前次说"考虑 Supabase",本周决策"用 TypeORM + PostgreSQL"\n2. 产品定位:早期说"AI 助手",现在明确"Agent Computer"\n3. 命名:从"Clone"改为"nexu(奈苏)"\n\n建议确认这些决策变更,我会自动清理旧记忆。',
- },
- ],
- fileOps: [
- { action: "write", path: "memory/decisions/" },
- { action: "write", path: ".soul/identity.md" },
- { action: "read", path: "memory/facts/" },
- ],
- },
- f6: {
- messages: [
- { from: "system", content: "📬 定时任务 飞书日报 触发 12:00" },
- {
- from: "clone",
- content:
- "飞书日报已推送到「产品核心群」:\n\n今日工作摘要:\n• 完成注册流程 PRD\n• 竞品分析 - Linear/Notion/Cursor 对比\n• 数据库迁移 SQL 编写(3 个 migration)\n\n推送成功 ✅ 已有 3 人已读",
- },
- ],
- fileOps: [{ action: "create", path: "artifacts/reports/daily-summary-0221.md" }],
- },
- f7: {
- messages: [
- {
- from: "clone",
- content:
- 'Deep Research 报告完成(AI Agent 市场分析):\n\n📚 数据源:23 篇文献 + 5 个竞品\n📝 报告:8000 字深度分析\n\n核心发现:\n1. AI Agent 市场 2026 预计 $47B\n2. 个人 Agent 赛道尚无明确赢家\n3. "Agent Computer" 定位可建立差异化\n4. 文件系统 + 技能系统是关键壁垒',
- },
- ],
- fileOps: [
- { action: "create", path: "artifacts/research/ai-agent-market-2026.md" },
- { action: "write", path: "memory/context/market-landscape.md" },
- ],
- sessionId: "deep-research-agent-market",
- },
- f8: {
- messages: [
- { from: "system", content: "🚀 Skill 执行完成 — deploy-vercel" },
- {
- from: "clone",
- content:
- "部署完成 ✅\n\n• 构建耗时:42s\n• 部署环境:Vercel Production\n• URL: https://nexu.app\n• Bundle size: 312 KB (gzipped)\n\n无错误,所有检查通过。",
- },
- ],
- fileOps: [{ action: "create", path: "artifacts/reports/deploy-log-0220.md" }],
- },
-};
-
-const FILE_OP_ACTION_STYLES: Record = {
- create: { color: "text-success bg-success-subtle", label: "CREATE" },
- write: { color: "text-clone bg-clone/10", label: "WRITE" },
- read: { color: "text-info bg-info-subtle", label: "READ" },
-};
-
-function FeedDetailPanel({ item, onClose }: { item: FeedItem; onClose: () => void }) {
- const navigate = useNavigate();
- const [followUp, setFollowUp] = useState("");
- const detail = FEED_DETAILS[item.id];
- const style = FEED_TYPE_STYLES[item.type];
-
- if (!detail) return null;
-
- const handleFollowUp = () => {
- if (!followUp.trim()) return;
- navigate("/app/sessions");
- };
-
- return (
-
- {/* Header */}
-
-
{item.icon}
-
-
-
- {style.label}
-
- {item.time}
-
-
{item.title}
-
-
-
-
- {/* Messages */}
-
- {detail.messages.map((msg) => (
-
- {msg.from === "system" ? (
-
- ) : (
-
-
- 😊
-
-
- {msg.content}
-
-
- )}
-
- ))}
-
- {/* File ops in chat */}
- {detail.fileOps.length > 0 && (
-
-
- 文件操作
-
- {detail.fileOps.map((op) => {
- const opStyle = FILE_OP_ACTION_STYLES[op.action];
- const parts = op.path.split("/");
- const fileName = parts.pop() || "";
- return (
-
-
- {opStyle.label}
-
-
- {fileName}
-
- {parts.join("/")}/
-
-
- );
- })}
-
- )}
-
-
- {/* Follow-up input */}
-
-
-
-
- {/* Action buttons */}
-
- {detail.sessionId && (
-
- )}
-
-
-
-
- );
-}
-
-function FeedsTab() {
- const navigate = useNavigate();
- const [chatInput, setChatInput] = useState("");
- const [selectedFeed, setSelectedFeed] = useState(null);
-
- const handleSend = () => {
- if (!chatInput.trim()) return;
- navigate("/app/sessions");
- setChatInput("");
- };
-
- return (
-
- {/* Feed list */}
-
- {/* Quick chat input */}
-
-
-
- setChatInput(e.target.value)}
- onKeyDown={(e) => e.key === "Enter" && handleSend()}
- placeholder="有什么想法?随时开始对话..."
- className="bg-surface-0"
- />
-
-
-
-
- 快捷:
- {["帮我写 PRD", "跑一下竞品监控", "今天做了什么"].map((q) => (
-
- ))}
-
-
-
- {/* Activity summary bar */}
-
-
-
-
-
- 7
- 文件
-
-
-
-
- 14
- 记忆
-
-
-
自动刷新 · 5 分钟前
-
-
- {/* Feed stream */}
-
- {FEED_ITEMS.map((item) => {
- const style = FEED_TYPE_STYLES[item.type];
- const isSelected = selectedFeed?.id === item.id;
- return (
-
- );
- })}
-
-
- {/* Load more */}
-
-
-
-
-
- {/* Detail panel */}
- {selectedFeed && (
-
- setSelectedFeed(null)} />
-
- )}
-
- );
-}
-
-function ChannelCard({ ch }: { ch: Channel }) {
- return (
-
-
-
- {ch.icon}
-
-
-
- {ch.name}
- {ch.badge && (
-
- {ch.badge}
-
- )}
-
-
{ch.desc}
-
-
- {ch.status === "connected" && (
-
- 已连接
-
- )}
- {ch.status === "pending" && (
-
- )}
- {ch.status === "off" && —}
-
-
-
- {/* Native channel highlight */}
- {ch.highlight && ch.status !== "off" && (
-
-
-
- )}
-
- {ch.stats && (
-
-
-
-
-
-
-
-
- {ch.recent.length > 0 && (
-
- {ch.recent.map((r) => (
-
-
{r.type === "memory" ? "🧠" : "📄"}
-
- {r.label}
-
-
{r.time}
-
-
- ))}
-
- )}
-
- )}
-
- );
-}
-
-function ChannelsTab() {
- const nativeChannels = CHANNELS.filter((c) => c.category === "native");
- const imChannels = CHANNELS.filter((c) => c.category === "im");
-
- return (
-
- {/* Native channels section */}
-
-
-
- 无需下载任何 App — 每个手机都有短信和邮件。发一条消息就能启动分身工作。
-
-
- {nativeChannels.map((ch) => (
-
- ))}
-
-
-
- {/* IM platform channels section */}
-
-
-
-
-
-
IM 平台
-
团队协作 · 群聊 · 卡片交互
-
-
- {imChannels.map((ch) => (
-
- ))}
-
-
-
-
-
- );
-}
-
-function ContactsTab() {
- return (
-
- {/* Stats */}
-
-
- {/* Groups */}
-
-
~/clone/contacts/_groups/
-
- {CONTACT_GROUPS.map((g) => (
-
- {g.icon}
- {g.name}
- {g.members.length} 人
-
- ))}
-
-
-
- {/* People */}
-
-
-
~/clone/contacts/
-
-
-
- {CONTACTS.map((c) => (
-
-
-
- {c.avatar}
-
-
-
- {c.name}
-
- {c.role}
-
-
- {c.relation}
-
-
-
- {c.notes}
-
-
-
-
- {c.channel === "Email" ? (
-
- ) : c.channel === "Slack" ? (
-
- ) : (
-
- )}
- {c.channel}
-
-
{c.lastInteraction}
-
-
-
- {c.file}
-
-
-
- ))}
-
-
-
-
-
- );
-}
-
-function MemoryTab() {
- const [activeCat, setActiveCat] = useState("all");
- const [showChangelog, setShowChangelog] = useState(false);
-
- const filtered =
- activeCat === "all" ? MEMORY_ENTRIES : MEMORY_ENTRIES.filter((m) => m.category === activeCat);
-
- return (
-
- {/* Category filter bar */}
-
value && setActiveCat(value)}>
-
- {MEMORY_CATEGORIES.map((cat) => (
-
- {cat.icon}
- {cat.label}
- {cat.count}
-
- ))}
-
-
-
- {/* Update history link */}
-
-
- {/* Changelog panel */}
- {showChangelog && (
-
-
记忆记录
- {MEMORY_CHANGELOG.map((log) => (
-
-
- {log.action === "merge" && 🔗}
- {log.action === "extract" && 💎}
- {log.action === "edit" && ✏️}
-
-
-
{log.desc}
- {log.source && (
-
来源:{log.source}
- )}
-
-
{log.time}
-
- ))}
-
- )}
-
- {/* Memory entries */}
-
- {filtered.map((m) => {
- const cat = MEMORY_CATEGORIES.find((c) => c.id === m.category);
- return (
-
-
-
{cat?.icon}
-
{cat?.label}
-
- {m.source === "fine-tuned" && (
-
- 微调
-
- )}
- {m.source === "auto-extracted" && (
-
- 自动提取
-
- )}
- {m.source === "proactive" && (
-
- 主动更新
-
- )}
- {m.time}
-
-
-
{m.content}
-
- {m.private && (
-
-
- 私密记忆
-
- )}
-
-
-
- );
- })}
-
-
- {/* Fine-tune button */}
-
-
-
-
- );
-}
-
-function ArtifactsTab() {
- return (
-
-
~/clone/artifacts/
-
- {ARTIFACT_FOLDERS.map((t) => (
-
-
-
-
-
{t.folder}
-
{t.desc}
-
-
{t.count} files
-
-
-
- {t.files.map((f) => (
-
- {f}
-
- ))}
-
-
- ))}
-
-
-
- );
-}
-
-function PersonaPanel({ onOpenOnboarding }: { onOpenOnboarding: () => void }) {
- return (
-
- {/* Avatar & Identity */}
-
-
-
我的分身
-
全栈工程师
-
-
- {/* Onboarding entry */}
-
-
- {/* Alignment rate */}
-
-
- 对齐率
- 78%
-
-
-
- 多聊天多"喂养",对齐率越高分身越懂你
-
-
-
-
- {/* Vital Stats */}
-
-
- {/* Soul Properties */}
-
-
-
-
- 人设特质
-
-
-
- {SOUL_FILES.map((f) => (
-
-
- {f.label}
-
-
{f.value}
- {f.editable && (
-
- )}
-
- ))}
-
-
-
- {/* Worldview Summary */}
-
-
-
-
- 世界观
-
-
-
- {WORLDVIEW_FILES.slice(0, 3).map((w) => (
-
-
{w.icon}
-
-
{w.label}
-
{w.value}
-
-
- ))}
-
-
-
- {/* File Path */}
-
-
- ~/.soul/identity.md · persona.md · worldview.md
-
-
-
- );
-}
-
-function WorldviewTab() {
- return (
-
- {WORLDVIEW_FILES.map((w) => (
-
-
-
{w.icon}
-
{w.label}
-
- {w.path}
-
-
-
-
{w.value}
-
- ))}
-
-
- );
-}
-
-const TAB_COMPONENTS: Record React.JSX.Element> = {
- feeds: FeedsTab,
- channels: ChannelsTab,
- contacts: ContactsTab,
- memory: MemoryTab,
- artifacts: ArtifactsTab,
- worldview: WorldviewTab,
-};
-
-export default function CloneBuilderPage() {
- const [searchParams] = useSearchParams();
- const tabFromUrl = searchParams.get("tab") as TabId | null;
- const [activeTab, setActiveTab] = useState(
- tabFromUrl && TABS.some((t) => t.id === tabFromUrl) ? tabFromUrl : "feeds",
- );
- const [showOnboarding, setShowOnboarding] = useState(false);
-
- useEffect(() => {
- if (tabFromUrl && TABS.some((t) => t.id === tabFromUrl)) {
- setActiveTab(tabFromUrl);
- }
- }, [tabFromUrl]);
-
- const TabContent = TAB_COMPONENTS[activeTab];
- const { expandFileTree } = useProductLayout();
-
- return (
-
-
-
- 配置你的数字分身 — 所有配置存储在
-
- 文件系统中
- >
- }
- />
-
-
- {/* Left: Persona — always visible */}
-
-
setShowOnboarding(true)} />
-
-
- {/* Right: Configuration tabs */}
-
- {
- if (value) setActiveTab(value as TabId);
- }}
- variant="underline"
- aria-label="Clone builder sections"
- className="mb-6"
- >
- {TABS.map((t) => (
-
-
- {t.label}
-
- ))}
-
-
-
-
-
-
- {showOnboarding &&
setShowOnboarding(false)} />}
-
- );
-}
diff --git a/apps/demo/src/pages/product/FileEditor.tsx b/apps/demo/src/pages/product/FileEditor.tsx
deleted file mode 100644
index dfe7d2dd..00000000
--- a/apps/demo/src/pages/product/FileEditor.tsx
+++ /dev/null
@@ -1,356 +0,0 @@
-import { Badge, Button, Textarea } from "@nexu-design/ui-web";
-import {
- Bot,
- Check,
- ChevronRight,
- Eye,
- File,
- type FileText,
- Film,
- FolderOpen,
- Image,
- Music,
- Pencil,
- Save,
- User,
- X,
-} from "lucide-react";
-import { useCallback, useEffect, useRef, useState } from "react";
-import ReactMarkdown from "react-markdown";
-import remarkGfm from "remark-gfm";
-import { getFile, saveFile } from "./fileStore";
-import type { FileType } from "./sessionsData";
-
-const EDITABLE_TYPES = new Set([
- "markdown",
- "yaml",
- "code",
- "jsonl",
- "contact",
- "skill",
- "config",
- "html",
- "sql",
-]);
-
-const BINARY_PLACEHOLDERS: Partial> = {
- image: { icon: Image, label: "图片文件 — 不支持在线编辑" },
- video: { icon: Film, label: "视频文件 — 不支持在线编辑" },
- audio: { icon: Music, label: "音频文件 — 不支持在线编辑" },
- pdf: { icon: File, label: "PDF 文件 — 不支持在线编辑" },
- xlsx: { icon: File, label: "Excel 文件 — 不支持在线编辑" },
- docx: { icon: File, label: "Word 文件 — 不支持在线编辑" },
- pptx: { icon: File, label: "演示文稿 — 不支持在线编辑" },
- archive: { icon: File, label: "压缩文件 — 不支持在线编辑" },
- figma: { icon: File, label: "Figma 文件 — 在 Figma 中打开" },
- svg: { icon: Image, label: "SVG 文件 — 不支持在线编辑" },
- csv: { icon: File, label: "CSV 文件 — 不支持在线编辑" },
-};
-
-interface FileEditorProps {
- filePath: string;
- initialContent: string;
- fileType: FileType;
- lastEditedBy?: "human" | "agent";
- lastEditedAt?: string;
- onSave?: (content: string) => void;
- onClose?: () => void;
- readOnly?: boolean;
- compact?: boolean;
-}
-
-export default function FileEditor({
- filePath,
- initialContent,
- fileType,
- lastEditedBy: propEditedBy,
- lastEditedAt: propEditedAt,
- onSave,
- onClose,
- readOnly = false,
- compact = false,
-}: FileEditorProps) {
- const stored = getFile(filePath);
- const content = stored?.content ?? initialContent;
- const editedBy = propEditedBy ?? stored?.lastEditedBy ?? "agent";
- const editedAt = propEditedAt ?? stored?.lastEditedAt ?? "";
-
- const [mode, setMode] = useState<"preview" | "edit">("preview");
- const [draft, setDraft] = useState(content);
- const [saved, setSaved] = useState(false);
- const textareaRef = useRef(null);
- const isEditable = EDITABLE_TYPES.has(fileType) && !readOnly;
- const isMarkdown = fileType === "markdown" || fileType === "contact" || fileType === "skill";
- const binary = BINARY_PLACEHOLDERS[fileType];
-
- useEffect(() => {
- setDraft(content);
- setMode("preview");
- setSaved(false);
- }, [content]);
-
- useEffect(() => {
- if (mode === "edit" && textareaRef.current) {
- textareaRef.current.focus();
- }
- }, [mode]);
-
- const handleSave = useCallback(() => {
- saveFile(filePath, draft, "human");
- onSave?.(draft);
- setSaved(true);
- setMode("preview");
- setTimeout(() => setSaved(false), 2000);
- }, [filePath, draft, onSave]);
-
- const handleCancel = useCallback(() => {
- setDraft(content);
- setMode("preview");
- }, [content]);
-
- const pathParts = filePath.split("/");
- const fileName = pathParts.pop() || "";
-
- if (compact) {
- return (
-
- );
- }
-
- return (
-
- {/* Header */}
-
-
-
- {pathParts.map((part, i) => (
-
- {i > 0 && }
- {part}
-
- ))}
-
- {fileName}
-
-
- {isEditable && (
-
-
-
-
- )}
- {onClose && (
-
- )}
-
-
-
- {/* Content */}
-
- {binary ? (
-
- ) : mode === "edit" ? (
-
-
- {/* Footer */}
-
-
- {editedBy === "agent" ? : }
-
- {editedBy === "agent" ? "Agent" : "You"} edited {editedAt && `at ${editedAt}`}
-
- {saved && (
-
-
- Saved
-
- )}
-
- {mode === "edit" && (
-
-
-
-
- )}
-
-
- );
-}
-
-function CompactEditor({
- content,
- draft,
- setDraft,
- mode,
- setMode,
- isEditable,
- isMarkdown,
- binary,
- saved,
- editedBy,
- editedAt,
- onSave,
- onCancel,
- textareaRef,
-}: {
- content: string;
- draft: string;
- setDraft: (v: string) => void;
- mode: "preview" | "edit";
- setMode: (m: "preview" | "edit") => void;
- isEditable: boolean;
- isMarkdown: boolean;
- binary: { icon: typeof FileText; label: string } | undefined;
- saved: boolean;
- editedBy: "human" | "agent";
- editedAt: string;
- onSave: () => void;
- onCancel: () => void;
- textareaRef: React.RefObject;
-}) {
- return (
-
- {/* Compact toolbar */}
-
-
- {editedBy === "agent" ? : }
-
- {editedBy === "agent" ? "Agent" : "You"} · {editedAt}
-
- {saved && (
-
- Saved
-
- )}
-
-
- {isEditable && mode === "preview" && (
-
- )}
- {mode === "edit" && (
- <>
-
-
- >
- )}
-
-
-
- {/* Content */}
-
- {binary ? (
-
- ) : mode === "edit" ? (
-
-
- );
-}
-
-function BinaryPlaceholder({
- icon: Icon,
- label,
-}: {
- icon: typeof FileText;
- label: string;
-}) {
- return (
-
-
- {label}
-
- );
-}
diff --git a/apps/demo/src/pages/product/FileTree.tsx b/apps/demo/src/pages/product/FileTree.tsx
deleted file mode 100644
index 3acea325..00000000
--- a/apps/demo/src/pages/product/FileTree.tsx
+++ /dev/null
@@ -1,629 +0,0 @@
-import {
- Brain,
- ChevronDown,
- ChevronRight,
- Clock,
- Database,
- File,
- FileCode,
- FileSpreadsheet,
- FileText,
- Film,
- FolderClosed,
- FolderOpen,
- Image,
- Music,
- Presentation,
- Sparkles,
- Terminal as TermIcon,
- Users,
- Wrench,
-} from "lucide-react";
-import { type ReactNode, useState } from "react";
-
-export interface FileNode {
- name: string;
- type: "file" | "folder";
- children?: FileNode[];
- modified?: boolean;
- isNew?: boolean;
- active?: boolean;
- icon?: ReactNode;
-}
-
-export const FOLDER_ROUTES: Record = {
- ".soul": "/app/clone",
- contacts: "/app/clone?tab=contacts",
- memory: "/app/clone?tab=memory",
- knowledge: "/app/clone?tab=memory",
- artifacts: "/app/clone?tab=artifacts",
- team: "/app/team",
- sessions: "/app/sessions",
- automation: "/app/automation",
- skills: "/app/skills",
-};
-
-export const FOLDER_ICONS: Record = {
- ".soul": ,
- contacts: ,
- memory: ,
- knowledge: ,
- artifacts: ,
- team: ,
- sessions: ,
- automation: ,
- skills: ,
-};
-
-export const CLONE_FILE_TREE: FileNode[] = [
- {
- name: ".soul",
- type: "folder",
- children: [
- { name: "identity.md", type: "file" },
- { name: "identity-source.md", type: "file" },
- { name: "persona.md", type: "file" },
- { name: "values.md", type: "file" },
- { name: "values-source.md", type: "file" },
- { name: "worldview.md", type: "file" },
- ],
- },
- {
- name: "contacts",
- type: "folder",
- children: [
- {
- name: "_groups",
- type: "folder",
- children: [
- { name: "product-team.md", type: "file" },
- { name: "engineering.md", type: "file" },
- { name: "founders.md", type: "file" },
- ],
- },
- { name: "林远-CEO.md", type: "file" },
- { name: "周明-PM.md", type: "file" },
- { name: "赵雪-设计.md", type: "file" },
- { name: "吴恒-研发.md", type: "file" },
- { name: "张毅-增长.md", type: "file" },
- { name: "刘晴-测试.md", type: "file" },
- { name: "王谦-investor.md", type: "file" },
- ],
- },
- {
- name: "memory",
- type: "folder",
- children: [
- { name: "decisions-all.md", type: "file" },
- { name: "insights.md", type: "file" },
- {
- name: "decisions",
- type: "folder",
- children: [
- { name: "2026-02-22-clone-filesystem.md", type: "file" },
- { name: "2026-02-22-8week-roadmap.md", type: "file" },
- { name: "2026-02-22-agent-native-team.md", type: "file" },
- { name: "2026-02-21-product-philosophy.md", type: "file" },
- { name: "2026-02-20-v3-universal-agent.md", type: "file" },
- { name: "2026-02-18-product-naming.md", type: "file" },
- ],
- },
- {
- name: "ideas",
- type: "folder",
- children: [
- { name: "data-flywheel-architecture.md", type: "file" },
- { name: "stopping-cost-psychology.md", type: "file" },
- { name: "im-group-virality.md", type: "file" },
- { name: "seven-new-skills.md", type: "file" },
- {
- name: "2026-02-22-happycappy-product-learnings.md",
- type: "file",
- isNew: true,
- },
- ],
- },
- {
- name: "preferences",
- type: "folder",
- children: [
- { name: "tech-stack.md", type: "file" },
- { name: "communication-style.md", type: "file" },
- { name: "work-habits.md", type: "file" },
- ],
- },
- {
- name: "facts",
- type: "folder",
- children: [
- { name: "project-refly.md", type: "file" },
- { name: "project-context.md", type: "file" },
- { name: "team.md", type: "file" },
- { name: "team-structure.md", type: "file" },
- { name: "fundraising.md", type: "file" },
- { name: "growth.md", type: "file" },
- { name: "market.md", type: "file" },
- { name: "operations.md", type: "file" },
- ],
- },
- {
- name: "context",
- type: "folder",
- children: [
- { name: "current-sprint.md", type: "file", modified: true },
- { name: "blockers.md", type: "file" },
- { name: "ownership.md", type: "file" },
- { name: "todo.md", type: "file" },
- {
- name: "okr",
- type: "folder",
- children: [{ name: "current.md", type: "file" }],
- },
- {
- name: "sprint",
- type: "folder",
- children: [{ name: "current.md", type: "file", active: true }],
- },
- {
- name: "week",
- type: "folder",
- children: [{ name: "current.md", type: "file" }],
- },
- ],
- },
- ],
- },
- {
- name: "knowledge",
- type: "folder",
- children: [
- { name: "architecture.md", type: "file" },
- { name: "tech-stack.md", type: "file" },
- {
- name: "team",
- type: "folder",
- children: [
- { name: "agent-native-team-philosophy.md", type: "file" },
- { name: "culture-playbook.md", type: "file" },
- ],
- },
- {
- name: "operations",
- type: "folder",
- children: [
- { name: "goal-tracking-okr-sprint-week.md", type: "file" },
- { name: "linear-integration.md", type: "file" },
- { name: "weekly-review-template.md", type: "file" },
- ],
- },
- {
- name: "references",
- type: "folder",
- children: [
- { name: "growth-strategy.md", type: "file" },
- { name: "fundraising-brief.md", type: "file" },
- {
- name: "articles",
- type: "folder",
- children: [
- {
- name: "openclaw-ecosystem-kimi-claw-cloud-agent.md",
- type: "file",
- },
- { name: "pi-mono-minimalism-agent-philosophy.md", type: "file" },
- { name: "proactive-coding-agent-as-infra.md", type: "file" },
- {
- name: "memory-context-flow-recsys-digital-avatar.md",
- type: "file",
- },
- {
- name: "happycappy-skill-is-new-app.md",
- type: "file",
- isNew: true,
- },
- {
- name: "happycappy-use-cases-guide.md",
- type: "file",
- isNew: true,
- },
- ],
- },
- ],
- },
- ],
- },
- {
- name: "artifacts",
- type: "folder",
- children: [
- {
- name: "prds",
- type: "folder",
- children: [
- { name: "universal-agent-v3.md", type: "file", active: true },
- { name: "clone-filesystem.md", type: "file" },
- ],
- },
- {
- name: "research",
- type: "folder",
- children: [
- { name: "evolution.md", type: "file" },
- { name: "execution-risk-mitigations.md", type: "file" },
- { name: "openclaw-power-user-usecases.md", type: "file" },
- {
- name: "v0-openclaw",
- type: "folder",
- children: [
- { name: "product-plan.md", type: "file" },
- { name: "personal-agent-plan.md", type: "file" },
- { name: "org-network-plan.md", type: "file" },
- ],
- },
- {
- name: "v1-digital-clone",
- type: "folder",
- children: [
- { name: "mvp-thought.md", type: "file" },
- { name: "architecture.md", type: "file" },
- { name: "growth-strategy.md", type: "file" },
- ],
- },
- {
- name: "v2-opc-programmer",
- type: "folder",
- children: [
- { name: "opc-programmer-vertical.md", type: "file" },
- { name: "refly-nexu-architecture.md", type: "file" },
- ],
- },
- {
- name: "v3-universal-agent",
- type: "folder",
- children: [
- { name: "universal-agent-strategy.md", type: "file" },
- { name: "roadmap.md", type: "file" },
- { name: "refly-positioning.md", type: "file" },
- { name: "refly-design-system.md", type: "file" },
- { name: "refly-copy-system.md", type: "file" },
- { name: "caicai-openclaw-analysis.md", type: "file" },
- ],
- },
- ],
- },
- {
- name: "designs",
- type: "folder",
- children: [{ name: "design-system-overview.md", type: "file" }],
- },
- {
- name: "reports",
- type: "folder",
- children: [
- { name: "sprint-review-s0-planning.md", type: "file" },
- { name: "investor-narrative.md", type: "file" },
- {
- name: "investor-bp",
- type: "folder",
- children: [
- { name: "bp-deck.md", type: "file" },
- { name: "bp-document.md", type: "file" },
- { name: "investor-qa.md", type: "file" },
- { name: "speech-outline.md", type: "file" },
- { name: "data-metrics.md", type: "file" },
- ],
- },
- {
- name: "投资人BP准备",
- type: "folder",
- children: [
- { name: "final-bp.md", type: "file" },
- { name: "whole-bp.md", type: "file" },
- { name: "investor-qa-answers.md", type: "file" },
- ],
- },
- ],
- },
- ],
- },
- {
- name: "team",
- type: "folder",
- children: [
- { name: "sprint.md", type: "file", modified: true },
- {
- name: "standup",
- type: "folder",
- children: [
- { name: "2026-02-23.md", type: "file", isNew: true },
- { name: "2026-02-22.md", type: "file" },
- { name: "2026-02-21.md", type: "file" },
- ],
- },
- {
- name: "decisions",
- type: "folder",
- children: [{ name: "2026-02-23-gateway-priority.md", type: "file", isNew: true }],
- },
- { name: "topology.md", type: "file" },
- ],
- },
- {
- name: "sessions",
- type: "folder",
- children: [
- {
- name: "2026-02-22-clone文件系统验证",
- type: "folder",
- children: [{ name: "thread.jsonl", type: "file", active: true }],
- },
- {
- name: "2026-02-22-roadmap规划",
- type: "folder",
- children: [{ name: "thread.jsonl", type: "file" }],
- },
- {
- name: "2026-02-21-设计系统",
- type: "folder",
- children: [{ name: "thread.jsonl", type: "file" }],
- },
- ],
- },
- {
- name: "automation",
- type: "folder",
- children: [
- { name: "morning-digest.yaml", type: "file" },
- { name: "weekly-retro.yaml", type: "file" },
- { name: "todo-reminder.yaml", type: "file" },
- { name: "competitor-watch.yaml", type: "file" },
- { name: "proactive-rules.yaml", type: "file" },
- ],
- },
- {
- name: "skills",
- type: "folder",
- children: [
- {
- name: "memory-notes",
- type: "folder",
- children: [{ name: "SKILL.md", type: "file" }],
- },
- {
- name: "task-manager",
- type: "folder",
- children: [{ name: "SKILL.md", type: "file" }],
- },
- {
- name: "code-automation",
- type: "folder",
- children: [{ name: "SKILL.md", type: "file" }],
- },
- {
- name: "web-research",
- type: "folder",
- children: [{ name: "SKILL.md", type: "file" }],
- },
- {
- name: "daily-digest",
- type: "folder",
- children: [{ name: "SKILL.md", type: "file" }],
- },
- {
- name: "investor-prep",
- type: "folder",
- children: [{ name: "SKILL.md", type: "file" }],
- },
- ],
- },
-];
-
-const DEFAULT_OPEN = new Set([
- ".soul",
- "contacts",
- "memory",
- "artifacts",
- "prds",
- "knowledge",
- "sessions",
- "2026-02-22-clone文件系统验证",
- "decisions",
-]);
-
-function FileIcon({ node }: { node: FileNode }) {
- const ext = node.name.split(".").pop()?.toLowerCase();
- if (ext === "md") return ;
- if (ext === "yaml" || ext === "yml") return ;
- if (ext === "sql") return ;
- if (ext === "jsonl" || ext === "json")
- return ;
- if (ext === "pdf") return ;
- if (ext === "docx" || ext === "doc") return ;
- if (ext === "xlsx" || ext === "xls" || ext === "csv")
- return ;
- if (ext === "pptx" || ext === "ppt")
- return ;
- if (
- ext === "html" ||
- ext === "css" ||
- ext === "tsx" ||
- ext === "ts" ||
- ext === "js" ||
- ext === "py"
- )
- return ;
- if (
- ext === "png" ||
- ext === "jpg" ||
- ext === "jpeg" ||
- ext === "webp" ||
- ext === "svg" ||
- ext === "gif"
- )
- return ;
- if (ext === "mp4" || ext === "mov" || ext === "webm")
- return ;
- if (ext === "mp3" || ext === "wav" || ext === "ogg" || ext === "m4a")
- return ;
- if (ext === "figma") return ;
- return ;
-}
-
-function TreeNode({
- node,
- depth,
- path,
- openFolders,
- toggleFolder,
- selectedFile,
- onSelectFile,
- onNavigate,
- onOpenFile,
-}: {
- node: FileNode;
- depth: number;
- path: string;
- openFolders: Set;
- toggleFolder: (name: string) => void;
- selectedFile: string | null;
- onSelectFile: (name: string) => void;
- onNavigate?: (route: string) => void;
- onOpenFile?: (fullPath: string) => void;
-}) {
- const isOpen = openFolders.has(node.name);
- const isFolder = node.type === "folder";
- const isSelected = !isFolder && selectedFile === node.name;
- const hasRoute = isFolder && FOLDER_ROUTES[node.name];
-
- const handleClick = () => {
- if (isFolder) {
- toggleFolder(node.name);
- if (hasRoute && onNavigate) {
- onNavigate(FOLDER_ROUTES[node.name]);
- }
- } else {
- onSelectFile(node.name);
- const fullPath = path ? `${path}/${node.name}` : node.name;
- onOpenFile?.(fullPath);
- const parentFolder = path.split("/")[0];
- if (parentFolder && FOLDER_ROUTES[parentFolder] && onNavigate) {
- onNavigate(FOLDER_ROUTES[parentFolder]);
- }
- }
- };
-
- return (
- <>
-
- {isFolder &&
- isOpen &&
- node.children?.map((child) => (
-
- ))}
- >
- );
-}
-
-export default function FileTree({
- collapsed,
- onNavigate,
- onOpenFile,
-}: {
- collapsed?: boolean;
- onNavigate?: (route: string) => void;
- onOpenFile?: (fullPath: string) => void;
-}) {
- const [openFolders, setOpenFolders] = useState>(new Set(DEFAULT_OPEN));
- const [selectedFile, setSelectedFile] = useState("universal-agent-v3.md");
-
- const toggleFolder = (name: string) => {
- setOpenFolders((prev) => {
- const next = new Set(prev);
- next.has(name) ? next.delete(name) : next.add(name);
- return next;
- });
- };
-
- if (collapsed) return null;
-
- return (
-
- {/* Header */}
-
-
- {/* Tree */}
-
- {CLONE_FILE_TREE.map((node) => (
-
- ))}
-
-
- {/* Footer stats */}
-
-
- 137 files
- 1 modified · 4 new
-
-
-
- );
-}
diff --git a/apps/demo/src/pages/product/OnboardingChat.tsx b/apps/demo/src/pages/product/OnboardingChat.tsx
deleted file mode 100644
index 7e4f3d5f..00000000
--- a/apps/demo/src/pages/product/OnboardingChat.tsx
+++ /dev/null
@@ -1,618 +0,0 @@
-import {
- Badge,
- Button,
- ConversationMessage,
- Progress,
- Stepper,
- StepperItem,
- StepperSeparator,
- Textarea,
-} from "@nexu-design/ui-web";
-import {
- ArrowRight,
- Brain,
- Check,
- CheckCircle,
- Database,
- Globe,
- Link2,
- MessageSquare,
- RefreshCw,
- Send,
- Shield,
- Sparkles,
- Upload,
- UserPlus,
- Users,
- Wrench,
- X,
-} from "lucide-react";
-import { useState } from "react";
-
-interface OnboardingStep {
- id: string;
- label: string;
- icon: React.ElementType;
- status: "done" | "active" | "pending";
-}
-
-const STEPS: OnboardingStep[] = [
- { id: "persona", label: "基础人设", icon: Shield, status: "done" },
- { id: "worldview", label: "世界观", icon: Globe, status: "done" },
- { id: "memory", label: "记忆导入", icon: Database, status: "active" },
- { id: "integrations", label: "渠道授权", icon: Link2, status: "pending" },
- { id: "skills", label: "能力配置", icon: Sparkles, status: "pending" },
- { id: "knowledge", label: "知识库", icon: Brain, status: "pending" },
- { id: "team", label: "团队协作", icon: Users, status: "pending" },
-];
-
-interface ChatMsg {
- id: string;
- from: "clone" | "user" | "system";
- content: string;
- widget?: "integrations" | "skills" | "upload" | "progress" | "team";
-}
-
-const INITIAL_MESSAGES: ChatMsg[] = [
- {
- id: "system-1",
- from: "system",
- content: "🎉 分身初始化 · 持续对话",
- },
- {
- id: "clone-1",
- from: "clone",
- content:
- "你好!我是你的数字分身 😊\n\n让我先了解你,这样我才能更好地帮你。我们可以随时聊,不用一次搞定 — 你说到哪儿算哪儿,之后随时回来补充。",
- },
- {
- id: "clone-2",
- from: "clone",
- content:
- "先来最基础的:\n\n1. 你希望我叫你什么?\n2. 你主要做什么工作?(角色/领域)\n3. 你希望我用什么风格跟你沟通?(正式/轻松/技术范/随意聊)",
- },
- {
- id: "user-1",
- from: "user",
- content:
- "叫我 Tom,我是产品经理 + 技术合伙人,做 AI SaaS 方向。沟通风格要简洁直接,技术术语可以直接用英文。",
- },
- {
- id: "clone-3",
- from: "clone",
- content:
- "明白了 Tom 👋\n\n已记录:\n✅ 称呼:Tom\n✅ 角色:产品经理 + 技术合伙人\n✅ 领域:AI SaaS\n✅ 沟通风格:简洁直接 · 技术术语用英文\n\n接下来我想了解你的价值观和做事原则 — 这样我做决策时才不会跑偏。",
- },
- {
- id: "clone-4",
- from: "clone",
- content:
- '你做产品和技术决策时,有没有几条核心原则?\n比如"用户体验优先"、"先跑起来再说"、"不过度工程化"之类的。',
- },
- {
- id: "user-2",
- from: "user",
- content:
- '有的:\n1. 用户体验 > 功能数量\n2. 实用主义,先跑起来再优化\n3. 判断标准是"这让分身更懂用户了吗?"\n4. 直说结论不说废话',
- },
- {
- id: "clone-5",
- from: "clone",
- content:
- '非常清晰 ✅ 已存入世界观:\n\n🎯 产品哲学:用户体验 > 功能数量\n⚡ 技术观:实用主义,先跑起来再优化\n🧭 决策标准:"这让分身更懂用户了吗?"\n💬 沟通准则:直说结论不说废话\n\n现在最关键的一步 — 让我获取你已有的记忆和内容。有几个方式可以快速导入:',
- },
- {
- id: "clone-6",
- from: "clone",
- content:
- "你可以:\n\n📎 **直接上传文件** — 简历、笔记、文档、项目资料等,我会自动提取关键信息\n\n🔗 **授权已有工具** — 连接你日常用的工具,我会从中学习你的习惯和偏好\n\n💬 **继续跟我聊** — 聊你最近在做的事、你的想法和计划,我边聊边记\n\n想先从哪个开始?",
- widget: "integrations",
- },
-];
-
-interface IntegrationItem {
- name: string;
- icon: string;
- desc: string;
- status: "connected" | "available" | "coming";
- importable: string;
-}
-
-const INTEGRATIONS: IntegrationItem[] = [
- {
- name: "飞书",
- icon: "🐦",
- desc: "消息、文档、日历、审批",
- status: "connected",
- importable: "1,247 条消息 · 89 文档",
- },
- {
- name: "Slack",
- icon: "💬",
- desc: "频道消息、DM、Threads",
- status: "connected",
- importable: "523 条消息 · 34 文档",
- },
- {
- name: "Notion",
- icon: "📝",
- desc: "页面、数据库、知识库",
- status: "available",
- importable: "导入 Notion 工作空间",
- },
- {
- name: "Gmail",
- icon: "📧",
- desc: "邮件内容、联系人",
- status: "available",
- importable: "扫描重要邮件和联系人",
- },
- {
- name: "GitHub",
- icon: "🐙",
- desc: "代码仓库、Issues、PR",
- status: "available",
- importable: "导入项目上下文",
- },
- {
- name: "Linear",
- icon: "🔵",
- desc: "Issues、Sprint、Roadmap",
- status: "available",
- importable: "同步项目进度",
- },
- {
- name: "n8n",
- icon: "⚡",
- desc: "自动化工作流",
- status: "available",
- importable: "导入现有工作流",
- },
- {
- name: "Google Calendar",
- icon: "📅",
- desc: "日程、会议",
- status: "available",
- importable: "同步日历和会议",
- },
- { name: "Figma", icon: "🎨", desc: "设计稿、评论", status: "coming", importable: "即将支持" },
- { name: "WeChat", icon: "💚", desc: "微信对话", status: "coming", importable: "即将支持" },
-];
-
-interface SkillOption {
- name: string;
- desc: string;
- icon: string;
- recommended: boolean;
- selected: boolean;
-}
-
-const SKILL_OPTIONS: SkillOption[] = [
- { name: "记忆管理", desc: "自动记忆、知识沉淀", icon: "🧠", recommended: true, selected: true },
- { name: "任务管理", desc: "待办创建、追踪、提醒", icon: "✅", recommended: true, selected: true },
- { name: "每日汇报", desc: "晨间日报 + 日程提醒", icon: "📋", recommended: true, selected: true },
- { name: "联网搜索", desc: "实时搜索 + 信息整理", icon: "🔍", recommended: true, selected: true },
- { name: "代码助手", desc: "代码生成、PR、审查", icon: "💻", recommended: false, selected: false },
- { name: "文档写作", desc: "PRD、方案、报告生成", icon: "📄", recommended: false, selected: true },
- { name: "竞品监控", desc: "定期扫描竞品动态", icon: "📊", recommended: false, selected: false },
- {
- name: "会议纪要",
- desc: "录音转写 + Action Items",
- icon: "🎙️",
- recommended: false,
- selected: false,
- },
- { name: "邮件管理", desc: "邮件分类 + 摘要", icon: "📬", recommended: false, selected: false },
- { name: "社交媒体", desc: "内容发布 + 互动", icon: "📱", recommended: false, selected: false },
-];
-
-function StepIndicator({ steps }: { steps: OnboardingStep[] }) {
- return (
-
- {steps.flatMap((step, i) => {
- const status =
- step.status === "done" ? "completed" : step.status === "active" ? "current" : "pending";
- return [
- }
- label={step.label}
- className="min-w-[88px]"
- />,
- i < steps.length - 1 ? (
-
- ) : null,
- ];
- })}
-
- );
-}
-
-function IntegrationsWidget() {
- const [expanded, setExpanded] = useState(false);
- const shown = expanded ? INTEGRATIONS : INTEGRATIONS.slice(0, 4);
-
- return (
-
-
- {shown.map((item) => (
-
-
- {item.icon}
- {item.name}
- {item.status === "connected" && (
-
- )}
- {item.status === "coming" && (
- 即将
- )}
-
-
{item.desc}
- {item.status === "connected" && (
-
-
- {item.importable}
-
- )}
- {item.status === "available" && (
-
- )}
-
- ))}
-
- {!expanded && INTEGRATIONS.length > 4 && (
-
- )}
-
- );
-}
-
-function SkillsWidget() {
- const [skills, setSkills] = useState(SKILL_OPTIONS);
-
- const toggleSkill = (name: string) => {
- setSkills((prev) => prev.map((s) => (s.name === name ? { ...s, selected: !s.selected } : s)));
- };
-
- return (
-
-
- {skills.map((s) => (
-
- ))}
-
-
- 已选 {skills.filter((s) => s.selected).length} 个能力 · 之后随时可在 Skills 页面调整
-
-
- );
-}
-
-function UploadWidget() {
- return (
-
-
-
拖拽文件到这里,或点击上传
-
- 支持 PDF、Word、Excel、Markdown、代码、图片、音视频等
-
-
- {["简历", "笔记", "项目文档", "会议录音"].map((tag) => (
-
- {tag}
-
- ))}
-
-
- );
-}
-
-interface TeamInviteMember {
- name: string;
- channel: string;
- icon: string;
- status: "invited" | "joined" | "pending";
-}
-
-const INVITE_LIST: TeamInviteMember[] = [
- { name: "张三", channel: "飞书", icon: "👨💻", status: "joined" },
- { name: "李四", channel: "飞书", icon: "🧑💻", status: "joined" },
- { name: "王五", channel: "Slack", icon: "👩🎨", status: "invited" },
- { name: "赵六", channel: "飞书", icon: "👩💼", status: "pending" },
-];
-
-function TeamSetupWidget() {
- const joined = INVITE_LIST.filter((m) => m.status === "joined").length;
-
- return (
-
-
-
- 团队成员
-
- {joined}/{INVITE_LIST.length} 已加入
-
-
-
- {INVITE_LIST.map((m) => (
-
- {m.icon}
- {m.name}
- {m.channel}
- {m.status === "joined" ? (
-
- ) : m.status === "invited" ? (
-
- 已邀请
-
- ) : (
-
- 待邀请
-
- )}
-
- ))}
-
-
-
-
-
🤖 团队分身网络
-
- 当团队成员加入后,你的分身可以:
-
-
- {[
- "📋 自动生成每日站会汇总",
- "🔍 代你查询其他成员任务进度",
- "⚠️ 检测依赖风险并主动发起对齐",
- "📊 生成团队 Sprint 报告",
- ].map((item) => (
-
- {item}
-
- ))}
-
-
-
- );
-}
-
-function ProgressWidget() {
- const items = [
- { label: "基础人设", done: true, detail: "称呼、角色、沟通风格" },
- { label: "世界观", done: true, detail: "4 条核心原则" },
- { label: "记忆导入", done: false, detail: "0 条记忆 · 0 文件" },
- { label: "渠道授权", done: false, detail: "2 已连接 · 8 可连接" },
- { label: "能力配置", done: false, detail: "4 个推荐能力" },
- { label: "知识库", done: false, detail: "等待导入" },
- { label: "团队协作", done: false, detail: "2/4 成员已加入" },
- ];
-
- const doneCount = items.filter((i) => i.done).length;
- const pct = Math.round((doneCount / items.length) * 100);
-
- return (
-
-
- 初始化进度
- {pct}%
-
-
-
- {items.map((item) => (
-
- {item.done ? (
-
- ) : (
-
- )}
-
- {item.label}
-
-
{item.detail}
-
- ))}
-
-
- );
-}
-
-export default function OnboardingChat({ onClose }: { onClose: () => void }) {
- const [input, setInput] = useState("");
- const [messages] = useState(INITIAL_MESSAGES);
-
- const handleSend = () => {
- if (!input.trim()) return;
- setInput("");
- };
-
- return (
-
-
-
- );
-}
diff --git a/apps/demo/src/pages/product/PricingModal.tsx b/apps/demo/src/pages/product/PricingModal.tsx
deleted file mode 100644
index ec4a62d1..00000000
--- a/apps/demo/src/pages/product/PricingModal.tsx
+++ /dev/null
@@ -1,118 +0,0 @@
-import {
- Button,
- Dialog,
- DialogBody,
- DialogContent,
- DialogDescription,
- DialogHeader,
- DialogTitle,
- PricingCard,
-} from "@nexu-design/ui-web";
-import { Crown, Sparkles, Users } from "lucide-react";
-
-const PLANS = [
- {
- name: "基础版",
- price: "免费",
- desc: "体验分身核心能力",
- icon: Sparkles,
- color: "text-text-muted",
- features: ["500 credits/月", "3 个 Skills", "基础记忆", "1 个渠道"],
- cta: "当前方案",
- ctaStyle: "bg-surface-3 text-text-muted cursor-default",
- },
- {
- name: "专业版",
- price: "¥199/月",
- desc: "释放分身全部潜力",
- icon: Crown,
- color: "text-accent",
- badge: "推荐",
- features: [
- "5,000 credits/月",
- "无限 Skills",
- "深度记忆 + 知识库",
- "全部渠道",
- "Proxy 代理对话",
- "自动化无限制",
- ],
- cta: "升级 Pro",
- ctaStyle: "bg-accent text-accent-fg hover:bg-accent/90",
- },
- {
- name: "团队版",
- price: "¥399/人/月",
- desc: "团队协作 + 分身互联",
- icon: Users,
- color: "text-clone",
- features: [
- "Pro 全部功能",
- "团队共享记忆",
- "Agent-to-Agent 协作",
- "OKR + Sprint 联动",
- "管理后台",
- "优先支持",
- ],
- cta: "联系我们",
- ctaStyle: "bg-clone text-white hover:bg-clone/90",
- },
-];
-
-export default function PricingModal({ open, onClose }: { open: boolean; onClose: () => void }) {
- return (
-
- );
-}
diff --git a/apps/demo/src/pages/product/ProductDemoPage.tsx b/apps/demo/src/pages/product/ProductDemoPage.tsx
deleted file mode 100644
index e82edce9..00000000
--- a/apps/demo/src/pages/product/ProductDemoPage.tsx
+++ /dev/null
@@ -1,250 +0,0 @@
-import {
- ActivityBar,
- ActivityBarContent,
- ActivityBarFooter,
- ActivityBarHeader,
- ActivityBarIndicator,
- ActivityBarItem,
- DetailPanel,
- NavigationMenu,
- NavigationMenuButton,
- NavigationMenuItem,
- Sidebar,
- SidebarContent,
- SidebarHeader,
-} from "@nexu-design/ui-web";
-import {
- Clock,
- FolderTree,
- MessageSquare,
- PanelLeft,
- PanelLeftClose,
- Settings,
- Sparkles,
- Users,
- Wrench,
- X,
- Zap,
-} from "lucide-react";
-import { useCallback, useEffect, useState } from "react";
-import { useLocation, useNavigate } from "react-router-dom";
-
-import AutomationPage from "./AutomationPage";
-import CloneBuilderPage from "./CloneBuilderPage";
-import FileEditor from "./FileEditor";
-import FileTree from "./FileTree";
-import { ProductLayoutContext } from "./ProductLayoutContext";
-import SessionsPage from "./SessionsPage";
-import SkillsPage from "./SkillsPage";
-import TeamPage from "./TeamPage";
-import WorkspaceShell from "./WorkspaceShell";
-import { getFile, saveFile } from "./fileStore";
-
-const PAGES = [
- { id: "sessions", icon: MessageSquare, label: "Sessions", component: SessionsPage },
- { id: "team", icon: Users, label: "团队协作", component: TeamPage },
- { id: "explorer", icon: FolderTree, label: "Explorer", component: null },
- { id: "clone", icon: Wrench, label: "分身搭建", component: CloneBuilderPage },
- { id: "automation", icon: Clock, label: "Automation", component: AutomationPage },
- { id: "skills", icon: Sparkles, label: "Skills", component: SkillsPage },
-] as const;
-
-const TREE_MIN = 180;
-const TREE_MAX = 480;
-const TREE_DEFAULT = 224;
-function inferFileType(path: string) {
- if (path.endsWith(".md")) return "markdown" as const;
- if (path.endsWith(".yaml") || path.endsWith(".yml")) return "yaml" as const;
- if (path.endsWith(".json") || path.endsWith(".jsonl")) return "jsonl" as const;
- if (path.endsWith(".ts") || path.endsWith(".tsx") || path.endsWith(".js")) return "code" as const;
- return "markdown" as const;
-}
-
-export default function ProductDemoPage() {
- const [activeTab, setActiveTab] = useState("sessions");
- const [treeCollapsed, setTreeCollapsed] = useState(false);
- const [treeWidth, setTreeWidth] = useState(TREE_DEFAULT);
- const [openFilePath, setOpenFilePath] = useState(null);
- const navigate = useNavigate();
- const location = useLocation();
-
- useEffect(() => {
- const hash = location.hash.replace("#", "");
- if (hash && PAGES.some((page) => page.id === hash && page.component)) {
- setActiveTab(hash);
- }
- }, [location.hash]);
-
- useEffect(() => {
- const handler = (event: KeyboardEvent) => {
- if (event.key === "Escape") navigate("/openclaw/workspace");
- };
-
- window.addEventListener("keydown", handler);
- return () => window.removeEventListener("keydown", handler);
- }, [navigate]);
-
- const expandFileTree = useCallback(() => {
- setTreeCollapsed(false);
- }, []);
-
- const handleOpenFile = useCallback((fullPath: string) => {
- setOpenFilePath(fullPath);
- }, []);
-
- const handleCloseFile = useCallback(() => {
- setOpenFilePath(null);
- }, []);
-
- const handleTreeNavigate = useCallback((route: string) => {
- const tab = route.replace("/app/", "").split("?")[0];
- if (PAGES.some((page) => page.id === tab)) {
- setActiveTab(tab);
- }
- }, []);
-
- const activePage = PAGES.find((page) => page.id === activeTab);
- const ActiveComponent = activePage?.component ?? CloneBuilderPage;
-
- return (
-
-
-
- navigate("/openclaw/workspace")}
- className="rounded-lg p-1 text-text-muted transition-colors hover:bg-surface-3"
- title="返回 Workspace (Esc)"
- >
-
-
- nexu Product Demo
-
- {PAGES.filter((page) => page.component).map((page) => (
- setActiveTab(page.id)}
- className={`rounded px-2.5 py-1 text-[11px] font-medium transition-colors ${
- activeTab === page.id
- ? "bg-accent text-accent-fg"
- : "text-text-muted hover:bg-surface-3 hover:text-text-primary"
- }`}
- >
- {page.label}
-
- ))}
-
-
- 按 Esc 退出
-
-
-
-
-
-
-
-
- {PAGES.map(({ id, icon: Icon, label }) => {
- const isExplorer = id === "explorer";
- const active = isExplorer ? !treeCollapsed : activeTab === id;
-
- return (
-
- isExplorer ? setTreeCollapsed((collapsed) => !collapsed) : setActiveTab(id)
- }
- >
- {active ? : null}
-
-
- );
- })}
-
-
-
- {treeCollapsed ? (
- setTreeCollapsed(false)}>
-
-
- ) : null}
-
-
-
-
-
-
-
-
- }
- sidebar={
-
-
-
- Explorer
-
-
-
- setTreeCollapsed(true)}
- >
-
-
-
-
-
-
-
-
-
- }
- detailPanel={
- openFilePath ? (
-
- saveFile(openFilePath, content, "human")}
- />
-
- ) : null
- }
- >
-
-
-
-
- );
-}
diff --git a/apps/demo/src/pages/product/ProductLayout.tsx b/apps/demo/src/pages/product/ProductLayout.tsx
deleted file mode 100644
index 1c5c5cbb..00000000
--- a/apps/demo/src/pages/product/ProductLayout.tsx
+++ /dev/null
@@ -1,206 +0,0 @@
-import {
- ActivityBar,
- ActivityBarContent,
- ActivityBarFooter,
- ActivityBarHeader,
- ActivityBarIndicator,
- ActivityBarItem,
- DetailPanel,
- NavigationMenu,
- NavigationMenuButton,
- NavigationMenuItem,
- Sidebar,
- SidebarContent,
- SidebarHeader,
-} from "@nexu-design/ui-web";
-import {
- Clock,
- FolderTree,
- MessageSquare,
- PanelLeft,
- PanelLeftClose,
- Settings,
- Sparkles,
- Users,
- Wrench,
- Zap,
-} from "lucide-react";
-import { type ReactNode, useCallback, useState } from "react";
-import { NavLink, useLocation, useNavigate } from "react-router-dom";
-
-import FileEditor from "./FileEditor";
-import FileTree from "./FileTree";
-import { ProductLayoutContext } from "./ProductLayoutContext";
-import WorkspaceShell from "./WorkspaceShell";
-import { getFile, saveFile } from "./fileStore";
-
-const ACTIVITY_NAV = [
- { to: "/app/sessions", id: "sessions", icon: MessageSquare, label: "Sessions" },
- { to: "/app/team", id: "team", icon: Users, label: "团队协作" },
- { to: null, id: "explorer", icon: FolderTree, label: "Explorer" },
- { to: "/app/clone", id: "clone", icon: Wrench, label: "分身搭建" },
- { to: "/app/automation", id: "automation", icon: Clock, label: "Automation" },
- { to: "/app/skills", id: "skills", icon: Sparkles, label: "Skills" },
-];
-
-const TREE_MIN = 180;
-const TREE_MAX = 480;
-const TREE_DEFAULT = 224;
-function inferFileType(path: string) {
- if (path.endsWith(".md")) return "markdown" as const;
- if (path.endsWith(".yaml") || path.endsWith(".yml")) return "yaml" as const;
- if (path.endsWith(".json") || path.endsWith(".jsonl")) return "jsonl" as const;
- if (path.endsWith(".ts") || path.endsWith(".tsx") || path.endsWith(".js")) return "code" as const;
- if (path.endsWith(".sql")) return "sql" as const;
- if (path.endsWith(".html")) return "html" as const;
- if (path.endsWith(".css")) return "code" as const;
- if (path.endsWith(".svg")) return "svg" as const;
- if (path.endsWith(".png") || path.endsWith(".jpg") || path.endsWith(".gif"))
- return "image" as const;
- if (path.endsWith(".pdf")) return "pdf" as const;
- return "markdown" as const;
-}
-
-export default function ProductLayout({ children }: { children: ReactNode }) {
- const [treeCollapsed, setTreeCollapsed] = useState(false);
- const [treeWidth, setTreeWidth] = useState(TREE_DEFAULT);
- const [openFilePath, setOpenFilePath] = useState(null);
- const location = useLocation();
- const navigate = useNavigate();
-
- const isActive = (to: string | null) => {
- if (!to) return !treeCollapsed;
- return location.pathname.startsWith(to);
- };
-
- const expandFileTree = useCallback(() => {
- setTreeCollapsed(false);
- }, []);
-
- const handleOpenFile = useCallback((fullPath: string) => {
- setOpenFilePath(fullPath);
- }, []);
-
- const handleCloseFile = useCallback(() => {
- setOpenFilePath(null);
- }, []);
-
- return (
-
-
-
-
-
-
-
- {ACTIVITY_NAV.map(({ to, id, icon: Icon, label }) => {
- const active = isActive(to);
-
- if (to) {
- return (
-
-
- {active ? : null}
-
-
-
- );
- }
-
- return (
- setTreeCollapsed((collapsed) => !collapsed)}
- >
- {!treeCollapsed ? : null}
-
-
- );
- })}
-
-
-
- {treeCollapsed ? (
- setTreeCollapsed(false)}>
-
-
- ) : null}
-
-
-
-
-
-
-
-
- }
- sidebar={
-
-
-
- Explorer
-
-
-
- setTreeCollapsed(true)}
- >
-
-
-
-
-
-
-
-
-
- }
- detailPanel={
- openFilePath ? (
-
- saveFile(openFilePath, content, "human")}
- />
-
- ) : null
- }
- >
-
- {children}
-
-
-
- );
-}
diff --git a/apps/demo/src/pages/product/ProductLayoutContext.tsx b/apps/demo/src/pages/product/ProductLayoutContext.tsx
deleted file mode 100644
index bc1077b5..00000000
--- a/apps/demo/src/pages/product/ProductLayoutContext.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { createContext, useContext } from "react";
-
-export interface ProductLayoutContextValue {
- expandFileTree: () => void;
- openFile: (path: string) => void;
-}
-
-export const ProductLayoutContext = createContext({
- expandFileTree: () => {},
- openFile: () => {},
-});
-
-export function useProductLayout() {
- return useContext(ProductLayoutContext);
-}
diff --git a/apps/demo/src/pages/product/SessionsPage.tsx b/apps/demo/src/pages/product/SessionsPage.tsx
deleted file mode 100644
index 9541bb2b..00000000
--- a/apps/demo/src/pages/product/SessionsPage.tsx
+++ /dev/null
@@ -1,1122 +0,0 @@
-import {
- Badge,
- Breadcrumb,
- BreadcrumbItem,
- BreadcrumbList,
- BreadcrumbPage,
- BreadcrumbSeparator,
- Button,
- Collapsible,
- CollapsibleContent,
- CollapsibleTrigger,
- Combobox,
- ComboboxContent,
- ComboboxInput,
- ComboboxItem,
- ComboboxTrigger,
- ConversationMessage,
- DataTable,
- InteractiveRow,
- InteractiveRowContent,
- InteractiveRowTrailing,
- PageHeader,
- ScrollArea,
- Table,
- TableBody,
- TableCell,
- TableHead,
- TableHeader,
- TableRow,
- Textarea,
-} from "@nexu-design/ui-web";
-import {
- BarChart3,
- Bookmark,
- Clock,
- Code,
- Eye,
- File,
- FileSpreadsheet,
- FileText,
- Film,
- FolderOpen,
- Hash,
- Image,
- Mic,
- MoreHorizontal,
- Music,
- Paperclip,
- Plus,
- Presentation,
- Search,
- Send,
- Settings,
- Sparkles,
- Terminal,
- UserPlus,
- Users,
- Wrench,
- X,
-} from "lucide-react";
-import { useState } from "react";
-import { useNavigate } from "react-router-dom";
-
-import ChatCardGroup from "./ChatCards";
-import type { CardAction } from "./ChatCards";
-import FileEditor from "./FileEditor";
-import PricingModal from "./PricingModal";
-import { useProductLayout } from "./ProductLayoutContext";
-import {
- type Attachment,
- type AttachmentType,
- type FileOp,
- type FileOpAction,
- SESSIONS,
- SESSION_DATA,
- type SessionFileOp,
-} from "./sessionsData";
-
-const QUICK_ACTIONS = [
- { label: "帮我写一份 PRD", icon: FileText, color: "text-emerald-400" },
- { label: "随手记一下...", icon: Bookmark, color: "text-violet-400" },
- { label: "帮我问李四进度", icon: Users, color: "text-cyan-400" },
- { label: "创建一个 automation", icon: Clock, color: "text-blue-400" },
- { label: "安装一个新 skill", icon: Wrench, color: "text-amber-400" },
- { label: "分析竞品", icon: BarChart3, color: "text-clone" },
-];
-
-const CAPABILITY_DOMAINS = [
- {
- domain: "📄 文件系统",
- accent: "border-emerald-500/40",
- items: ["写 PRD / 报告 / 代码", "搜索知识库", "生成文件并自动归档"],
- },
- {
- domain: "🧠 记忆",
- accent: "border-violet-500/40",
- items: ["随手记笔记", "管理联系人", "记住偏好和决策"],
- },
- {
- domain: "🔧 技能",
- accent: "border-amber-500/40",
- items: ["调用 数千种能力", "安装社区 Skill", "创建自定义 Skill"],
- },
- {
- domain: "⏰ 自动化",
- accent: "border-blue-500/40",
- items: ["定时任务", "主动式推送", "条件触发规则"],
- },
- {
- domain: "👥 团队协作",
- accent: "border-cyan-500/40",
- items: ["代问同事进度", "发起对齐请求", "团队 Insights 分析"],
- },
- {
- domain: "💰 升级",
- accent: "border-orange-500/40",
- items: ["查看用量", "升级 Pro/Team", "邀请同事裂变"],
- },
-];
-
-const ACTIVE_SKILLS = [
- "Memory & Notes",
- "Task Manager",
- "Web Research",
- "Code Automation",
- "Daily Digest",
-];
-
-const FILE_OP_STYLES: Record = {
- read: { color: "text-info bg-info-subtle", label: "READ" },
- write: { color: "text-clone bg-clone/10", label: "WRITE" },
- create: { color: "text-success bg-success-subtle", label: "CREATE" },
- delete: { color: "text-danger bg-danger-subtle", label: "DELETE" },
- execute: { color: "text-warning bg-warning-subtle", label: "EXEC" },
- install: {
- color: "text-role-designer bg-role-designer/10",
- label: "INSTALL",
- },
-};
-
-function FileOpBadge({ op }: { op: FileOp }) {
- const style = FILE_OP_STYLES[op.action];
- return (
-
-
- {style.label}
-
- {op.path}
-
- );
-}
-
-const ATTACHMENT_STYLES: Record<
- AttachmentType,
- { icon: typeof FileText; color: string; bg: string }
-> = {
- image: {
- icon: Image,
- color: "text-role-designer",
- bg: "bg-role-designer/10",
- },
- pdf: { icon: File, color: "text-danger", bg: "bg-danger-subtle" },
- document: { icon: FileText, color: "text-info", bg: "bg-info-subtle" },
- spreadsheet: {
- icon: FileSpreadsheet,
- color: "text-success",
- bg: "bg-success-subtle",
- },
- audio: { icon: Music, color: "text-role-ops", bg: "bg-role-ops/10" },
- video: { icon: Film, color: "text-role-designer", bg: "bg-role-designer/10" },
- code: {
- icon: Code,
- color: "text-role-programmer",
- bg: "bg-role-programmer/10",
- },
- archive: { icon: File, color: "text-text-muted", bg: "bg-surface-3" },
- other: { icon: File, color: "text-text-muted", bg: "bg-surface-3" },
-};
-
-function AttachmentChip({
- attachment,
- variant = "light",
-}: {
- attachment: Attachment;
- variant?: "light" | "dark";
-}) {
- const style = ATTACHMENT_STYLES[attachment.type];
- const Icon = style.icon;
- const isImage = attachment.type === "image";
- const isAudio = attachment.type === "audio";
- const isVideo = attachment.type === "video";
-
- if (isImage && variant === "dark") {
- return (
-
-
-
-
-
-
{attachment.name}
-
{attachment.size}
-
-
- );
- }
-
- if (isImage) {
- return (
-
-
-
-
-
-
{attachment.name}
-
{attachment.size}
-
-
- );
- }
-
- const bgClass = variant === "dark" ? "bg-white/10 border-white/10" : `${style.bg} border-border`;
- const nameClass = variant === "dark" ? "text-white/90" : "text-text-primary";
- const sizeClass = variant === "dark" ? "text-white/40" : "text-text-muted";
- const iconClass = variant === "dark" ? "text-white/60" : style.color;
-
- return (
-
-
- {isAudio ? (
-
-
-
- {[
- { id: "b1", height: 3 },
- { id: "b2", height: 5 },
- { id: "b3", height: 8 },
- { id: "b4", height: 6 },
- { id: "b5", height: 10 },
- { id: "b6", height: 7 },
- { id: "b7", height: 4 },
- { id: "b8", height: 9 },
- { id: "b9", height: 5 },
- { id: "b10", height: 7 },
- { id: "b11", height: 3 },
- ].map((bar) => (
-
- ))}
-
-
- ) : isVideo ? (
-
-
-
- ) : (
-
- )}
-
-
-
{attachment.name}
-
{attachment.size}
-
-
- );
-}
-
-function NewSessionView({
- onStartChat,
-}: {
- onStartChat: (msg: string) => void;
-}) {
- const [input, setInput] = useState("");
- const [showSkills, setShowSkills] = useState(false);
-
- const handleSubmit = () => {
- if (input.trim()) onStartChat(input);
- };
-
- return (
-
-
-
-
- 😊
-
-
- 你的主线入口 — 对话即操控一切
-
- 写文件、记笔记、问同事、设自动化、装技能、查 OKR — 这一个对话窗就是你的 agent
- computer。所有操作都沉淀在 分身的大脑里
- >
- }
- />
-
-
- {/* Input */}
-
-
- {/* Skills dropdown */}
- {showSkills && (
-
-
- 已激活的 Skills
-
- {ACTIVE_SKILLS.map((s) => (
-
- {s}
-
- ))}
-
-
-
- 浏览 Skills Store...
-
-
-
- )}
-
- {/* Quick action pills */}
-
- {QUICK_ACTIONS.map((t) => (
- onStartChat(t.label)}
- className="rounded-full"
- >
-
- {t.label}
-
- ))}
-
-
- {/* 6 Domain capability grid — maps to the 6 card types */}
-
-
-
- {CAPABILITY_DOMAINS.map((d) => (
-
onStartChat(d.items[0])}
- className={`h-auto p-3 ${d.accent} border-l-2 text-left group`}
- >
- {d.domain}
-
- {d.items.map((item) => (
-
- · {item}
-
- ))}
-
-
- ))}
-
-
-
- {/* Scoped session hint */}
-
-
-
- 在其他页面你会看到 scoped sessions — 它们和这里一样是 Chat,但限定了特定的 Skills
- 和上下文:
-
-
- {[
- {
- label: "Team Insights",
- desc: "团队数据分析",
- color: "bg-cyan-500/10 text-cyan-400 border-cyan-500/20",
- },
- {
- label: "Sprint 分析",
- desc: "冲刺进度跟踪",
- color: "bg-blue-500/10 text-blue-400 border-blue-500/20",
- },
- {
- label: "OKR 对齐",
- desc: "目标跟踪分析",
- color: "bg-violet-500/10 text-violet-400 border-violet-500/20",
- },
- ].map((s) => (
-
- {s.label}
- · {s.desc}
-
- ))}
-
-
-
- {/* Footer hint */}
-
-
-
- 所有操作产出 6 种标准卡片:文件 · 记忆 · 技能 · 自动化 · 协作 · 升级 — 卡片可交互
-
-
-
-
- );
-}
-
-function FileTypeIcon({ fileType }: { fileType: SessionFileOp["fileType"] }) {
- switch (fileType) {
- case "markdown":
- return ;
- case "yaml":
- return ;
- case "code":
- case "html":
- case "sql":
- return ;
- case "jsonl":
- return ;
- case "contact":
- return ;
- case "skill":
- return ;
- case "config":
- return ;
- case "pdf":
- return ;
- case "docx":
- return ;
- case "xlsx":
- case "csv":
- return ;
- case "pptx":
- return ;
- case "image":
- case "svg":
- return ;
- case "video":
- return ;
- case "audio":
- return ;
- case "figma":
- return ;
- default:
- return ;
- }
-}
-
-function SessionFileOpsTable({
- title,
- ops,
- safeIdx,
- fileOps,
- onSelect,
-}: {
- title: string;
- ops: SessionFileOp[];
- safeIdx: number;
- fileOps: SessionFileOp[];
- onSelect: (idx: number) => void;
-}) {
- if (ops.length === 0) return null;
-
- return (
-
-
-
- {title}
-
- {ops.length}
-
-
-
-
-
-
-
- Op
- File
- Diff / Size
- Time
-
-
-
- {ops.map((op) => {
- const idx = fileOps.indexOf(op);
- const style = FILE_OP_STYLES[op.action];
- const fileName = op.path.split("/").pop() || op.path;
-
- return (
- onSelect(idx)}
- >
-
-
- {style.label}
-
-
-
-
-
-
-
- {fileName}
-
-
- {op.path}
-
-
-
-
-
-
- {op.diff ? (
- <>
- {op.diff.added > 0 ? (
- +{op.diff.added}
- ) : null}
- {op.diff.removed > 0 ? (
- -{op.diff.removed}
- ) : null}
- >
- ) : null}
- {op.size ? {op.size} : null}
-
-
-
- {op.time}
-
-
- );
- })}
-
-
-
-
-
- );
-}
-
-const CHANNEL_ICONS: Record = {
- web: { icon: "🌐", color: "text-info" },
- feishu: { icon: "🐦", color: "text-role-ops" },
- slack: { icon: "💬", color: "text-role-designer" },
- whatsapp: { icon: "📱", color: "text-success" },
- telegram: { icon: "✈️", color: "text-info" },
-};
-
-function ActiveChatView({
- sessionId,
- previewOpen,
- setPreviewOpen,
-}: {
- sessionId: number;
- previewOpen: boolean;
- setPreviewOpen: (v: boolean) => void;
-}) {
- const [input, setInput] = useState("");
- const [selectedFileOp, setSelectedFileOp] = useState(0);
- const [pricingOpen, setPricingOpen] = useState(false);
- const navigate = useNavigate();
- const { openFile } = useProductLayout();
-
- const handleCardAction = (action: CardAction) => {
- switch (action.type) {
- case "openFile":
- openFile(action.payload);
- break;
- case "navigate":
- navigate(action.payload);
- break;
- case "showPricing":
- setPricingOpen(true);
- break;
- }
- };
-
- const session = SESSIONS.find((s) => s.id === sessionId);
- if (!session) return null;
- const data = SESSION_DATA[sessionId];
- const messages = data?.messages || [];
- const fileOps = data?.fileOps || [];
- const ch = CHANNEL_ICONS[session.channel];
-
- const safeIdx = selectedFileOp < fileOps.length ? selectedFileOp : 0;
- const currentOp = fileOps[safeIdx];
- const rawPathParts = currentOp ? currentOp.path.split("/") : [];
- const fileName = currentOp ? rawPathParts[rawPathParts.length - 1] || "" : "";
- const pathParts = fileName ? rawPathParts.slice(0, -1) : rawPathParts;
- const breadcrumbs = pathParts.map((part, idx, parts) => ({
- label: part,
- key: parts.slice(0, idx + 1).join("/"),
- }));
-
- const writeOps = fileOps.filter(
- (op) => op.action === "create" || op.action === "write" || op.action === "delete",
- );
- const readOps = fileOps.filter((op) => op.action === "read");
- const execOps = fileOps.filter((op) => op.action === "execute" || op.action === "install");
-
- return (
- <>
- {/* Chat thread */}
-
-
-
- {session.emoji}
- {session.title}
-
- {ch?.icon}
- {session.channel}
-
-
- {fileOps.length} file ops
-
-
-
- setPreviewOpen(!previewOpen)}
- title="文件预览"
- >
-
-
-
-
-
-
-
-
-
-
- {messages.map((msg, i) => (
-
- {msg.attachments && msg.attachments.length > 0 && (
-
- {msg.attachments.map((att) => (
-
- ))}
-
- )}
- {msg.cards && msg.cards.length > 0 ? (
-
- ) : msg.fileOps ? (
-
- {msg.fileOps.map((op) => (
-
- ))}
-
- ) : null}
- {msg.tool && !msg.cards && (
-
-
- {msg.tool.name}
- ✓
-
- )}
- {msg.content && (
-
- 😊
-
- ) : undefined
- }
- bubbleClassName={
- msg.from === "user"
- ? "bg-accent text-accent-fg text-[12px]"
- : "bg-surface-2 text-[12px]"
- }
- >
- {msg.content}
-
- )}
-
- ))}
-
-
-
- {/* Input */}
-
- {/* Pending uploads bar */}
-
-
-
- screenshot.png
-
-
-
-
-
-
- report.pdf
-
-
-
-
-
-
-
-
-
-
-
-
- {/* File Preview panel */}
- {previewOpen && currentOp && (
-
- {/* Preview header — shows selected file */}
-
-
-
- {fileName}
- {(currentOp.action === "create" || currentOp.action === "write") && (
-
- {currentOp.action === "create" ? "新建" : "已修改"}
-
- )}
- {currentOp.action === "execute" && (
-
- 已执行
-
- )}
- {currentOp.action === "install" && (
-
- 已安装
-
- )}
-
-
setPreviewOpen(false)}
- className="p-1 rounded hover:bg-surface-3 text-text-muted transition-colors"
- >
-
-
-
-
- {/* Breadcrumb path */}
-
-
-
-
- ~/clone
-
- {breadcrumbs.map((part) => (
-
-
- {part.label}
-
- ))}
-
-
-
- {fileName}
-
-
-
-
-
- {/* Editable file content */}
-
- {currentOp.preview ? (
-
- ) : (
-
-
- 无预览内容
-
- )}
- {currentOp.diff && (
-
- +{currentOp.diff.added} lines
- {currentOp.diff.removed > 0 && (
- -{currentOp.diff.removed} lines
- )}
- {currentOp.size && (
- {currentOp.size}
- )}
-
- )}
-
-
- {/* File operations list */}
-
-
-
- 本次会话文件变更
-
-
-
-
- {fileOps.length}
-
-
-
-
-
-
-
-
-
-
-
-
- )}
- setPricingOpen(false)} />
- >
- );
-}
-
-export default function SessionsPage() {
- const [activeSession, setActiveSession] = useState(null);
- const [previewOpen, setPreviewOpen] = useState(true);
- const activeSessionOption = SESSIONS.find((session) => session.id === activeSession) ?? null;
-
- const handleStartChat = (_msg: string) => {
- setActiveSession(1);
- };
-
- return (
-
- {/* Session list */}
-
-
-
-
setActiveSession(Number(value))}
- >
-
-
-
-
- {activeSessionOption ? activeSessionOption.title : "搜索对话..."}
-
-
-
-
- } />
-
- {SESSIONS.map((session) => (
-
-
-
- {session.title}
-
-
- {session.channel} · {session.time}
-
-
-
- ))}
-
-
-
-
setActiveSession(null)}
- className="p-1 rounded-md hover:bg-surface-3 text-text-secondary transition-colors"
- title="新建对话"
- >
-
-
-
-
-
-
- {SESSIONS.map((s) => {
- const ch = CHANNEL_ICONS[s.channel];
- const isActive = activeSession === s.id;
- return (
-
setActiveSession(s.id)}
- className={`px-2.5 py-2 rounded-lg ${
- isActive ? "bg-accent text-accent-fg" : "hover:bg-surface-3"
- }`}
- >
-
-
{s.emoji}
-
-
- {s.title}
-
-
-
- {s.time}
-
-
- ·
-
-
- {ch.icon}
-
- {s.fileOps > 0 && (
- <>
-
- ·
-
-
- {s.fileOps} ops
-
- >
- )}
-
-
-
- {s.isProxy && !isActive && (
-
- 代问
-
- )}
- {s.isProactive && !isActive && !s.isProxy && (
-
- 主动
-
- )}
- {s.unread && !isActive && !s.isProactive && !s.isProxy && (
-
- )}
-
-
-
- );
- })}
-
-
-
-
- {/* Main content: new session vs active chat */}
- {activeSession === null ? (
-
- ) : (
-
- )}
-
- );
-}
diff --git a/apps/demo/src/pages/product/SkillsPage.tsx b/apps/demo/src/pages/product/SkillsPage.tsx
deleted file mode 100644
index 173d4702..00000000
--- a/apps/demo/src/pages/product/SkillsPage.tsx
+++ /dev/null
@@ -1,1252 +0,0 @@
-import {
- Badge,
- Button,
- Combobox,
- ComboboxContent,
- ComboboxInput,
- ComboboxItem,
- ComboboxTrigger,
- ConversationMessage,
- Dialog,
- DialogBody,
- DialogContent,
- DialogDescription,
- DialogFooter,
- DialogHeader,
- DialogTitle,
- EntityCard,
- EntityCardContent,
- EntityCardDescription,
- EntityCardHeader,
- EntityCardMeta,
- EntityCardTitle,
- FilterPillTrigger,
- FilterPills,
- FilterPillsList,
- FormField,
- FormFieldControl,
- Input,
- InteractiveRow,
- InteractiveRowContent,
- InteractiveRowLeading,
- InteractiveRowTrailing,
- PageHeader,
- PanelFooter,
- PanelFooterActions,
- PanelFooterMeta,
- ScrollArea,
- Sheet,
- SheetContent,
- Tabs,
- TabsContent,
- TabsList,
- TabsTrigger,
- Textarea,
-} from "@nexu-design/ui-web";
-import {
- BarChart3,
- Building,
- Check,
- Code,
- Download,
- FileText,
- FolderOpen,
- GitBranch,
- Lock,
- Megaphone,
- MessageSquare,
- Pencil,
- Plus,
- RefreshCw,
- Search,
- Send,
- Server,
- Settings,
- Shield,
- Sparkles,
- Star,
- Users,
- Workflow,
- Wrench,
- Zap,
-} from "lucide-react";
-import { useState } from "react";
-import { useNavigate } from "react-router-dom";
-
-import { useProductLayout } from "./ProductLayoutContext";
-import { ImportSkillModal } from "./import-skill-modal";
-
-type TabId = "installed" | "featured" | "explore";
-type ExploreCategory = "All" | "integration" | "developer" | "productivity" | "design" | "business";
-
-interface Skill {
- name: string;
- desc: string;
- icon: React.ElementType;
- author: string;
- installs: string;
- certified: boolean;
- installed: boolean;
- category: string;
-}
-
-function buildImportedSkillName(fileName: string, existingNames: string[]) {
- const baseName = fileName.replace(/\.zip$/i, "").trim() || "Imported Skill";
- const normalizedBase = baseName
- .split(/[-_\s]+/)
- .filter(Boolean)
- .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
- .join(" ");
-
- if (!existingNames.includes(normalizedBase)) {
- return normalizedBase;
- }
-
- let suffix = 2;
- let nextName = `${normalizedBase} ${suffix}`;
-
- while (existingNames.includes(nextName)) {
- suffix += 1;
- nextName = `${normalizedBase} ${suffix}`;
- }
-
- return nextName;
-}
-
-function createImportedSkill(fileName: string, existingSkills: Skill[]): Skill {
- return {
- name: buildImportedSkillName(
- fileName,
- existingSkills.map((skill) => skill.name),
- ),
- desc: "Imported from a local ZIP package.",
- icon: FileText,
- author: "local workspace",
- installs: "—",
- certified: false,
- installed: true,
- category: "custom",
- };
-}
-
-const INSTALLED_SKILLS: Skill[] = [
- {
- name: "Memory & Notes",
- desc: "自动记忆管理,知识沉淀",
- icon: FileText,
- author: "nexu",
- installs: "12.4k",
- certified: true,
- installed: true,
- category: "base",
- },
- {
- name: "Task Manager",
- desc: "待办创建、追踪、提醒",
- icon: BarChart3,
- author: "nexu",
- installs: "11.2k",
- certified: true,
- installed: true,
- category: "base",
- },
- {
- name: "Daily Digest",
- desc: "每日汇总日程 + 待办 + 要事",
- icon: FileText,
- author: "nexu",
- installs: "9.8k",
- certified: true,
- installed: true,
- category: "base",
- },
- {
- name: "Web Research",
- desc: "联网搜索 + 信息整理",
- icon: Search,
- author: "nexu",
- installs: "10.1k",
- certified: true,
- installed: true,
- category: "base",
- },
- {
- name: "Code Automation",
- desc: "代码生成、PR、自动化开发",
- icon: Code,
- author: "nexu",
- installs: "8.3k",
- certified: true,
- installed: true,
- category: "developer",
- },
-];
-
-const FEATURED_SKILLS: { title: string; badge: string; desc: string; color: string }[] = [
- {
- title: "Advisory Board (Committee)",
- badge: "SKILLS WE LOVE",
- desc: "Multiple expert agents debate and produce actionable insights.",
- color: "bg-clone/10",
- },
- {
- title: "Contact Intelligence + CRM",
- badge: "NEW",
- desc: "AI-powered relationship management with health scoring.",
- color: "bg-info-subtle",
- },
- {
- title: "Zero-friction Knowledge Ingestion",
- badge: "NEW",
- desc: "Drop links, PDFs, screenshots — auto-process and organize.",
- color: "bg-success-subtle",
- },
-];
-
-const RECOMMENDED_SKILLS: Skill[] = [
- {
- name: "Contact Intelligence",
- desc: "联系人健康评分、互动分析、关系管理、主动提醒",
- icon: Users,
- author: "nexu",
- installs: "7.2k",
- certified: true,
- installed: false,
- category: "base",
- },
- {
- name: "Meeting Action Tracker",
- desc: "会议 action item 提取 + mine/theirs 分类 + 完成追踪",
- icon: FileText,
- author: "nexu",
- installs: "6.1k",
- certified: true,
- installed: false,
- category: "productivity",
- },
- {
- name: "Advisory Board",
- desc: "多 Agent 并行分析 → 辩论 → 综合建议 (Committee Technique)",
- icon: Building,
- author: "nexu",
- installs: "3.8k",
- certified: true,
- installed: false,
- category: "founder",
- },
- {
- name: "Knowledge Ingester",
- desc: "零摩擦知识入库:链接/PDF/截图 → 自动抓取、摘要、向量化",
- icon: FileText,
- author: "nexu",
- installs: "5.6k",
- certified: true,
- installed: false,
- category: "base",
- },
- {
- name: "Content Pipeline",
- desc: "灵感 → 全网搜索 → 去重 → 大纲 → 任务卡片",
- icon: Megaphone,
- author: "nexu",
- installs: "4.5k",
- certified: true,
- installed: false,
- category: "marketing",
- },
- {
- name: "Security Auditor",
- desc: "多视角审查系统安全,自我进化规则,异常立即告警",
- icon: Shield,
- author: "nexu",
- installs: "3.2k",
- certified: true,
- installed: false,
- category: "devops",
- },
- {
- name: "PRD Generator",
- desc: "需求文档生成与迭代",
- icon: FileText,
- author: "nexu",
- installs: "6.7k",
- certified: true,
- installed: false,
- category: "product",
- },
- {
- name: "GitHub Digest",
- desc: "每日 PR/Issue 摘要,代码审查提醒",
- icon: Code,
- author: "community/dev-tools",
- installs: "4.1k",
- certified: true,
- installed: false,
- category: "developer",
- },
- {
- name: "Notion Sync",
- desc: "双向同步 Notion 数据库和页面",
- icon: FileText,
- author: "community/alex",
- installs: "3.2k",
- certified: false,
- installed: false,
- category: "integration",
- },
- {
- name: "Email Classifier",
- desc: "邮件智能分类 + 过滤营销/冷推销 + 优先级标注",
- icon: FileText,
- author: "community/inbox-zero",
- installs: "1.9k",
- certified: false,
- installed: false,
- category: "productivity",
- },
- {
- name: "Investor Update",
- desc: "自动生成投资人周报 + 数据可视化",
- icon: Building,
- author: "community/startups",
- installs: "1.5k",
- certified: false,
- installed: false,
- category: "business",
- },
- {
- name: "Deploy Checklist",
- desc: "部署前自动检查清单,CI/CD 集成",
- icon: Server,
- author: "community/devops",
- installs: "2.1k",
- certified: true,
- installed: false,
- category: "devops",
- },
-];
-
-const SKILL_DETAILS: Record<
- string,
- {
- longDesc: string;
- triggers: string[];
- tools: string[];
- auth: string[];
- version: string;
- updated: string;
- skillMd: string;
- }
-> = {
- "Memory & Notes": {
- longDesc:
- "自动从对话中提取关键记忆,管理知识沉淀。支持记忆分类(想法、口吻、喜好、习惯、近况、目标、世界观、决策)、自动合并去重、对齐率计算。",
- triggers: ["对话中出现重要信息", "用户主动标记", "记忆微调"],
- tools: ["memory_write", "memory_search", "embedding_index"],
- auth: [],
- version: "2.1.0",
- updated: "2026-02-20",
- skillMd:
- '# Memory & Notes\n\ntriggers: ["记忆", "记住", "记录"]\ntools: [memory_write, memory_search]\n\n## Instructions\n自动从对话中提取有价值的信息...\n\n## Categories\n想法, 口吻, 喜好, 习惯, 近况, 目标, 世界观, 决策',
- },
- "Task Manager": {
- longDesc:
- "待办事项的完整生命周期管理:创建、分配、追踪、提醒。支持自然语言输入、自动拆解子任务、截止日提醒、与 Sprint 关联。",
- triggers: ["创建待办", "TODO 提醒", "截止日预警"],
- tools: ["task_create", "task_update", "calendar_read", "feishu_send"],
- auth: ["飞书 OAuth"],
- version: "1.8.0",
- updated: "2026-02-18",
- skillMd:
- '# Task Manager\n\ntriggers: ["待办", "任务", "TODO"]\nschedule: "0 10,15 * * *"\ntools: [task_create, task_update]\n\n## Instructions\n管理待办事项...',
- },
- "Daily Digest": {
- longDesc:
- "每日汇总日程、待办、紧急事项、记忆更新,生成简洁的晨间报告。支持自定义格式和推送渠道。",
- triggers: ["每天 08:30 自动触发"],
- tools: ["calendar_read", "task_list", "memory_search", "feishu_send"],
- auth: ["飞书 OAuth"],
- version: "1.5.0",
- updated: "2026-02-19",
- skillMd:
- '# Daily Digest\n\nschedule: "30 8 * * *"\ntools: [calendar_read, task_list, feishu_send]\n\n## Instructions\n汇总今日日程和待办...',
- },
- "Web Research": {
- longDesc: "联网搜索、信息整理、竞品分析。支持多源搜索、自动摘要、关键信息提取并写入记忆系统。",
- triggers: ["用户请求搜索", "竞品分析", "信息调研"],
- tools: ["web_search", "url_fetch", "markdown_write", "memory_write"],
- auth: [],
- version: "2.0.0",
- updated: "2026-02-21",
- skillMd:
- '# Web Research\n\ntriggers: ["搜索", "查一下", "调研"]\ntools: [web_search, url_fetch]\n\n## Instructions\n联网搜索相关信息...',
- },
- "Code Automation": {
- longDesc:
- "代码生成、PR 创建、自动化开发任务。支持读取项目上下文、生成代码片段、创建 PR、代码审查摘要。",
- triggers: ["代码生成请求", "PR 相关操作"],
- tools: ["code_write", "github_api", "file_read", "file_write"],
- auth: ["GitHub OAuth"],
- version: "1.3.0",
- updated: "2026-02-17",
- skillMd:
- '# Code Automation\n\ntriggers: ["写代码", "生成", "PR"]\ntools: [code_write, github_api]\n\n## Instructions\n根据用户需求生成代码...',
- },
- "PRD Generator": {
- longDesc:
- "需求文档生成与迭代。基于用户描述自动生成结构化 PRD,支持竞品参考、用户故事、优先级排序。",
- triggers: ["需求文档请求", "PRD 生成"],
- tools: ["markdown_write", "memory_search", "web_search"],
- auth: [],
- version: "1.0.0",
- updated: "2026-02-15",
- skillMd:
- '# PRD Generator\n\ntriggers: ["PRD", "需求文档", "产品方案"]\ntools: [markdown_write, memory_search]\n\n## Instructions\n生成产品需求文档...',
- },
- "Contact Intelligence": {
- longDesc:
- "联系人智能管理系统。自动从对话、会议、邮件中提取联系人信息,计算关系健康评分,追踪互动频率,标记需要关注的关键人脉。支持自然语言查询和跨模块主动关联。",
- triggers: ["联系人查询", "关系分析", "人脉管理", "谁"],
- tools: ["contact_scan", "contact_write", "memory_search", "feishu_contacts"],
- auth: ["飞书通讯录"],
- version: "1.0.0",
- updated: "2026-02-22",
- skillMd:
- '# Contact Intelligence\n\ntriggers: ["联系人", "关系", "谁", "上次聊"]\nschedule: "0 9 * * 1"\ntools: [contact_scan, contact_write, memory_search]\n\n## Instructions\n管理联系人网络,计算关系健康度...\n\n## Features\n- 关系健康评分 (互动频率 × 重要性)\n- 重复联系人检测和合并建议\n- 跨模块主动关联 (在其他 session 中插入相关联系人)',
- },
- "Meeting Action Tracker": {
- longDesc:
- '会议行动项全生命周期管理。从会议转录中提取 action items,区分"我的"和"对方的"(waiting on),自动追踪完成情况,未完成时主动提醒跟进。支持自我学习过滤。',
- triggers: ["会议", "action item", "行动项", "纪要"],
- tools: ["transcript_parse", "contact_match", "todo_create", "feishu_send"],
- auth: ["飞书 OAuth"],
- version: "1.0.0",
- updated: "2026-02-22",
- skillMd:
- '# Meeting Action Tracker\n\ntriggers: ["会议", "action item", "行动项"]\ntools: [transcript_parse, contact_match, todo_create]\n\n## Instructions\n1. 解析会议转录\n2. 匹配联系人\n3. 提取 action items,区分 mine vs theirs\n4. 创建 Todo,设置追踪\n\n## Smart Features\n- "waiting on" 追踪对方承诺\n- 自我学习过滤(用户拒绝后更新规则)\n- 每天 3 次自动检查完成情况\n- 14 天自动归档',
- },
- "Advisory Board": {
- longDesc:
- "多 Agent 顾问委员会。将业务数据分配给多个专家角色(财务/营销/增长/运营/产品等),各自独立分析后互相讨论分歧,合并成按优先级排序的建议清单。每天凌晨自动运行。",
- triggers: ["顾问", "分析", "决策建议", "综合评估"],
- tools: ["multi_agent_dispatch", "data_aggregate", "markdown_write", "feishu_send"],
- auth: [],
- version: "1.0.0",
- updated: "2026-02-22",
- skillMd:
- '# Advisory Board\n\ntriggers: ["顾问", "分析", "决策"]\nschedule: "0 2 * * *"\ntools: [multi_agent_dispatch, data_aggregate]\n\n## Instructions\n1. 收集 N 个数据源\n2. 分配给 M 个专家 Agent 并行分析\n3. 汇总分歧,互相辩论\n4. 合并为按优先级排序的建议清单\n5. 编号摘要发送到 IM\n\n## Expert Roles\n财务, 营销, 增长, 运营, 产品, 技术, 用户体验, 竞争分析',
- },
-};
-
-function SkillDetailPanel({ skill, onClose }: { skill: Skill; onClose: () => void }) {
- const detail = SKILL_DETAILS[skill.name];
- const { expandFileTree } = useProductLayout();
-
- return (
- !open && onClose()}>
-
-
-
-
-
-
-
-
-
-
{skill.name}
- {skill.certified ? : null}
-
-
{skill.author}
-
-
-
- {skill.installs} 安装
-
- {detail ? (
- <>
- v{detail.version}
- 更新于 {detail.updated}
- >
- ) : null}
-
-
-
-
-
-
-
- {skill.installed ? (
- <>
-
-
- 已安装
-
-
- 卸载
-
- >
- ) : (
-
-
- 安装此 Skill
-
- )}
-
-
-
-
-
-
-
- 描述
-
-
- {detail?.longDesc || skill.desc}
-
-
-
- {detail && (
-
-
- 触发条件
-
-
- {detail.triggers.map((t) => (
-
-
- {t}
-
- ))}
-
-
- )}
-
- {detail && (
-
-
- 使用工具
-
-
- {detail.tools.map((t) => (
-
- {t}
-
- ))}
-
-
- )}
-
- {detail && detail.auth.length > 0 && (
-
-
- 需要授权
-
-
- {detail.auth.map((a) => (
-
-
- {a}
-
- 已授权
-
-
- ))}
-
-
- )}
-
- {detail && (
-
-
-
-
- SKILL.md
-
-
- ~/clone/skills/{skill.name.toLowerCase().replace(/\s+/g, "-")}/
-
-
-
- {detail.skillMd}
-
-
- )}
-
-
-
- Skill metadata, auth, and source are managed here.
-
- 打开 Session
-
-
-
-
-
- );
-}
-
-function ChatCreatorModal({ onClose }: { onClose: () => void }) {
- const [input, setInput] = useState("");
- const chatMessages = [
- { from: "system" as const, content: "你好!告诉我你想要什么样的 Skill,我帮你生成。" },
- { from: "user" as const, content: "我想要一个每天早上自动汇总 GitHub PR 的技能" },
- {
- from: "system" as const,
- content:
- "明白了!让我帮你拆解:\n\n📌 技能名称:GitHub PR Digest\n⏰ 触发条件:每天 09:00\n🔧 调用工具:GitHub API\n📄 输出格式:Markdown 摘要\n\n我来生成 SKILL.md...",
- },
- ];
-
- return (
-
- );
-}
-
-function WorkflowEditorModal({ onClose }: { onClose: () => void }) {
- const NODES = [
- {
- id: "trigger",
- label: "触发",
- desc: "每天 09:00",
- icon: Zap,
- x: 60,
- y: 40,
- color: "text-warning",
- },
- {
- id: "fetch",
- label: "GitHub API",
- desc: "获取 Open PRs",
- icon: Code,
- x: 220,
- y: 40,
- color: "text-info",
- },
- {
- id: "filter",
- label: "过滤",
- desc: "只看 my team",
- icon: GitBranch,
- x: 380,
- y: 40,
- color: "text-role-programmer",
- },
- {
- id: "format",
- label: "格式化",
- desc: "Markdown 摘要",
- icon: FileText,
- x: 220,
- y: 140,
- color: "text-clone",
- },
- {
- id: "output",
- label: "推送",
- desc: "发到飞书",
- icon: Send,
- x: 380,
- y: 140,
- color: "text-success",
- },
- ];
-
- return (
-
- );
-}
-
-function SkillRow({ skill, onSelect }: { skill: Skill; onSelect: (s: Skill) => void }) {
- return (
- onSelect(skill)}
- tone="subtle"
- className="group border-transparent p-3"
- >
-
-
-
-
-
-
-
- {skill.name}
- {skill.certified && }
-
- {skill.desc}
-
-
- {skill.installed ? (
- e.stopPropagation()}
- aria-label={`编辑 ${skill.name}`}
- >
-
-
- ) : (
- {
- e.stopPropagation();
- }}
- aria-label={`安装 ${skill.name}`}
- title="安装"
- >
-
-
- )}
-
-
- );
-}
-
-function InstalledTab({
- installedSkills,
- onSelectSkill,
-}: {
- installedSkills: Skill[];
- onSelectSkill: (s: Skill) => void;
-}) {
- const [chatModal, setChatModal] = useState(false);
- const [workflowModal, setWorkflowModal] = useState(false);
-
- return (
-
-
-
setChatModal(true)}
- className="h-auto items-start justify-start gap-3 rounded-xl bg-surface-2 p-4 text-left"
- >
-
-
-
Skill Creator
-
Create or update a skill
-
-
-
setWorkflowModal(true)}
- className="h-auto items-start justify-start gap-3 rounded-xl bg-surface-2 p-4 text-left"
- >
-
-
-
-
-
Workflow Editor
-
Build visual skill workflows
-
-
-
-
-
- {installedSkills.map((s) => (
-
- ))}
-
-
- {chatModal &&
setChatModal(false)} />}
- {workflowModal && setWorkflowModal(false)} />}
-
- );
-}
-
-function FeaturedTab({ onSelectSkill }: { onSelectSkill: (s: Skill) => void }) {
- return (
-
-
- {FEATURED_SKILLS.map((f) => (
-
-
-
-
- {f.badge}
-
- {f.title}
-
-
-
- {f.desc}
- 精选推荐
-
-
- ))}
-
-
-
- {RECOMMENDED_SKILLS.slice(0, 6).map((s) => (
-
- ))}
-
-
- );
-}
-
-function ExploreTab({ onSelectSkill }: { onSelectSkill: (s: Skill) => void }) {
- const [query, setQuery] = useState("");
- const [category, setCategory] = useState("All");
-
- const filteredSkills = RECOMMENDED_SKILLS.filter((skill) => {
- const matchesQuery =
- query.trim().length === 0 ||
- `${skill.name} ${skill.desc} ${skill.author} ${skill.category}`
- .toLowerCase()
- .includes(query.toLowerCase());
- const matchesCategory = category === "All" || skill.category === category;
-
- return matchesQuery && matchesCategory;
- });
-
- return (
-
-
- setQuery(e.target.value)}
- placeholder="Search skills..."
- leadingIcon={}
- className="bg-surface-2"
- />
-
-
-
setCategory(value as ExploreCategory)}
- >
-
- {EXPLORE_CATEGORIES.map((item) => (
-
- {item === "All" ? item : `#${item}`}
-
- ))}
-
-
-
-
- {filteredSkills.length} skills available
-
-
- {filteredSkills.map((s) => (
-
- ))}
-
-
- );
-}
-
-const TABS_CONFIG = [
- { id: "installed" as const, label: "Installed", icon: Wrench },
- { id: "featured" as const, label: "Featured", icon: Star },
- { id: "explore" as const, label: "Explore", icon: Sparkles },
-];
-
-const EXPLORE_CATEGORIES: ExploreCategory[] = [
- "All",
- "integration",
- "developer",
- "productivity",
- "design",
- "business",
-];
-
-function isTabId(value: string): value is TabId {
- return TABS_CONFIG.some((tab) => tab.id === value);
-}
-
-export default function SkillsPage() {
- const [activeTab, setActiveTab] = useState("installed");
- const [selectedSkill, setSelectedSkill] = useState(null);
- const [importModalOpen, setImportModalOpen] = useState(false);
- const [importedSkills, setImportedSkills] = useState([]);
- const { expandFileTree } = useProductLayout();
- const navigate = useNavigate();
- const installedSkills = [...importedSkills, ...INSTALLED_SKILLS];
- const tabCounts: Record = {
- installed: installedSkills.length,
- featured: null,
- explore: RECOMMENDED_SKILLS.length,
- };
- const quickFindSkills = [...installedSkills, ...RECOMMENDED_SKILLS].filter(
- (skill, index, skills) =>
- skills.findIndex((candidate) => candidate.name === skill.name) === index,
- );
-
- const handleImportSkill = async (file: File) => {
- await new Promise((resolve) => window.setTimeout(resolve, 800));
-
- const nextSkill = createImportedSkill(file.name, installedSkills);
-
- setImportedSkills((current) => [nextSkill, ...current]);
- setActiveTab("installed");
- setSelectedSkill(nextSkill);
- };
-
- return (
-
-
-
- Give your clone superpowers.
-
-
- ~/clone/skills/
-
- >
- }
- actions={
-
-
setImportModalOpen(true)}>
-
- Import skill
-
-
navigate("/app/sessions")}>
-
- New skill
-
-
- }
- />
-
- {
- if (isTabId(value)) {
- setActiveTab(value);
- }
- }}
- >
-
-
- {TABS_CONFIG.map((t) => (
-
- {t.label}
- {tabCounts[t.id] != null && (
- {tabCounts[t.id]}
- )}
-
- ))}
-
-
-
-
-
-
{
- const nextSkill = quickFindSkills.find((skill) => skill.name === value);
- if (!nextSkill) return;
- setSelectedSkill(nextSkill);
- setActiveTab(nextSkill.installed ? "installed" : "explore");
- }}
- >
-
-
-
-
- {selectedSkill ? selectedSkill.name : "Search skills"}
-
-
-
-
- } />
-
- {quickFindSkills.map((skill) => (
-
-
-
- {skill.name}
-
-
- {skill.category} · {skill.author}
-
-
-
- ))}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {selectedSkill && (
-
setSelectedSkill(null)} />
- )}
- setImportModalOpen(false)}
- onImport={handleImportSkill}
- />
-
- );
-}
diff --git a/apps/demo/src/pages/product/TeamDetailPanels.tsx b/apps/demo/src/pages/product/TeamDetailPanels.tsx
deleted file mode 100644
index cb23cd2d..00000000
--- a/apps/demo/src/pages/product/TeamDetailPanels.tsx
+++ /dev/null
@@ -1,1703 +0,0 @@
-import {
- Badge,
- Button,
- DetailPanel,
- DetailPanelCloseButton,
- DetailPanelContent,
- DetailPanelHeader,
- DetailPanelTitle,
- FollowUpInput,
- PanelFooter,
- PanelFooterActions,
- TagGroup,
- TagGroupItem,
-} from "@nexu-design/ui-web";
-import {
- Activity,
- AlertTriangle,
- ArrowRight,
- ArrowUpRight,
- BarChart3,
- CheckCircle,
- Clock,
- FileText,
- GitPullRequest,
- MessageSquare,
- Users,
- X,
-} from "lucide-react";
-import type * as React from "react";
-import {
- type ALIGNMENT_HISTORY,
- type ActivityItem,
- type BIPStep,
- CARD_BIP_FLOWS,
- CARD_FILE_OPS,
- type FileOp,
- type IMCard,
- MEMBER_ACTIVITIES,
- OBJECTIVES,
- SPRINT_TASKS,
- type SprintTask,
- TASK_BOARD,
- TASK_CHANGE_LOGS,
- TEAM_MEMBERS,
- type TaskItem,
- type TeamMember,
-} from "./teamData";
-
-// ─── Shared Components ─────────────────────────────────────
-
-function PanelShell({
- title,
- badge,
- badgeColor,
- icon: Icon,
- onClose,
- children,
- footer,
-}: {
- title: string;
- badge?: string;
- badgeColor?: string;
- icon: React.ElementType;
- onClose: () => void;
- children: React.ReactNode;
- footer?: React.ReactNode;
-}) {
- return (
-
-
-
-
-
-
- {title}
-
- {badge ? (
-
- {badge}
-
- ) : null}
-
-
-
- {children}
-
- {footer ? (
-
- {footer}
-
- ) : null}
-
- );
-}
-
-function BIPFlowSection({ steps }: { steps: BIPStep[] }) {
- return (
-
-
- BIP 协议流程
-
-
- {steps.map((step, i) => (
-
-
-
- {step.status === "done" ? "✓" : step.status === "active" ? "⏳" : i + 1}
-
- {i < steps.length - 1 && (
-
- )}
-
-
-
{step.label}
- {step.detail && (
-
{step.detail}
- )}
-
-
- ))}
-
-
- );
-}
-
-function FileOpsSection({ ops }: { ops: FileOp[] }) {
- const ACTION_STYLES: Record = {
- read: { color: "text-info bg-info-subtle", label: "READ" },
- write: { color: "text-clone bg-clone/10", label: "WRITE" },
- create: { color: "text-success bg-success-subtle", label: "CREATE" },
- };
-
- return (
-
-
- 文件操作
-
-
- {ops.map((op) => {
- const s = ACTION_STYLES[op.action];
- const parts = op.path.split("/");
- const file = parts[parts.length - 1] ?? op.path;
- return (
-
-
- {s.label}
-
-
- {file}
-
- {parts.join("/")}/
-
-
- );
- })}
-
-
- );
-}
-
-function ActivitySection({
- items,
- title,
-}: {
- items: ActivityItem[];
- title?: string;
-}) {
- const TYPE_ICONS: Record = {
- card: { icon: MessageSquare, color: "text-clone" },
- task: { icon: Activity, color: "text-info" },
- alignment: { icon: GitPullRequest, color: "text-warning" },
- session: { icon: MessageSquare, color: "text-success" },
- };
-
- return (
-
-
- {title || "最近活动"}
-
-
- {items.map((item) => {
- const t = TYPE_ICONS[item.type];
- return (
-
-
-
-
{item.content}
-
{item.time}
-
-
- );
- })}
-
-
- );
-}
-
-function getCardPanelTitle(card: IMCard): string {
- if (card.type === "summary_report") return "站会汇总详情";
- if (card.type === "status_query") return `${card.target} 任务进度`;
- if (card.type === "alignment_request") return card.topic;
- if (card.type === "event_notification") return card.event;
- return card.taskTitle;
-}
-
-// ─── Card Detail Panel ─────────────────────────────────────
-
-const CARD_TYPE_LABELS: Record = {
- summary_report: { label: "站会汇总", color: "bg-clone/10 text-clone" },
- status_query: { label: "状态查询", color: "bg-info-subtle text-info" },
- alignment_request: {
- label: "对齐请求",
- color: "bg-warning-subtle text-warning",
- },
- event_notification: {
- label: "事件通知",
- color: "bg-success-subtle text-success",
- },
- growth_trigger: { label: "裂变触发", color: "bg-accent/10 text-accent" },
-};
-
-export function CardDetailPanel({
- card,
- onClose,
-}: {
- card: IMCard;
- onClose: () => void;
-}) {
- const typeInfo = CARD_TYPE_LABELS[card.type];
- const bipFlow = CARD_BIP_FLOWS[card.id];
- const fileOps = CARD_FILE_OPS[card.id];
-
- return (
-
-
-
-
- 在 Session 中展开
-
-
- 查看相关任务
-
-
-
- }
- >
- {/* Card meta */}
-
-
- {/* Type-specific summary */}
-
-
- 摘要
-
- {card.type === "summary_report" && (
-
-
- Sprint 进度
- {card.progress}%
-
-
-
- {card.members.map((m) => (
-
- {m.avatar}
- {m.name}
- — {m.summary}
-
- ))}
-
- {card.risks.length > 0 && (
-
- {card.risks.map((r) => (
-
- ))}
-
- )}
-
- )}
- {card.type === "status_query" && (
-
- {card.tasks.map((t) => (
-
- {t.name}
- = 100 ? "text-success font-medium" : "text-text-muted"}
- >
- {t.progress}%
-
-
- ))}
- {card.note && (
-
- 💬 {card.note}
-
- )}
-
- )}
- {card.type === "alignment_request" && (
-
-
{card.topic}
-
{card.reason}
-
🎯 {card.suggestion}
-
- )}
- {card.type === "event_notification" && (
-
-
{card.impact}
- {card.updates.map((u) => (
-
- ))}
-
- )}
- {card.type === "growth_trigger" && (
-
-
-
-
{card.timeSaved}
-
实际耗时
-
-
-
- {card.manualEstimate}
-
-
手动预估
-
-
-
- 💡 本周: {card.weeklyStats.tasks} 任务 · 节省 {card.weeklyStats.hours}h
-
-
- )}
-
-
- {/* BIP Flow */}
- {bipFlow && }
-
- {/* File Ops */}
- {fileOps && fileOps.length > 0 && }
-
- );
-}
-
-// ─── Member Detail Panel ───────────────────────────────────
-
-export function MemberDetailPanel({
- member,
- onClose,
-}: {
- member: TeamMember;
- onClose: () => void;
-}) {
- const tasks = SPRINT_TASKS.filter((t) => t.assignee === member.name);
- const activities = MEMBER_ACTIVITIES[member.name] || [];
-
- const STATUS_LABELS: Record = {
- online: { label: "在线", color: "text-success" },
- busy: { label: "忙碌", color: "text-warning" },
- away: { label: "离开", color: "text-text-muted" },
- offline: { label: "离线", color: "text-text-muted" },
- };
-
- const TASK_STYLES: Record = {
- done: { bg: "bg-success-subtle", text: "text-success", label: "完成" },
- in_progress: { bg: "bg-clone/10", text: "text-clone", label: "进行中" },
- blocked: { bg: "bg-danger-subtle", text: "text-danger", label: "阻塞" },
- todo: { bg: "bg-surface-3", text: "text-text-muted", label: "待开始" },
- };
-
- const statusInfo = STATUS_LABELS[member.status];
-
- return (
-
-
- 查询进度
-
-
- 发起对齐
-
-
- }
- >
- {/* Profile header */}
-
-
-
-
- {member.avatar}
-
-
-
-
-
- {member.name}
-
- Lv.{member.level}
-
- {statusInfo.label}
-
-
- {member.role} · {member.channel}
-
-
-
-
- {[
- {
- label: "进行中",
- value: member.tasksInProgress,
- color: "text-text-primary",
- },
- {
- label: "已完成",
- value: member.tasksCompleted,
- color: "text-success",
- },
- {
- label: "默契度",
- value: `${member.alignmentRate}%`,
- color: "text-clone",
- },
- {
- label: "最近活跃",
- value: member.lastActive,
- color: "text-text-muted",
- small: true,
- },
- ].map((s: { label: string; value: string | number; color: string; small?: boolean }) => (
-
-
- {s.value}
-
-
{s.label}
-
- ))}
-
-
-
- {/* Current tasks */}
-
-
- 当前任务 ({tasks.length})
-
-
- {tasks.map((task) => {
- const st = TASK_STYLES[task.status];
- return (
-
-
- {st.label}
-
-
{task.title}
-
-
= 100 ? "bg-success" : "bg-clone"
- }`}
- style={{ width: `${task.progress}%` }}
- />
-
-
{task.progress}%
-
- );
- })}
- {tasks.length === 0 && (
-
暂无任务
- )}
-
-
-
- {/* Recent activities */}
-
-
- );
-}
-
-// ─── Alignment Detail Panel ────────────────────────────────
-
-export function AlignmentDetailPanel({
- alignment,
- onClose,
-}: {
- alignment: (typeof ALIGNMENT_HISTORY)[number];
- onClose: () => void;
-}) {
- return (
-
-
- 查看相关对话
-
-
- 重新发起
-
-
- }
- >
- {/* Alignment summary */}
-
-
-
- {alignment.fromAvatar}
-
-
-
- 来自 {alignment.from}的分身
-
-
{alignment.time}
-
-
-
-
-
话题
-
{alignment.topic}
-
-
-
📎 原因
-
{alignment.reason}
-
-
-
-
- {/* Decision */}
-
-
- 处理结果
-
-
- {alignment.status === "accepted" ? (
-
- ) : (
-
- )}
-
-
- {alignment.status === "accepted" ? "已同意" : "已拒绝"}
-
-
{alignment.response}
-
-
-
-
- {/* BIP flow */}
-
-
- {/* Impact */}
-
-
- 影响范围
-
-
-
-
- 涉及成员
- {alignment.from}、你
-
-
-
- 相关文件
-
- team/decisions/
-
-
-
-
-
- );
-}
-
-// ─── Task Detail Panel ─────────────────────────────────────
-
-export function TaskDetailPanel({
- task,
- onClose,
-}: {
- task: SprintTask;
- onClose: () => void;
-}) {
- const member = TEAM_MEMBERS.find((m) => m.name === task.assignee);
- const changeLogs = TASK_CHANGE_LOGS[task.id] || [];
- const downstream = SPRINT_TASKS.filter((t) => t.dependency === task.id);
- const upstream = task.dependency ? SPRINT_TASKS.find((t) => t.id === task.dependency) : null;
-
- const TASK_STYLES: Record
= {
- done: { bg: "bg-success-subtle", text: "text-success", label: "已完成" },
- in_progress: { bg: "bg-clone/10", text: "text-clone", label: "进行中" },
- blocked: { bg: "bg-danger-subtle", text: "text-danger", label: "阻塞中" },
- todo: { bg: "bg-surface-3", text: "text-text-muted", label: "待开始" },
- };
-
- const st = TASK_STYLES[task.status];
-
- return (
-
-
-
-
- 查询详细进度
-
-
-
- }
- >
- {/* Task overview */}
-
-
-
-
进度
-
-
-
= 100 ? "bg-success" : "bg-clone"
- }`}
- style={{ width: `${task.progress}%` }}
- />
-
-
- {task.progress}%
-
-
-
-
-
-
- {/* Assignee */}
- {member && (
-
-
- {member.avatar}
-
-
-
{member.name}
-
- {member.role} · {member.channel}
-
-
-
Lv.{member.level}
-
- )}
-
-
- {/* Dependencies */}
- {(upstream || downstream.length > 0) && (
-
-
- 依赖关系
-
-
- {upstream && (
-
-
- 上游
-
- {upstream.id}
- {upstream.title}
- {upstream.assignee}
-
- )}
- {downstream.map((d) => (
-
-
- 下游
-
- {d.id}
- {d.title}
- {d.assignee}
-
- ))}
-
-
- )}
-
- {/* Change log */}
- {changeLogs.length > 0 && (
-
-
- 变更记录
-
-
- {changeLogs.map((log) => (
-
-
- {log.time}
-
- {log.from} → {log.to}
-
-
- ))}
-
-
- )}
-
- {/* Related files */}
-
-
- 相关文件
-
-
-
-
- sprint.md
- team/
-
- {task.status === "blocked" && upstream && (
-
-
- gateway-priority.md
- team/decisions/
-
- )}
-
-
-
- );
-}
-
-// ─── Stats Detail Panel ────────────────────────────────────
-
-const STAT_PANEL_CONFIG: Record
= {
- okr: { title: "OKR 概览", icon: Activity },
- online: { title: "分身在线状态", icon: Users },
- cards: { title: "今日任务流", icon: MessageSquare },
- alignments: { title: "待对齐请求", icon: GitPullRequest },
- tasks: { title: "活跃任务", icon: CheckCircle },
- sprint: { title: "Sprint 进度", icon: BarChart3 },
-};
-
-export function StatsDetailPanel({
- statId,
- onClose,
-}: {
- statId: string;
- onClose: () => void;
-}) {
- const cfg = STAT_PANEL_CONFIG[statId] || STAT_PANEL_CONFIG.sprint;
- return (
-
- {statId === "online" && (
-
-
- 成员状态
-
-
- {TEAM_MEMBERS.map((m) => (
-
-
-
-
- {m.status === "online" ? "在线" : m.status === "busy" ? "忙碌" : "离开"}
-
-
{m.lastActive}
-
- ))}
-
-
- )}
- {statId === "cards" && (
-
-
- 今日卡片分布
-
-
- {[
- { type: "站会汇总", count: 1, color: "bg-clone" },
- { type: "状态查询", count: 1, color: "bg-info" },
- { type: "事件通知", count: 1, color: "bg-success" },
- { type: "对齐请求", count: 1, color: "bg-warning" },
- { type: "裂变触发", count: 1, color: "bg-accent" },
- ].map((c) => (
-
-
-
{c.type}
-
- {c.count}
-
-
- ))}
-
-
-
- 未读
- 2
-
-
- 已读
- 3
-
-
-
- )}
- {statId === "alignments" && (
-
-
- 待处理
-
-
-
Gateway 重构排期提前
-
- 来自张三的分身 · 紧急程度:高
-
-
-
- ✅ 同意
-
-
- ❌ 拒绝
-
-
-
-
- 本周统计
-
-
-
- )}
- {statId === "sprint" && (
-
-
- Sprint 3 概览
-
-
-
- 整体进度
- 58%
-
-
-
- 02-17 → 03-02
- 剩余 7 天
-
-
-
- {[
- {
- label: "已完成",
- value: SPRINT_TASKS.filter((t) => t.status === "done").length,
- color: "text-success",
- },
- {
- label: "进行中",
- value: SPRINT_TASKS.filter((t) => t.status === "in_progress").length,
- color: "text-clone",
- },
- {
- label: "阻塞",
- value: SPRINT_TASKS.filter((t) => t.status === "blocked").length,
- color: "text-danger",
- },
- {
- label: "待开始",
- value: SPRINT_TASKS.filter((t) => t.status === "todo").length,
- color: "text-text-muted",
- },
- ].map((s) => (
-
-
{s.value}
-
{s.label}
-
- ))}
-
-
- )}
- {statId === "okr" &&
- (() => {
- const okrProgress = Math.round(
- OBJECTIVES.reduce((s, o) => s + o.progress, 0) / OBJECTIVES.length,
- );
- const atRisk = OBJECTIVES.filter((o) => o.status === "at_risk" || o.status === "behind");
- const onTrack = OBJECTIVES.filter((o) => o.status === "on_track");
- const achieved = OBJECTIVES.filter((o) => o.status === "achieved");
- return (
-
-
-
- 整体 OKR 完成度
- {okrProgress}%
-
-
-
-
-
-
- {achieved.length + onTrack.length}
-
-
正常
-
-
-
- {atRisk.filter((o) => o.status === "at_risk").length}
-
-
有风险
-
-
-
- {atRisk.filter((o) => o.status === "behind").length}
-
-
落后
-
-
-
- 各目标进度
-
-
- {OBJECTIVES.map((o) => {
- const st =
- o.status === "on_track"
- ? "text-success"
- : o.status === "at_risk"
- ? "text-warning"
- : o.status === "behind"
- ? "text-danger"
- : "text-success";
- return (
-
-
-
- {o.title}
-
- {o.progress}%
-
-
-
- {o.owner}
-
- {o.keyResults.length} KRs
-
-
-
- );
- })}
-
-
- );
- })()}
- {statId === "tasks" &&
- (() => {
- const inProgress = TASK_BOARD.filter((t) => t.status === "in_progress");
- const todo = TASK_BOARD.filter((t) => t.status === "todo");
- const done = TASK_BOARD.filter((t) => t.status === "done");
- const agentTasks = TASK_BOARD.filter((t) => t.executor === "agent");
- const activeTasks = [...inProgress, ...todo];
- return (
-
-
-
-
{inProgress.length}
-
进行中
-
-
-
-
-
{agentTasks.length}
-
Agent 执行
-
-
-
- 活跃任务
-
-
- {activeTasks.slice(0, 6).map((t) => {
- const prioColor =
- t.priority === "urgent"
- ? "text-danger"
- : t.priority === "high"
- ? "text-warning"
- : "text-text-muted";
- const statusDot =
- t.status === "in_progress" ? "bg-clone animate-pulse" : "bg-surface-4";
- const execIcon =
- t.executor === "agent" ? "🤖" : t.executor === "hybrid" ? "🤝" : "👤";
- return (
-
-
-
-
- {t.title}
-
-
- {t.priority}
- {t.assignee}
-
-
-
{execIcon}
- {t.progress > 0 && (
-
- {t.progress}%
-
- )}
-
- );
- })}
-
-
- );
- })()}
-
- );
-}
-
-// ─── OKR Detail Panel ──────────────────────────────────────
-
-const OKR_STATUS_INFO: Record = {
- on_track: { label: "On Track", color: "bg-success-subtle text-success" },
- at_risk: { label: "At Risk", color: "bg-warning-subtle text-warning" },
- behind: { label: "Behind", color: "bg-danger-subtle text-danger" },
- achieved: { label: "Achieved", color: "bg-success-subtle text-success" },
-};
-
-export function OKRDetailPanel({
- objectiveId,
- krId,
- onClose,
-}: {
- objectiveId?: string;
- krId?: string;
- onClose: () => void;
-}) {
- const objective = OBJECTIVES.find(
- (o) => o.id === objectiveId || o.keyResults.some((kr) => kr.id === krId),
- );
- const keyResult = objective?.keyResults.find((kr) => kr.id === krId);
-
- if (!objective) return null;
-
- const statusInfo = OKR_STATUS_INFO[objective.status];
-
- return (
- = 80
- ? "bg-success-subtle text-success"
- : keyResult.progress >= 50
- ? "bg-clone/10 text-clone"
- : "bg-warning-subtle text-warning"
- : statusInfo.color
- }
- icon={Activity}
- onClose={onClose}
- footer={
-
-
- 讨论 OKR
-
-
- 编辑目标
-
-
- }
- >
- {/* Objective overview */}
-
-
- {objective.id}
-
- {statusInfo.label}
-
- {objective.quarter}
-
-
- {objective.title}
-
-
{objective.description}
-
-
-
- 整体进度
- {objective.progress}%
-
-
-
= 80
- ? "bg-success"
- : objective.progress >= 50
- ? "bg-clone"
- : "bg-warning"
- }`}
- style={{ width: `${objective.progress}%` }}
- />
-
-
-
-
- {/* Key Results list */}
-
-
- Key Results ({objective.keyResults.length})
-
-
- {objective.keyResults.map((kr) => {
- const isHighlighted = kr.id === krId;
- return (
-
-
- {kr.title}
- = 100
- ? "text-success"
- : kr.progress >= 50
- ? "text-clone"
- : "text-warning"
- }`}
- >
- {kr.progress}%
-
-
-
-
= 100
- ? "bg-success"
- : kr.progress >= 50
- ? "bg-clone"
- : "bg-warning"
- }`}
- style={{ width: `${kr.progress}%` }}
- />
-
-
-
- {kr.current} / {kr.target}
-
- {kr.owner}
-
- {kr.linkedTasks.length > 0 && (
-
- {kr.linkedTasks.map((tid) => {
- const task = SPRINT_TASKS.find((t) => t.id === tid);
- return task ? (
-
- {tid} {task.title}
-
- ) : null;
- })}
-
- )}
-
- );
- })}
-
-
-
- {/* Owner & tags */}
-
-
- 信息
-
-
-
-
- 负责人
-
- {objective.ownerAvatar} {objective.owner}
-
-
-
-
-
达标 KR
-
- {objective.keyResults.filter((kr) => kr.progress >= 100).length}/
- {objective.keyResults.length}
-
-
-
-
- {objective.tags.map((t) => (
-
- {t}
-
- ))}
-
-
-
- );
-}
-
-// ─── Task Item Detail Panel ─────────────────────────────────
-
-const TASK_STATUS_MAP: Record
= {
- backlog: { bg: "bg-surface-3", text: "text-text-muted", label: "待规划" },
- todo: { bg: "bg-info-subtle", text: "text-info", label: "待开始" },
- in_progress: { bg: "bg-clone/10", text: "text-clone", label: "进行中" },
- done: { bg: "bg-success-subtle", text: "text-success", label: "已完成" },
- archived: { bg: "bg-surface-3", text: "text-text-muted", label: "已归档" },
-};
-
-const PRIORITY_MAP: Record = {
- urgent: { text: "text-danger", label: "紧急" },
- high: { text: "text-warning", label: "高" },
- medium: { text: "text-info", label: "中" },
- low: { text: "text-text-muted", label: "低" },
-};
-
-const EXECUTOR_MAP: Record = {
- human: { label: "人工执行", emoji: "👤" },
- agent: { label: "Agent 执行", emoji: "🤖" },
- hybrid: { label: "人 + Agent", emoji: "🤝" },
-};
-
-export function TaskItemDetailPanel({
- task,
- onClose,
-}: {
- task: TaskItem;
- onClose: () => void;
-}) {
- const st = TASK_STATUS_MAP[task.status];
- const pr = PRIORITY_MAP[task.priority];
- const ex = EXECUTOR_MAP[task.executor];
- const member = TEAM_MEMBERS.find((m) => m.name === task.assignee);
- const deps = task.dependencies ? TASK_BOARD.filter((t) => task.dependencies?.includes(t.id)) : [];
- const dependents = TASK_BOARD.filter((t) => t.dependencies?.includes(task.id));
- const subtasksDone = task.subtasks?.filter((s) => s.done).length ?? 0;
- const subtasksTotal = task.subtasks?.length ?? 0;
-
- return (
-
-
-
- {task.status === "in_progress" && (
-
- 标记完成
-
- )}
- {task.executor !== "agent" && (
-
- 🤖 委托给 Agent
-
- )}
-
-
- }
- >
- {/* Overview */}
-
-
-
-
-
-
执行方式
-
- {ex.emoji} {ex.label}
-
-
-
-
- {/* Progress */}
-
-
-
- 进度 {subtasksTotal > 0 && `(${subtasksDone}/${subtasksTotal} 子任务)`}
-
-
- {task.progress}%
-
-
-
-
= 100 ? "bg-success" : "bg-clone"}`}
- style={{ width: `${task.progress}%` }}
- />
-
-
-
- {/* Assignee */}
- {member && (
-
-
- {member.avatar}
-
-
-
{member.name}
-
- {member.role} · Lv.{member.level}
-
-
-
{member.channel}
-
- )}
-
-
- {/* Description */}
- {task.description && (
-
-
- 描述
-
-
{task.description}
-
- )}
-
- {/* Subtasks */}
- {task.subtasks && task.subtasks.length > 0 && (
-
-
- 子任务 ({subtasksDone}/{subtasksTotal})
-
-
- {task.subtasks.map((sub) => (
-
- {sub.done ? (
-
- ) : (
-
- )}
-
- {sub.title}
-
-
- ))}
-
-
- )}
-
- {/* Meta */}
-
-
- 详细信息
-
-
- {task.sprintId && (
-
- Sprint
- {task.sprintId}
-
- )}
- {task.okrTitle && (
-
- OKR
-
- {task.okrId} {task.okrTitle}
-
-
- )}
- {task.dueDate && (
-
- 截止日期
-
- {task.dueDate}
-
-
- )}
-
- 来源
- {task.sourceRef ?? task.source}
-
-
- 创建时间
- {task.createdAt}
-
-
- 更新时间
- {task.updatedAt}
-
-
-
-
- {/* Dependencies */}
- {(deps.length > 0 || dependents.length > 0) && (
-
-
- 依赖关系
-
- {deps.length > 0 && (
-
-
依赖(上游)
- {deps.map((d) => (
-
-
-
{d.id}
-
{d.title}
-
{d.progress}%
-
- ))}
-
- )}
- {dependents.length > 0 && (
-
-
被依赖(下游)
- {dependents.map((d) => (
-
- ))}
-
- )}
-
- )}
-
- {/* Linked files */}
- {task.linkedFiles && task.linkedFiles.length > 0 && (
-
-
- 关联文件
-
-
- {task.linkedFiles.map((f) => (
-
- ))}
-
-
- )}
-
- {/* Tags */}
-
-
- 标签
-
-
- {task.tags.map((tag) => (
-
- {tag}
-
- ))}
-
-
-
- );
-}
diff --git a/apps/demo/src/pages/product/TeamInsightsChat.tsx b/apps/demo/src/pages/product/TeamInsightsChat.tsx
deleted file mode 100644
index c13bdc9e..00000000
--- a/apps/demo/src/pages/product/TeamInsightsChat.tsx
+++ /dev/null
@@ -1,335 +0,0 @@
-import { Badge, Button, ConversationMessage, Progress, Textarea } from "@nexu-design/ui-web";
-import {
- BarChart3,
- ChevronDown,
- ChevronUp,
- Lightbulb,
- Link2,
- Maximize2,
- MessageSquare,
- Minimize2,
- Send,
- Sparkles,
- Target,
- Users,
-} from "lucide-react";
-import { useEffect, useRef, useState } from "react";
-import { INSIGHT_CONVERSATIONS, INSIGHT_SUGGESTIONS, type InsightMessage } from "./teamData";
-
-const REF_TYPE_STYLES: Record
= {
- task: { icon: BarChart3, color: "text-clone bg-clone/10" },
- member: { icon: Users, color: "text-info bg-info-subtle" },
- okr: { icon: Target, color: "text-accent bg-accent/10" },
- card: { icon: MessageSquare, color: "text-warning bg-warning-subtle" },
-};
-
-function InlineChart({
- chart,
-}: {
- chart: NonNullable;
-}) {
- if (chart.type === "bar") {
- const max = Math.max(...chart.data.map((d) => d.value));
- return (
-
-
成员进度对比
-
- {chart.data.map((d) => (
-
-
{d.label}
-
-
- {d.value > 15 && (
-
{d.value}%
- )}
-
- {d.value <= 15 && (
-
{d.value}%
- )}
-
- ))}
-
-
- );
- }
-
- return (
-
- {chart.data.map((d) => (
-
-
-
-
- {d.value}%
-
-
-
{d.label}
-
- ))}
-
- );
-}
-
-function ChatMessage({ msg }: { msg: InsightMessage }) {
- const isAgent = msg.from === "agent";
-
- return (
-
-
-
-
- ) : undefined
- }
- bubbleClassName={
- isAgent ? "bg-surface-1 text-[12px]" : "bg-accent text-accent-fg text-[12px]"
- }
- meta={msg.time}
- >
-
- {msg.content.split(/(\*\*[^*]+\*\*)/g).map((part) => {
- if (part.startsWith("**") && part.endsWith("**")) {
- return (
-
- {part.slice(2, -2)}
-
- );
- }
- return {part};
- })}
-
- {msg.chart && }
-
-
- {msg.references && msg.references.length > 0 && (
-
- {msg.references.map((ref) => {
- const st = REF_TYPE_STYLES[ref.type];
- return (
-
-
- {ref.label}
-
-
- );
- })}
-
- )}
-
- );
-}
-
-type ChatMode = "collapsed" | "default" | "fullscreen";
-
-const MODE_HEIGHT: Record
= {
- collapsed: "h-[44px]",
- default: "h-[380px]",
- fullscreen: "h-[80vh]",
-};
-
-export default function TeamInsightsChat() {
- const [mode, setMode] = useState("collapsed");
- const [input, setInput] = useState("");
- const [messages, setMessages] = useState(INSIGHT_CONVERSATIONS);
- const scrollRef = useRef(null);
-
- const isOpen = mode !== "collapsed";
-
- useEffect(() => {
- if (isOpen && scrollRef.current) {
- scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
- }
- }, [isOpen]);
-
- const toggleCollapse = () => {
- setMode((prev) => (prev === "collapsed" ? "default" : "collapsed"));
- };
-
- const toggleFullscreen = (e: React.MouseEvent) => {
- e.stopPropagation();
- setMode((prev) => (prev === "fullscreen" ? "default" : "fullscreen"));
- };
-
- const handleSend = () => {
- if (!input.trim()) return;
- const newMsg: InsightMessage = {
- id: `i-${Date.now()}`,
- from: "user",
- content: input,
- time: new Date().toLocaleTimeString("zh-CN", {
- hour: "2-digit",
- minute: "2-digit",
- }),
- };
- setMessages((prev) => [...prev, newMsg]);
- setInput("");
-
- setTimeout(() => {
- const reply: InsightMessage = {
- id: `i-${Date.now()}-r`,
- from: "agent",
- content:
- "正在分析团队数据...\n\n我已检索了 Sprint 任务状态、OKR 进度、成员负载和 IM 卡片流。基于当前数据,我建议关注以下几点:\n\n1. 优先推动 Gateway 重构加速\n2. 重新评估王五的任务分配\n3. 在下周站会中同步 OKR 进展",
- time: new Date().toLocaleTimeString("zh-CN", {
- hour: "2-digit",
- minute: "2-digit",
- }),
- references: [
- { type: "task", label: "T-003 Gateway 重构", id: "T-003" },
- { type: "member", label: "王五", id: "王五" },
- ],
- };
- setMessages((prev) => [...prev, reply]);
- }, 800);
- };
-
- return (
-
- {/* Header bar — always visible */}
-
-
- Team Insights
-
- Scoped Session
-
- — 限定团队分析 Skills
-
- {!isOpen && 点击展开对话...}
- {isOpen && (
-
- {mode === "fullscreen" ? : }
-
- )}
- {isOpen ? (
-
- ) : (
-
- )}
-
-
-
- {/* Chat area */}
- {isOpen && (
-
- {/* Messages */}
-
- {/* Welcome message if empty */}
- {messages.length === 0 && (
-
-
-
- 问我任何关于团队的问题
-
-
- 我可以分析 Sprint 进度、OKR 健康度、成员负载、依赖风险等
-
-
- 这是一个 Scoped Session — 和主
- Session 一样是 Chat,但限定了团队分析相关的 Skills
- 和上下文。更通用的操作可以回到主线会话
-
-
- )}
- {messages.map((msg) => (
-
- ))}
-
-
- {/* Suggestions */}
-
- 快捷:
- {INSIGHT_SUGGESTIONS.slice(0, 4).map((s) => (
- {
- setInput(s);
- }}
- className="h-6 whitespace-nowrap"
- >
- {s}
-
- ))}
-
-
- {/* Input */}
-
-
- )}
-
- );
-}
diff --git a/apps/demo/src/pages/product/TeamOKR.tsx b/apps/demo/src/pages/product/TeamOKR.tsx
deleted file mode 100644
index 15130251..00000000
--- a/apps/demo/src/pages/product/TeamOKR.tsx
+++ /dev/null
@@ -1,344 +0,0 @@
-import {
- AlertCircle,
- AlertTriangle,
- BarChart3,
- CheckCircle,
- ChevronDown,
- ChevronRight,
- Link2,
- Target,
- Users,
-} from "lucide-react";
-import { useState } from "react";
-import { type KeyResult, OBJECTIVES, type Objective, SPRINT_TASKS } from "./teamData";
-
-const OKR_STATUS_STYLES: Record<
- Objective["status"],
- { bg: string; text: string; label: string; icon: React.ElementType }
-> = {
- on_track: {
- bg: "bg-success-subtle",
- text: "text-success",
- label: "On Track",
- icon: CheckCircle,
- },
- at_risk: {
- bg: "bg-warning-subtle",
- text: "text-warning",
- label: "At Risk",
- icon: AlertTriangle,
- },
- behind: {
- bg: "bg-danger-subtle",
- text: "text-danger",
- label: "Behind",
- icon: AlertCircle,
- },
- achieved: {
- bg: "bg-success-subtle",
- text: "text-success",
- label: "Achieved",
- icon: CheckCircle,
- },
-};
-
-function ProgressRing({
- value,
- size = 36,
- stroke = 3,
- className = "",
-}: {
- value: number;
- size?: number;
- stroke?: number;
- className?: string;
-}) {
- const radius = (size - stroke) / 2;
- const circumference = 2 * Math.PI * radius;
- const offset = circumference - (value / 100) * circumference;
- const color =
- value >= 80
- ? "stroke-success"
- : value >= 50
- ? "stroke-clone"
- : value >= 30
- ? "stroke-warning"
- : "stroke-danger";
-
- return (
-
- );
-}
-
-function KRRow({
- kr,
- isSelected,
- onSelect,
-}: {
- kr: KeyResult;
- isSelected: boolean;
- onSelect: () => void;
-}) {
- const linkedTasks = SPRINT_TASKS.filter((t) => kr.linkedTasks.includes(t.id));
-
- return (
-
-
-
-
-
{kr.title}
-
-
- {kr.current} / {kr.target}
-
- · {kr.owner}
-
-
- {linkedTasks.length > 0 && (
-
-
- {linkedTasks.length} 任务
-
- )}
-
-
-
- {linkedTasks.length > 0 && (
-
- {linkedTasks.map((t) => {
- const statusColor =
- t.status === "done"
- ? "bg-success/10 text-success"
- : t.status === "blocked"
- ? "bg-danger/10 text-danger"
- : "bg-clone/10 text-clone";
- return (
-
- {t.id} {t.title}
-
- );
- })}
-
- )}
-
- );
-}
-
-function ObjectiveCard({
- objective,
- selectedKR,
- onSelectKR,
- onSelectObjective,
- isSelected,
-}: {
- objective: Objective;
- selectedKR: string | null;
- onSelectKR: (kr: KeyResult) => void;
- onSelectObjective: (o: Objective) => void;
- isSelected: boolean;
-}) {
- const [expanded, setExpanded] = useState(true);
- const statusStyle = OKR_STATUS_STYLES[objective.status];
- const StatusIcon = statusStyle.icon;
- const achieved = objective.keyResults.filter((kr) => kr.progress >= 100).length;
-
- return (
-
- {/* Objective header */}
-
onSelectObjective(objective)}
- className="px-4 py-3 bg-surface-1 cursor-pointer hover:bg-surface-1/80 transition-colors"
- >
-
-
-
-
- {objective.id}
-
- {statusStyle.label}
-
- {objective.quarter}
-
-
- {objective.title}
-
-
- {objective.description}
-
-
-
{
- e.stopPropagation();
- setExpanded(!expanded);
- }}
- className="p-1 rounded hover:bg-surface-3 text-text-muted shrink-0"
- >
- {expanded ? : }
-
-
-
-
- {objective.ownerAvatar} {objective.owner}
-
-
- {achieved}/{objective.keyResults.length} KR 达标
-
-
- {objective.tags.map((t) => (
-
- {t}
-
- ))}
-
-
-
-
- {/* Key Results */}
- {expanded && (
-
-
- Key Results ({objective.keyResults.length})
-
- {objective.keyResults.map((kr) => (
-
onSelectKR(kr)}
- />
- ))}
-
- )}
-
- );
-}
-
-export default function OKRTab({
- selectedOKR,
- onSelectObjective,
- onSelectKR,
-}: {
- selectedOKR: string | null;
- onSelectObjective: (o: Objective) => void;
- onSelectKR: (kr: KeyResult) => void;
-}) {
- const totalProgress = Math.round(
- OBJECTIVES.reduce((s, o) => s + o.progress, 0) / OBJECTIVES.length,
- );
- const atRisk = OBJECTIVES.filter((o) => o.status === "at_risk" || o.status === "behind").length;
-
- return (
-
-
-
-
- OKR · 2026-Q1
- 3 Objectives · 11 Key Results
-
-
- {atRisk > 0 && (
-
- {atRisk} 需关注
-
- )}
- {totalProgress}%
-
-
-
- {/* OKR summary strip */}
-
- {OBJECTIVES.map((o) => {
- const st = OKR_STATUS_STYLES[o.status];
- return (
-
-
-
-
{o.id}
-
- {o.title.slice(0, 20)}...
-
-
-
- {st.label}
-
-
- );
- })}
-
-
- {/* Objectives list */}
-
- {OBJECTIVES.map((o) => (
-
- ))}
-
-
- );
-}
diff --git a/apps/demo/src/pages/product/TeamPage.tsx b/apps/demo/src/pages/product/TeamPage.tsx
deleted file mode 100644
index 04028705..00000000
--- a/apps/demo/src/pages/product/TeamPage.tsx
+++ /dev/null
@@ -1,1025 +0,0 @@
-import {
- Badge,
- Button,
- Card,
- PageHeader,
- Progress,
- StatsBar,
- StatusDot,
- ToggleGroup,
- ToggleGroupItem,
-} from "@nexu-design/ui-web";
-import {
- AlertTriangle,
- BarChart3,
- CheckCircle,
- ChevronRight,
- Clock,
- GitPullRequest,
- Radio,
- Sparkles,
- Target,
- UserPlus,
- Users,
- X,
- Zap,
-} from "lucide-react";
-import { useState } from "react";
-import {
- AlignmentDetailPanel,
- CardDetailPanel,
- MemberDetailPanel,
- OKRDetailPanel,
- StatsDetailPanel,
- TaskDetailPanel,
- TaskItemDetailPanel,
-} from "./TeamDetailPanels";
-import TeamInsightsChat from "./TeamInsightsChat";
-import OKRTab from "./TeamOKR";
-import SprintTabEnhanced from "./TeamSprint";
-import TeamTasks from "./TeamTasks";
-import {
- ALIGNMENT_HISTORY,
- type IMCard,
- IM_CARDS,
- type KeyResult,
- OBJECTIVES,
- type Objective,
- type SprintTask,
- TASK_BOARD,
- TEAM_MEMBERS,
- type TaskItem,
- type TeamMember,
-} from "./teamData";
-
-type TabId = "okr" | "cards" | "members" | "alignments" | "sprint" | "tasks";
-
-type SelectedItem =
- | { type: "card"; data: IMCard }
- | { type: "member"; data: TeamMember }
- | { type: "alignment"; data: (typeof ALIGNMENT_HISTORY)[number] }
- | { type: "task"; data: SprintTask }
- | { type: "taskItem"; data: TaskItem }
- | { type: "stat"; data: string }
- | { type: "okr"; data: { objectiveId?: string; krId?: string } };
-
-const TABS = [
- { id: "cards" as TabId, label: "任务流", icon: Radio },
- { id: "alignments" as TabId, label: "对齐请求", icon: GitPullRequest },
- { id: "tasks" as TabId, label: "任务", icon: CheckCircle },
- { id: "okr" as TabId, label: "OKR", icon: Target },
- { id: "sprint" as TabId, label: "Sprint", icon: BarChart3 },
- { id: "members" as TabId, label: "成员", icon: Users },
-];
-
-const STATUS_VARIANTS: Record = {
- online: "success",
- busy: "warning",
- away: "neutral",
- offline: "neutral",
-};
-
-const URGENCY_STYLES: Record = {
- low: { bg: "bg-info-subtle", text: "text-info", label: "低" },
- medium: { bg: "bg-warning-subtle", text: "text-warning", label: "中" },
- high: { bg: "bg-danger-subtle", text: "text-danger", label: "高" },
-};
-
-// ─── Shared UI ─────────────────────────────────────────────
-
-function ProgressBar({
- value,
- className = "",
-}: {
- value: number;
- className?: string;
-}) {
- const variant = value >= 100 ? "success" : value >= 50 ? "accent" : "warning";
-
- return ;
-}
-
-function CardWrapper({
- children,
- accent,
- onClick,
- selected,
-}: {
- children: React.ReactNode;
- accent?: string;
- onClick?: () => void;
- selected?: boolean;
-}) {
- return (
-
- {onClick && (
-
- )}
- {children}
-
- );
-}
-
-function CardButton({
- children,
- variant = "default",
- onClick,
-}: {
- children: React.ReactNode;
- variant?: "default" | "primary" | "success" | "danger";
- onClick?: (e: React.MouseEvent) => void;
-}) {
- const styles = {
- default: "outline",
- primary: "soft",
- success: "soft",
- danger: "destructive",
- };
- return (
- {
- e.stopPropagation();
- onClick?.(e);
- }}
- className="h-7 px-3 text-[11px]"
- >
- {children}
-
- );
-}
-
-// ─── IM Card Components ────────────────────────────────────
-
-function SummaryReportIMCard({
- card,
- onSelect,
- selected,
-}: {
- card: Extract;
- onSelect: () => void;
- selected: boolean;
-}) {
- return (
-
-
-
-
-
- 团队站会 · 2026-02-23(周一)
-
-
-
{card.sprintName}
-
-
-
-
- 整体进度
-
- {card.progress}%
-
-
-
-
-
- {card.members.map((m) => (
-
-
{m.avatar}
-
{m.name}
-
{m.summary}
- {m.done &&
}
- {m.risk &&
}
-
- ))}
-
- {card.risks.length > 0 && (
-
-
- {card.risks.map((r) => (
-
- {r}
-
- ))}
-
- )}
-
- 📋 查看完整报告
- 💬 讨论
-
-
-
- );
-}
-
-function StatusQueryIMCard({
- card,
- onSelect,
- selected,
-}: {
- card: Extract;
- onSelect: () => void;
- selected: boolean;
-}) {
- return (
-
-
-
-
- {card.target} · 任务进度
-
-
-
- {card.tasks.map((t) => (
-
-
- {t.name}
- = 100 ? "text-success" : "text-text-secondary"
- }`}
- >
- {t.progress}%
-
-
-
-
{t.status}
-
- ))}
- {card.note && (
-
- )}
-
- 📌 关注此任务
- 💬 发起对齐
-
-
-
- via 王五的分身 · 自动回复 · 无需打扰本人
-
-
- );
-}
-
-function AlignmentRequestIMCard({
- card,
- onSelect,
- selected,
-}: {
- card: Extract;
- onSelect: () => void;
- selected: boolean;
-}) {
- const [responded, setResponded] = useState(card.status !== "pending");
- const urgency = URGENCY_STYLES[card.urgency];
- return (
-
-
-
-
-
- 对齐请求 · 来自{card.from.replace("的分身", "")}
-
-
-
- ⚡ {urgency.label}
-
-
-
-
-
-
🎯 建议:{card.suggestion}
- {!responded ? (
-
- setResponded(true)}>
- ✅ 同意调整
-
- ❌ 无法调整
- 💬 回复详情
-
- ) : (
-
-
-
- 已同意 · Gateway 重构提前到明天启动
-
-
- )}
-
-
- 自动发起 · 基于任务依赖分析
-
-
- );
-}
-
-function EventNotificationIMCard({
- card,
- onSelect,
- selected,
-}: {
- card: Extract;
- onSelect: () => void;
- selected: boolean;
-}) {
- return (
-
-
-
- {card.event}
-
-
-
{card.impact}
-
- {card.updates.map((u) => (
-
- ))}
-
-
- 🚀 开始任务
- 📅 调整排期
-
-
-
- );
-}
-
-function GrowthTriggerIMCard({
- card,
- onSelect,
- selected,
-}: {
- card: Extract;
- onSelect: () => void;
- selected: boolean;
-}) {
- return (
-
-
-
- {card.from}完成了任务
-
-
-
📝 {card.taskTitle}已生成
-
-
-
{card.timeSaved}
-
实际耗时
-
-
-
- {card.manualEstimate}
-
-
手动预估
-
-
-
- 💡 本周已帮{card.from.replace("的分身", "")}完成 {card.weeklyStats.tasks} 项任务 · 节省约{" "}
- {card.weeklyStats.hours}h
-
-
e.stopPropagation()}
- className="w-full py-2 bg-accent text-accent-fg rounded-lg text-[12px] font-medium hover:bg-accent-hover transition-colors flex items-center justify-center gap-1.5"
- >
- 🤖 我也想要一个分身
-
-
-
- );
-}
-
-function IMCardRenderer({
- card,
- onSelect,
- selected,
-}: {
- card: IMCard;
- onSelect: () => void;
- selected: boolean;
-}) {
- switch (card.type) {
- case "summary_report":
- return ;
- case "status_query":
- return ;
- case "alignment_request":
- return ;
- case "event_notification":
- return ;
- case "growth_trigger":
- return ;
- }
-}
-
-// ─── IM Message Thread Wrapper ─────────────────────────────
-
-function IMMessage({
- card,
- onSelect,
- selected,
-}: {
- card: IMCard;
- onSelect: () => void;
- selected: boolean;
-}) {
- return (
-
-
- {card.fromAvatar}
-
-
-
-
{card.from}
-
- BOT
-
-
{card.time}
- {!card.read &&
}
-
-
-
-
- );
-}
-
-// ─── Tab: IM Cards Stream ──────────────────────────────────
-
-function CardsTab({
- selectedCard,
- onSelectCard,
-}: {
- selectedCard: IMCard | null;
- onSelectCard: (c: IMCard) => void;
-}) {
- return (
-
-
-
-
- 📱 飞书
-
- #product-team
-
- · {TEAM_MEMBERS.filter((m) => m.status === "online").length} 个分身在线
-
-
-
今日 {IM_CARDS.length} 条卡片
-
-
-
- {IM_CARDS.map((card) => (
-
onSelectCard(card)}
- selected={selectedCard?.id === card.id}
- />
- ))}
-
-
- );
-}
-
-// ─── Tab: Members ──────────────────────────────────────────
-
-function MemberCard({
- member,
- onSelect,
- selected,
-}: {
- member: TeamMember;
- onSelect: () => void;
- selected: boolean;
-}) {
- return (
-
-
-
-
- {member.avatar}
-
-
-
-
-
- {member.name}
-
- Lv.{member.level}
-
-
-
{member.role}
-
-
{member.channel}
-
-
-
-
{member.tasksInProgress}
-
进行中
-
-
-
{member.tasksCompleted}
-
已完成
-
-
-
{member.alignmentRate}%
-
默契度
-
-
-
- 最近活跃:{member.lastActive}
-
- 查看详情
-
-
-
- );
-}
-
-function MembersTab({
- selectedMember,
- onSelectMember,
-}: {
- selectedMember: TeamMember | null;
- onSelectMember: (m: TeamMember) => void;
-}) {
- const online = TEAM_MEMBERS.filter((m) => m.status === "online").length;
- const total = TEAM_MEMBERS.length;
- return (
-
-
-
- 团队分身
-
- {online}/{total} 在线
-
-
-
- 网络效应 +{Math.round((total / 3 - 1) * 100)}% vs 3 人
-
-
-
- {TEAM_MEMBERS.map((m) => (
-
onSelectMember(m)}
- selected={selectedMember?.name === m.name}
- />
- ))}
-
-
-
-
-
邀请成员
-
- 发送飞书/Slack 邀请
-
1 分钟创建分身
-
-
-
-
- );
-}
-
-// ─── Tab: Alignments ───────────────────────────────────────
-
-function AlignmentsTab({
- selectedAlignment,
- onSelectCard,
- onSelectAlignment,
-}: {
- selectedAlignment: (typeof ALIGNMENT_HISTORY)[number] | null;
- onSelectCard: (c: IMCard) => void;
- onSelectAlignment: (a: (typeof ALIGNMENT_HISTORY)[number]) => void;
-}) {
- const pendingCards = IM_CARDS.filter((c) => c.type === "alignment_request") as Extract<
- IMCard,
- { type: "alignment_request" }
- >[];
- return (
-
-
- 对齐请求
-
-
- {pendingCards.length > 0 && (
-
-
- 待处理 ({pendingCards.length})
-
-
- {pendingCards.map((card) => (
- onSelectCard(card)}
- selected={false}
- />
- ))}
-
-
- )}
-
-
- 历史记录
-
-
- {ALIGNMENT_HISTORY.map((a) => (
-
onSelectAlignment(a)}
- className={`w-full flex items-center gap-3 p-3 bg-surface-1 border rounded-lg cursor-pointer transition-colors text-left ${
- selectedAlignment?.id === a.id
- ? "ring-2 ring-accent/30 border-accent/40"
- : "border-border hover:border-border-hover"
- }`}
- >
- {a.status === "accepted" ? (
-
- ) : (
-
- )}
-
-
{a.topic}
-
- 来自 {a.from}的分身 · {a.time}
-
-
-
- {a.status === "accepted" ? "已同意" : "已拒绝"}
-
-
-
- ))}
-
-
-
-
- );
-}
-
-// ─── Stats Bar ─────────────────────────────────────────────
-
-function TeamStatsBar({
- onSelectStat,
- selectedStat,
- onSwitchTab,
-}: {
- onSelectStat: (id: string) => void;
- selectedStat: string | null;
- onSwitchTab: (tab: TabId) => void;
-}) {
- const online = TEAM_MEMBERS.filter((m) => m.status === "online").length;
- const okrProgress = Math.round(
- OBJECTIVES.reduce((s, o) => s + o.progress, 0) / OBJECTIVES.length,
- );
- const stats = [
- {
- id: "okr",
- label: "OKR",
- value: `${okrProgress}%`,
- tone: "accent" as const,
- tab: "okr" as TabId,
- selected: selectedStat === "okr",
- onSelect: () => {
- onSelectStat("okr");
- onSwitchTab("okr");
- },
- },
- {
- id: "online",
- label: "分身在线",
- value: `${online}/${TEAM_MEMBERS.length}`,
- tone: "success" as const,
- tab: "members" as TabId,
- selected: selectedStat === "online",
- onSelect: () => {
- onSelectStat("online");
- onSwitchTab("members");
- },
- },
- {
- id: "cards",
- label: "今日卡片",
- value: `${IM_CARDS.length}`,
- tone: "accent" as const,
- tab: "cards" as TabId,
- selected: selectedStat === "cards",
- onSelect: () => {
- onSelectStat("cards");
- onSwitchTab("cards");
- },
- },
- {
- id: "alignments",
- label: "待对齐",
- value: `${IM_CARDS.filter((c) => c.type === "alignment_request" && !c.read).length}`,
- tone: "warning" as const,
- tab: "alignments" as TabId,
- selected: selectedStat === "alignments",
- onSelect: () => {
- onSelectStat("alignments");
- onSwitchTab("alignments");
- },
- },
- {
- id: "tasks",
- label: "活跃任务",
- value: `${TASK_BOARD.filter((t) => t.status === "in_progress" || t.status === "todo").length}`,
- tone: "accent" as const,
- tab: "tasks" as TabId,
- selected: selectedStat === "tasks",
- onSelect: () => {
- onSelectStat("tasks");
- onSwitchTab("tasks");
- },
- },
- {
- id: "sprint",
- label: "Sprint",
- value: "58%",
- tone: "info" as const,
- tab: "sprint" as TabId,
- selected: selectedStat === "sprint",
- onSelect: () => {
- onSelectStat("sprint");
- onSwitchTab("sprint");
- },
- },
- ];
-
- return ;
-}
-
-// ─── Detail Panel Router ───────────────────────────────────
-
-function DetailPanelRouter({
- selected,
- onClose,
-}: {
- selected: SelectedItem;
- onClose: () => void;
-}) {
- switch (selected.type) {
- case "card":
- return ;
- case "member":
- return ;
- case "alignment":
- return ;
- case "task":
- return ;
- case "taskItem":
- return ;
- case "stat":
- return ;
- case "okr":
- return (
-
- );
- }
-}
-
-// ─── Main Page ─────────────────────────────────────────────
-
-export default function TeamPage() {
- const [activeTab, setActiveTab] = useState("cards");
- const [selected, setSelected] = useState(null);
-
- const handleSelectCard = (card: IMCard) => {
- setSelected((prev) =>
- prev?.type === "card" && prev.data.id === card.id ? null : { type: "card", data: card },
- );
- };
- const handleSelectMember = (member: TeamMember) => {
- setSelected((prev) =>
- prev?.type === "member" && prev.data.name === member.name
- ? null
- : { type: "member", data: member },
- );
- };
- const handleSelectAlignment = (a: (typeof ALIGNMENT_HISTORY)[number]) => {
- setSelected((prev) =>
- prev?.type === "alignment" && prev.data.id === a.id ? null : { type: "alignment", data: a },
- );
- };
- const handleSelectTask = (task: SprintTask) => {
- setSelected((prev) =>
- prev?.type === "task" && prev.data.id === task.id ? null : { type: "task", data: task },
- );
- };
- const handleSelectTaskItem = (task: TaskItem) => {
- setSelected((prev) =>
- prev?.type === "taskItem" && prev.data.id === task.id
- ? null
- : { type: "taskItem", data: task },
- );
- };
- const handleSelectStat = (statId: string) => {
- setSelected((prev) =>
- prev?.type === "stat" && prev.data === statId ? null : { type: "stat", data: statId },
- );
- };
- const handleSelectObjective = (o: Objective) => {
- setSelected((prev) =>
- prev?.type === "okr" && prev.data.objectiveId === o.id && !prev.data.krId
- ? null
- : { type: "okr", data: { objectiveId: o.id } },
- );
- };
- const handleSelectKR = (kr: KeyResult) => {
- setSelected((prev) =>
- prev?.type === "okr" && prev.data.krId === kr.id
- ? null
- : { type: "okr", data: { krId: kr.id } },
- );
- };
-
- const handleTabSwitch = (tab: TabId, keepSelection = false) => {
- if (activeTab !== tab) {
- setActiveTab(tab);
- if (!keepSelection) setSelected(null);
- }
- };
-
- const handleClose = () => setSelected(null);
-
- const atRiskOKR = OBJECTIVES.filter(
- (o) => o.status === "at_risk" || o.status === "behind",
- ).length;
-
- return (
-
-
-
-
- 邀请成员
-
- }
- />
- handleTabSwitch(tab, true)}
- />
-
-
- {/* Tab bar */}
-
{
- if (value) handleTabSwitch(value as TabId);
- }}
- variant="underline"
- aria-label="Team views"
- className="px-5 bg-surface-0"
- >
- {TABS.map((tab) => (
-
-
- {tab.label}
- {tab.id === "tasks" && (
-
- {TASK_BOARD.filter((t) => t.status === "in_progress").length}
-
- )}
- {tab.id === "alignments" && (
-
- 1
-
- )}
- {tab.id === "okr" && atRiskOKR > 0 && (
-
- {atRiskOKR}
-
- )}
-
- ))}
-
-
- {/* Content + Detail Panel + Insights Chat */}
-
-
-
-
- {activeTab === "okr" && (
-
- )}
- {activeTab === "cards" && (
-
- )}
- {activeTab === "members" && (
-
- )}
- {activeTab === "alignments" && (
-
- )}
- {activeTab === "tasks" && (
-
- )}
- {activeTab === "sprint" && (
-
- )}
-
-
-
- {selected &&
}
-
-
- {/* Persistent Insights Chat */}
-
-
-
- );
-}
diff --git a/apps/demo/src/pages/product/TeamSprint.tsx b/apps/demo/src/pages/product/TeamSprint.tsx
deleted file mode 100644
index c5be93f4..00000000
--- a/apps/demo/src/pages/product/TeamSprint.tsx
+++ /dev/null
@@ -1,361 +0,0 @@
-import { ToggleGroup, ToggleGroupItem } from "@nexu-design/ui-web";
-import {
- AlertTriangle,
- ArrowRight,
- Calendar,
- ChevronRight,
- GanttChart,
- List,
- Users,
-} from "lucide-react";
-import { useState } from "react";
-import {
- SPRINT_META,
- SPRINT_TASKS,
- SPRINT_TASKS_GANTT,
- type SprintTask,
- TEAM_MEMBERS,
-} from "./teamData";
-
-type SprintView = "list" | "gantt";
-
-const STATUS_STYLES: Record = {
- done: { bg: "bg-success-subtle", text: "text-success", label: "完成" },
- in_progress: { bg: "bg-clone/10", text: "text-clone", label: "进行中" },
- blocked: { bg: "bg-danger-subtle", text: "text-danger", label: "阻塞" },
- todo: { bg: "bg-surface-3", text: "text-text-muted", label: "待开始" },
-};
-
-const STATUS_BAR_COLORS: Record = {
- done: "bg-success",
- in_progress: "bg-clone",
- blocked: "bg-danger",
- todo: "bg-surface-4",
-};
-
-function ProgressBar({ value, className = "" }: { value: number; className?: string }) {
- return (
-
-
= 100 ? "bg-success" : value >= 50 ? "bg-clone" : "bg-warning"}`}
- style={{ width: `${Math.min(value, 100)}%` }}
- />
-
- );
-}
-
-// ─── List View ─────────────────────────────────────────────
-
-function ListView({
- selectedTask,
- onSelectTask,
-}: {
- selectedTask: SprintTask | null;
- onSelectTask: (t: SprintTask) => void;
-}) {
- const byAssignee = TEAM_MEMBERS.map((m) => ({
- member: m,
- tasks: SPRINT_TASKS.filter((t) => t.assignee === m.name),
- })).filter((g) => g.tasks.length > 0);
-
- return (
-
- {byAssignee.map(({ member, tasks }) => (
-
-
- {member.avatar}
- {member.name}
- · {member.role}
-
-
- {tasks.map((task) => {
- const style = STATUS_STYLES[task.status];
- const isSelected = selectedTask?.id === task.id;
- return (
-
onSelectTask(task)}
- onKeyDown={(e) => {
- if (e.key === "Enter") onSelectTask(task);
- }}
- className={`flex items-center gap-2 p-2.5 bg-surface-1 border rounded-lg cursor-pointer transition-colors text-left w-full ${
- isSelected
- ? "ring-2 ring-accent/30 border-accent/40"
- : "border-border hover:border-border-hover"
- }`}
- >
-
- {style.label}
-
- {task.title}
- {task.dependency && (
-
- 依赖 {task.dependency}
-
- )}
-
-
- {task.progress}%
-
-
-
- );
- })}
-
-
- ))}
-
- );
-}
-
-// ─── Gantt View ────────────────────────────────────────────
-
-function dayOffset(dateStr: string, baseStr: string): number {
- const d = new Date(dateStr);
- const b = new Date(baseStr);
- return Math.round((d.getTime() - b.getTime()) / (1000 * 60 * 60 * 24));
-}
-
-function GanttView({
- selectedTask,
- onSelectTask,
-}: {
- selectedTask: SprintTask | null;
- onSelectTask: (t: SprintTask) => void;
-}) {
- const { startDate, totalDays } = SPRINT_META;
- const today = "2026-02-23";
- const todayOffset = dayOffset(today, startDate);
-
- const days = Array.from({ length: totalDays }, (_, i) => {
- const d = new Date(startDate);
- d.setDate(d.getDate() + i);
- return {
- date: d.toISOString().slice(0, 10),
- day: d.getDate(),
- weekday: ["日", "一", "二", "三", "四", "五", "六"][d.getDay()],
- isToday: d.toISOString().slice(0, 10) === today,
- isWeekend: d.getDay() === 0 || d.getDay() === 6,
- };
- });
-
- return (
-
-
- {/* Timeline header */}
-
-
-
- {days.map((d) => (
-
-
- {d.weekday}
-
-
- {d.day}
-
-
- ))}
-
-
-
- {/* Today marker line */}
-
-
- {/* Task rows */}
-
- {SPRINT_TASKS_GANTT.map((task) => {
- const start = dayOffset(task.startDate, startDate);
- const end = dayOffset(task.endDate, startDate);
- const duration = end - start;
- const leftPct = (start / totalDays) * 100;
- const widthPct = (duration / totalDays) * 100;
- const style = STATUS_STYLES[task.status];
- const barColor = STATUS_BAR_COLORS[task.status];
- const isSelected = selectedTask?.id === task.id;
- const dep = task.dependency
- ? SPRINT_TASKS_GANTT.find((t) => t.id === task.dependency)
- : null;
-
- return (
-
onSelectTask(task)}
- onKeyDown={(e) => {
- if (e.key === "Enter") onSelectTask(task);
- }}
- className={`flex items-center h-[32px] cursor-pointer rounded transition-colors w-full text-left ${
- isSelected ? "bg-accent/5" : "hover:bg-surface-1"
- }`}
- >
- {/* Task label */}
-
-
- {task.id}
-
-
- {task.title}
-
- {task.status === "blocked" && (
-
- )}
-
-
- {/* Gantt bar area */}
-
- {/* Dependency arrow */}
- {dep && (
-
- )}
-
- {/* Bar */}
-
- {/* Progress fill */}
-
- {/* Label on bar */}
- {widthPct > 8 && (
-
- {task.progress}%
-
- )}
-
-
-
- );
- })}
-
-
- {/* Legend */}
-
- {Object.entries(STATUS_STYLES).map(([key, st]) => (
-
- ))}
-
-
-
-
- );
-}
-
-// ─── Sprint Tab (Enhanced) ─────────────────────────────────
-
-export default function SprintTab({
- selectedTask,
- onSelectTask,
-}: {
- selectedTask: SprintTask | null;
- onSelectTask: (t: SprintTask) => void;
-}) {
- const [view, setView] = useState
("list");
- const done = SPRINT_TASKS.filter((t) => t.status === "done").length;
- const total = SPRINT_TASKS.length;
- const progress = Math.round((done / total) * 100);
-
- return (
-
- {/* Sprint header with view toggle */}
-
-
- {SPRINT_META.name}
-
- {SPRINT_META.startDate.slice(5)} → {SPRINT_META.endDate.slice(5)}
-
- {progress}%
-
-
{
- if (value) setView(value as SprintView);
- }}
- variant="default"
- size="sm"
- aria-label="Sprint view"
- >
-
-
列表
-
-
- 甘特图
-
-
-
-
- {/* Progress bar */}
-
-
-
-
-
- {done}/{total} 任务完成
-
-
- {" "}
- {TEAM_MEMBERS.filter((m) => SPRINT_TASKS.some((t) => t.assignee === m.name)).length}{" "}
- 人参与
-
-
-
剩余 7 天
-
-
-
- {/* View content */}
-
- {view === "list" ? (
-
- ) : (
-
- )}
-
-
- );
-}
diff --git a/apps/demo/src/pages/product/TeamTasks.tsx b/apps/demo/src/pages/product/TeamTasks.tsx
deleted file mode 100644
index b79dc25a..00000000
--- a/apps/demo/src/pages/product/TeamTasks.tsx
+++ /dev/null
@@ -1,863 +0,0 @@
-import {
- Badge,
- Button,
- DataTable,
- DataTableDescription,
- DataTableFooter,
- DataTableHeader,
- DataTableTitle,
- Progress,
- Table,
- TableBody,
- TableCell,
- TableHead,
- TableHeader,
- TableRow,
-} from "@nexu-design/ui-web";
-import {
- Archive,
- ArrowDown,
- ArrowUp,
- Bot,
- CheckCircle2,
- ChevronDown,
- ChevronRight,
- Circle,
- Clock,
- FileText,
- Filter,
- Inbox,
- Link2,
- MessageSquare,
- Minus,
- Plus,
- Search,
- Target,
- User,
- Users,
- Zap,
-} from "lucide-react";
-import { useState } from "react";
-import {
- TASK_BOARD,
- type TaskExecutor,
- type TaskItem,
- type TaskPriority,
- type TaskStatus,
-} from "./teamData";
-
-// ─── Constants ──────────────────────────────────────────────
-
-type FilterStatus = TaskStatus | "all";
-type GroupBy = "status" | "assignee" | "priority" | "sprint";
-
-const STATUS_CONFIG: Record<
- TaskStatus,
- {
- label: string;
- icon: typeof Circle;
- color: string;
- bg: string;
- }
-> = {
- backlog: { label: "待规划", icon: Inbox, color: "text-text-muted", bg: "bg-surface-3" },
- todo: { label: "待开始", icon: Circle, color: "text-info", bg: "bg-info-subtle" },
- in_progress: { label: "进行中", icon: Clock, color: "text-clone", bg: "bg-clone/10" },
- done: { label: "已完成", icon: CheckCircle2, color: "text-success", bg: "bg-success-subtle" },
- archived: { label: "已归档", icon: Archive, color: "text-text-muted", bg: "bg-surface-3" },
-};
-
-const PRIORITY_CONFIG: Record<
- TaskPriority,
- {
- label: string;
- icon: typeof ArrowUp;
- color: string;
- }
-> = {
- urgent: { label: "紧急", icon: ArrowUp, color: "text-danger" },
- high: { label: "高", icon: ArrowUp, color: "text-warning" },
- medium: { label: "中", icon: Minus, color: "text-info" },
- low: { label: "低", icon: ArrowDown, color: "text-text-muted" },
-};
-
-const EXECUTOR_CONFIG: Record<
- TaskExecutor,
- {
- label: string;
- icon: typeof User;
- color: string;
- }
-> = {
- human: { label: "人工", icon: User, color: "text-text-secondary" },
- agent: { label: "Agent", icon: Bot, color: "text-clone" },
- hybrid: { label: "人+Agent", icon: Users, color: "text-info" },
-};
-
-const FILTER_TABS: { id: FilterStatus; label: string; count?: (tasks: TaskItem[]) => number }[] = [
- { id: "all", label: "全部" },
- {
- id: "in_progress",
- label: "进行中",
- count: (ts) => ts.filter((t) => t.status === "in_progress").length,
- },
- { id: "todo", label: "待开始", count: (ts) => ts.filter((t) => t.status === "todo").length },
- {
- id: "backlog",
- label: "待规划",
- count: (ts) => ts.filter((t) => t.status === "backlog").length,
- },
- { id: "done", label: "已完成", count: (ts) => ts.filter((t) => t.status === "done").length },
- {
- id: "archived",
- label: "归档",
- count: (ts) => ts.filter((t) => t.status === "archived").length,
- },
-];
-
-// ─── Task Card ──────────────────────────────────────────────
-
-function TaskCard({
- task,
- onSelect,
- selected,
- expanded,
- onToggleExpand,
-}: {
- task: TaskItem;
- onSelect: () => void;
- selected: boolean;
- expanded: boolean;
- onToggleExpand: () => void;
-}) {
- const status = STATUS_CONFIG[task.status];
- const priority = PRIORITY_CONFIG[task.priority];
- const executor = EXECUTOR_CONFIG[task.executor];
- const StatusIcon = status.icon;
- const PriorityIcon = priority.icon;
-
- const subtasksDone = task.subtasks?.filter((s) => s.done).length ?? 0;
- const subtasksTotal = task.subtasks?.length ?? 0;
-
- return (
-
- {/* Main row */}
-
{
- if (e.key === "Enter") onSelect();
- }}
- className="flex w-full items-start gap-3 px-4 py-3 text-left cursor-pointer"
- >
- {/* Expand toggle */}
- {
- e.stopPropagation();
- onToggleExpand();
- }}
- className="mt-0.5 p-0.5 rounded hover:bg-surface-3 text-text-muted transition-colors shrink-0"
- >
- {expanded ? : }
-
-
- {/* Status icon */}
-
-
- {/* Content */}
-
-
-
{task.id}
-
- {task.dependencies?.length ? (
-
- 有依赖
-
- ) : null}
-
-
- {task.title}
-
-
- {/* Tags */}
- {task.tags.slice(0, 3).map((tag) => (
-
- {tag}
-
- ))}
- {/* Subtasks */}
- {subtasksTotal > 0 && (
-
- {subtasksDone}/{subtasksTotal}
-
- )}
- {/* Comments */}
- {task.comments > 0 && (
-
- {task.comments}
-
- )}
- {/* Linked files */}
- {task.linkedFiles?.length ? (
-
- {task.linkedFiles.length}
-
- ) : null}
-
-
-
- {/* Right meta */}
-
-
- {task.assigneeAvatar}
-
-
-
- {executor.label}
-
- {task.dueDate && (
-
- 截止 {task.dueDate}
-
- )}
-
-
-
- {/* Progress bar */}
- {task.progress > 0 && task.progress < 100 && (
-
-
-
= 80 ? "bg-success" : task.progress >= 40 ? "bg-clone" : "bg-warning"}`}
- style={{ width: `${task.progress}%` }}
- />
-
-
- )}
-
- {/* Expanded content */}
- {expanded && (
-
- {/* Description */}
- {task.description && (
-
- {task.description}
-
- )}
-
- {/* Meta grid */}
-
-
-
-
- {task.sprintId && (
-
- )}
- {task.okrTitle && (
-
- )}
- {task.source !== "manual" && (
-
- )}
-
-
- {/* Subtasks */}
- {task.subtasks && task.subtasks.length > 0 && (
-
-
子任务
-
- {task.subtasks.map((sub) => (
-
- {sub.done ? (
-
- ) : (
-
- )}
-
- {sub.title}
-
-
- ))}
-
-
- )}
-
- {/* Linked files */}
- {task.linkedFiles && task.linkedFiles.length > 0 && (
-
-
关联文件
-
- {task.linkedFiles.map((f) => (
-
- {f}
-
- ))}
-
-
- )}
-
- {/* Dependencies */}
- {task.dependencies && task.dependencies.length > 0 && (
-
- 依赖:
- {task.dependencies.map((d) => (
-
- {d}
-
- ))}
-
- )}
-
- {/* Actions */}
-
- {task.status === "todo" && (
-
- )}
- {task.status === "in_progress" && (
-
- )}
- {task.executor !== "agent" &&
}
- {task.status === "done" &&
}
-
-
-
-
- 创建于 {task.createdAt} · 更新于 {task.updatedAt}
-
-
- )}
-
- );
-}
-
-function MetaChip({
- label,
- value,
- icon: Icon,
- color,
- className = "",
-}: {
- label: string;
- value: string;
- icon: typeof Circle;
- color: string;
- className?: string;
-}) {
- return (
-
-
{label}
-
- {value}
-
-
- );
-}
-
-function ActionBtn({
- icon: Icon,
- label,
- variant = "default",
-}: {
- icon: typeof Circle;
- label: string;
- variant?: "default" | "primary" | "success";
-}) {
- const styles = {
- default: "bg-surface-2 text-text-secondary hover:bg-surface-3",
- primary: "bg-accent/10 text-accent hover:bg-accent/15",
- success: "bg-success-subtle text-success hover:bg-success/20",
- };
- return (
-
e.stopPropagation()}
- className={`px-2.5 py-1.5 rounded-lg text-[11px] font-medium transition-colors flex items-center gap-1.5 ${styles[variant]}`}
- >
- {label}
-
- );
-}
-
-function CompactTaskTable({
- tasks,
- selectedTask,
- onSelectTask,
- expandedIds,
- onToggleExpand,
-}: {
- tasks: TaskItem[];
- selectedTask: TaskItem | null;
- onSelectTask: (t: TaskItem) => void;
- expandedIds: Set
;
- onToggleExpand: (id: string) => void;
-}) {
- return (
-
-
-
- 紧凑列表视图
- 用于快速扫描负责人、优先级与进度
-
- {tasks.length} 条任务
-
-
-
-
-
- 任务
- 状态
- 优先级
- 负责人
- 进度
- 来源
- 更新
-
-
-
- {tasks.map((task) => {
- const status = STATUS_CONFIG[task.status];
- const priority = PRIORITY_CONFIG[task.priority];
- const executor = EXECUTOR_CONFIG[task.executor];
- const expanded = expandedIds.has(task.id);
- const StatusIcon = status.icon;
- const PriorityIcon = priority.icon;
-
- return (
- onSelectTask(task)}
- >
-
- {
- e.stopPropagation();
- onToggleExpand(task.id);
- }}
- className="rounded p-1 text-text-muted transition-colors hover:bg-surface-3 hover:text-text-secondary"
- aria-label={expanded ? "收起详情" : "展开详情"}
- >
- {expanded ? : }
-
-
-
-
-
- {task.id}
- {task.dependencies?.length ? (
-
- 有依赖
-
- ) : null}
-
-
- {task.title}
-
-
-
-
-
-
- {status.label}
-
-
-
-
-
-
-
-
{task.assigneeAvatar}
-
-
{task.assignee}
-
-
- {executor.label}
-
-
-
-
-
-
-
- {task.progress}%
- {task.comments > 0 ? (
- {task.comments} 评论
- ) : null}
-
-
-
-
-
- {task.sourceRef ?? task.source}
-
-
- {task.updatedAt}
-
-
- );
- })}
-
-
-
- 点击行查看详情,左侧按钮展开更多上下文。
- {expandedIds.size} 条已展开
-
-
- );
-}
-
-// ─── Status Group ───────────────────────────────────────────
-
-function TaskGroup({
- title,
- count,
- tasks,
- icon: Icon,
- color,
- selectedTask,
- onSelectTask,
- expandedIds,
- onToggleExpand,
- defaultOpen = true,
-}: {
- title: string;
- count: number;
- tasks: TaskItem[];
- icon: typeof Circle;
- color: string;
- selectedTask: TaskItem | null;
- onSelectTask: (t: TaskItem) => void;
- expandedIds: Set;
- onToggleExpand: (id: string) => void;
- defaultOpen?: boolean;
-}) {
- const [open, setOpen] = useState(defaultOpen);
-
- return (
-
-
setOpen(!open)}
- className="flex items-center gap-2 w-full px-1 py-1.5 hover:bg-surface-2 rounded-lg transition-colors"
- >
- {open ? (
-
- ) : (
-
- )}
-
- {title}
-
- {count}
-
-
- {open && (
-
- {tasks.map((task) => (
- onSelectTask(task)}
- selected={selectedTask?.id === task.id}
- expanded={expandedIds.has(task.id)}
- onToggleExpand={() => onToggleExpand(task.id)}
- />
- ))}
-
- )}
-
- );
-}
-
-// ─── Main Component ─────────────────────────────────────────
-
-export default function TeamTasks({
- selectedTask,
- onSelectTask,
-}: {
- selectedTask: TaskItem | null;
- onSelectTask: (t: TaskItem) => void;
-}) {
- const [filterStatus, setFilterStatus] = useState("all");
- const [groupBy, setGroupBy] = useState("status");
- const [searchQuery, setSearchQuery] = useState("");
- const [expandedIds, setExpandedIds] = useState>(new Set());
- const [showGroupMenu, setShowGroupMenu] = useState(false);
-
- const toggleExpand = (id: string) => {
- setExpandedIds((prev) => {
- const next = new Set(prev);
- if (next.has(id)) next.delete(id);
- else next.add(id);
- return next;
- });
- };
-
- const filtered = TASK_BOARD.filter((t) => {
- if (filterStatus !== "all" && t.status !== filterStatus) return false;
- if (searchQuery) {
- const q = searchQuery.toLowerCase();
- return (
- t.title.toLowerCase().includes(q) ||
- t.id.toLowerCase().includes(q) ||
- t.tags.some((tag) => tag.includes(q))
- );
- }
- return true;
- });
-
- const grouped = groupTasks(filtered, groupBy);
-
- const totalActive = TASK_BOARD.filter((t) => t.status === "in_progress").length;
- const totalDone = TASK_BOARD.filter((t) => t.status === "done").length;
- const agentTasks = TASK_BOARD.filter((t) => t.executor === "agent").length;
-
- return (
-
- {/* Header */}
-
-
-
- 任务看板
-
- {totalActive} 进行中 · {totalDone} 已完成 · {agentTasks} 个 Agent 任务
-
-
-
- {/* Group by */}
-
-
setShowGroupMenu(!showGroupMenu)}
- className="flex items-center gap-1 px-2.5 py-1.5 bg-surface-2 rounded-lg text-[11px] text-text-secondary hover:bg-surface-3 transition-colors"
- >
- 分组:{GROUP_LABELS[groupBy]}
-
-
- {showGroupMenu && (
-
- {(Object.keys(GROUP_LABELS) as GroupBy[]).map((g) => (
- {
- setGroupBy(g);
- setShowGroupMenu(false);
- }}
- className={`w-full text-left px-3 py-1.5 text-[11px] transition-colors ${groupBy === g ? "text-accent bg-accent/5" : "text-text-secondary hover:bg-surface-2"}`}
- >
- {GROUP_LABELS[g]}
-
- ))}
-
- )}
-
-
- 新建任务
-
-
-
-
- {/* Search + filter tabs */}
-
-
-
- setSearchQuery(e.target.value)}
- placeholder="搜索任务..."
- className="bg-transparent text-[11px] text-text-primary placeholder:text-text-muted outline-none w-full"
- />
-
-
- {FILTER_TABS.map((tab) => {
- const count = tab.count?.(TASK_BOARD);
- const active = filterStatus === tab.id;
- return (
- setFilterStatus(tab.id)}
- className={`px-2.5 py-1 rounded-md text-[11px] font-medium transition-colors ${
- active
- ? "bg-accent/10 text-accent"
- : "text-text-muted hover:text-text-secondary hover:bg-surface-2"
- }`}
- >
- {tab.label}
- {count !== undefined && count > 0 && (
-
- {count}
-
- )}
-
- );
- })}
-
-
-
-
- {/* Task list */}
-
- {filtered.length > 0 && (
-
- )}
- {grouped.map((group) => (
-
- ))}
- {filtered.length === 0 && (
-
没有匹配的任务
- )}
-
-
- );
-}
-
-// ─── Helpers ────────────────────────────────────────────────
-
-const GROUP_LABELS: Record = {
- status: "按状态",
- assignee: "按负责人",
- priority: "按优先级",
- sprint: "按 Sprint",
-};
-
-interface TaskGroup {
- key: string;
- title: string;
- icon: typeof Circle;
- color: string;
- tasks: TaskItem[];
-}
-
-function groupTasks(tasks: TaskItem[], by: GroupBy): TaskGroup[] {
- switch (by) {
- case "status": {
- const order: TaskStatus[] = ["in_progress", "todo", "backlog", "done", "archived"];
- return order
- .map((s) => ({
- key: s,
- title: STATUS_CONFIG[s].label,
- icon: STATUS_CONFIG[s].icon,
- color: STATUS_CONFIG[s].color,
- tasks: tasks.filter((t) => t.status === s),
- }))
- .filter((g) => g.tasks.length > 0);
- }
- case "assignee": {
- const assignees = [...new Set(tasks.map((t) => t.assignee))];
- return assignees.map((a) => ({
- key: a,
- title: a,
- icon: User,
- color: "text-text-secondary",
- tasks: tasks.filter((t) => t.assignee === a),
- }));
- }
- case "priority": {
- const order: TaskPriority[] = ["urgent", "high", "medium", "low"];
- return order
- .map((p) => ({
- key: p,
- title: PRIORITY_CONFIG[p].label,
- icon: PRIORITY_CONFIG[p].icon,
- color: PRIORITY_CONFIG[p].color,
- tasks: tasks.filter((t) => t.priority === p),
- }))
- .filter((g) => g.tasks.length > 0);
- }
- case "sprint": {
- const sprints = [...new Set(tasks.map((t) => t.sprintId ?? "Backlog"))];
- return sprints.map((s) => ({
- key: s,
- title: s,
- icon: s === "Backlog" ? Inbox : Target,
- color: s === "Backlog" ? "text-text-muted" : "text-info",
- tasks: tasks.filter((t) => (t.sprintId ?? "Backlog") === s),
- }));
- }
- }
-}
diff --git a/apps/demo/src/pages/product/WorkspaceShell.tsx b/apps/demo/src/pages/product/WorkspaceShell.tsx
deleted file mode 100644
index 238bf9cc..00000000
--- a/apps/demo/src/pages/product/WorkspaceShell.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import type { ReactNode } from "react";
-
-interface WorkspaceShellProps {
- activityBar?: ReactNode;
- sidebar?: ReactNode;
- detailPanel?: ReactNode;
- children: ReactNode;
- className?: string;
- contentClassName?: string;
- sidebarCollapsed?: boolean;
- onSidebarCollapsedChange?: (collapsed: boolean) => void;
- sidebarWidth?: number;
- onSidebarWidthChange?: (width: number) => void;
- sidebarDefaultWidth?: number;
- sidebarMinWidth?: number;
- sidebarMaxWidth?: number;
-}
-
-export default function WorkspaceShell({
- activityBar,
- sidebar,
- detailPanel,
- children,
- className,
- contentClassName,
- sidebarCollapsed,
-}: WorkspaceShellProps) {
- return (
-
- {activityBar}
- {!sidebarCollapsed ? sidebar : null}
- {children}
- {detailPanel}
-
- );
-}
diff --git a/apps/demo/src/pages/product/fileStore.ts b/apps/demo/src/pages/product/fileStore.ts
deleted file mode 100644
index d1a11dd7..00000000
--- a/apps/demo/src/pages/product/fileStore.ts
+++ /dev/null
@@ -1,131 +0,0 @@
-import { SESSION_DATA } from "./sessionsData";
-
-interface FileEntry {
- content: string;
- lastEditedBy: "human" | "agent";
- lastEditedAt: string;
-}
-
-type Listener = () => void;
-
-const store = new Map();
-const listeners = new Set();
-
-function seedFromSessions() {
- for (const [, data] of Object.entries(SESSION_DATA)) {
- for (const op of data.fileOps) {
- if (op.preview && !store.has(op.path)) {
- store.set(op.path, {
- content: op.preview,
- lastEditedBy: "agent",
- lastEditedAt: op.time,
- });
- }
- }
- }
-}
-
-const MOCK_FILES: Record = {
- "memory/preferences/tech-stack.md": `# Tech Stack Preferences
-
-- **Auth**: OAuth 优先,减少表单
-- **Frontend**: React + Tailwind
-- **Backend**: NestJS + PostgreSQL
-- **Database**: TypeORM, auto-sync dev
-- **Deployment**: Vercel (frontend), Railway (backend)`,
-
- "memory/decisions/2026-02-21-auth-oauth.md": `# Auth Decision: OAuth 优先
-
-**日期**: 2026-02-21
-**类型**: 产品架构
-**重要度**: 4
-
-## 决策
-
-采用 Google OAuth + 飞书扫码的双通道注册方案。
-
-## 理由
-
-1. 减少注册摩擦(零表单)
-2. 竞品调研显示 OAuth 转化率 80%+
-3. 飞书扫码覆盖国内企业用户
-
-## Related
-
-- [竞品注册流程对比](../../artifacts/research/竞品注册流程对比.md)
-- [注册流程优化 PRD](../../artifacts/prds/注册流程优化.md)`,
-
- "knowledge/architecture.md": `# nexu Architecture
-
-## Overview
-
-nexu 采用 filesystem-first 架构,所有数据以结构化文件形式存储在分身的大脑中。
-
-## Core Modules
-
-### Chat (NestJS)
-- WebSocket 实时通信
-- 多渠道统一接入 (Web, Feishu, Slack)
-
-### Memory
-- 基于文件系统的持久化记忆
-- 自动关联和检索
-
-### Scheduler
-- Cron-based automation
-- Proactive agent triggers
-
-## Tech Stack
-- Backend: NestJS + TypeORM + PostgreSQL
-- Frontend: React + Vite + Tailwind 4
-- LLM: litellm proxy → Claude Sonnet`,
-
- "contacts/王浩-前端.md": `# 王浩
-
-**角色**: 前端工程师
-**专长**: React, 飞书 SDK, Tailwind
-**状态**: 活跃
-**最近交互**: 2026-02-21 — 注册流程优化讨论
-
-## 备注
-- 有飞书扫码集成经验
-- 负责 OAuth 回调页面开发
-
-## 历史
-- 2026-02-21: 参与注册方案技术评审
-- 2026-02-18: 完成首页 Landing Page 开发`,
-};
-
-function seedMockFiles() {
- for (const [path, content] of Object.entries(MOCK_FILES)) {
- if (!store.has(path)) {
- store.set(path, {
- content,
- lastEditedBy: "agent",
- lastEditedAt: "18:30",
- });
- }
- }
-}
-
-seedFromSessions();
-seedMockFiles();
-
-function notify() {
- for (const fn of listeners) {
- fn();
- }
-}
-
-export function getFile(path: string): FileEntry | undefined {
- return store.get(path);
-}
-
-export function saveFile(path: string, content: string, editedBy: "human" | "agent" = "human") {
- store.set(path, {
- content,
- lastEditedBy: editedBy,
- lastEditedAt: new Date().toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit" }),
- });
- notify();
-}
diff --git a/apps/demo/src/pages/product/import-skill-modal-state.ts b/apps/demo/src/pages/product/import-skill-modal-state.ts
deleted file mode 100644
index 870eb630..00000000
--- a/apps/demo/src/pages/product/import-skill-modal-state.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-export function getSelectedZipFile(
- file: T | null | undefined,
-): T | null {
- if (!file) {
- return null;
- }
-
- return file.name.toLowerCase().endsWith(".zip") ? file : null;
-}
-
-export function createAutoCloseController() {
- let timeoutId: ReturnType | null = null;
-
- return {
- schedule(onClose: () => void, delayMs: number) {
- if (timeoutId !== null) {
- clearTimeout(timeoutId);
- }
-
- timeoutId = setTimeout(() => {
- timeoutId = null;
- onClose();
- }, delayMs);
- },
- cancel() {
- if (timeoutId === null) {
- return;
- }
-
- clearTimeout(timeoutId);
- timeoutId = null;
- },
- };
-}
diff --git a/apps/demo/src/pages/product/import-skill-modal.tsx b/apps/demo/src/pages/product/import-skill-modal.tsx
deleted file mode 100644
index f31122d8..00000000
--- a/apps/demo/src/pages/product/import-skill-modal.tsx
+++ /dev/null
@@ -1,261 +0,0 @@
-import {
- Badge,
- Button,
- Dialog,
- DialogBody,
- DialogContent,
- DialogDescription,
- DialogFooter,
- DialogHeader,
- DialogTitle,
- Input,
- Tabs,
- TabsContent,
- TabsList,
- TabsTrigger,
-} from "@nexu-design/ui-web";
-import { AlertCircle, CheckCircle2, Info, Lock, Upload } from "lucide-react";
-import { useCallback, useEffect, useRef, useState } from "react";
-
-import { createAutoCloseController, getSelectedZipFile } from "./import-skill-modal-state";
-
-type ImportTab = "zip" | "github";
-
-interface ImportSkillModalProps {
- open: boolean;
- onClose: () => void;
- onImport: (file: File) => Promise | void;
-}
-
-export function ImportSkillModal({ open, onClose, onImport }: ImportSkillModalProps) {
- const [tab, setTab] = useState("zip");
- const [dragOver, setDragOver] = useState(false);
- const [selectedFile, setSelectedFile] = useState(null);
- const [done, setDone] = useState(false);
- const [error, setError] = useState(null);
- const [importing, setImporting] = useState(false);
- const fileInputRef = useRef(null);
- const autoCloseControllerRef = useRef(createAutoCloseController());
-
- const reset = useCallback(() => {
- autoCloseControllerRef.current.cancel();
- setTab("zip");
- setDragOver(false);
- setSelectedFile(null);
- setDone(false);
- setError(null);
- setImporting(false);
- }, []);
-
- useEffect(() => {
- return () => {
- autoCloseControllerRef.current.cancel();
- };
- }, []);
-
- const handleClose = useCallback(() => {
- reset();
- onClose();
- }, [onClose, reset]);
-
- const handleFileClick = () => {
- fileInputRef.current?.click();
- };
-
- const handleFileSelection = (file: File | null | undefined) => {
- const zipFile = getSelectedZipFile(file);
-
- if (!zipFile && file) {
- setSelectedFile(null);
- setError("Only .zip skill packages are supported in this demo.");
- return;
- }
-
- setSelectedFile(zipFile);
- setError(null);
- };
-
- const handleFileChange = (event: React.ChangeEvent) => {
- handleFileSelection(event.target.files?.[0]);
- event.target.value = "";
- };
-
- const handleDrop = (event: React.DragEvent) => {
- event.preventDefault();
- setDragOver(false);
- handleFileSelection(event.dataTransfer.files[0]);
- };
-
- const handleImport = async () => {
- if (!selectedFile) return;
-
- try {
- setImporting(true);
- setError(null);
- await onImport(selectedFile);
- setDone(true);
- autoCloseControllerRef.current.schedule(handleClose, 1200);
- } catch (importError) {
- setError(importError instanceof Error ? importError.message : "Import failed");
- } finally {
- setImporting(false);
- }
- };
-
- return (
-
- );
-}
diff --git a/apps/demo/src/pages/product/sessionsData.ts b/apps/demo/src/pages/product/sessionsData.ts
deleted file mode 100644
index 2447955d..00000000
--- a/apps/demo/src/pages/product/sessionsData.ts
+++ /dev/null
@@ -1,1578 +0,0 @@
-import { BarChart3, Clock, GitBranch, Globe, type LucideIcon, Palette, Shield } from "lucide-react";
-
-export type FileOpAction = "read" | "write" | "create" | "delete" | "execute" | "install";
-
-export interface FileOp {
- action: FileOpAction;
- path: string;
-}
-
-export type FileType =
- | "markdown"
- | "yaml"
- | "code"
- | "jsonl"
- | "contact"
- | "skill"
- | "config"
- | "pdf"
- | "docx"
- | "xlsx"
- | "csv"
- | "pptx"
- | "image"
- | "video"
- | "audio"
- | "figma"
- | "svg"
- | "html"
- | "sql"
- | "archive"
- | "other";
-
-export interface SessionFileOp {
- action: FileOpAction;
- path: string;
- fileType: FileType;
- size?: string;
- time: string;
- preview?: string;
- diff?: { added: number; removed: number };
-}
-
-export type AttachmentType =
- | "image"
- | "pdf"
- | "document"
- | "spreadsheet"
- | "audio"
- | "video"
- | "code"
- | "archive"
- | "other";
-
-export interface Attachment {
- name: string;
- type: AttachmentType;
- size: string;
- thumbnail?: string;
-}
-
-export type CardType = "file" | "memory" | "skill" | "automation" | "collaboration" | "upgrade";
-export type CardStatus = "success" | "running" | "warning" | "info" | "locked";
-
-export interface ChatCard {
- type: CardType;
- title: string;
- status: CardStatus;
- body: string;
- path?: string;
- diff?: { added: number; removed: number };
- actions?: { label: string; primary?: boolean }[];
- viralCta?: string;
- meta?: string;
-}
-
-export interface Message {
- from: "user" | "clone";
- content: string;
- fileOps?: FileOp[];
- tool?: { name: string; icon: LucideIcon; status: string };
- attachments?: Attachment[];
- cards?: ChatCard[];
-}
-
-export interface SessionData {
- messages: Message[];
- fileOps: SessionFileOp[];
-}
-
-export interface SessionMeta {
- id: number;
- title: string;
- time: string;
- emoji: string;
- unread: boolean;
- channel: string;
- fileOps: number;
- contacts: number;
- isProactive?: boolean;
- isProxy?: boolean;
- proxyTarget?: string;
-}
-
-export const SESSIONS: SessionMeta[] = [
- {
- id: 1,
- title: "注册流程优化方案",
- time: "刚刚",
- emoji: "📄",
- unread: false,
- channel: "web",
- fileOps: 10,
- contacts: 3,
- },
- {
- id: 9,
- title: "查询李四 Gateway 进度",
- time: "30 分钟前",
- emoji: "🤝",
- unread: true,
- channel: "feishu",
- fileOps: 2,
- contacts: 1,
- isProxy: true,
- proxyTarget: "李四",
- },
- {
- id: 6,
- title: "今日战况复盘",
- time: "22:00",
- emoji: "📡",
- unread: true,
- channel: "feishu",
- fileOps: 7,
- contacts: 0,
- isProactive: true,
- },
- {
- id: 7,
- title: "联系人关系分析",
- time: "1 小时前",
- emoji: "👥",
- unread: true,
- channel: "web",
- fileOps: 8,
- contacts: 6,
- },
- {
- id: 8,
- title: "产品会 Action Items",
- time: "3 小时前",
- emoji: "📋",
- unread: false,
- channel: "feishu",
- fileOps: 6,
- contacts: 4,
- },
- {
- id: 2,
- title: "竞品分析报告",
- time: "2 小时前",
- emoji: "🔍",
- unread: true,
- channel: "feishu",
- fileOps: 9,
- contacts: 1,
- },
- {
- id: 3,
- title: "数据库迁移计划",
- time: "昨天",
- emoji: "💾",
- unread: false,
- channel: "slack",
- fileOps: 11,
- contacts: 2,
- },
- {
- id: 4,
- title: "本周 Sprint 回顾",
- time: "2 天前",
- emoji: "📊",
- unread: false,
- channel: "feishu",
- fileOps: 8,
- contacts: 5,
- },
- {
- id: 5,
- title: "Landing Page 文案",
- time: "3 天前",
- emoji: "✍️",
- unread: false,
- channel: "whatsapp",
- fileOps: 10,
- contacts: 0,
- },
-];
-
-// ─── Session 1: PRD + Research ───────────────────────────────
-
-const SESSION_1_MESSAGES: Message[] = [
- {
- from: "user",
- content: '帮我做一个注册流程优化方案,参考之前我说的"注册要尽量简单",这是老版注册流程',
- attachments: [
- { name: "当前注册流程.pdf", type: "pdf", size: "560 KB" },
- { name: "注册页截图.png", type: "image", size: "180 KB" },
- ],
- },
- {
- from: "clone",
- content: "收到。让我先查一下你的记忆...",
- cards: [
- {
- type: "memory",
- title: "检索到 3 条相关记忆",
- status: "success",
- body: "偏好 OAuth 减少表单 · 已决定 Google 登录优先 · 注册加谷歌登录灵感",
- path: "memory/",
- meta: "记忆检索 · 匹配度 92%",
- actions: [{ label: "查看详情" }],
- },
- ],
- fileOps: [
- { action: "read", path: "memory/preferences/tech-stack.md" },
- { action: "read", path: "memory/decisions/2026-02-21-auth-oauth.md" },
- { action: "read", path: "memory/ideas/google-login-onboarding.md" },
- ],
- },
- {
- from: "clone",
- content: "另外,王浩(前端)上周在群里提过飞书扫码的技术方案,我一起参考。",
- cards: [
- {
- type: "collaboration",
- title: "关联联系人:王浩",
- status: "info",
- body: "前端工程师 · 有飞书扫码集成经验\n上周在产品群提过技术方案",
- path: "contacts/王浩-前端.md",
- actions: [{ label: "查看联系人" }],
- },
- ],
- fileOps: [{ action: "read", path: "contacts/王浩-前端.md" }],
- },
- {
- from: "clone",
- content: "",
- cards: [
- {
- type: "skill",
- title: "搜索竞品注册流程",
- status: "success",
- body: "✓ 搜索了 5 个竞品注册流程\n✓ 对比 Notion / Linear / Figma",
- path: "skills/web-research/SKILL.md",
- meta: "web-research · 耗时 12s",
- actions: [{ label: "查看日志" }, { label: "重试" }],
- },
- ],
- tool: { name: "搜索竞品注册流程", icon: Globe, status: "done" },
- },
- {
- from: "clone",
- content: "方案已生成:",
- cards: [
- {
- type: "file",
- title: "注册流程优化 PRD",
- status: "success",
- body: "方案 A(推荐):Google OAuth + 飞书扫码\n预计注册转化率提升 40%",
- path: "artifacts/prds/注册流程优化.md",
- diff: { added: 48, removed: 0 },
- actions: [{ label: "打开编辑", primary: true }, { label: "分享" }],
- },
- {
- type: "file",
- title: "竞品注册流程对比",
- status: "success",
- body: "对比 Notion / Linear / Figma 注册方式\n含 20 家 SaaS 转化率数据",
- path: "artifacts/research/竞品注册流程对比.md",
- diff: { added: 72, removed: 0 },
- actions: [{ label: "打开编辑", primary: true }],
- },
- ],
- fileOps: [
- { action: "create", path: "artifacts/research/竞品注册流程对比.md" },
- { action: "create", path: "artifacts/prds/注册流程优化.md" },
- ],
- },
- {
- from: "clone",
- content:
- "推荐方案 A:Google OAuth + 飞书扫码(基于你的偏好 + 王浩的技术调研)\n\n需要我帮你拆成开发任务吗?我可以直接分配给王浩和陈杰。",
- cards: [
- {
- type: "memory",
- title: "决策已记录",
- status: "success",
- body: "Auth 方案确认:Google OAuth + 飞书扫码双通道",
- path: "memory/decisions/2026-02-21-auth-oauth.md",
- diff: { added: 12, removed: 3 },
- meta: "决策记录 · 自动关联",
- actions: [{ label: "查看决策" }, { label: "修正" }],
- },
- {
- type: "automation",
- title: "Sprint 自动更新",
- status: "success",
- body: "新增任务:注册流程优化(OAuth 方案)\n已分配:王浩 → Google OAuth · 陈杰 → 服务端集成",
- path: "memory/context/current-sprint.md",
- diff: { added: 5, removed: 2 },
- meta: "Sprint W9 · 自动同步",
- },
- ],
- fileOps: [
- { action: "write", path: "memory/decisions/2026-02-21-auth-oauth.md" },
- { action: "write", path: "memory/context/current-sprint.md" },
- { action: "write", path: "contacts/李薇-PM.md" },
- ],
- },
-];
-
-const SESSION_1_FILE_OPS: SessionFileOp[] = [
- {
- action: "create",
- path: "artifacts/prds/注册流程优化.md",
- fileType: "markdown",
- size: "2.1 KB",
- time: "18:32",
- diff: { added: 48, removed: 0 },
- preview:
- "# 注册流程优化 PRD\n\n## 背景\n基于用户历史偏好和竞品调研,优化注册流程以降低用户进入门槛。\n\n## 方案 A(推荐):OAuth 优先\n- **Google OAuth** — 一键登录,零表单\n- **飞书扫码** — 面向国内企业用户\n- 预计注册转化率提升 40%",
- },
- {
- action: "create",
- path: "artifacts/prds/onboarding-flowchart.svg",
- fileType: "svg",
- size: "12 KB",
- time: "18:32",
- preview: "[SVG 流程图] 注册 → OAuth 验证 → 角色选择 → 上岗完成",
- },
- {
- action: "create",
- path: "artifacts/research/竞品注册流程对比.md",
- fileType: "markdown",
- size: "3.4 KB",
- time: "18:31",
- diff: { added: 72, removed: 0 },
- preview:
- "# 竞品注册流程对比\n\n| 产品 | 注册方式 | 步骤数 | 转化率 |\n|------|---------|--------|--------|\n| Notion | Google OAuth | 1 | ~85% |\n| Linear | Google/GitHub | 1 | ~82% |\n| Figma | Google/SSO | 2 | ~78% |",
- },
- {
- action: "create",
- path: "artifacts/research/市场调研数据.xlsx",
- fileType: "xlsx",
- size: "156 KB",
- time: "18:31",
- preview:
- "[Excel 表格] 20 家 SaaS 产品注册转化率数据\n\n含 4 个 sheet: 概览, 详情, 趋势图, 原始数据",
- },
- {
- action: "write",
- path: "memory/decisions/auth-oauth.md",
- fileType: "markdown",
- size: "0.8 KB",
- time: "18:33",
- diff: { added: 12, removed: 3 },
- preview:
- "# Auth Decision: OAuth 优先\n\n**更新**: 2026-02-21\n**状态**: 已确认\n\n基于竞品调研和用户偏好,决定采用 Google OAuth + 飞书扫码的双通道方案。",
- },
- {
- action: "write",
- path: "memory/context/current-sprint.md",
- fileType: "markdown",
- size: "1.2 KB",
- time: "18:33",
- diff: { added: 5, removed: 2 },
- preview:
- "# Current Sprint — W9\n\n## 新增任务\n- [ ] 注册流程优化(OAuth 方案)\n- [ ] 王浩:Google OAuth 回调页面\n- [ ] 陈杰:OAuth 服务端集成",
- },
- {
- action: "write",
- path: "contacts/李薇-PM.md",
- fileType: "contact",
- size: "0.6 KB",
- time: "18:34",
- diff: { added: 3, removed: 0 },
- preview:
- "# 李薇\n\n**角色**: PM\n**最近交互**: 注册流程优化 PRD 评审\n**待办**: 评审注册流程 PRD",
- },
- {
- action: "read",
- path: "memory/preferences/tech-stack.md",
- fileType: "markdown",
- size: "0.5 KB",
- time: "18:30",
- preview:
- "# Tech Stack Preferences\n\n- **Auth**: OAuth 优先,减少表单\n- **Frontend**: React + Tailwind\n- **Backend**: NestJS + PostgreSQL",
- },
- {
- action: "read",
- path: "memory/ideas/google-login-onboarding.md",
- fileType: "markdown",
- size: "0.3 KB",
- time: "18:30",
- preview:
- "# 灵感:Google Login + Onboarding\n\n2026-02-15 记录\n\n注册加谷歌登录,减少用户注册摩擦。参考 Linear 的做法。",
- },
- {
- action: "read",
- path: "contacts/王浩-前端.md",
- fileType: "contact",
- size: "0.7 KB",
- time: "18:31",
- preview:
- "# 王浩\n\n**角色**: 前端工程师\n**专长**: React, 飞书 SDK\n**备注**: 有飞书扫码集成经验",
- },
- {
- action: "execute",
- path: "skills/web-research/SKILL.md",
- fileType: "skill",
- size: "—",
- time: "18:31",
- preview:
- '# Web Research\n\ntriggers: ["搜索", "调研", "竞品"]\ntools: [web_search, markdown_write]\n\n## 执行结果\n✓ 搜索了 5 个竞品的注册流程\n✓ 生成了对比报告',
- },
- {
- action: "install",
- path: "skills/prd-generator/SKILL.md",
- fileType: "skill",
- size: "1.1 KB",
- time: "18:29",
- preview:
- '# PRD Generator\n\ntriggers: ["PRD", "需求文档", "产品方案"]\ntools: [markdown_write, memory_search]\n\n## Instructions\n生成产品需求文档,自动关联记忆和联系人。',
- },
-];
-
-// ─── Session 2: Proactive Daily Digest (Automation) ───────────
-
-const SESSION_2_MESSAGES: Message[] = [
- {
- from: "clone",
- content: "",
- cards: [
- {
- type: "automation",
- title: "🔔 今日战况复盘",
- status: "running",
- body: "分身主动触发 · automation/daily-digest.yaml\n正在扫描今日 3 个活跃 Session...",
- path: "automation/daily-digest.yaml",
- meta: "cron: 每天 22:00 · 飞书群推送",
- actions: [{ label: "暂停规则" }, { label: "修改配置" }],
- },
- ],
- },
- {
- from: "clone",
- content: "",
- cards: [
- {
- type: "skill",
- title: "Daily Digest Automation",
- status: "success",
- body: "✓ 扫描 3 个活跃 Session\n✓ 检测 5 个新文件变更\n✓ 关联 3 位联系人",
- path: "automation/daily-digest.yaml",
- meta: "耗时 8s · 自动执行",
- },
- ],
- tool: { name: "执行 Daily Digest Automation", icon: Clock, status: "done" },
- },
- {
- from: "clone",
- content: "",
- cards: [
- {
- type: "file",
- title: "今日战况复盘 — 2026-02-21",
- status: "success",
- body: "✅ 完成:注册流程优化 PRD、竞品调研\n🔄 进行中:OAuth 集成(王浩)、数据库 Schema(陈杰)\n⚠️ 风险:Google OAuth 密钥未配置\n\n📈 产出:新增 5 文件 · 更新 3 条记忆",
- path: "artifacts/reports/daily-digest-0221.md",
- diff: { added: 35, removed: 0 },
- actions: [{ label: "打开报告", primary: true }, { label: "发到飞书群" }],
- viralCta: "让同事的分身也加入日报?邀请 →",
- },
- {
- type: "collaboration",
- title: "已推送到飞书「产品团队」群",
- status: "success",
- body: "@张明 @李薇 @王浩 已通知\n卡片已发送至群聊",
- meta: "feishu-push · 3 人已读",
- viralCta: "群成员也想要自己的分身?",
- },
- ],
- fileOps: [
- { action: "create", path: "artifacts/reports/daily-digest-0221.md" },
- { action: "write", path: "memory/context/current-sprint.md" },
- ],
- },
- { from: "user", content: "帮我把这个 digest 的频率改成每天 21:00,不要 22:00" },
- {
- from: "clone",
- content: "",
- cards: [
- {
- type: "automation",
- title: "Automation 配置已更新",
- status: "success",
- body: "⏰ cron: 0 22 * * * → 0 21 * * *\n每天 21:00 自动执行战况复盘",
- path: "automation/daily-digest.yaml",
- diff: { added: 1, removed: 1 },
- meta: "下次触发:明天 21:00",
- actions: [{ label: "查看规则" }, { label: "测试执行" }],
- },
- ],
- fileOps: [{ action: "write", path: "automation/daily-digest.yaml" }],
- },
-];
-
-const SESSION_2_FILE_OPS: SessionFileOp[] = [
- {
- action: "create",
- path: "artifacts/reports/daily-digest-0221.md",
- fileType: "markdown",
- size: "1.8 KB",
- time: "22:00",
- diff: { added: 35, removed: 0 },
- preview:
- "# 今日战况复盘 — 2026-02-21\n\n## 完成\n- ✅ 注册流程优化 PRD\n- ✅ 竞品注册流程调研\n\n## 进行中\n- 🔄 OAuth 集成(王浩)\n- 🔄 数据库 Schema 设计(陈杰)\n\n## 风险\n- ⚠️ Google OAuth 密钥未配置\n\n## 产出\n- 新增 5 个文件\n- 更新 3 条记忆\n- 涉及 3 位联系人",
- },
- {
- action: "write",
- path: "automation/daily-digest.yaml",
- fileType: "yaml",
- size: "0.4 KB",
- time: "22:05",
- diff: { added: 1, removed: 1 },
- preview:
- '# Daily Digest Automation\n\nname: 今日战况复盘\ncron: "0 21 * * *"\nchannel: feishu\n\nsteps:\n - scan_sessions\n - scan_memory_changes\n - generate_report\n - push_to_feishu',
- },
- {
- action: "write",
- path: "memory/context/current-sprint.md",
- fileType: "markdown",
- size: "1.2 KB",
- time: "22:01",
- diff: { added: 8, removed: 2 },
- preview:
- "# Current Sprint — W9\n\n## 今日进展(自动更新)\n- 注册优化 PRD 已完成\n- 竞品分析已生成\n- OAuth 集成进行中",
- },
- {
- action: "read",
- path: "sessions/2026-02-21-注册优化/thread.jsonl",
- fileType: "jsonl",
- size: "4.2 KB",
- time: "22:00",
- preview: "(会话日志 — 28 条消息)\n\n扫描今日所有会话,提取关键产出和决策...",
- },
- {
- action: "read",
- path: "memory/context/current-sprint.md",
- fileType: "markdown",
- size: "1.0 KB",
- time: "22:00",
- preview: "# Current Sprint — W9\n\n读取当前 sprint 状态以生成日报...",
- },
- {
- action: "execute",
- path: "automation/daily-digest.yaml",
- fileType: "yaml",
- size: "—",
- time: "22:00",
- preview:
- "# Daily Digest Automation\n\n## 执行结果\n✓ 扫描 3 个活跃 session\n✓ 检测到 5 个新文件变更\n✓ 生成战况报告\n✓ 推送到飞书群",
- },
- {
- action: "execute",
- path: "skills/feishu-push/SKILL.md",
- fileType: "skill",
- size: "—",
- time: "22:01",
- preview:
- '# Feishu Push\n\ntriggers: ["推送", "飞书", "通知"]\ntools: [feishu_api, markdown_read]\n\n## 执行结果\n✓ 推送到「产品团队」群\n✓ @了张明、李薇、王浩',
- },
-];
-
-// ─── Session 3: Deep Research + Context Upload ───────────────
-
-const SESSION_3_MESSAGES: Message[] = [
- {
- from: "user",
- content: "帮我做一份深度竞品分析报告,这是我收集的资料",
- attachments: [
- { name: "linear-pricing.png", type: "image", size: "240 KB" },
- { name: "notion-ai-features.png", type: "image", size: "185 KB" },
- { name: "cursor-agent-mode.png", type: "image", size: "320 KB" },
- { name: "AI Agent 市场格局报告.pdf", type: "pdf", size: "2.3 MB" },
- ],
- },
- {
- from: "clone",
- content: "收到 4 份资料(3 张截图 + 1 份 PDF 报告)。让我先整理上传的 context...",
- fileOps: [
- { action: "create", path: "knowledge/references/competitor-linear-pricing.png" },
- { action: "create", path: "knowledge/references/competitor-linear.md" },
- { action: "create", path: "knowledge/references/competitor-notion.md" },
- { action: "create", path: "knowledge/references/competitor-cursor.md" },
- { action: "create", path: "knowledge/references/ai-agent-landscape.pdf" },
- ],
- },
- {
- from: "clone",
- content: "",
- tool: { name: "Deep Research — 联网搜索竞品信息", icon: Globe, status: "done" },
- },
- {
- from: "clone",
- content: "",
- tool: { name: "Deep Research — 分析产品定价策略", icon: BarChart3, status: "done" },
- },
- {
- from: "clone",
- content: "",
- fileOps: [
- { action: "read", path: "memory/facts/project-refly.md" },
- { action: "read", path: "knowledge/architecture.md" },
- ],
- },
- {
- from: "clone",
- content:
- "深度分析完成。结合你上传的资料 + 联网搜索 + 你的项目上下文,生成了完整报告:\n\n📄 artifacts/research/竞品深度分析.md\n\n关键发现:\n1. Linear 的 AI-first 策略正在吃掉 Jira 份额\n2. Notion AI 月付费转化率仅 12%\n3. Cursor 的 agent 模式是我们最直接的参考\n\n建议 nexu 差异化方向:记忆 + 文件系统 + 多渠道。",
- fileOps: [
- { action: "create", path: "artifacts/research/竞品深度分析.md" },
- { action: "write", path: "memory/decisions/competitive-positioning.md" },
- ],
- },
-];
-
-const SESSION_3_FILE_OPS: SessionFileOp[] = [
- {
- action: "create",
- path: "artifacts/research/竞品深度分析.md",
- fileType: "markdown",
- size: "5.8 KB",
- time: "16:45",
- diff: { added: 128, removed: 0 },
- preview:
- "# 竞品深度分析报告\n\n## Linear\n- AI-first 项目管理\n- 月活 200K+,ARR $50M\n- 强项:速度、设计、AI triage\n\n## Notion\n- AI 助手 + 知识库\n- Notion AI 付费转化率 ~12%\n- 弱项:agent 能力有限\n\n## Cursor\n- AI-native IDE\n- Agent mode 是关键差异化\n- 参考:filesystem + agent 交互模式",
- },
- {
- action: "create",
- path: "artifacts/research/竞品对比数据.xlsx",
- fileType: "xlsx",
- size: "89 KB",
- time: "16:44",
- preview:
- "[Excel] 3 个竞品的功能矩阵对比\n\nSheet 1: 功能对比 (34 维度)\nSheet 2: 定价对比\nSheet 3: 技术栈分析",
- },
- {
- action: "create",
- path: "knowledge/references/competitor-linear-pricing.png",
- fileType: "image",
- size: "240 KB",
- time: "16:30",
- preview: "[截图] Linear 定价页面截图 — $8/user/mo, 3 tier 结构",
- },
- {
- action: "create",
- path: "knowledge/references/competitor-linear.md",
- fileType: "markdown",
- size: "1.2 KB",
- time: "16:30",
- diff: { added: 24, removed: 0 },
- preview:
- "# Linear — 竞品资料\n\n**来源**: 用户上传截图 + 联网搜索\n**定价**: $8/user/mo\n**特点**: AI triage, cycles, projects",
- },
- {
- action: "create",
- path: "knowledge/references/competitor-notion.md",
- fileType: "markdown",
- size: "1.0 KB",
- time: "16:30",
- diff: { added: 20, removed: 0 },
- preview:
- "# Notion — 竞品资料\n\n**来源**: 用户上传截图 + 联网搜索\n**定价**: $10/user/mo (AI add-on)\n**特点**: 知识库, wiki, AI Q&A",
- },
- {
- action: "create",
- path: "knowledge/references/competitor-cursor.md",
- fileType: "markdown",
- size: "1.1 KB",
- time: "16:30",
- diff: { added: 22, removed: 0 },
- preview:
- "# Cursor — 竞品资料\n\n**来源**: 用户上传截图 + 联网搜索\n**定价**: $20/mo Pro\n**特点**: Agent mode, codebase-aware, tab completion",
- },
- {
- action: "create",
- path: "knowledge/references/ai-agent-landscape.pdf",
- fileType: "pdf",
- size: "2.3 MB",
- time: "16:28",
- preview:
- "[PDF] AI Agent 2026 市场格局报告\n\n来源: a16z Research, 45 pages\n用户上传的参考文献,OCR 提取关键数据用于分析",
- },
- {
- action: "write",
- path: "memory/decisions/competitive-positioning.md",
- fileType: "markdown",
- size: "0.9 KB",
- time: "16:46",
- diff: { added: 18, removed: 0 },
- preview:
- "# Competitive Positioning\n\n**决策**: nexu 差异化方向\n- 记忆系统(vs Notion 的无状态 AI)\n- 文件系统范式(vs Linear 的 SaaS 范式)\n- 多渠道集成(vs Cursor 的 IDE-only)",
- },
- {
- action: "read",
- path: "memory/facts/project-refly.md",
- fileType: "markdown",
- size: "0.8 KB",
- time: "16:35",
- preview: "# Project Refly\n\n核心产品信息,用于对比竞品时理解自身定位...",
- },
- {
- action: "read",
- path: "knowledge/architecture.md",
- fileType: "markdown",
- size: "1.5 KB",
- time: "16:35",
- preview: "# Architecture\n\n技术架构文档,用于评估竞品技术方案可行性...",
- },
- {
- action: "execute",
- path: "skills/web-research/SKILL.md",
- fileType: "skill",
- size: "—",
- time: "16:32",
- preview:
- "# Web Research\n\n## 执行结果\n✓ 搜索 Linear, Notion, Cursor 最新动态\n✓ 抓取定价页面和 changelog\n✓ 分析 ProductHunt 评论",
- },
- {
- action: "execute",
- path: "skills/deep-analysis/SKILL.md",
- fileType: "skill",
- size: "—",
- time: "16:40",
- preview:
- '# Deep Analysis\n\ntriggers: ["分析", "对比", "研究"]\ntools: [web_search, markdown_write, memory_read]\n\n## 执行结果\n✓ 交叉对比 3 个竞品\n✓ SWOT 分析完成\n✓ 生成定位建议',
- },
-];
-
-// ─── Session 4: Linear + Code + Deploy ───────────────────────
-
-const SESSION_4_MESSAGES: Message[] = [
- {
- from: "user",
- content: "帮我拉一下 Linear 上这周的需求,然后写数据库迁移的代码",
- attachments: [
- { name: "db-schema-v2.sql", type: "code", size: "3.4 KB" },
- { name: "migration-guide.md", type: "document", size: "1.8 KB" },
- ],
- },
- {
- from: "clone",
- content: "正在连接 Linear...",
- tool: { name: "拉取 Linear Issues — Sprint W9", icon: GitBranch, status: "done" },
- },
- {
- from: "clone",
- content: "",
- fileOps: [
- { action: "read", path: "knowledge/architecture.md" },
- { action: "read", path: "memory/preferences/tech-stack.md" },
- ],
- },
- {
- from: "clone",
- content:
- "从 Linear 拉取了 4 个 Issue:\n\n1. NEX-42: 用户表增加 OAuth 字段\n2. NEX-43: 创建 sessions 表\n3. NEX-44: 添加 memory 索引\n4. NEX-45: 联系人关联表\n\n基于你的技术栈偏好(PostgreSQL + TypeORM),我来生成迁移代码。",
- },
- {
- from: "clone",
- content: "",
- fileOps: [
- { action: "create", path: "artifacts/code/migration-001-oauth.sql" },
- { action: "create", path: "artifacts/code/migration-002-sessions.sql" },
- { action: "create", path: "artifacts/code/migration-003-memory-index.sql" },
- ],
- },
- {
- from: "clone",
- content: "",
- tool: { name: "Code Review — 检查 SQL 语法", icon: Shield, status: "done" },
- },
- {
- from: "clone",
- content:
- "3 个迁移文件已生成:\n\n```\nmigration-001-oauth.sql — 用户表 OAuth 字段\nmigration-002-sessions.sql — sessions 表\nmigration-003-memory-index.sql — memory 全文索引\n```\n\n代码已通过 lint 检查。要我帮你创建 PR 吗?",
- fileOps: [
- { action: "write", path: "memory/context/current-sprint.md" },
- { action: "write", path: "contacts/陈杰-后端.md" },
- ],
- },
- { from: "user", content: "创建 PR 吧,分配给陈杰 review" },
- {
- from: "clone",
- content: "",
- tool: { name: "创建 GitHub PR #127", icon: GitBranch, status: "done" },
- },
- {
- from: "clone",
- content:
- "PR 已创建:\n\n🔗 PR #127: feat: database migrations for OAuth, sessions, memory\n📋 Reviewer: 陈杰\n🏷️ Labels: database, migration\n\nLinear issues 状态已更新为 In Review。",
- fileOps: [{ action: "write", path: "contacts/陈杰-后端.md" }],
- },
-];
-
-const SESSION_4_FILE_OPS: SessionFileOp[] = [
- {
- action: "create",
- path: "artifacts/code/migration-001-oauth.sql",
- fileType: "code",
- size: "0.9 KB",
- time: "14:20",
- diff: { added: 24, removed: 0 },
- preview:
- "-- Migration 001: OAuth Fields\n\nALTER TABLE users\n ADD COLUMN google_id VARCHAR(255),\n ADD COLUMN avatar_url TEXT,\n ADD COLUMN auth_provider VARCHAR(50) DEFAULT 'email',\n ADD COLUMN last_login_at TIMESTAMP;\n\nCREATE INDEX idx_users_google_id ON users(google_id);",
- },
- {
- action: "create",
- path: "artifacts/code/migration-002-sessions.sql",
- fileType: "code",
- size: "1.2 KB",
- time: "14:21",
- diff: { added: 32, removed: 0 },
- preview:
- "-- Migration 002: Sessions Table\n\nCREATE TABLE sessions (\n id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n user_id UUID REFERENCES users(id),\n title VARCHAR(255),\n channel VARCHAR(50),\n created_at TIMESTAMP DEFAULT now(),\n updated_at TIMESTAMP DEFAULT now()\n);",
- },
- {
- action: "create",
- path: "artifacts/code/migration-003-memory-index.sql",
- fileType: "code",
- size: "0.6 KB",
- time: "14:22",
- diff: { added: 16, removed: 0 },
- preview:
- "-- Migration 003: Memory Full-Text Index\n\nCREATE EXTENSION IF NOT EXISTS pg_trgm;\n\nCREATE INDEX idx_memory_content_trgm\n ON memories USING gin(content gin_trgm_ops);\n\nCREATE INDEX idx_memory_tags\n ON memories USING gin(tags);",
- },
- {
- action: "write",
- path: "memory/context/current-sprint.md",
- fileType: "markdown",
- size: "1.4 KB",
- time: "14:25",
- diff: { added: 6, removed: 1 },
- preview:
- "# Current Sprint — W9\n\n## 更新\n- NEX-42~45 迁移代码已完成\n- PR #127 已创建,等待陈杰 review",
- },
- {
- action: "write",
- path: "contacts/陈杰-后端.md",
- fileType: "contact",
- size: "0.8 KB",
- time: "14:26",
- diff: { added: 4, removed: 0 },
- preview:
- "# 陈杰\n\n**角色**: 后端工程师\n**最近交互**: 数据库迁移 PR review\n**待办**: Review PR #127\n**专长**: PostgreSQL, TypeORM, NestJS",
- },
- {
- action: "read",
- path: "knowledge/architecture.md",
- fileType: "markdown",
- size: "1.5 KB",
- time: "14:18",
- preview: "# Architecture\n\n读取架构文档以理解数据库 schema 设计...",
- },
- {
- action: "read",
- path: "memory/preferences/tech-stack.md",
- fileType: "markdown",
- size: "0.5 KB",
- time: "14:18",
- preview: "# Tech Stack Preferences\n\n读取技术栈偏好以选择正确的迁移方案...",
- },
- {
- action: "execute",
- path: "skills/linear-sync/SKILL.md",
- fileType: "skill",
- size: "—",
- time: "14:15",
- preview:
- '# Linear Sync\n\ntriggers: ["linear", "需求", "issue"]\ntools: [linear_api, markdown_write]\nauth: linear_oauth (✓ 已授权)\n\n## 执行结果\n✓ 拉取 Sprint W9 的 4 个 issue\n✓ 状态同步完成',
- },
- {
- action: "execute",
- path: "skills/code-automation/SKILL.md",
- fileType: "skill",
- size: "—",
- time: "14:20",
- preview:
- '# Code Automation\n\ntriggers: ["写代码", "迁移", "PR"]\ntools: [code_write, github_api, lint]\n\n## 执行结果\n✓ 生成 3 个 SQL 迁移文件\n✓ 通过 SQL lint 检查\n✓ 创建 PR #127',
- },
- {
- action: "execute",
- path: "skills/github-pr/SKILL.md",
- fileType: "skill",
- size: "—",
- time: "14:25",
- preview:
- '# GitHub PR\n\ntriggers: ["PR", "review", "合并"]\ntools: [github_api]\nauth: github_oauth (✓ 已授权)\n\n## 执行结果\n✓ 创建 PR #127\n✓ 分配 reviewer: 陈杰\n✓ 添加 labels: database, migration',
- },
- {
- action: "write",
- path: "contacts/陈杰-后端.md",
- fileType: "contact",
- size: "0.8 KB",
- time: "14:28",
- diff: { added: 2, removed: 0 },
- preview: "# 陈杰\n\n**待办更新**: Review PR #127",
- },
-];
-
-// ─── Session 5: Create Skills + Automation ───────────────────
-
-const SESSION_5_MESSAGES: Message[] = [
- {
- from: "user",
- content: "帮我创建一个新 skill:每周 Sprint 回顾自动化。还需要配一个 automation 定时触发",
- },
- {
- from: "clone",
- content: "好的,我来帮你搭建这个 skill + automation 组合。\n\n先看看现有的 sprint 数据结构...",
- fileOps: [
- { action: "read", path: "memory/context/current-sprint.md" },
- { action: "read", path: "automation/daily-digest.yaml" },
- ],
- },
- {
- from: "clone",
- content: "",
- fileOps: [
- { action: "create", path: "skills/sprint-review/SKILL.md" },
- { action: "create", path: "skills/sprint-review/config.yaml" },
- ],
- },
- {
- from: "clone",
- content:
- "Skill 已创建:\n\n📦 skills/sprint-review/\n├── SKILL.md — skill 定义和 triggers\n└── config.yaml — 工具和权限配置\n\n这个 skill 需要用到 Linear API,我检测到你还没有授权。需要我帮你配置吗?",
- },
- { from: "user", content: "好的,帮我授权 Linear,然后配 automation" },
- {
- from: "clone",
- content: "",
- tool: { name: "配置 Linear OAuth 授权", icon: Shield, status: "done" },
- },
- {
- from: "clone",
- content: "",
- fileOps: [
- { action: "install", path: "skills/sprint-review/SKILL.md" },
- { action: "create", path: "automation/weekly-sprint-review.yaml" },
- ],
- },
- {
- from: "clone",
- content:
- "全部配置完成:\n\n✅ Linear OAuth 已授权\n✅ sprint-review skill 已安装并激活\n✅ automation 已创建:每周五 18:00 自动执行\n\n流程:Linear Issues → 分析完成度 → 生成回顾报告 → 推送飞书\n\n下周五 18:00 会自动执行第一次。你也可以手动触发测试。",
- fileOps: [{ action: "write", path: "memory/decisions/sprint-review-automation.md" }],
- },
-];
-
-const SESSION_5_FILE_OPS: SessionFileOp[] = [
- {
- action: "create",
- path: "skills/sprint-review/SKILL.md",
- fileType: "skill",
- size: "1.4 KB",
- time: "10:15",
- diff: { added: 35, removed: 0 },
- preview:
- '# Sprint Review\n\ntriggers: ["sprint", "回顾", "复盘", "周报"]\ntools: [linear_api, markdown_write, feishu_push]\nauth: [linear_oauth]\n\n## Instructions\n1. 从 Linear 拉取当前 sprint 所有 issues\n2. 统计完成率、velocity\n3. 生成 sprint 回顾报告\n4. 推送到飞书',
- },
- {
- action: "create",
- path: "skills/sprint-review/config.yaml",
- fileType: "yaml",
- size: "0.5 KB",
- time: "10:16",
- diff: { added: 15, removed: 0 },
- preview:
- "# Sprint Review Config\n\nname: sprint-review\nversion: 1.0.0\n\ntools:\n - linear_api\n - markdown_write\n - feishu_push\n\nauth:\n linear:\n type: oauth\n status: authorized",
- },
- {
- action: "create",
- path: "automation/weekly-sprint-review.yaml",
- fileType: "yaml",
- size: "0.4 KB",
- time: "10:20",
- diff: { added: 12, removed: 0 },
- preview:
- '# Weekly Sprint Review\n\nname: 本周 Sprint 回顾\ncron: "0 18 * * 5"\nskill: sprint-review\nchannel: feishu\n\nsteps:\n - pull_linear_issues\n - analyze_completion\n - generate_report\n - push_to_feishu',
- },
- {
- action: "write",
- path: "memory/decisions/sprint-review-automation.md",
- fileType: "markdown",
- size: "0.6 KB",
- time: "10:22",
- diff: { added: 12, removed: 0 },
- preview:
- "# Decision: Sprint Review Automation\n\n**日期**: 2026-02-19\n**决策**: 使用自建 skill + automation 实现每周 sprint 回顾\n**工具**: Linear API + 飞书推送\n**频率**: 每周五 18:00",
- },
- {
- action: "read",
- path: "memory/context/current-sprint.md",
- fileType: "markdown",
- size: "1.2 KB",
- time: "10:12",
- preview: "# Current Sprint — W9\n\n读取当前 sprint 结构作为 skill 设计参考...",
- },
- {
- action: "read",
- path: "automation/daily-digest.yaml",
- fileType: "yaml",
- size: "0.3 KB",
- time: "10:12",
- preview: "# Daily Digest\n\n参考现有 automation 的配置格式...",
- },
- {
- action: "install",
- path: "skills/sprint-review/SKILL.md",
- fileType: "skill",
- size: "1.4 KB",
- time: "10:18",
- preview:
- "# Sprint Review — 安装完成\n\n✓ Skill 已激活\n✓ Linear OAuth 已授权\n✓ 工具权限已配置\n✓ 加入已安装列表",
- },
- {
- action: "execute",
- path: "skills/sprint-review/SKILL.md",
- fileType: "skill",
- size: "—",
- time: "10:22",
- preview:
- "# Sprint Review — 测试运行\n\n## 执行结果(测试)\n✓ 连接 Linear API 成功\n✓ 拉取 Sprint W9: 12 issues\n✓ 完成率: 67% (8/12)\n✓ Velocity: 42 pts\n✓ 报告生成成功",
- },
-];
-
-// ─── Session 6: Design + Notes + Knowledge Management ────────
-
-const SESSION_6_MESSAGES: Message[] = [
- {
- from: "user",
- content: "我有一些关于 landing page 的想法,先帮我记下来,然后用 Figma skill 出几个设计方案",
- attachments: [
- { name: "灵感语音备忘.m4a", type: "audio", size: "1.2 MB" },
- { name: "linear-homepage-ref.png", type: "image", size: "450 KB" },
- { name: "vercel-landing-ref.png", type: "image", size: "380 KB" },
- ],
- },
- {
- from: "clone",
- content: "好的,先记录你的想法到记忆系统...",
- fileOps: [{ action: "create", path: "memory/ideas/landing-page-v2.md" }],
- },
- {
- from: "user",
- content:
- '- hero section 要大胆一点,突出"你的数字分身"\n- 加竞品对比表\n- 底部要有 FAQ\n- 整体风格偏 Linear 那种克制感\n- CTA 要明确:立即体验',
- },
- {
- from: "clone",
- content: "已记录 5 条想法。让我把这些组织一下...",
- fileOps: [
- { action: "write", path: "memory/ideas/landing-page-v2.md" },
- { action: "read", path: "knowledge/references/competitor-linear.md" },
- { action: "read", path: "artifacts/prds/注册流程优化.md" },
- ],
- },
- {
- from: "clone",
- content: "",
- tool: { name: "搜索优秀 SaaS Landing Page 案例", icon: Globe, status: "done" },
- },
- {
- from: "clone",
- content: "",
- tool: { name: "Figma — 生成 Landing Page 设计方案", icon: Palette, status: "done" },
- },
- {
- from: "clone",
- content: "",
- fileOps: [
- { action: "create", path: "artifacts/designs/landing-page-v2-A.md" },
- { action: "create", path: "artifacts/designs/landing-page-v2-B.md" },
- { action: "execute", path: "skills/figma-design/SKILL.md" },
- ],
- },
- {
- from: "clone",
- content:
- '设计方案已生成:\n\n🎨 方案 A:大字报风格 — "Your mind, extended."\n - Hero 全屏渐变 + 浮动终端动画\n - 突出文件系统交互\n\n🎨 方案 B:产品截图风格 — Show, don\'t tell\n - Hero 区展示真实产品截图\n - 侧重功能演示\n\n两个方案的 Figma 文件已生成。你的笔记已归档到知识库。',
- fileOps: [
- { action: "write", path: "knowledge/references/landing-page-best-practices.md" },
- { action: "write", path: "memory/ideas/landing-page-v2.md" },
- ],
- },
-];
-
-const SESSION_6_FILE_OPS: SessionFileOp[] = [
- {
- action: "create",
- path: "artifacts/designs/landing-v2.figma",
- fileType: "figma",
- size: "4.2 MB",
- time: "15:40",
- preview:
- "[Figma 文件] Landing Page V2\n\n含 2 个 Page:\n- 方案 A: 大字报风格\n- 方案 B: 产品截图风格\n\n8 个 Frame, 24 个组件",
- },
- {
- action: "create",
- path: "artifacts/designs/hero-mockup.png",
- fileType: "image",
- size: "380 KB",
- time: "15:41",
- preview: "[PNG 图片] Hero 区域设计稿预览\n\n1440×900, 方案 A\n全屏渐变背景 + 浮动终端动画",
- },
- {
- action: "create",
- path: "artifacts/designs/landing-page-v2-A.md",
- fileType: "markdown",
- size: "2.8 KB",
- time: "15:40",
- diff: { added: 56, removed: 0 },
- preview:
- '# Landing Page V2 — 方案 A\n\n## 风格:大字报\n标语: "Your mind, extended."\n\n### Hero\n- 全屏渐变背景(暖白 → 浅金)\n- 中间浮动终端动画:展示文件系统交互\n- CTA: "立即体验" (醒目按钮)',
- },
- {
- action: "create",
- path: "artifacts/designs/landing-page-v2-B.md",
- fileType: "markdown",
- size: "2.4 KB",
- time: "15:42",
- diff: { added: 48, removed: 0 },
- preview:
- '# Landing Page V2 — 方案 B\n\n## 风格:产品截图\n标语: "Meet your digital clone."\n\n### Hero\n- 左文右图:真实产品截图\n- 动态演示会话 + 文件树',
- },
- {
- action: "create",
- path: "artifacts/designs/onboarding-flow.svg",
- fileType: "svg",
- size: "18 KB",
- time: "15:43",
- preview:
- "[SVG 矢量图] Onboarding 用户流程图\n\n入口 → 角色选择 → 技能激活 → 首次对话 → 上岗完成",
- },
- {
- action: "create",
- path: "artifacts/media/product-demo.mp4",
- fileType: "video",
- size: "12.6 MB",
- time: "15:44",
- preview:
- "[视频] 产品演示录屏 — 45 秒\n\n内容:从添加 Bot → 对话 → 生成 PRD → Feeds 查看\n分辨率:1920×1080, 30fps",
- },
- {
- action: "create",
- path: "memory/ideas/landing-page-v2.md",
- fileType: "markdown",
- size: "0.8 KB",
- time: "15:25",
- diff: { added: 18, removed: 0 },
- preview:
- '# Landing Page V2 Ideas\n\n## 用户想法(原始记录)\n- hero section 要大胆,突出"你的数字分身"\n- 加竞品对比表\n- 底部要有 FAQ',
- },
- {
- action: "write",
- path: "memory/ideas/landing-page-v2.md",
- fileType: "markdown",
- size: "1.2 KB",
- time: "15:45",
- diff: { added: 8, removed: 0 },
- preview:
- "# Landing Page V2 Ideas\n\n## 已整理\n- 方案 A & B 已生成 Figma + PNG\n- 产品 demo 视频已录制\n- 参考了 Linear, Vercel, Raycast 案例",
- },
- {
- action: "write",
- path: "knowledge/references/landing-page-best-practices.md",
- fileType: "markdown",
- size: "1.6 KB",
- time: "15:43",
- diff: { added: 32, removed: 0 },
- preview:
- "# Landing Page Best Practices\n\n## 来源\n联网搜索 + 案例分析\n\n## 关键原则\n- Above the fold: 价值主张 + CTA\n- Mobile-first 设计",
- },
- {
- action: "read",
- path: "knowledge/references/competitor-linear.md",
- fileType: "markdown",
- size: "1.2 KB",
- time: "15:30",
- preview: "# Linear — 竞品资料\n\n参考 Linear 的设计风格和克制感...",
- },
- {
- action: "read",
- path: "artifacts/prds/注册流程优化.md",
- fileType: "markdown",
- size: "2.1 KB",
- time: "15:30",
- preview: "# 注册流程优化 PRD\n\n参考注册流程以确保 landing page CTA 与注册衔接...",
- },
- {
- action: "execute",
- path: "skills/figma-design/SKILL.md",
- fileType: "skill",
- size: "—",
- time: "15:38",
- preview:
- '# Figma Design\n\ntriggers: ["设计", "figma", "UI", "出图"]\ntools: [figma_api, image_gen]\nauth: figma_oauth (✓ 已授权)\n\n## 执行结果\n✓ 生成 Figma 文件 (2 方案)\n✓ 导出 PNG 预览\n✓ 生成 SVG 流程图\n✓ 录制产品 demo 视频',
- },
- {
- action: "execute",
- path: "skills/web-research/SKILL.md",
- fileType: "skill",
- size: "—",
- time: "15:32",
- preview:
- '# Web Research\n\n## 执行结果\n✓ 搜索 "best SaaS landing pages 2026"\n✓ 分析 Linear, Vercel, Raycast, Supabase\n✓ 提取设计模式和最佳实践',
- },
- {
- action: "install",
- path: "skills/figma-design/SKILL.md",
- fileType: "skill",
- size: "1.3 KB",
- time: "15:26",
- preview:
- "# Figma Design — 安装\n\n⚠️ 此 skill 需要 Figma OAuth 授权\n\n✓ 授权完成\n✓ Skill 已激活\n✓ 支持自动出图、导出、评审",
- },
-];
-
-// ─── Session 7: CRM Intelligence — Contact Relationship Analysis ──
-
-const SESSION_7_MESSAGES: Message[] = [
- { from: "user", content: "帮我分析一下我最近的联系人情况,有哪些人超过 30 天没联系了?" },
- {
- from: "clone",
- content: "正在扫描你的联系人网络...",
- fileOps: [
- { action: "read", path: "contacts/张明-CTO.md" },
- { action: "read", path: "contacts/李薇-PM.md" },
- { action: "read", path: "contacts/王浩-前端.md" },
- { action: "read", path: "contacts/陈杰-后端.md" },
- ],
- },
- {
- from: "clone",
- content: "",
- tool: { name: "联系人健康度扫描", icon: BarChart3, status: "done" },
- },
- {
- from: "clone",
- content:
- "联系人关系分析完成。共 24 位联系人,6 位需要关注:\n\n🔴 超过 60 天未联系:\n · 刘强 (投资人) — 上次互动 2/1,讨论 Series A\n · 赵雪 (设计师) — 上次互动 1/25,外包 Logo\n\n🟡 超过 30 天未联系:\n · 周磊 (前同事) — 上次互动 2/8,推荐候选人\n · 孙倩 (市场) — 上次互动 2/5,合作推广\n · 马飞 (CEO/合作方) — 上次互动 2/10,API 对接\n · 林涛 (技术顾问) — 上次互动 2/12,架构讨论\n\n💡 建议:刘强是 Series A 关键联系人,建议本周主动更新进展。",
- fileOps: [
- { action: "create", path: "artifacts/reports/contact-health-0222.md" },
- { action: "write", path: "contacts/刘强-投资人.md" },
- ],
- },
- { from: "user", content: "帮我给刘强起草一封邮件,更新最近的产品进展" },
- {
- from: "clone",
- content: "让我先整理最近的进展...",
- fileOps: [
- { action: "read", path: "memory/decisions/competitive-positioning.md" },
- { action: "read", path: "contacts/刘强-投资人.md" },
- { action: "read", path: "memory/context/current-sprint.md" },
- ],
- },
- {
- from: "clone",
- content:
- "邮件草稿已生成:\n\n📧 给刘强的进展更新\n\n基于你上次和他讨论的 3 个关注点(产品定位、用户数据、团队)逐一更新。\n\n已保存到 artifacts/,需要我通过飞书邮箱发送吗?发送前你确认一下内容。",
- fileOps: [
- { action: "create", path: "artifacts/emails/investor-update-liuqiang-0222.md" },
- { action: "write", path: "contacts/刘强-投资人.md" },
- ],
- },
-];
-
-const SESSION_7_FILE_OPS: SessionFileOp[] = [
- {
- action: "create",
- path: "artifacts/reports/contact-health-0222.md",
- fileType: "markdown",
- size: "2.4 KB",
- time: "19:15",
- diff: { added: 52, removed: 0 },
- preview:
- "# 联系人健康度报告 — 2026-02-22\n\n## 统计\n- 总联系人: 24\n- 活跃 (7天内): 8\n- 正常 (30天内): 10\n- 需关注 (30-60天): 4\n- 流失风险 (>60天): 2\n\n## 建议行动\n1. 刘强 — 投资人更新\n2. 赵雪 — 设计交付确认",
- },
- {
- action: "create",
- path: "artifacts/emails/investor-update-liuqiang-0222.md",
- fileType: "markdown",
- size: "1.8 KB",
- time: "19:20",
- diff: { added: 38, removed: 0 },
- preview:
- '# Investor Update — 刘强\n\n刘强你好,\n\n上次见面后产品有了重要进展:\n\n1. 产品定位确认为"数字分身"\n2. 核心记忆系统已上线\n3. 团队新增 1 名后端工程师\n\n附:最新 demo 录屏链接',
- },
- {
- action: "write",
- path: "contacts/刘强-投资人.md",
- fileType: "contact",
- size: "1.1 KB",
- time: "19:21",
- diff: { added: 5, removed: 0 },
- preview:
- "# 刘强\n\n**角色**: 投资人 (Series A)\n**关系健康度**: 🔴 需要关注\n**上次互动**: 2026-02-01\n**关注点**: 产品定位、用户数据、团队\n**待办**: 发送进展更新邮件",
- },
- {
- action: "read",
- path: "contacts/张明-CTO.md",
- fileType: "contact",
- size: "0.7 KB",
- time: "19:10",
- preview: "# 张明\n\n读取联系人信息用于健康度分析...",
- },
- {
- action: "read",
- path: "contacts/李薇-PM.md",
- fileType: "contact",
- size: "0.6 KB",
- time: "19:10",
- preview: "# 李薇\n\n读取联系人信息用于健康度分析...",
- },
- {
- action: "read",
- path: "contacts/王浩-前端.md",
- fileType: "contact",
- size: "0.7 KB",
- time: "19:10",
- preview: "# 王浩\n\n读取联系人信息用于健康度分析...",
- },
- {
- action: "read",
- path: "memory/decisions/competitive-positioning.md",
- fileType: "markdown",
- size: "0.9 KB",
- time: "19:18",
- preview: "# Competitive Positioning\n\n读取竞争定位决策,用于投资人更新...",
- },
- {
- action: "execute",
- path: "skills/contact-intelligence/SKILL.md",
- fileType: "skill",
- size: "—",
- time: "19:12",
- preview:
- '# Contact Intelligence\n\ntriggers: ["联系人", "关系", "谁"]\ntools: [contact_scan, memory_search]\n\n## 执行结果\n✓ 扫描 24 个联系人\n✓ 计算关系健康度\n✓ 生成 6 条关注建议',
- },
-];
-
-// ─── Session 8: Meeting Action Item Tracker ───────────────────
-
-const SESSION_8_MESSAGES: Message[] = [
- { from: "user", content: "帮我整理今天下午产品对齐会的行动项,这是会议录音的转录" },
- {
- from: "clone",
- content: "正在分析会议内容并匹配联系人...",
- fileOps: [
- { action: "read", path: "contacts/张明-CTO.md" },
- { action: "read", path: "contacts/李薇-PM.md" },
- { action: "read", path: "contacts/王浩-前端.md" },
- { action: "read", path: "contacts/陈杰-后端.md" },
- ],
- },
- {
- from: "clone",
- content: "",
- tool: { name: "会议 Action Item 提取", icon: Clock, status: "done" },
- },
- {
- from: "clone",
- content:
- "从会议转录中提取了 7 个行动项:\n\n📌 你的行动项 (3):\n 1. ☐ 定稿注册流程 PRD — 截止明天\n 2. ☐ 和刘强确认 Series A 时间线 — 本周内\n 3. ☐ 审核飞书 Bot 权限设计 — 周三前\n\n⏳ 等待对方 (4):\n 4. 🔄 张明:完成安全审计方案 — 周三前\n 5. 🔄 李薇:输出竞品功能对比 — 周四前\n 6. 🔄 王浩:飞书扫码 demo — 明天\n 7. 🔄 陈杰:数据库 Schema 初稿 — 周三前\n\n要我创建对应的 Todo 吗?分身会自动追踪每个人是否按时完成。",
- fileOps: [
- { action: "create", path: "artifacts/meeting-notes/product-alignment-0222.md" },
- { action: "write", path: "contacts/张明-CTO.md" },
- { action: "write", path: "contacts/李薇-PM.md" },
- ],
- },
- { from: "user", content: "好的,创建 Todo 吧" },
- {
- from: "clone",
- content:
- '已创建 7 个 Todo,分为两组:\n\n✅ 你的 3 个已加入今日/本周待办\n🔄 对方的 4 个设为"等待中"状态\n\n分身每天 10:00 / 15:00 / 20:00 会自动检查完成情况。如果王浩明天没提交 demo,我会提醒你跟进。',
- fileOps: [
- { action: "write", path: "memory/context/current-sprint.md" },
- { action: "write", path: "memory/decisions/product-alignment-0222.md" },
- ],
- },
-];
-
-const SESSION_8_FILE_OPS: SessionFileOp[] = [
- {
- action: "create",
- path: "artifacts/meeting-notes/product-alignment-0222.md",
- fileType: "markdown",
- size: "3.2 KB",
- time: "16:30",
- diff: { added: 68, removed: 0 },
- preview:
- "# 产品对齐会纪要 — 2026-02-22\n\n## 参会人\n黄巍(CEO), 张明(CTO), 李薇(PM), 王浩(前端), 陈杰(后端)\n\n## 讨论要点\n1. 注册流程优化 — 采用 OAuth 方案\n2. 安全架构 — 需要独立审计\n3. 飞书 Bot — 扫码登录 demo\n\n## 行动项\n- [owner:黄巍] 定稿注册流程 PRD\n- [waiting:张明] 安全审计方案\n- [waiting:王浩] 飞书扫码 demo",
- },
- {
- action: "write",
- path: "memory/decisions/product-alignment-0222.md",
- fileType: "markdown",
- size: "0.8 KB",
- time: "16:35",
- diff: { added: 15, removed: 0 },
- preview:
- "# Product Alignment Decision — 2026-02-22\n\n**参会人**: 5 人\n**关键决策**:\n- OAuth 方案确认\n- 安全审计独立进行\n- 飞书 Bot 优先做扫码",
- },
- {
- action: "write",
- path: "memory/context/current-sprint.md",
- fileType: "markdown",
- size: "1.5 KB",
- time: "16:36",
- diff: { added: 7, removed: 0 },
- preview:
- '# Current Sprint — W9\n\n## 更新(产品对齐会后)\n- 新增 3 个你的 action items\n- 新增 4 个"等待中"追踪项',
- },
- {
- action: "write",
- path: "contacts/张明-CTO.md",
- fileType: "contact",
- size: "0.9 KB",
- time: "16:32",
- diff: { added: 3, removed: 0 },
- preview: "# 张明\n\n**待办**: 完成安全审计方案 (周三前)\n**状态**: waiting on",
- },
- {
- action: "write",
- path: "contacts/李薇-PM.md",
- fileType: "contact",
- size: "0.7 KB",
- time: "16:32",
- diff: { added: 3, removed: 0 },
- preview: "# 李薇\n\n**待办**: 输出竞品功能对比 (周四前)\n**状态**: waiting on",
- },
- {
- action: "execute",
- path: "skills/meeting-action-tracker/SKILL.md",
- fileType: "skill",
- size: "—",
- time: "16:28",
- preview:
- '# Meeting Action Tracker\n\ntriggers: ["会议", "action item", "行动项"]\ntools: [transcript_parse, contact_match, todo_create]\n\n## 执行结果\n✓ 解析会议转录\n✓ 匹配 4 位联系人\n✓ 提取 7 个 action items\n✓ 区分 mine (3) vs waiting (4)',
- },
-];
-
-// ─── Session 9: Proxy Session (分身代问) ─────────────────────
-
-const SESSION_9_MESSAGES: Message[] = [
- {
- from: "user",
- content: "帮我问一下李四 Gateway 重构进度怎么样了,会不会影响我的前端集成?",
- },
- {
- from: "clone",
- content: "",
- cards: [
- {
- type: "collaboration",
- title: "正在连接李四的分身",
- status: "running",
- body: "你的分身 → 李四的分身\n代理查询 Gateway 重构进度",
- path: "contacts/李四-后端.md",
- meta: "Proxy 模式 · 自动发起",
- },
- ],
- fileOps: [{ action: "read", path: "contacts/李四-后端.md" }],
- },
- {
- from: "clone",
- content: "",
- cards: [
- {
- type: "collaboration",
- title: "李四分身回复:Gateway 进度",
- status: "success",
- body: "整体进度:15%(刚启动)\n✓ API 路由层重构:已完成\n🔄 中间件迁移:进行中(鉴权兼容问题)\n📅 预计完成:周四下午",
- path: "contacts/李四-后端.md",
- meta: "Proxy 回复 · 2 分钟",
- actions: [{ label: "查看详情" }, { label: "追问" }],
- viralCta: "李四还没有分身?邀请他创建 →",
- },
- ],
- },
- {
- from: "clone",
- content: "⚠️ 按照当前进度,你的前端集成可能需要延后 1 天。",
- cards: [
- {
- type: "memory",
- title: "决策已记录",
- status: "success",
- body: "Gateway 重构优先级调整\n建议优先处理中间件迁移",
- path: "team/decisions/2026-02-23-gateway-priority.md",
- meta: "团队决策 · 自动归档",
- },
- ],
- fileOps: [{ action: "write", path: "team/decisions/2026-02-23-gateway-priority.md" }],
- },
- {
- from: "user",
- content: "发起对齐,建议他优先处理中间件迁移",
- },
- {
- from: "clone",
- content: "",
- cards: [
- {
- type: "collaboration",
- title: "对齐请求已发送",
- status: "success",
- body: "🤝 推送到 #product-team 群\n内容:建议优先处理中间件迁移\n等待李四确认...",
- meta: "Team Alignment · 待确认",
- actions: [{ label: "查看卡片", primary: true }, { label: "撤回" }],
- },
- {
- type: "upgrade",
- title: "Proxy 功能试用额度",
- status: "warning",
- body: "本月已使用 8/10 次 Proxy 代理对话\n升级 Pro 可无限使用 Proxy + 团队协作",
- actions: [{ label: "升级 Pro — ¥199/月", primary: true }, { label: "暂不需要" }],
- viralCta: "邀请 3 位同事,免费获得 Pro 30 天",
- },
- ],
- },
-];
-
-const SESSION_9_FILE_OPS: SessionFileOp[] = [
- {
- action: "read",
- path: "contacts/李四-后端.md",
- fileType: "contact",
- size: "2.1 KB",
- time: "10:30",
- },
- {
- action: "write",
- path: "team/decisions/2026-02-23-gateway-priority.md",
- fileType: "markdown",
- size: "1.4 KB",
- time: "10:32",
- preview:
- "# Gateway 重构优先级调整\n\n**日期**: 2026-02-23\n**类型**: 团队对齐\n\n## 决策\n建议李四优先处理中间件迁移,确保前端集成不延期。",
- },
-];
-
-// ─── Session Data Map ─────────────────────────────────────────
-
-export const SESSION_DATA: Record = {
- 1: { messages: SESSION_1_MESSAGES, fileOps: SESSION_1_FILE_OPS },
- 6: { messages: SESSION_2_MESSAGES, fileOps: SESSION_2_FILE_OPS },
- 7: { messages: SESSION_7_MESSAGES, fileOps: SESSION_7_FILE_OPS },
- 8: { messages: SESSION_8_MESSAGES, fileOps: SESSION_8_FILE_OPS },
- 2: { messages: SESSION_3_MESSAGES, fileOps: SESSION_3_FILE_OPS },
- 3: { messages: SESSION_4_MESSAGES, fileOps: SESSION_4_FILE_OPS },
- 4: { messages: SESSION_5_MESSAGES, fileOps: SESSION_5_FILE_OPS },
- 5: { messages: SESSION_6_MESSAGES, fileOps: SESSION_6_FILE_OPS },
- 9: { messages: SESSION_9_MESSAGES, fileOps: SESSION_9_FILE_OPS },
-};
diff --git a/apps/demo/src/pages/product/teamData.ts b/apps/demo/src/pages/product/teamData.ts
deleted file mode 100644
index 80d6343d..00000000
--- a/apps/demo/src/pages/product/teamData.ts
+++ /dev/null
@@ -1,1268 +0,0 @@
-import { Briefcase, Clipboard, Code, type LucideIcon, Palette, Shield } from "lucide-react";
-
-export interface TeamMember {
- name: string;
- role: string;
- avatar: string;
- level: number;
- alignmentRate: number;
- status: "online" | "busy" | "away" | "offline";
- tasksInProgress: number;
- tasksCompleted: number;
- lastActive: string;
- channel: string;
- icon: LucideIcon;
-}
-
-export type IMCardType =
- | "status_query"
- | "alignment_request"
- | "event_notification"
- | "summary_report"
- | "growth_trigger";
-
-export interface TaskProgress {
- name: string;
- progress: number;
- status: string;
- risk?: boolean;
-}
-
-export interface StandupMember {
- name: string;
- avatar: string;
- summary: string;
- risk?: string;
- done?: boolean;
-}
-
-export interface IMCardBase {
- id: number;
- type: IMCardType;
- from: string;
- fromAvatar: string;
- channel: string;
- time: string;
- read: boolean;
-}
-
-export interface StatusQueryCard extends IMCardBase {
- type: "status_query";
- target: string;
- tasks: TaskProgress[];
- note: string;
-}
-
-export interface AlignmentRequestCard extends IMCardBase {
- type: "alignment_request";
- topic: string;
- reason: string;
- suggestion: string;
- urgency: "low" | "medium" | "high";
- status: "pending" | "accepted" | "rejected";
-}
-
-export interface EventNotificationCard extends IMCardBase {
- type: "event_notification";
- event: string;
- impact: string;
- updates: string[];
-}
-
-export interface SummaryReportCard extends IMCardBase {
- type: "summary_report";
- sprintName: string;
- progress: number;
- members: StandupMember[];
- risks: string[];
-}
-
-export interface GrowthTriggerCard extends IMCardBase {
- type: "growth_trigger";
- taskTitle: string;
- timeSaved: string;
- manualEstimate: string;
- weeklyStats: { tasks: number; hours: number };
-}
-
-export type IMCard =
- | StatusQueryCard
- | AlignmentRequestCard
- | EventNotificationCard
- | SummaryReportCard
- | GrowthTriggerCard;
-
-export interface SprintTask {
- id: string;
- title: string;
- assignee: string;
- status: "done" | "in_progress" | "blocked" | "todo";
- progress: number;
- dependency?: string;
-}
-
-export const TEAM_MEMBERS: TeamMember[] = [
- {
- name: "张三",
- role: "前端工程师",
- avatar: "👨💻",
- level: 3,
- alignmentRate: 87,
- status: "online",
- tasksInProgress: 2,
- tasksCompleted: 14,
- lastActive: "刚刚",
- channel: "飞书",
- icon: Code,
- },
- {
- name: "李四",
- role: "后端工程师",
- avatar: "🧑💻",
- level: 2,
- alignmentRate: 73,
- status: "online",
- tasksInProgress: 1,
- tasksCompleted: 9,
- lastActive: "5 分钟前",
- channel: "飞书",
- icon: Shield,
- },
- {
- name: "王五",
- role: "UI/UX 设计师",
- avatar: "👩🎨",
- level: 3,
- alignmentRate: 91,
- status: "busy",
- tasksInProgress: 3,
- tasksCompleted: 18,
- lastActive: "20 分钟前",
- channel: "Slack",
- icon: Palette,
- },
- {
- name: "赵六",
- role: "产品经理",
- avatar: "👩💼",
- level: 4,
- alignmentRate: 95,
- status: "online",
- tasksInProgress: 2,
- tasksCompleted: 22,
- lastActive: "刚刚",
- channel: "飞书",
- icon: Briefcase,
- },
- {
- name: "孙七",
- role: "QA 工程师",
- avatar: "🧑🔬",
- level: 1,
- alignmentRate: 45,
- status: "away",
- tasksInProgress: 0,
- tasksCompleted: 3,
- lastActive: "2 小时前",
- channel: "飞书",
- icon: Clipboard,
- },
-];
-
-export const IM_CARDS: IMCard[] = [
- {
- id: 1,
- type: "summary_report",
- from: "赵六的分身",
- fromAvatar: "👩💼",
- channel: "飞书",
- time: "09:05",
- read: true,
- sprintName: "Sprint 3",
- progress: 58,
- members: [
- {
- name: "张三",
- avatar: "👨💻",
- summary: "前端集成(等Gateway) + 单元测试 85%",
- risk: undefined,
- },
- {
- name: "李四",
- avatar: "🧑💻",
- summary: "Gateway 重构刚启动",
- risk: "Gateway 进度偏慢",
- },
- { name: "王五", avatar: "👩🎨", summary: "设计稿 v2 完成 90%", done: true },
- ],
- risks: ["Gateway 重构进度偏慢,可能影响前端集成"],
- },
- {
- id: 2,
- type: "status_query",
- from: "你的分身",
- fromAvatar: "😊",
- channel: "飞书",
- time: "10:30",
- read: true,
- target: "设计组",
- tasks: [
- { name: "设计稿 v2", progress: 90, status: "周三前完成" },
- { name: "暗色主题", progress: 100, status: "已完成" },
- { name: "交互原型", progress: 60, status: "周三评审" },
- ],
- note: "周三下午可以评审交互原型,提前发你 Figma 链接",
- },
- {
- id: 3,
- type: "event_notification",
- from: "系统通知",
- fromAvatar: "🔔",
- channel: "飞书",
- time: "11:20",
- read: false,
- event: "阻塞解除",
- impact: "你的「前端集成」可以启动了",
- updates: ["任务状态:blocked → ready", "预计完成:周五"],
- },
- {
- id: 4,
- type: "alignment_request",
- from: "张三的分身",
- fromAvatar: "👨💻",
- channel: "飞书",
- time: "14:00",
- read: false,
- topic: "Gateway 重构排期提前",
- reason: "前端集成依赖 Gateway 重构,当前尚未开始,整体可能延期 2 天。",
- suggestion: "提前启动 Gateway 重构",
- urgency: "high",
- status: "pending",
- },
- {
- id: 5,
- type: "growth_trigger",
- from: "张三的分身",
- fromAvatar: "👨💻",
- channel: "飞书",
- time: "17:30",
- read: true,
- taskTitle: "Sprint 3 周报",
- timeSaved: "2 分钟",
- manualEstimate: "45 分钟",
- weeklyStats: { tasks: 12, hours: 6.5 },
- },
-];
-
-// ─── Detail Data ─────────────────────────────────────────
-
-export interface BIPStep {
- label: string;
- status: "done" | "active" | "pending";
- detail?: string;
-}
-
-export interface FileOp {
- action: "read" | "write" | "create";
- path: string;
- time?: string;
-}
-
-export interface ActivityItem {
- time: string;
- content: string;
- type: "card" | "task" | "alignment" | "session";
-}
-
-export interface TaskChangeLog {
- time: string;
- from: string;
- to: string;
-}
-
-export const CARD_BIP_FLOWS: Record = {
- 1: [
- {
- label: "每日 09:00 触发站会汇总",
- status: "done",
- detail: "cron: 0 9 * * 1-5",
- },
- {
- label: "BIP query → 张三、李四、王五的分身",
- status: "done",
- detail: "并行查询 3 个分身的 workspace",
- },
- {
- label: "各分身检索 Sprint 任务记忆",
- status: "done",
- detail: "读取任务状态、进度、风险标注",
- },
- {
- label: "汇总数据 + 风险分析",
- status: "done",
- detail: "聚合进度、检测依赖风险",
- },
- {
- label: "生成 IM 卡片 → 推送飞书 #product-team",
- status: "done",
- detail: "Interactive Card JSON",
- },
- ],
- 2: [
- {
- label: '你发起"查询设计组进度"',
- status: "done",
- detail: "用户在 Session 中输入",
- },
- {
- label: "BIP query → 王五的分身",
- status: "done",
- detail: "路由到 /bip/query",
- },
- {
- label: "王五分身检索 Sprint 任务记忆",
- status: "done",
- detail: "读取设计相关任务",
- },
- {
- label: "组装回复 + 分身备注",
- status: "done",
- detail: "附加周三评审时间提醒",
- },
- {
- label: "返回结果 → 渲染 IM 卡片",
- status: "done",
- detail: "自动回复,无需打扰王五",
- },
- ],
- 3: [
- {
- label: "李四完成 API 路由层重构",
- status: "done",
- detail: "任务 T-003 进度变更",
- },
- {
- label: "依赖图检测:T-001 阻塞解除",
- status: "done",
- detail: "T-001 依赖 T-003",
- },
- {
- label: "BIP event → 通知张三的分身",
- status: "done",
- detail: "推送阻塞解除事件",
- },
- { label: "生成事件通知卡片", status: "done" },
- { label: "推送飞书 #product-team", status: "done" },
- ],
- 4: [
- {
- label: "张三分身检测到依赖风险",
- status: "done",
- detail: "T-001 依赖 T-003,T-003 进度 15%",
- },
- { label: "分析影响:前端集成可能延期 2 天", status: "done" },
- {
- label: "BIP action → 发起对齐请求",
- status: "done",
- detail: "路由到 /bip/action/alignment",
- },
- { label: "生成对齐请求 IM 卡片", status: "done" },
- { label: "推送卡片 → 等待李四确认", status: "active", detail: "⏳ 待回复" },
- ],
- 5: [
- {
- label: '张三分身完成"Sprint 3 周报"',
- status: "done",
- detail: "耗时 2 分钟",
- },
- {
- label: "计算效率对比",
- status: "done",
- detail: "手动预估 45 分钟 → 实际 2 分钟",
- },
- { label: "汇总本周数据:12 任务 / 6.5h 节省", status: "done" },
- { label: "生成裂变触发卡片", status: "done" },
- {
- label: "推送到 #product-team(含 CTA)",
- status: "done",
- detail: '"我也想要一个分身"',
- },
- ],
-};
-
-export const CARD_FILE_OPS: Record = {
- 1: [
- { action: "read", path: "team/sprint.md", time: "09:05" },
- { action: "create", path: "team/standup/2026-02-23.md", time: "09:05" },
- { action: "write", path: "team/sprint.md", time: "09:05" },
- ],
- 2: [
- { action: "read", path: "contacts/王五-设计.md", time: "10:30" },
- { action: "read", path: "team/sprint.md", time: "10:30" },
- ],
- 3: [{ action: "write", path: "team/sprint.md", time: "11:20" }],
- 4: [
- { action: "read", path: "team/sprint.md", time: "14:00" },
- {
- action: "create",
- path: "team/decisions/2026-02-23-gateway-priority.md",
- time: "14:00",
- },
- ],
- 5: [
- {
- action: "create",
- path: "artifacts/reports/sprint-3-weekly.md",
- time: "17:30",
- },
- ],
-};
-
-export const MEMBER_ACTIVITIES: Record = {
- 张三: [
- {
- time: "14:00",
- content: "发起对齐请求:Gateway 重构排期提前",
- type: "alignment",
- },
- { time: "10:30", content: "被查询任务进度(设计组)", type: "card" },
- {
- time: "09:05",
- content: "站会汇总:前端集成(等Gateway) + 测试 85%",
- type: "card",
- },
- { time: "昨天 16:00", content: "完成单元测试 80% → 85%", type: "task" },
- { time: "昨天 10:00", content: "代问:李四 Gateway 计划", type: "session" },
- ],
- 李四: [
- {
- time: "14:00",
- content: "收到对齐请求:Gateway 重构排期",
- type: "alignment",
- },
- { time: "09:05", content: "站会汇总:Gateway 重构刚启动 ⚠️", type: "card" },
- { time: "昨天 18:00", content: "完成 API 路由层重构", type: "task" },
- {
- time: "昨天 14:00",
- content: "接收代问:Gateway 进度查询",
- type: "session",
- },
- ],
- 王五: [
- { time: "10:30", content: "分身自动回复:设计组任务进度", type: "card" },
- { time: "09:05", content: "站会汇总:设计稿 v2 完成 90% ✓", type: "card" },
- { time: "昨天 20:00", content: "完成暗色主题适配 100%", type: "task" },
- {
- time: "昨天 16:30",
- content: "对齐通过:设计稿评审时间调整",
- type: "alignment",
- },
- ],
- 赵六: [
- { time: "09:05", content: "分身生成站会汇总卡片", type: "card" },
- { time: "昨天 17:00", content: "需求评审进度更新 60% → 70%", type: "task" },
- { time: "昨天 09:05", content: "分身生成昨日站会汇总", type: "card" },
- ],
- 孙七: [
- { time: "2 小时前", content: "分身初始化中(Lv.1)", type: "session" },
- { time: "昨天 15:00", content: "创建分身账号", type: "session" },
- ],
-};
-
-export const TASK_CHANGE_LOGS: Record = {
- "T-001": [
- { time: "11:20 今天", from: "blocked", to: "blocked(部分解除)" },
- { time: "02-22 14:00", from: "in_progress", to: "blocked" },
- { time: "02-20 10:00", from: "todo", to: "in_progress" },
- ],
- "T-002": [
- { time: "昨天 16:00", from: "80%", to: "85%" },
- { time: "02-21 10:00", from: "60%", to: "80%" },
- { time: "02-20 14:00", from: "todo", to: "in_progress" },
- ],
- "T-003": [
- { time: "今天 08:00", from: "todo", to: "in_progress(15%)" },
- { time: "02-22 09:00", from: "—", to: "todo" },
- ],
- "T-005": [
- { time: "今天 09:00", from: "85%", to: "90%" },
- { time: "02-21 14:00", from: "70%", to: "85%" },
- { time: "02-19 10:00", from: "todo", to: "in_progress" },
- ],
- "T-006": [
- { time: "昨天 20:00", from: "in_progress", to: "done(100%)" },
- { time: "02-20 10:00", from: "todo", to: "in_progress" },
- ],
-};
-
-export const ALIGNMENT_HISTORY = [
- {
- id: "a1",
- topic: "设计稿评审时间调整",
- from: "王五",
- fromAvatar: "👩🎨",
- status: "accepted" as const,
- time: "昨天 16:30",
- reason: "设计稿 v2 需要更多时间打磨暗色主题细节",
- response: "同意,评审推迟到周三",
- },
- {
- id: "a2",
- topic: "API 版本升级方案",
- from: "李四",
- fromAvatar: "🧑💻",
- status: "accepted" as const,
- time: "2 天前",
- reason: "v2 API 可以向后兼容,建议逐步迁移",
- response: "同意渐进式升级",
- },
- {
- id: "a3",
- topic: "测试环境部署窗口",
- from: "孙七",
- fromAvatar: "🧑🔬",
- status: "rejected" as const,
- time: "3 天前",
- reason: "希望每天下午固定部署窗口",
- response: "当前开发节奏不适合固定窗口",
- },
-];
-
-// ─── OKR Data ──────────────────────────────────────────────
-
-export interface KeyResult {
- id: string;
- title: string;
- target: string;
- current: string;
- progress: number;
- owner: string;
- linkedTasks: string[];
- unit?: string;
-}
-
-export interface Objective {
- id: string;
- title: string;
- description: string;
- owner: string;
- ownerAvatar: string;
- quarter: string;
- progress: number;
- status: "on_track" | "at_risk" | "behind" | "achieved";
- keyResults: KeyResult[];
- tags: string[];
-}
-
-export const OBJECTIVES: Objective[] = [
- {
- id: "O-1",
- title: "建立完整的分身协作网络,实现团队效率 2x 提升",
- description:
- "通过 BIP 协议实现分身间自动通信和任务协调,减少人工协调成本,让每个成员的分身成为其 24/7 数字代理",
- owner: "赵六",
- ownerAvatar: "👩💼",
- quarter: "2026-Q1",
- progress: 52,
- status: "on_track",
- keyResults: [
- {
- id: "KR-1-1",
- title: "分身网络覆盖率达到 100%",
- target: "5/5 成员",
- current: "4/5 成员",
- progress: 80,
- owner: "赵六",
- linkedTasks: [],
- },
- {
- id: "KR-1-2",
- title: "代问 Session 日均使用量 ≥ 10 次",
- target: "10 次/天",
- current: "6 次/天",
- progress: 60,
- owner: "张三",
- linkedTasks: ["T-001", "T-003"],
- unit: "次/天",
- },
- {
- id: "KR-1-3",
- title: "对齐请求自动发起率 ≥ 70%",
- target: "70%",
- current: "45%",
- progress: 64,
- owner: "李四",
- linkedTasks: ["T-003"],
- unit: "%",
- },
- {
- id: "KR-1-4",
- title: "站会汇总自动化替代率达到 100%",
- target: "100%",
- current: "100%",
- progress: 100,
- owner: "赵六",
- linkedTasks: ["T-008"],
- },
- ],
- tags: ["分身网络", "BIP 协议", "效率"],
- },
- {
- id: "O-2",
- title: "完成 nexu v3 核心产品交付,达到 Demo Day 水准",
- description:
- "前端 + 后端 + 设计系统完成 MVP,具备可展示的端到端用户体验,覆盖 Onboarding → 对话 → 自动化 → 团队 全流程",
- owner: "赵六",
- ownerAvatar: "👩💼",
- quarter: "2026-Q1",
- progress: 48,
- status: "at_risk",
- keyResults: [
- {
- id: "KR-2-1",
- title: "前端核心页面完成度 ≥ 90%",
- target: "90%",
- current: "65%",
- progress: 72,
- owner: "张三",
- linkedTasks: ["T-001", "T-002"],
- },
- {
- id: "KR-2-2",
- title: "Gateway API 重构完成并通过集成测试",
- target: "100%",
- current: "15%",
- progress: 15,
- owner: "李四",
- linkedTasks: ["T-003", "T-004"],
- },
- {
- id: "KR-2-3",
- title: "设计系统组件覆盖率 ≥ 85%",
- target: "85%",
- current: "90%",
- progress: 100,
- owner: "王五",
- linkedTasks: ["T-005", "T-006", "T-007"],
- },
- {
- id: "KR-2-4",
- title: "端到端用户旅程可走通(Onboarding → Team)",
- target: "完成",
- current: "70%",
- progress: 70,
- owner: "赵六",
- linkedTasks: ["T-009"],
- },
- ],
- tags: ["产品交付", "v3", "Demo Day"],
- },
- {
- id: "O-3",
- title: "构建数据驱动的团队健康度系统",
- description: "通过分身网络收集任务进度、依赖关系、沟通频率等数据,自动生成团队健康度指标和预警",
- owner: "赵六",
- ownerAvatar: "👩💼",
- quarter: "2026-Q1",
- progress: 30,
- status: "behind",
- keyResults: [
- {
- id: "KR-3-1",
- title: "依赖风险自动检测准确率 ≥ 80%",
- target: "80%",
- current: "50%",
- progress: 62,
- owner: "李四",
- linkedTasks: ["T-003"],
- },
- {
- id: "KR-3-2",
- title: "团队负载均衡指数达标(无人超 120%)",
- target: "≤ 120%",
- current: "王五 135%",
- progress: 40,
- owner: "赵六",
- linkedTasks: [],
- },
- {
- id: "KR-3-3",
- title: "周报/月报自动生成功能上线",
- target: "上线",
- current: "开发中",
- progress: 25,
- owner: "张三",
- linkedTasks: ["T-002"],
- },
- ],
- tags: ["数据驱动", "团队健康度", "预警"],
- },
-];
-
-// ─── Sprint Enhanced Data (for Gantt) ──────────────────────
-
-export interface SprintTaskGantt extends SprintTask {
- startDate: string;
- endDate: string;
- color?: string;
-}
-
-export const SPRINT_META = {
- name: "Sprint 3",
- startDate: "2026-02-17",
- endDate: "2026-03-02",
- totalDays: 14,
-};
-
-export const SPRINT_TASKS_GANTT: SprintTaskGantt[] = [
- {
- id: "T-001",
- title: "前端集成",
- assignee: "张三",
- status: "blocked",
- progress: 30,
- dependency: "T-003",
- startDate: "2026-02-20",
- endDate: "2026-02-28",
- color: "bg-danger",
- },
- {
- id: "T-002",
- title: "单元测试",
- assignee: "张三",
- status: "in_progress",
- progress: 85,
- startDate: "2026-02-18",
- endDate: "2026-02-25",
- },
- {
- id: "T-003",
- title: "Gateway 重构",
- assignee: "李四",
- status: "in_progress",
- progress: 15,
- startDate: "2026-02-23",
- endDate: "2026-03-01",
- color: "bg-warning",
- },
- {
- id: "T-004",
- title: "用户鉴权模块",
- assignee: "李四",
- status: "todo",
- progress: 0,
- dependency: "T-005",
- startDate: "2026-02-26",
- endDate: "2026-03-02",
- },
- {
- id: "T-005",
- title: "设计稿 v2",
- assignee: "王五",
- status: "in_progress",
- progress: 90,
- startDate: "2026-02-17",
- endDate: "2026-02-25",
- },
- {
- id: "T-006",
- title: "暗色主题适配",
- assignee: "王五",
- status: "done",
- progress: 100,
- startDate: "2026-02-17",
- endDate: "2026-02-22",
- },
- {
- id: "T-007",
- title: "交互原型",
- assignee: "王五",
- status: "in_progress",
- progress: 60,
- startDate: "2026-02-19",
- endDate: "2026-02-26",
- },
- {
- id: "T-008",
- title: "Sprint 规划",
- assignee: "赵六",
- status: "done",
- progress: 100,
- startDate: "2026-02-17",
- endDate: "2026-02-18",
- },
- {
- id: "T-009",
- title: "需求评审",
- assignee: "赵六",
- status: "in_progress",
- progress: 70,
- startDate: "2026-02-18",
- endDate: "2026-02-24",
- },
-];
-
-// ─── Insights Chat Data ────────────────────────────────────
-
-export interface InsightMessage {
- id: string;
- from: "user" | "agent";
- content: string;
- time: string;
- references?: {
- type: "task" | "member" | "okr" | "card";
- label: string;
- id: string;
- }[];
- chart?: {
- type: "bar" | "metric";
- data: { label: string; value: number; color?: string }[];
- };
-}
-
-export const INSIGHT_SUGGESTIONS = [
- "本周 Sprint 有什么风险?",
- "谁的任务负载最重?",
- "OKR 哪些 KR 落后了?",
- "张三和李四之间的依赖关系是什么?",
- "帮我生成本周周报",
- "对比上周和本周的进度变化",
-];
-
-export const INSIGHT_CONVERSATIONS: InsightMessage[] = [
- {
- id: "i1",
- from: "user",
- content: "Sprint 3 目前有什么风险?",
- time: "14:35",
- },
- {
- id: "i2",
- from: "agent",
- content:
- "分析了 Sprint 3 的 9 个任务,发现 **2 个关键风险**:\n\n1. **Gateway 重构(T-003)进度偏慢** — 当前 15%,预期本周应达 50%。这会直接阻塞张三的前端集成(T-001),影响链路:T-003 → T-001。建议李四优先处理。\n\n2. **王五任务负载过高** — 同时进行 3 个任务(设计稿 v2、交互原型、暗色主题),负载约 135%。虽然暗色主题已完成,但交互原型仅 60% 可能延期。",
- time: "14:35",
- references: [
- { type: "task", label: "T-003 Gateway 重构", id: "T-003" },
- { type: "task", label: "T-001 前端集成", id: "T-001" },
- { type: "member", label: "王五", id: "王五" },
- ],
- chart: {
- type: "bar",
- data: [
- { label: "张三", value: 57, color: "bg-clone" },
- { label: "李四", value: 8, color: "bg-danger" },
- { label: "王五", value: 83, color: "bg-warning" },
- { label: "赵六", value: 85, color: "bg-success" },
- ],
- },
- },
- {
- id: "i3",
- from: "user",
- content: "OKR 进展怎么样?哪些 KR 需要关注?",
- time: "14:38",
- },
- {
- id: "i4",
- from: "agent",
- content:
- "当前 3 个 Objective 的整体健康度:\n\n- **O-1 分身协作网络** (52%) — ✅ On Track,站会汇总已 100% 自动化,但代问使用量和对齐自动率还需提升\n- **O-2 产品交付** (48%) — ⚠️ At Risk,主要瓶颈是 Gateway API 重构仅 15%,拖累整体\n- **O-3 团队健康度** (30%) — 🔴 Behind,负载均衡和自动报告功能均未达标\n\n**最需关注的 KR**:\n1. KR-2-2 Gateway API (15%) — 直接影响产品交付目标\n2. KR-3-2 负载均衡(王五 135%) — 需重新分配任务\n3. KR-1-2 代问使用量(6/10 次/天) — 需推广使用习惯",
- time: "14:38",
- references: [
- { type: "okr", label: "O-2 产品交付", id: "O-2" },
- { type: "okr", label: "KR-2-2 Gateway API", id: "KR-2-2" },
- { type: "member", label: "王五", id: "王五" },
- ],
- chart: {
- type: "metric",
- data: [
- { label: "O-1 协作网络", value: 52, color: "bg-success" },
- { label: "O-2 产品交付", value: 48, color: "bg-warning" },
- { label: "O-3 健康度", value: 30, color: "bg-danger" },
- ],
- },
- },
-];
-
-// ─── Task Board Data ────────────────────────────────────────
-
-export type TaskStatus = "backlog" | "todo" | "in_progress" | "done" | "archived";
-export type TaskPriority = "urgent" | "high" | "medium" | "low";
-export type TaskSource = "manual" | "session" | "im" | "automation" | "okr";
-export type TaskExecutor = "human" | "agent" | "hybrid";
-
-export interface TaskItem {
- id: string;
- title: string;
- description?: string;
- status: TaskStatus;
- priority: TaskPriority;
- assignee: string;
- assigneeAvatar: string;
- executor: TaskExecutor;
- source: TaskSource;
- sourceRef?: string;
- sprintId?: string;
- okrId?: string;
- okrTitle?: string;
- tags: string[];
- createdAt: string;
- updatedAt: string;
- dueDate?: string;
- progress: number;
- subtasks?: { title: string; done: boolean }[];
- linkedFiles?: string[];
- comments: number;
- dependencies?: string[];
-}
-
-export const TASK_BOARD: TaskItem[] = [
- {
- id: "TK-001",
- title: "前端登录页集成 Gateway API",
- description: "完成前端登录页与新 Gateway API 的对接,包括 OAuth 流程和 token 刷新机制",
- status: "in_progress",
- priority: "urgent",
- assignee: "张三",
- assigneeAvatar: "👨💻",
- executor: "human",
- source: "okr",
- sourceRef: "KR-2-1",
- sprintId: "Sprint 3",
- okrId: "KR-2-1",
- okrTitle: "前端核心页面完成度 ≥ 90%",
- tags: ["前端", "集成", "阻塞中"],
- createdAt: "02-20",
- updatedAt: "今天 11:20",
- dueDate: "02-28",
- progress: 30,
- subtasks: [
- { title: "OAuth 流程适配", done: true },
- { title: "Token 刷新机制", done: false },
- { title: "错误处理和重试", done: false },
- { title: "登录状态持久化", done: false },
- ],
- linkedFiles: ["frontend/src/auth/login.tsx", "frontend/src/hooks/useAuth.ts"],
- comments: 4,
- dependencies: ["TK-003"],
- },
- {
- id: "TK-002",
- title: "单元测试覆盖率提升至 85%",
- description: "为核心模块补充单元测试,目标覆盖率 85%",
- status: "in_progress",
- priority: "high",
- assignee: "张三",
- assigneeAvatar: "👨💻",
- executor: "hybrid",
- source: "manual",
- sprintId: "Sprint 3",
- okrId: "KR-2-1",
- okrTitle: "前端核心页面完成度 ≥ 90%",
- tags: ["测试", "CI/CD"],
- createdAt: "02-18",
- updatedAt: "今天 09:00",
- dueDate: "02-25",
- progress: 85,
- subtasks: [
- { title: "Auth 模块测试", done: true },
- { title: "Chat 模块测试", done: true },
- { title: "File 模块测试", done: true },
- { title: "Team 模块测试", done: false },
- ],
- linkedFiles: ["frontend/src/__tests__/"],
- comments: 2,
- },
- {
- id: "TK-003",
- title: "Gateway API 重构",
- description: "重构 Gateway 层,支持 BIP 协议和分身间通信",
- status: "in_progress",
- priority: "urgent",
- assignee: "李四",
- assigneeAvatar: "🧑💻",
- executor: "human",
- source: "okr",
- sourceRef: "KR-2-2",
- sprintId: "Sprint 3",
- okrId: "KR-2-2",
- okrTitle: "Gateway API 重构完成并通过集成测试",
- tags: ["后端", "架构", "关键路径"],
- createdAt: "02-22",
- updatedAt: "今天 08:00",
- dueDate: "03-01",
- progress: 15,
- subtasks: [
- { title: "路由层重构", done: true },
- { title: "BIP 协议接入", done: false },
- { title: "分身通信通道", done: false },
- { title: "集成测试", done: false },
- ],
- linkedFiles: ["backend/src/gateway/", "backend/src/bip/"],
- comments: 6,
- },
- {
- id: "TK-004",
- title: "竞品分析报告更新",
- description: "本周竞品动态汇总,包括 Notion AI blocks 发布分析",
- status: "done",
- priority: "medium",
- assignee: "赵六",
- assigneeAvatar: "👩💼",
- executor: "agent",
- source: "automation",
- sourceRef: "竞品监控自动任务",
- tags: ["市场", "竞品", "自动生成"],
- createdAt: "02-23",
- updatedAt: "今天 09:00",
- progress: 100,
- linkedFiles: ["clone/artifacts/reports/competitive-weekly.md"],
- comments: 1,
- },
- {
- id: "TK-005",
- title: "设计稿 v2 最终审查",
- description: "暗色主题和交互原型的最终设计审查",
- status: "in_progress",
- priority: "high",
- assignee: "王五",
- assigneeAvatar: "👩🎨",
- executor: "human",
- source: "manual",
- sprintId: "Sprint 3",
- okrId: "KR-2-3",
- okrTitle: "设计系统组件覆盖率 ≥ 85%",
- tags: ["设计", "评审"],
- createdAt: "02-17",
- updatedAt: "今天 10:30",
- dueDate: "02-25",
- progress: 90,
- subtasks: [
- { title: "亮色主题", done: true },
- { title: "暗色主题", done: true },
- { title: "响应式适配", done: true },
- { title: "动效规范", done: false },
- ],
- comments: 3,
- },
- {
- id: "TK-006",
- title: "整理本周站会纪要",
- description: "分身自动汇总本周 5 次站会的要点",
- status: "done",
- priority: "low",
- assignee: "赵六",
- assigneeAvatar: "👩💼",
- executor: "agent",
- source: "session",
- sourceRef: "Session #daily-standup",
- tags: ["文档", "自动生成"],
- createdAt: "02-23",
- updatedAt: "今天 17:30",
- progress: 100,
- linkedFiles: ["clone/artifacts/reports/standup-week-8.md"],
- comments: 0,
- },
- {
- id: "TK-007",
- title: "Landing Page 团队协作模块",
- description: "在 Landing Page 增加团队协作、邀请裂变相关展示",
- status: "done",
- priority: "high",
- assignee: "张三",
- assigneeAvatar: "👨💻",
- executor: "hybrid",
- source: "session",
- sourceRef: "Session #design-system",
- sprintId: "Sprint 3",
- okrId: "KR-2-4",
- okrTitle: "端到端用户旅程可走通",
- tags: ["前端", "设计系统", "增长"],
- createdAt: "02-23",
- updatedAt: "今天 15:00",
- progress: 100,
- linkedFiles: ["design-system/src/pages/LandingPreview.tsx"],
- comments: 2,
- },
- {
- id: "TK-008",
- title: "用户鉴权模块开发",
- description: "实现用户注册、登录、权限管理模块",
- status: "todo",
- priority: "high",
- assignee: "李四",
- assigneeAvatar: "🧑💻",
- executor: "human",
- source: "okr",
- sourceRef: "KR-2-2",
- sprintId: "Sprint 3",
- okrId: "KR-2-2",
- okrTitle: "Gateway API 重构完成并通过集成测试",
- tags: ["后端", "安全"],
- createdAt: "02-22",
- updatedAt: "02-22",
- dueDate: "03-02",
- progress: 0,
- dependencies: ["TK-005"],
- comments: 1,
- },
- {
- id: "TK-009",
- title: "投资人 BP 材料更新",
- description: "基于最新产品进展更新 BP 文档和 Demo 材料",
- status: "backlog",
- priority: "medium",
- assignee: "赵六",
- assigneeAvatar: "👩💼",
- executor: "hybrid",
- source: "manual",
- tags: ["融资", "文档"],
- createdAt: "02-20",
- updatedAt: "02-20",
- progress: 0,
- linkedFiles: ["clone/artifacts/reports/investor-bp/"],
- comments: 0,
- },
- {
- id: "TK-010",
- title: "飞书机器人消息卡片适配",
- description: "将 6 种标准 IM 卡片适配为飞书 Interactive Card 格式",
- status: "backlog",
- priority: "medium",
- assignee: "张三",
- assigneeAvatar: "👨💻",
- executor: "human",
- source: "im",
- sourceRef: "#product-team",
- tags: ["IM", "飞书", "集成"],
- createdAt: "02-21",
- updatedAt: "02-21",
- progress: 0,
- comments: 3,
- },
- {
- id: "TK-011",
- title: "每日竞品监控自动任务优化",
- description: "优化竞品监控的数据源和分析质量",
- status: "backlog",
- priority: "low",
- assignee: "赵六",
- assigneeAvatar: "👩💼",
- executor: "agent",
- source: "automation",
- tags: ["自动化", "竞品"],
- createdAt: "02-19",
- updatedAt: "02-19",
- progress: 0,
- comments: 0,
- },
- {
- id: "TK-012",
- title: "上线前安全审查清单",
- description: "QA 整理安全审查清单,覆盖鉴权、数据隔离、API 限流",
- status: "todo",
- priority: "medium",
- assignee: "孙七",
- assigneeAvatar: "🧑🔬",
- executor: "hybrid",
- source: "manual",
- sprintId: "Sprint 3",
- tags: ["QA", "安全"],
- createdAt: "02-22",
- updatedAt: "02-22",
- dueDate: "03-02",
- progress: 0,
- subtasks: [
- { title: "鉴权流程审查", done: false },
- { title: "数据隔离检查", done: false },
- { title: "API 限流配置", done: false },
- ],
- comments: 0,
- },
- {
- id: "TK-013",
- title: "周报自动生成",
- description: "分身自动汇总本周产出,生成结构化周报",
- status: "archived",
- priority: "low",
- assignee: "张三",
- assigneeAvatar: "👨💻",
- executor: "agent",
- source: "automation",
- tags: ["自动化", "文档"],
- createdAt: "02-16",
- updatedAt: "02-21",
- progress: 100,
- linkedFiles: ["clone/artifacts/reports/sprint-3-weekly.md"],
- comments: 1,
- },
-];
-
-export const SPRINT_TASKS: SprintTask[] = [
- {
- id: "T-001",
- title: "前端集成",
- assignee: "张三",
- status: "blocked",
- progress: 30,
- dependency: "T-003",
- },
- {
- id: "T-002",
- title: "单元测试",
- assignee: "张三",
- status: "in_progress",
- progress: 85,
- },
- {
- id: "T-003",
- title: "Gateway 重构",
- assignee: "李四",
- status: "in_progress",
- progress: 15,
- },
- {
- id: "T-004",
- title: "用户鉴权模块",
- assignee: "李四",
- status: "todo",
- progress: 0,
- dependency: "T-005",
- },
- {
- id: "T-005",
- title: "设计稿 v2",
- assignee: "王五",
- status: "in_progress",
- progress: 90,
- },
- {
- id: "T-006",
- title: "暗色主题适配",
- assignee: "王五",
- status: "done",
- progress: 100,
- },
- {
- id: "T-007",
- title: "交互原型",
- assignee: "王五",
- status: "in_progress",
- progress: 60,
- },
- {
- id: "T-008",
- title: "Sprint 规划",
- assignee: "赵六",
- status: "done",
- progress: 100,
- },
- {
- id: "T-009",
- title: "需求评审",
- assignee: "赵六",
- status: "in_progress",
- progress: 70,
- },
-];
diff --git a/packages/demo-pages/src/pages/openclaw/HomeDashboard.tsx b/packages/demo-pages/src/pages/openclaw/HomeDashboard.tsx
index 09774699..fb678154 100644
--- a/packages/demo-pages/src/pages/openclaw/HomeDashboard.tsx
+++ b/packages/demo-pages/src/pages/openclaw/HomeDashboard.tsx
@@ -19,9 +19,9 @@ import {
ArrowUp,
ArrowUpRight,
Cable,
- Check,
ChevronDown,
Cpu,
+ HelpCircle,
KeyRound,
MessageCircle,
Search,
@@ -52,7 +52,13 @@ import {
WhatsAppIconSetup,
} from "./channelSetup";
import { MOCK_CHANNELS, getProviderDetails } from "./data";
-import { CreditIcon, ProviderLogo, getModelIconProvider } from "./iconHelpers";
+import {
+ CreditIcon,
+ ProviderLogo,
+ TierPlusBadge,
+ TierProBadge,
+ getModelIconProvider,
+} from "./iconHelpers";
const SEEDANCE_COUNTDOWN_CYCLE_MS = 2 * 24 * 60 * 60 * 1000;
const SEEDANCE_COUNTDOWN_LOOP_END_MS = Date.now() + SEEDANCE_COUNTDOWN_CYCLE_MS - 1000;
@@ -435,7 +441,7 @@ export function HomeDashboard({
className="ml-auto"
/>
-
+
setShowModelDropdown(!showModelDropdown)}
@@ -456,6 +462,12 @@ export function HomeDashboard({
{selectedModel?.name ?? t("ws.home.notSelected")}
+ {selectedModel?.tier === "pro" && (
+
+ )}
+ {selectedModel?.tier === "plus" && (
+
+ )}
p.models.length > 0);
return (
-
+
@@ -511,32 +523,44 @@ export function HomeDashboard({
const isExpanded = expandedProviders.has(provider.id) || !!query;
return (
-
{
- if (query) return;
- setExpandedProviders((prev) => {
- const next = new Set(prev);
- if (next.has(provider.id)) next.delete(provider.id);
- else next.add(provider.id);
- return next;
- });
- }}
- className="flex min-h-9 w-full items-center gap-2 rounded-lg pl-4 pr-3 py-2 transition-colors hover:bg-surface-2/50"
- >
-
-
-
-
-
- {provider.name}
-
-
- {provider.models.length}
-
-
+
+
{
+ if (query) return;
+ setExpandedProviders((prev) => {
+ const next = new Set(prev);
+ if (next.has(provider.id)) next.delete(provider.id);
+ else next.add(provider.id);
+ return next;
+ });
+ }}
+ className="flex min-h-9 flex-1 items-center gap-2 rounded-lg pl-4 pr-3 py-2 transition-colors hover:bg-surface-2"
+ >
+
+
+
+
+
+ {provider.name}
+
+
+ {provider.id === "nexu" && (
+
+ openExternal(
+ "https://docs.nexu.io/zh/guide/model-pricing",
+ )
+ }
+ className="flex size-7 shrink-0 items-center justify-center rounded-lg text-text-muted transition-colors hover:bg-surface-2 hover:text-text-primary"
+ title="模型积分消耗说明"
+ >
+
+
+ )}
+
{isExpanded &&
provider.models.map((model) => (
- {model.id === selectedModelId ? (
-
- ) : (
-
- )}
-
- {model.name}
+
+
-
- {model.contextWindow}
+
+
+ {model.name}
+
+ {model.tier === "pro" && (
+
+ )}
+ {model.tier === "plus" && (
+
+ )}
+ {provider.id === "nexu" && !model.tier && (
+
+ Unlimited
+
+ )}
+ {provider.id === "nexu" ? (
+
+ {"~"}
+ {model.creditsPerConversation}
+ {" 积分/次"}
+
+ ) : (
+
+ {model.inputPrice
+ .replace(/\.00/g, "")
+ .replace(/\/M$/, "")}
+ {" / "}
+ {model.outputPrice
+ .replace(/\.00/g, "")
+ .replace(/\/M$/, "")}
+
+ )}
))}
@@ -585,14 +641,7 @@ export function HomeDashboard({
);
})()}
-
-
- Agent running
-
-
+
{t("ws.home.messagesToday")}
·
{t("ws.home.activeAgo")}
diff --git a/packages/demo-pages/src/pages/openclaw/SettingsView.tsx b/packages/demo-pages/src/pages/openclaw/SettingsView.tsx
index e9cdcccd..b6f9b15a 100644
--- a/packages/demo-pages/src/pages/openclaw/SettingsView.tsx
+++ b/packages/demo-pages/src/pages/openclaw/SettingsView.tsx
@@ -25,6 +25,7 @@ import {
BookOpen,
Check,
Globe,
+ HelpCircle,
Info,
Mail,
Monitor,
@@ -40,6 +41,7 @@ import { type Locale, useLocale } from "../../hooks/useLocale";
import { openExternal } from "../../utils/open-external";
import { GitHubStarButton } from "./GitHubStarButton";
import { type ModelProvider, type ProviderDetail, getProviderDetails } from "./data";
+import { TierPlusBadge, TierProBadge } from "./iconHelpers";
const WORKSPACE_LOCALE_OPTIONS: { value: Locale; nativeLabel: string; englishLabel: string }[] = [
{ value: "en", nativeLabel: "English", englishLabel: "English" },
@@ -1008,8 +1010,20 @@ export function SettingsView({
) : null}
-
+
{t("ws.settings.model")} ({activeProvider.models.length})
+ {activeProvider.id === "nexu" && (
+
+ openExternal("https://docs.nexu.io/zh/guide/model-pricing")
+ }
+ className="flex size-4 items-center justify-center text-text-muted transition-colors hover:text-text-primary"
+ title="模型积分消耗说明"
+ >
+
+
+ )}
-
- {model.name}
-
-
- {model.contextWindow}
+
+
+ {model.name}
+
+ {model.tier === "pro" && (
+
+ )}
+ {model.tier === "plus" && (
+
+ )}
+ {activeProvider.id === "nexu" && !model.tier && (
+
+ Unlimited
+
+ )}
+ {activeProvider.id === "nexu" && model.creditsPerConversation ? (
+
+ ~{model.creditsPerConversation} 积分/次
+
+ ) : activeProvider.id !== "nexu" ? (
+
+ {model.inputPrice.replace(/\.00/g, "").replace(/\/M$/, "")}
+ {" / "}
+ {model.outputPrice.replace(/\.00/g, "").replace(/\/M$/, "")}
+
+ ) : null}
{isActive ? (
) : null}
diff --git a/packages/demo-pages/src/pages/openclaw/data.ts b/packages/demo-pages/src/pages/openclaw/data.ts
index 8fcc5981..2b4fd999 100644
--- a/packages/demo-pages/src/pages/openclaw/data.ts
+++ b/packages/demo-pages/src/pages/openclaw/data.ts
@@ -114,6 +114,7 @@ export interface ProviderModel {
inputPrice: string;
outputPrice: string;
tier?: "plus" | "pro";
+ creditsPerConversation?: string;
}
function createProviderModel(
@@ -151,33 +152,99 @@ const PROVIDER_DETAILS: ProviderDetail[] = [
proxyUrl: "https://api.nexu.dev/v1",
models: [
{
- id: "nexu-claude-sonnet-4-6",
- name: "Claude Sonnet 4.6",
+ id: "nexu-deepseek-v3.2",
+ name: "DeepSeek V3.2",
+ enabled: true,
+ contextWindow: "64K",
+ releasedAt: "2025-12-01",
+ inputPrice: "$0.27/M",
+ outputPrice: "$1.10/M",
+ creditsPerConversation: "0.5~2",
+ },
+ {
+ id: "nexu-minimax-m2.7",
+ name: "MiniMax M2.7",
+ enabled: true,
+ contextWindow: "1M",
+ releasedAt: "2025-11-01",
+ inputPrice: "$0.30/M",
+ outputPrice: "$1.20/M",
+ creditsPerConversation: "1~4",
+ },
+ {
+ id: "nexu-gemini-3.1-flash-lite-preview",
+ name: "Gemini 3.1 Flash Lite",
+ enabled: true,
+ contextWindow: "1M",
+ releasedAt: "2026-01-01",
+ inputPrice: "$0.08/M",
+ outputPrice: "$0.30/M",
+ creditsPerConversation: "1~5",
+ },
+ {
+ id: "nexu-kimi-k2.5",
+ name: "Kimi K2.5",
enabled: true,
contextWindow: "200K",
- releasedAt: "2026-02-17",
- inputPrice: "$3.00/M",
- outputPrice: "$15.00/M",
+ releasedAt: "2025-10-01",
+ inputPrice: "$0.14/M",
+ outputPrice: "$0.56/M",
+ creditsPerConversation: "1~5",
+ },
+ {
+ id: "nexu-glm-5",
+ name: "GLM-5",
+ enabled: true,
+ contextWindow: "128K",
+ releasedAt: "2025-09-01",
+ inputPrice: "$0.14/M",
+ outputPrice: "$0.98/M",
tier: "plus",
+ creditsPerConversation: "2~6",
},
{
- id: "nexu-claude-opus-4-6",
- name: "Claude Opus 4.6",
+ id: "nexu-gemini-3-flash-preview",
+ name: "Gemini 3 Flash",
enabled: true,
- contextWindow: "200K",
- releasedAt: "2026-02-05",
- inputPrice: "$5.00/M",
- outputPrice: "$25.00/M",
+ contextWindow: "1M",
+ releasedAt: "2025-12-01",
+ inputPrice: "$0.10/M",
+ outputPrice: "$0.40/M",
+ tier: "plus",
+ creditsPerConversation: "2~7",
+ },
+ {
+ id: "nexu-mimo-v2-pro",
+ name: "Mimo V2 Pro",
+ enabled: true,
+ contextWindow: "128K",
+ releasedAt: "2026-02-01",
+ inputPrice: "$0.16/M",
+ outputPrice: "$0.64/M",
+ tier: "plus",
+ creditsPerConversation: "2~8",
+ },
+ {
+ id: "nexu-glm-5-turbo",
+ name: "GLM-5 Turbo",
+ enabled: true,
+ contextWindow: "128K",
+ releasedAt: "2025-09-01",
+ inputPrice: "$0.21/M",
+ outputPrice: "$1.40/M",
tier: "pro",
+ creditsPerConversation: "3~10",
},
{
- id: "nexu-claude-haiku-4-5",
- name: "Claude Haiku 4.5",
- enabled: false,
- contextWindow: "200K",
- releasedAt: "2025-10-16",
- inputPrice: "$1.00/M",
- outputPrice: "$5.00/M",
+ id: "nexu-gpt-5.4-mini",
+ name: "GPT-5.4 Mini",
+ enabled: true,
+ contextWindow: "128K",
+ releasedAt: "2026-01-01",
+ inputPrice: "$0.15/M",
+ outputPrice: "$0.60/M",
+ tier: "pro",
+ creditsPerConversation: "3~10",
},
],
},