@blade-hq/agent-kit 1.0.23 → 1.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/{SkillStatusBar-DluiBsVj.d.ts → SkillStatusBar-U6fbQxMu.d.ts} +2 -2
  2. package/dist/{blade-client-CseN7OW9.d.ts → blade-client-qTOovekU.d.ts} +2 -260
  3. package/dist/{chunk-ICV7OTGX.js → chunk-3I4ZURKH.js} +10 -10
  4. package/dist/{chunk-DQCXSPHP.js → chunk-4D4EXLVT.js} +2 -2
  5. package/dist/{chunk-7F6UP5LP.js → chunk-M45K3554.js} +1 -206
  6. package/dist/chunk-M45K3554.js.map +1 -0
  7. package/dist/{chunk-JCJFFJ42.js → chunk-QODAKTG5.js} +31 -2
  8. package/dist/chunk-QODAKTG5.js.map +1 -0
  9. package/dist/{chunk-TYM7KL2L.js → chunk-VJY6RLYU.js} +2 -2
  10. package/dist/{chunk-2QYV43YP.js → chunk-WPLEMYL7.js} +2 -2
  11. package/dist/{chunk-IMMRWXI7.js → chunk-WVXXQ3KM.js} +6 -6
  12. package/dist/{chunk-BQKF6HJH.js → chunk-XCIDE3JW.js} +4 -4
  13. package/dist/client/index.d.ts +3547 -6968
  14. package/dist/client/index.js +1 -5
  15. package/dist/react/cards/register.js +2 -3
  16. package/dist/react/cards/register.js.map +1 -1
  17. package/dist/react/components/chat/index.d.ts +4 -4
  18. package/dist/react/components/chat/index.js +6 -7
  19. package/dist/react/components/plan/index.js +6 -7
  20. package/dist/react/components/plan/index.js.map +1 -1
  21. package/dist/react/components/session/index.d.ts +1 -1
  22. package/dist/react/components/session/index.js +5 -6
  23. package/dist/react/components/session/index.js.map +1 -1
  24. package/dist/react/components/workspace/index.d.ts +3 -3
  25. package/dist/react/components/workspace/index.js +5 -6
  26. package/dist/react/components/workspace/index.js.map +1 -1
  27. package/dist/react/index.d.ts +8 -85
  28. package/dist/react/index.js +23 -74
  29. package/dist/react/index.js.map +1 -1
  30. package/dist/{session-CT8Y2KHr.d.ts → session-CNnotR90.d.ts} +1 -1
  31. package/dist/{sessions-DI9DVun7.d.ts → sessions-BvfLGbjw.d.ts} +2 -2
  32. package/package.json +1 -2
  33. package/dist/chunk-7F6UP5LP.js.map +0 -1
  34. package/dist/chunk-7LEKQI47.js +0 -32
  35. package/dist/chunk-7LEKQI47.js.map +0 -1
  36. package/dist/chunk-JCJFFJ42.js.map +0 -1
  37. package/dist/react/api/vibe-coding.d.ts +0 -55
  38. package/dist/react/api/vibe-coding.js +0 -47
  39. package/dist/react/api/vibe-coding.js.map +0 -1
  40. /package/dist/{chunk-ICV7OTGX.js.map → chunk-3I4ZURKH.js.map} +0 -0
  41. /package/dist/{chunk-DQCXSPHP.js.map → chunk-4D4EXLVT.js.map} +0 -0
  42. /package/dist/{chunk-TYM7KL2L.js.map → chunk-VJY6RLYU.js.map} +0 -0
  43. /package/dist/{chunk-2QYV43YP.js.map → chunk-WPLEMYL7.js.map} +0 -0
  44. /package/dist/{chunk-IMMRWXI7.js.map → chunk-WVXXQ3KM.js.map} +0 -0
  45. /package/dist/{chunk-BQKF6HJH.js.map → chunk-XCIDE3JW.js.map} +0 -0
@@ -1,5 +1,5 @@
1
- import { C as ChatViewCustomization, P as ParsedWhatIfPrompt } from '../../../SkillStatusBar-DluiBsVj.js';
2
- export { A as AssistantTurnComponentProps, a as ChatInput, b as ChatSendOptions, c as ChatView, d as ChatViewClassNames, e as ChatViewComponents, f as ChatViewProps, g as ChatViewRenderers, E as ErrorMessageBlock, F as FileComposerAttachment, h as FileSizeLimitDialog, M as MessageList, S as SkillStatusBar, i as SkillStatusBarComponentProps, T as ThinkingToggle, j as ToolCallComponentProps, k as ToolRendererProps, U as UserMessageBubble, l as isErrorMessage, m as isUserMessage } from '../../../SkillStatusBar-DluiBsVj.js';
1
+ import { C as ChatViewCustomization, P as ParsedWhatIfPrompt } from '../../../SkillStatusBar-U6fbQxMu.js';
2
+ export { A as AssistantTurnComponentProps, a as ChatInput, b as ChatSendOptions, c as ChatView, d as ChatViewClassNames, e as ChatViewComponents, f as ChatViewProps, g as ChatViewRenderers, E as ErrorMessageBlock, F as FileComposerAttachment, h as FileSizeLimitDialog, M as MessageList, S as SkillStatusBar, i as SkillStatusBarComponentProps, T as ThinkingToggle, j as ToolCallComponentProps, k as ToolRendererProps, U as UserMessageBubble, l as isErrorMessage, m as isUserMessage } from '../../../SkillStatusBar-U6fbQxMu.js';
3
3
  import * as react from 'react';
4
4
  import { ReactNode } from 'react';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
@@ -7,10 +7,10 @@ import { a as CompactionInfo, C as ChatMessage, A as AskUserAnswerData, T as Too
7
7
  export { b as AskUserQuestionBlock } from '../../../AskUserQuestionBlock---kOTouk.js';
8
8
  import { C as ContentBlock } from '../../../projection-BWYEFYNn.js';
9
9
  import 'zustand';
10
- import '../../../session-CT8Y2KHr.js';
10
+ import '../../../session-CNnotR90.js';
11
11
  import 'arktype/internal/variants/object.ts';
12
12
  import 'arktype/internal/variants/string.ts';
13
- import '../../../blade-client-CseN7OW9.js';
13
+ import '../../../blade-client-qTOovekU.js';
14
14
  import 'socket.io-client';
15
15
 
16
16
  /**
@@ -17,18 +17,17 @@ import {
17
17
  isErrorMessage,
18
18
  isUserMessage,
19
19
  useWhatIfQuoteContext
20
- } from "../../../chunk-ICV7OTGX.js";
20
+ } from "../../../chunk-3I4ZURKH.js";
21
21
  import {
22
22
  AskUserQuestionBlock
23
- } from "../../../chunk-BQKF6HJH.js";
23
+ } from "../../../chunk-XCIDE3JW.js";
24
24
  import "../../../chunk-2UP7MG3J.js";
25
25
  import "../../../chunk-H62LH2AG.js";
26
- import "../../../chunk-2QYV43YP.js";
27
- import "../../../chunk-IMMRWXI7.js";
26
+ import "../../../chunk-WPLEMYL7.js";
27
+ import "../../../chunk-WVXXQ3KM.js";
28
+ import "../../../chunk-M45K3554.js";
29
+ import "../../../chunk-QODAKTG5.js";
28
30
  import "../../../chunk-J3XVFPOV.js";
29
- import "../../../chunk-7F6UP5LP.js";
30
- import "../../../chunk-7LEKQI47.js";
31
- import "../../../chunk-JCJFFJ42.js";
32
31
  import "../../../chunk-PZ5AY32C.js";
33
32
  export {
34
33
  AskUserQuestionBlock,
@@ -3,16 +3,15 @@ import {
3
3
  PlanSummaryCard,
4
4
  extractLatestPlanMessages,
5
5
  parsePlanMessages
6
- } from "../../../chunk-BQKF6HJH.js";
6
+ } from "../../../chunk-XCIDE3JW.js";
7
7
  import "../../../chunk-2UP7MG3J.js";
8
- import "../../../chunk-2QYV43YP.js";
9
- import "../../../chunk-IMMRWXI7.js";
10
- import "../../../chunk-J3XVFPOV.js";
11
- import "../../../chunk-7F6UP5LP.js";
8
+ import "../../../chunk-WPLEMYL7.js";
9
+ import "../../../chunk-WVXXQ3KM.js";
10
+ import "../../../chunk-M45K3554.js";
12
11
  import {
13
12
  cn
14
- } from "../../../chunk-7LEKQI47.js";
15
- import "../../../chunk-JCJFFJ42.js";
13
+ } from "../../../chunk-QODAKTG5.js";
14
+ import "../../../chunk-J3XVFPOV.js";
16
15
  import "../../../chunk-PZ5AY32C.js";
17
16
 
18
17
  // src/react/components/plan/debug-log.ts
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/react/components/plan/debug-log.ts","../../../../src/react/components/plan/PlanVisualization.tsx","../../../../src/react/components/plan/phases/PlanTree.tsx","../../../../src/react/components/plan/phases/PlanMindMap.tsx","../../../../src/react/components/plan/phases/PlanStatusIcon.tsx","../../../../src/react/components/plan/phases/SkillAnalysis.tsx","../../../../src/react/components/plan/phases/SkillDiscovery.tsx"],"sourcesContent":["/**\n * Debug logger for Plan timeline events.\n * Stores events in memory with timestamps for debugging animation timing\n * in real conversation environments.\n *\n * Events are stored in window.__planTimelineLog and can be exported as JSON.\n */\n\nexport interface PlanTimelineEvent {\n /** ISO timestamp */\n ts: string\n /** Milliseconds since first event in this session */\n elapsed: number\n /** Event type */\n event: string\n /** Additional data */\n data?: Record<string, unknown>\n}\n\nlet events: PlanTimelineEvent[] = []\nlet startTime: number | null = null\n\n/** Set to true to enable console logging. Defaults to true in dev (localhost). */\nconst verbose =\n typeof window !== \"undefined\" &&\n (window.location?.hostname === \"localhost\" || window.location?.hostname === \"127.0.0.1\")\n\nexport function logPlanEvent(event: string, data?: Record<string, unknown>) {\n const now = Date.now()\n if (startTime === null) startTime = now\n\n const entry: PlanTimelineEvent = {\n ts: new Date(now).toISOString(),\n elapsed: now - startTime,\n event,\n data,\n }\n events.push(entry)\n\n if (verbose) {\n // Store on window for devtools access\n ;(window as unknown as Record<string, unknown>).__planTimelineLog = events\n console.log(`[PlanTimeline] +${entry.elapsed}ms ${event}`, data ?? \"\")\n }\n}\n\nexport function clearPlanLog() {\n events = []\n startTime = null\n}\n\nexport function exportPlanLog(): PlanTimelineEvent[] {\n return [...events]\n}\n\nexport function downloadPlanLog() {\n const blob = new Blob([JSON.stringify(events, null, 2)], { type: \"application/json\" })\n const url = URL.createObjectURL(blob)\n const a = document.createElement(\"a\")\n a.href = url\n a.download = `plan-timeline-${new Date().toISOString().slice(0, 19).replace(/:/g, \"-\")}.json`\n a.click()\n URL.revokeObjectURL(url)\n}\n","import { BookOpen, GitBranch, Search } from \"lucide-react\"\nimport { useMemo, useRef, useState } from \"react\"\nimport { cn } from \"../../lib/utils\"\nimport type { ChatMessage } from \"../../schemas/message\"\nimport { AskUserQuestionBlock, type AskUserAnswerData } from \"../chat/AskUserQuestionBlock\"\nimport { parsePlanMessages } from \"./parse-plan-messages\"\nimport { PlanTree } from \"./phases/PlanTree\"\nimport { SkillAnalysis } from \"./phases/SkillAnalysis\"\nimport { SkillDiscovery } from \"./phases/SkillDiscovery\"\nimport type { Phase, PlanData, SkillCatalogItem } from \"./types\"\n\ninterface Props {\n messages: ChatMessage[]\n /** All skill names from the registry, used as word cloud background in Phase 1 */\n allSkillNames?: SkillCatalogItem[]\n onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void\n sessionStatus?: string\n isStreaming?: boolean\n}\n\nconst PHASE_LABELS: { key: Phase; label: string; icon: typeof Search }[] = [\n { key: \"discovering\", label: \"技能发现\", icon: Search },\n { key: \"analyzing\", label: \"技能分析\", icon: BookOpen },\n { key: \"generating\", label: \"计划生成\", icon: GitBranch },\n]\n\nfunction getLatestPhaseIndex(data: PlanData): number {\n if (data.plan != null || data.hasPlanContent) return 2\n if (data.selectedSkills.length > 0) return 1\n if (data.searchResults.length > 0) return 0\n return -1\n}\n\nexport function PlanVisualization({\n messages: rawMessages,\n allSkillNames: rawAllSkillNames = [],\n onAnswer,\n sessionStatus,\n isStreaming = false,\n}: Props) {\n const messages = Array.isArray(rawMessages) ? rawMessages : []\n const allSkillNames = Array.isArray(rawAllSkillNames) ? rawAllSkillNames : []\n const data = useMemo(() => parsePlanMessages(messages), [messages])\n const latestIdx = getLatestPhaseIndex(data)\n const isWaitingForInput = sessionStatus === \"waiting_for_input\"\n const hasError = sessionStatus === \"failed\"\n const isInterrupted = sessionStatus === \"interrupted\"\n const isSessionActive =\n isStreaming ||\n sessionStatus === \"created\" ||\n sessionStatus === \"running\" ||\n sessionStatus === \"waiting_for_input\"\n const activeStatusIdx = latestIdx >= 0 ? latestIdx : 0\n const latestAskQuestion = data.askQuestions[data.askQuestions.length - 1]\n const hasPhaseData = latestIdx >= 0\n\n // Determine which interactive surface to show based on the last pause tool\n const showAskQuestion =\n latestAskQuestion &&\n isWaitingForInput &&\n data.lastPauseTool === \"AskUserQuestion\" &&\n onAnswer\n\n const [selectedTab, setSelectedTab] = useState<number | null>(null)\n // Reset manual selection when a new planning cycle starts (latestIdx drops backward)\n const prevLatestRef = useRef(latestIdx)\n if (latestIdx < prevLatestRef.current) {\n setSelectedTab(null)\n }\n prevLatestRef.current = latestIdx\n const activeSelectedTab = selectedTab != null && selectedTab <= latestIdx ? selectedTab : null\n const viewIdx = activeSelectedTab ?? latestIdx\n\n return (\n <div className=\"flex flex-col gap-4 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card)/0.4)] p-5\">\n {hasPhaseData && (\n <>\n {/* Phase indicator bar */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-1\">\n {PHASE_LABELS.map((p, i) => {\n const Icon = p.icon\n const isViewing = viewIdx === i\n const isDone = latestIdx > i\n const isStatusPhase = i === activeStatusIdx && (hasError || isInterrupted)\n const tabHasData =\n (i === 0 && data.searchResults.length > 0) ||\n (i === 1 && data.selectedSkills.length > 0) ||\n (i === 2 && (data.plan != null || data.hasPlanContent))\n const isReachable = i <= latestIdx || tabHasData\n return (\n <div key={p.key} className=\"flex items-center\">\n {i > 0 && (\n <div\n className={cn(\n \"mx-1.5 h-px w-6 transition-colors duration-300\",\n isDone && !isStatusPhase\n ? \"bg-[hsl(var(--primary))]\"\n : \"bg-[hsl(var(--border))]\",\n )}\n />\n )}\n <button\n type=\"button\"\n disabled={!isReachable}\n onClick={() => isReachable && setSelectedTab(i === latestIdx ? null : i)}\n className={cn(\n \"flex items-center gap-2 rounded-full px-3.5 py-2 text-sm font-medium transition-all duration-300\",\n isViewing && \"bg-[hsl(var(--primary)/0.15)] text-[hsl(var(--primary))]\",\n !isViewing &&\n isDone &&\n \"text-[hsl(var(--primary)/0.6)] hover:bg-[hsl(var(--primary)/0.08)]\",\n !isReachable && \"cursor-default text-[hsl(var(--muted-foreground))]\",\n isReachable &&\n !isViewing &&\n !isDone &&\n tabHasData &&\n \"text-[hsl(var(--primary)/0.5)] hover:bg-[hsl(var(--primary)/0.08)]\",\n isReachable &&\n !isViewing &&\n !isDone &&\n !tabHasData &&\n \"text-[hsl(var(--muted-foreground))]\",\n )}\n >\n <Icon size={12} />\n {p.label}\n {latestIdx === i && isSessionActive && activeSelectedTab === null && (\n <span\n className={cn(\n \"h-1.5 w-1.5 animate-pulse rounded-full\",\n hasError\n ? \"bg-[hsl(var(--destructive))]\"\n : isInterrupted\n ? \"bg-orange-400\"\n : \"bg-[hsl(var(--primary))]\",\n )}\n />\n )}\n {isStatusPhase && latestIdx !== i && (\n <span\n className={cn(\n \"h-1.5 w-1.5 rounded-full\",\n hasError ? \"bg-[hsl(var(--destructive))]\" : \"bg-orange-400\",\n )}\n />\n )}\n </button>\n </div>\n )\n })}\n </div>\n\n {/* Controls */}\n <div className=\"flex items-center gap-1\">\n {hasError && (\n <span className=\"rounded-full bg-[hsl(var(--destructive)/0.12)] px-2.5 py-1 text-xs font-medium text-[hsl(var(--destructive))]\">\n 出错\n </span>\n )}\n {isInterrupted && (\n <span className=\"rounded-full bg-orange-500/10 px-2.5 py-1 text-xs font-medium text-orange-300\">\n 已中断\n </span>\n )}\n </div>\n </div>\n\n {/* Phase content — conditional rendering instead of absolute overlay */}\n <div className=\"min-h-0\">\n {viewIdx === 0 && (\n <SkillDiscovery\n intent={data.intent}\n searchResults={data.searchResults}\n selectedSkills={data.selectedSkills}\n allSkillNames={allSkillNames}\n active\n />\n )}\n {viewIdx === 1 && (\n <SkillAnalysis skills={data.selectedSkills} active />\n )}\n {viewIdx === 2 &&\n (data.plan != null ? (\n <PlanTree root={data.plan.root} notes={data.plan.notes} active />\n ) : data.parseError ? (\n <div className=\"flex min-h-[240px] items-center justify-center rounded-xl border border-[hsl(var(--destructive)/0.35)] bg-[hsl(var(--destructive)/0.08)] px-6 text-sm text-[hsl(var(--destructive))]\">\n {data.parseError}\n </div>\n ) : data.hasPlanContent ? (\n <div className=\"flex min-h-[240px] items-center justify-center rounded-xl border border-dashed border-[hsl(var(--border))] bg-[hsl(var(--card)/0.3)] px-6 text-sm text-[hsl(var(--muted-foreground))]\">\n 计划解析中...\n </div>\n ) : null)}\n </div>\n </>\n )}\n\n {/* AskUserQuestion standalone card (when no phase data) */}\n {!hasPhaseData && showAskQuestion && (\n <AskUserQuestionBlock data={latestAskQuestion.data} answered={false} toolCallId={latestAskQuestion.toolCallId} sessionStatus={sessionStatus ?? \"\"} onAnswer={onAnswer} />\n )}\n\n {hasPhaseData && showAskQuestion && (\n <AskUserQuestionBlock data={latestAskQuestion.data} answered={false} toolCallId={latestAskQuestion.toolCallId} sessionStatus={sessionStatus ?? \"\"} onAnswer={onAnswer} />\n )}\n\n </div>\n )\n}\n","import {\n CheckSquare,\n ChevronRight,\n GitBranch,\n List,\n Workflow,\n} from \"lucide-react\"\nimport { useCallback, useMemo, useState } from \"react\"\nimport { cn } from \"../../../lib/utils\"\nimport type { PlanNode } from \"../types\"\nimport { PlanMindMap } from \"./PlanMindMap\"\nimport { PlanStatusIcon } from \"./PlanStatusIcon\"\n\ntype ViewMode = \"mindmap\" | \"tree\"\n\n/** Collect node ids up to (and including) a given depth. */\nfunction collectIdsToDepth(node: PlanNode, maxDepth: number, out: Set<string>) {\n if (node.depth > maxDepth) return\n out.add(node.id)\n for (const child of node.children ?? []) collectIdsToDepth(child, maxDepth, out)\n}\n\ninterface Props {\n root: PlanNode\n notes: string[]\n active: boolean\n}\n\n/** Recursively fingerprint the full tree so key changes on any structural/label change. */\nfunction treeFinger(node: PlanNode): string {\n const children = node.children ?? []\n if (children.length === 0) return node.label\n return `${node.label}[${children.map(treeFinger).join(\",\")}]`\n}\n\nexport function PlanTree({ root, notes, active }: Props) {\n return <PlanTreeContent key={treeFinger(root)} root={root} notes={notes ?? []} active={active} />\n}\n\nfunction PlanTreeContent({ root, notes, active }: Props) {\n const [viewMode, setViewMode] = useState<ViewMode>(\"mindmap\")\n\n // Compute default expanded set: root + depth-1 children\n const defaultExpanded = useMemo(() => {\n const ids = new Set<string>()\n collectIdsToDepth(root, 1, ids)\n return ids\n }, [root])\n\n const [expandedIds, setExpandedIds] = useState<Set<string>>(defaultExpanded)\n\n const toggle = useCallback((id: string) => {\n setExpandedIds((prev) => {\n const next = new Set(prev)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n return next\n })\n }, [])\n\n return (\n <div className={cn(!active && \"pointer-events-none opacity-0\")}>\n <div className=\"flex flex-col gap-3\">\n <div className=\"flex items-center justify-end\">\n <div className=\"flex items-center gap-0.5 rounded-lg border border-[hsl(var(--border))] p-0.5\">\n <button\n type=\"button\"\n onClick={() => setViewMode(\"mindmap\")}\n className={cn(\n \"rounded-md p-1.5 transition-colors\",\n viewMode === \"mindmap\"\n ? \"bg-[hsl(var(--accent))] text-[hsl(var(--foreground))]\"\n : \"text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))]\",\n )}\n title=\"思维导图\"\n >\n <GitBranch size={14} />\n </button>\n <button\n type=\"button\"\n onClick={() => setViewMode(\"tree\")}\n className={cn(\n \"rounded-md p-1.5 transition-colors\",\n viewMode === \"tree\"\n ? \"bg-[hsl(var(--accent))] text-[hsl(var(--foreground))]\"\n : \"text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))]\",\n )}\n title=\"列表视图\"\n >\n <List size={14} />\n </button>\n </div>\n </div>\n\n <div className=\"rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card)/0.5)] px-3 py-3\">\n {viewMode === \"mindmap\" ? (\n <PlanMindMap root={root} expandedIds={expandedIds} onToggle={toggle} />\n ) : (\n <TreeNode node={root} />\n )}\n </div>\n\n {notes.length > 0 && (\n <div className=\"rounded-xl border border-[hsl(var(--border)/0.5)] bg-[hsl(var(--card)/0.5)] px-4 py-3 text-sm text-[hsl(var(--muted-foreground))]\">\n {notes.map((note, i) => (\n <p key={i} className=\"py-0.5\">\n <span className=\"mr-1.5 text-[hsl(var(--primary)/0.6)]\">{i + 1}.</span>\n {note}\n </p>\n ))}\n </div>\n )}\n </div>\n </div>\n )\n}\n\nfunction TreeNode({ node }: { node: PlanNode }) {\n const children = node.children ?? []\n const hasChildren = children.length > 0\n\n return (\n <div>\n <div\n className=\"group flex min-w-0 items-center gap-2 rounded-md px-2 py-2 hover:bg-[hsl(var(--accent)/0.5)]\"\n style={{ paddingLeft: `${node.depth * 24 + 10}px` }}\n >\n {hasChildren ? (\n <ChevronRight\n size={16}\n className=\"shrink-0 rotate-90 text-[hsl(var(--muted-foreground)/0.6)]\"\n />\n ) : (\n <span className=\"w-4 shrink-0\" />\n )}\n\n <PlanStatusIcon status={node.status} />\n\n {node.skillRef ? (\n <Workflow size={15} className=\"shrink-0 text-[hsl(var(--primary))]\" />\n ) : (\n <CheckSquare size={15} className=\"shrink-0 text-[hsl(var(--muted-foreground))]\" />\n )}\n\n <span className=\"min-w-0 flex-1 truncate text-[15px] font-medium text-[hsl(var(--foreground))]\">\n {node.label}\n </span>\n\n {node.skillRef && (\n <span className=\"ml-auto max-w-[160px] shrink-0 truncate rounded bg-[hsl(var(--primary)/0.1)] px-2 py-0.5 text-sm font-medium text-[hsl(var(--primary)/0.8)]\">\n {node.skillRef}\n </span>\n )}\n </div>\n\n {hasChildren && (\n <div className=\"relative\">\n <div\n className=\"absolute bottom-1 top-0 w-px bg-[hsl(var(--border)/0.4)]\"\n style={{ left: `${node.depth * 24 + 18}px` }}\n />\n {children.map((child) => (\n <TreeNode key={child.id} node={child} />\n ))}\n </div>\n )}\n </div>\n )\n}\n","import { ChevronRight, Workflow } from \"lucide-react\"\nimport type { ReactNode } from \"react\"\nimport { cn } from \"../../../lib/utils\"\nimport type { PlanNode } from \"../types\"\nimport { PlanStatusIcon } from \"./PlanStatusIcon\"\n\ninterface Props {\n root: PlanNode\n expandedIds: Set<string>\n onToggle: (id: string) => void\n}\n\nexport function PlanMindMap({ root, expandedIds, onToggle }: Props) {\n return (\n <div className=\"overflow-x-auto py-2\">\n <MindMapSubtree node={root} expandedIds={expandedIds} onToggle={onToggle} isRoot />\n </div>\n )\n}\n\nfunction MindMapSubtree({\n node,\n expandedIds,\n onToggle,\n isRoot = false,\n}: {\n node: PlanNode\n expandedIds: Set<string>\n onToggle: (id: string) => void\n isRoot?: boolean\n}) {\n const children = node.children ?? []\n const hasChildren = children.length > 0\n const isExpanded = expandedIds.has(node.id)\n const visibleChildren = hasChildren && isExpanded ? children : []\n\n return (\n <div className=\"flex items-center\">\n {/* Node bubble */}\n <div\n role={hasChildren ? \"button\" : undefined}\n tabIndex={hasChildren ? 0 : undefined}\n aria-expanded={hasChildren ? isExpanded : undefined}\n onClick={hasChildren ? () => onToggle(node.id) : undefined}\n onKeyDown={\n hasChildren\n ? (e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault()\n onToggle(node.id)\n }\n }\n : undefined\n }\n className={cn(\n \"relative z-10 shrink-0 rounded-lg border px-3 py-1.5 text-sm font-medium whitespace-nowrap select-none\",\n hasChildren && \"cursor-pointer\",\n isRoot\n ? \"border-[hsl(var(--primary))] bg-[hsl(var(--primary)/0.15)] text-[hsl(var(--primary))]\"\n : node.skillRef\n ? \"border-[hsl(var(--primary)/0.4)] bg-[hsl(var(--primary)/0.08)] text-[hsl(var(--foreground))]\"\n : \"border-[hsl(var(--border))] bg-[hsl(var(--card))] text-[hsl(var(--foreground))]\",\n )}\n >\n <span className=\"flex items-center gap-1.5\">\n <PlanStatusIcon status={node.status} size={14} />\n {node.skillRef && <Workflow size={12} className=\"text-[hsl(var(--primary))]\" />}\n {node.label}\n {hasChildren && (\n <ChevronRight\n size={14}\n className={cn(\n \"text-[hsl(var(--muted-foreground))] transition-transform duration-150\",\n isExpanded && \"rotate-90\",\n )}\n />\n )}\n {hasChildren && !isExpanded && (\n <span className=\"ml-0.5 rounded-full bg-[hsl(var(--muted))] px-1.5 py-px text-[10px] text-[hsl(var(--muted-foreground))]\">\n +{children.length}\n </span>\n )}\n </span>\n </div>\n\n {/* Connector + Children */}\n {visibleChildren.length > 0 && (\n <>\n {/* Horizontal line from node to vertical rail */}\n <div className=\"h-px w-6 shrink-0 bg-[hsl(var(--border))]\" />\n\n <VerticalRail count={visibleChildren.length}>\n {visibleChildren.map((child) => (\n <div key={child.id} className=\"flex items-center\">\n {/* Horizontal branch line */}\n <div className=\"h-px w-4 shrink-0 bg-[hsl(var(--border))]\" />\n <MindMapSubtree node={child} expandedIds={expandedIds} onToggle={onToggle} />\n </div>\n ))}\n </VerticalRail>\n </>\n )}\n </div>\n )\n}\n\n/**\n * Draws a vertical rail from the center of the first child to the center\n * of the last child. Uses absolute-positioned segments per row:\n * - first: top 50% → bottom 0\n * - middle: top 0 → bottom 0\n * - last: top 0 → bottom 50%\n */\nfunction VerticalRail({ count, children }: { count: number; children: ReactNode[] }) {\n if (count <= 1) {\n return <div className=\"flex flex-col\">{children}</div>\n }\n\n return (\n <div className=\"flex flex-col\">\n {children.map((child, i) => (\n <div key={i} className={cn(\"relative\", i > 0 && \"pt-1.5\")}>\n <div\n className=\"absolute left-0 w-px bg-[hsl(var(--border))]\"\n style={{\n top: i === 0 ? \"50%\" : 0,\n bottom: i === count - 1 ? \"50%\" : 0,\n }}\n />\n {child}\n </div>\n ))}\n </div>\n )\n}\n","import { CheckCircle2, Circle, Loader2, XCircle } from \"lucide-react\"\nimport type { PlanNode } from \"../types\"\n\nexport function PlanStatusIcon({\n status,\n size = 16,\n}: {\n status: PlanNode[\"status\"]\n size?: number\n}) {\n if (status === \"pending\") {\n return (\n <Circle\n size={size}\n className=\"shrink-0 text-[hsl(var(--muted-foreground))] transition-transform duration-300\"\n />\n )\n }\n\n if (status === \"running\") {\n return (\n <Loader2\n size={size}\n className=\"shrink-0 animate-spin text-[hsl(var(--primary))] transition-transform duration-300\"\n />\n )\n }\n\n if (status === \"done\") {\n return (\n <CheckCircle2\n size={size}\n className=\"shrink-0 scale-105 text-green-500 transition-transform duration-300\"\n />\n )\n }\n\n return (\n <XCircle\n size={size}\n className=\"shrink-0 text-destructive transition-transform duration-300\"\n />\n )\n}\n","import { BookOpen, Link2 } from \"lucide-react\"\nimport { cn } from \"../../../lib/utils\"\nimport type { SkillInfo } from \"../types\"\n\ninterface Props {\n skills: SkillInfo[]\n active: boolean\n}\n\nfunction planSkillDisplayName(skill: SkillInfo) {\n return skill.displayName?.trim() || skill.skillId\n}\n\n/** Extract numbered steps from markdown content (e.g. \"1. foo\\n2. bar\") */\nfunction extractSteps(content: string): string[] {\n return content\n .split(\"\\n\")\n .filter((line) => /^\\d+\\.\\s/.test(line.trim()))\n .map((line) => line.trim().replace(/^\\d+\\.\\s*/, \"\"))\n .slice(0, 5)\n}\n\nexport function SkillAnalysis({ skills: rawSkills, active }: Props) {\n const skills = Array.isArray(rawSkills) ? rawSkills : []\n return (\n <div\n className={cn(\n \"transition-opacity duration-500\",\n active ? \"opacity-100\" : \"pointer-events-none opacity-0\",\n )}\n >\n <div className=\"columns-2 gap-4\">\n {skills.map((skill) => {\n const steps = skill.content ? extractSteps(skill.content) : []\n return (\n <div\n key={skill.skillId}\n className=\"mb-4 break-inside-avoid overflow-hidden rounded-xl border border-[hsl(var(--primary)/0.4)] bg-[hsl(var(--card))] shadow-lg shadow-[hsl(var(--primary)/0.05)] transition-all duration-500\"\n >\n <div className=\"flex items-center gap-2 px-4 py-3\">\n <BookOpen size={15} className=\"shrink-0 text-[hsl(var(--primary))]\" />\n <span className=\"min-w-0 truncate text-[15px] font-semibold text-[hsl(var(--foreground))]\">\n {planSkillDisplayName(skill)}\n </span>\n </div>\n\n <div className=\"border-t border-[hsl(var(--border)/0.5)] px-4 py-2.5\">\n <p className=\"text-sm leading-relaxed text-[hsl(var(--muted-foreground))]\">\n {skill.description}\n </p>\n </div>\n\n <div className=\"border-t border-[hsl(var(--border)/0.5)] px-4 py-2.5\">\n {skill.references && skill.references.length > 0 && (\n <div className=\"mb-2 flex flex-wrap gap-1.5\">\n {skill.references.map((ref, refIdx) => (\n <span\n key={`${refIdx}-${ref}`}\n className=\"inline-flex items-center gap-1 rounded-md bg-[hsl(var(--primary)/0.1)] px-2 py-0.5 text-xs text-[hsl(var(--primary))]\"\n >\n <Link2 size={10} />\n {ref}\n </span>\n ))}\n </div>\n )}\n {steps.length > 0 && (\n <ol className=\"list-inside list-decimal space-y-0.5 text-sm leading-relaxed text-[hsl(var(--muted-foreground)/0.8)]\">\n {steps.map((step, idx) => (\n <li key={idx}>{step}</li>\n ))}\n </ol>\n )}\n </div>\n </div>\n )\n })}\n </div>\n </div>\n )\n}\n","import { CheckCircle2, Search, Sparkles } from \"lucide-react\"\nimport { useMemo } from \"react\"\nimport { cn } from \"../../../lib/utils\"\nimport type { SkillCatalogItem, SkillInfo } from \"../types\"\n\ninterface Props {\n intent: string\n searchResults: SkillInfo[]\n selectedSkills: SkillInfo[]\n allSkillNames: SkillCatalogItem[]\n active: boolean\n}\n\n/** Stable pseudo-random size class for word cloud variety */\nfunction sizeClass(name: string): string {\n const hash = name.split(\"\").reduce((acc, c) => acc + c.charCodeAt(0), 0)\n const sizes = [\"text-xs\", \"text-sm\", \"text-[15px]\"]\n return sizes[hash % sizes.length]\n}\n\nfunction planSkillDisplayName(skill: { skillId: string; displayName?: string }) {\n return skill.displayName?.trim() || skill.skillId\n}\n\nexport function SkillDiscovery({\n intent,\n searchResults: rawSearchResults,\n selectedSkills: rawSelectedSkills,\n allSkillNames: rawAllSkillNames,\n active,\n}: Props) {\n const searchResults = Array.isArray(rawSearchResults) ? rawSearchResults : []\n const selectedSkills = Array.isArray(rawSelectedSkills) ? rawSelectedSkills : []\n const allSkillNames = Array.isArray(rawAllSkillNames) ? rawAllSkillNames : []\n const searchNames = useMemo(() => new Set(searchResults.map((s) => s.skillId)), [searchResults])\n const selectedNames = useMemo(\n () => new Set(selectedSkills.map((s) => s.skillId)),\n [selectedSkills],\n )\n\n const cloudItems = useMemo(() => {\n const bgItems = allSkillNames\n .filter((skill) => !searchNames.has(skill.skillId))\n .map((skill) => ({\n name: planSkillDisplayName(skill),\n key: `bg:${skill.skillId}`,\n isSearch: false,\n isSelected: false,\n }))\n const searchItems = searchResults.map((s) => ({\n name: planSkillDisplayName(s),\n key: `search:${s.skillId}`,\n isSearch: true,\n isSelected: selectedNames.has(s.skillId),\n }))\n\n const result = [...bgItems]\n for (let i = 0; i < searchItems.length; i++) {\n const insertAt = Math.round(((i + 1) / (searchItems.length + 1)) * result.length)\n result.splice(insertAt, 0, searchItems[i])\n }\n return result\n }, [allSkillNames, searchNames, searchResults, selectedNames])\n\n return (\n <div\n className={cn(\n \"flex h-full flex-col gap-6 transition-opacity duration-500\",\n active ? \"opacity-100\" : \"pointer-events-none opacity-0\",\n )}\n >\n <div className=\"flex shrink-0 max-w-md self-center flex-col items-center gap-2.5 rounded-2xl border border-[hsl(var(--primary)/0.4)] bg-[hsl(var(--primary)/0.08)] px-6 py-5 text-center shadow-lg shadow-[hsl(var(--primary)/0.1)]\">\n <Sparkles size={20} className=\"text-[hsl(var(--primary))]\" />\n <p className=\"break-words text-[15px] leading-relaxed text-[hsl(var(--foreground))]\">\n {intent}\n </p>\n </div>\n\n <div className=\"flex min-h-0 flex-1 flex-wrap content-start items-start justify-center gap-x-4 gap-y-3 overflow-y-auto px-6 pb-6\">\n {cloudItems.map((item) => {\n if (item.isSearch && item.isSelected) {\n return (\n <span\n key={item.key}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-[hsl(var(--primary)/0.5)] bg-[hsl(var(--primary)/0.12)] px-3 py-1.5 text-[15px] font-medium text-[hsl(var(--primary))] shadow-md shadow-[hsl(var(--primary)/0.15)] transition-all duration-500\"\n >\n <CheckCircle2 size={14} className=\"shrink-0\" />\n {item.name}\n </span>\n )\n }\n\n if (item.isSearch) {\n return (\n <span\n key={item.key}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-[hsl(var(--foreground)/0.3)] bg-[hsl(var(--foreground)/0.08)] px-3 py-1.5 text-[15px] font-medium text-[hsl(var(--foreground))] transition-all duration-500\"\n >\n <Search size={14} className=\"shrink-0\" />\n {item.name}\n </span>\n )\n }\n\n return (\n <span\n key={item.key}\n className={cn(\n \"select-none font-medium text-[hsl(var(--foreground)/0.45)] transition-all duration-500\",\n sizeClass(item.name),\n )}\n >\n {item.name}\n </span>\n )\n })}\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":["BookOpen","GitBranch","Search","useMemo","useState","ChevronRight","Workflow","jsx","jsx","jsxs","ChevronRight","Workflow","jsx","jsxs","CheckCircle2","useMemo","jsx","jsxs","planSkillDisplayName","useMemo","CheckCircle2","Fragment","jsx","jsxs","Search","BookOpen","GitBranch","useMemo","useState"]}
1
+ {"version":3,"sources":["../../../../src/react/components/plan/debug-log.ts","../../../../src/react/components/plan/PlanVisualization.tsx","../../../../src/react/components/plan/phases/PlanTree.tsx","../../../../src/react/components/plan/phases/PlanMindMap.tsx","../../../../src/react/components/plan/phases/PlanStatusIcon.tsx","../../../../src/react/components/plan/phases/SkillAnalysis.tsx","../../../../src/react/components/plan/phases/SkillDiscovery.tsx"],"sourcesContent":["/**\n * Debug logger for Plan timeline events.\n * Stores events in memory with timestamps for debugging animation timing\n * in real conversation environments.\n *\n * Events are stored in window.__planTimelineLog and can be exported as JSON.\n */\n\nexport interface PlanTimelineEvent {\n /** ISO timestamp */\n ts: string\n /** Milliseconds since first event in this session */\n elapsed: number\n /** Event type */\n event: string\n /** Additional data */\n data?: Record<string, unknown>\n}\n\nlet events: PlanTimelineEvent[] = []\nlet startTime: number | null = null\n\n/** Set to true to enable console logging. Defaults to true in dev (localhost). */\nconst verbose =\n typeof window !== \"undefined\" &&\n (window.location?.hostname === \"localhost\" || window.location?.hostname === \"127.0.0.1\")\n\nexport function logPlanEvent(event: string, data?: Record<string, unknown>) {\n const now = Date.now()\n if (startTime === null) startTime = now\n\n const entry: PlanTimelineEvent = {\n ts: new Date(now).toISOString(),\n elapsed: now - startTime,\n event,\n data,\n }\n events.push(entry)\n\n if (verbose) {\n // Store on window for devtools access\n ;(window as unknown as Record<string, unknown>).__planTimelineLog = events\n console.log(`[PlanTimeline] +${entry.elapsed}ms ${event}`, data ?? \"\")\n }\n}\n\nexport function clearPlanLog() {\n events = []\n startTime = null\n}\n\nexport function exportPlanLog(): PlanTimelineEvent[] {\n return [...events]\n}\n\nexport function downloadPlanLog() {\n const blob = new Blob([JSON.stringify(events, null, 2)], { type: \"application/json\" })\n const url = URL.createObjectURL(blob)\n const a = document.createElement(\"a\")\n a.href = url\n a.download = `plan-timeline-${new Date().toISOString().slice(0, 19).replace(/:/g, \"-\")}.json`\n a.click()\n URL.revokeObjectURL(url)\n}\n","import { BookOpen, GitBranch, Search } from \"lucide-react\"\nimport { useMemo, useRef, useState } from \"react\"\nimport { cn } from \"../../lib/utils\"\nimport type { ChatMessage } from \"../../schemas/message\"\nimport { AskUserQuestionBlock, type AskUserAnswerData } from \"../chat/AskUserQuestionBlock\"\nimport { parsePlanMessages } from \"./parse-plan-messages\"\nimport { PlanTree } from \"./phases/PlanTree\"\nimport { SkillAnalysis } from \"./phases/SkillAnalysis\"\nimport { SkillDiscovery } from \"./phases/SkillDiscovery\"\nimport type { Phase, PlanData, SkillCatalogItem } from \"./types\"\n\ninterface Props {\n messages: ChatMessage[]\n /** All skill names from the registry, used as word cloud background in Phase 1 */\n allSkillNames?: SkillCatalogItem[]\n onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void\n sessionStatus?: string\n isStreaming?: boolean\n}\n\nconst PHASE_LABELS: { key: Phase; label: string; icon: typeof Search }[] = [\n { key: \"discovering\", label: \"技能发现\", icon: Search },\n { key: \"analyzing\", label: \"技能分析\", icon: BookOpen },\n { key: \"generating\", label: \"计划生成\", icon: GitBranch },\n]\n\nfunction getLatestPhaseIndex(data: PlanData): number {\n if (data.plan != null || data.hasPlanContent) return 2\n if (data.selectedSkills.length > 0) return 1\n if (data.searchResults.length > 0) return 0\n return -1\n}\n\nexport function PlanVisualization({\n messages: rawMessages,\n allSkillNames: rawAllSkillNames = [],\n onAnswer,\n sessionStatus,\n isStreaming = false,\n}: Props) {\n const messages = Array.isArray(rawMessages) ? rawMessages : []\n const allSkillNames = Array.isArray(rawAllSkillNames) ? rawAllSkillNames : []\n const data = useMemo(() => parsePlanMessages(messages), [messages])\n const latestIdx = getLatestPhaseIndex(data)\n const isWaitingForInput = sessionStatus === \"waiting_for_input\"\n const hasError = sessionStatus === \"failed\"\n const isInterrupted = sessionStatus === \"interrupted\"\n const isSessionActive =\n isStreaming ||\n sessionStatus === \"created\" ||\n sessionStatus === \"running\" ||\n sessionStatus === \"waiting_for_input\"\n const activeStatusIdx = latestIdx >= 0 ? latestIdx : 0\n const latestAskQuestion = data.askQuestions[data.askQuestions.length - 1]\n const hasPhaseData = latestIdx >= 0\n\n // Determine which interactive surface to show based on the last pause tool\n const showAskQuestion =\n latestAskQuestion &&\n isWaitingForInput &&\n data.lastPauseTool === \"AskUserQuestion\" &&\n onAnswer\n\n const [selectedTab, setSelectedTab] = useState<number | null>(null)\n // Reset manual selection when a new planning cycle starts (latestIdx drops backward)\n const prevLatestRef = useRef(latestIdx)\n if (latestIdx < prevLatestRef.current) {\n setSelectedTab(null)\n }\n prevLatestRef.current = latestIdx\n const activeSelectedTab = selectedTab != null && selectedTab <= latestIdx ? selectedTab : null\n const viewIdx = activeSelectedTab ?? latestIdx\n\n return (\n <div className=\"flex flex-col gap-4 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card)/0.4)] p-5\">\n {hasPhaseData && (\n <>\n {/* Phase indicator bar */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-1\">\n {PHASE_LABELS.map((p, i) => {\n const Icon = p.icon\n const isViewing = viewIdx === i\n const isDone = latestIdx > i\n const isStatusPhase = i === activeStatusIdx && (hasError || isInterrupted)\n const tabHasData =\n (i === 0 && data.searchResults.length > 0) ||\n (i === 1 && data.selectedSkills.length > 0) ||\n (i === 2 && (data.plan != null || data.hasPlanContent))\n const isReachable = i <= latestIdx || tabHasData\n return (\n <div key={p.key} className=\"flex items-center\">\n {i > 0 && (\n <div\n className={cn(\n \"mx-1.5 h-px w-6 transition-colors duration-300\",\n isDone && !isStatusPhase\n ? \"bg-[hsl(var(--primary))]\"\n : \"bg-[hsl(var(--border))]\",\n )}\n />\n )}\n <button\n type=\"button\"\n disabled={!isReachable}\n onClick={() => isReachable && setSelectedTab(i === latestIdx ? null : i)}\n className={cn(\n \"flex items-center gap-2 rounded-full px-3.5 py-2 text-sm font-medium transition-all duration-300\",\n isViewing && \"bg-[hsl(var(--primary)/0.15)] text-[hsl(var(--primary))]\",\n !isViewing &&\n isDone &&\n \"text-[hsl(var(--primary)/0.6)] hover:bg-[hsl(var(--primary)/0.08)]\",\n !isReachable && \"cursor-default text-[hsl(var(--muted-foreground))]\",\n isReachable &&\n !isViewing &&\n !isDone &&\n tabHasData &&\n \"text-[hsl(var(--primary)/0.5)] hover:bg-[hsl(var(--primary)/0.08)]\",\n isReachable &&\n !isViewing &&\n !isDone &&\n !tabHasData &&\n \"text-[hsl(var(--muted-foreground))]\",\n )}\n >\n <Icon size={12} />\n {p.label}\n {latestIdx === i && isSessionActive && activeSelectedTab === null && (\n <span\n className={cn(\n \"h-1.5 w-1.5 animate-pulse rounded-full\",\n hasError\n ? \"bg-[hsl(var(--destructive))]\"\n : isInterrupted\n ? \"bg-orange-400\"\n : \"bg-[hsl(var(--primary))]\",\n )}\n />\n )}\n {isStatusPhase && latestIdx !== i && (\n <span\n className={cn(\n \"h-1.5 w-1.5 rounded-full\",\n hasError ? \"bg-[hsl(var(--destructive))]\" : \"bg-orange-400\",\n )}\n />\n )}\n </button>\n </div>\n )\n })}\n </div>\n\n {/* Controls */}\n <div className=\"flex items-center gap-1\">\n {hasError && (\n <span className=\"rounded-full bg-[hsl(var(--destructive)/0.12)] px-2.5 py-1 text-xs font-medium text-[hsl(var(--destructive))]\">\n 出错\n </span>\n )}\n {isInterrupted && (\n <span className=\"rounded-full bg-orange-500/10 px-2.5 py-1 text-xs font-medium text-orange-300\">\n 已中断\n </span>\n )}\n </div>\n </div>\n\n {/* Phase content — conditional rendering instead of absolute overlay */}\n <div className=\"min-h-0\">\n {viewIdx === 0 && (\n <SkillDiscovery\n intent={data.intent}\n searchResults={data.searchResults}\n selectedSkills={data.selectedSkills}\n allSkillNames={allSkillNames}\n active\n />\n )}\n {viewIdx === 1 && (\n <SkillAnalysis skills={data.selectedSkills} active />\n )}\n {viewIdx === 2 &&\n (data.plan != null ? (\n <PlanTree root={data.plan.root} notes={data.plan.notes} active />\n ) : data.parseError ? (\n <div className=\"flex min-h-[240px] items-center justify-center rounded-xl border border-[hsl(var(--destructive)/0.35)] bg-[hsl(var(--destructive)/0.08)] px-6 text-sm text-[hsl(var(--destructive))]\">\n {data.parseError}\n </div>\n ) : data.hasPlanContent ? (\n <div className=\"flex min-h-[240px] items-center justify-center rounded-xl border border-dashed border-[hsl(var(--border))] bg-[hsl(var(--card)/0.3)] px-6 text-sm text-[hsl(var(--muted-foreground))]\">\n 计划解析中...\n </div>\n ) : null)}\n </div>\n </>\n )}\n\n {/* AskUserQuestion standalone card (when no phase data) */}\n {!hasPhaseData && showAskQuestion && (\n <AskUserQuestionBlock data={latestAskQuestion.data} answered={false} toolCallId={latestAskQuestion.toolCallId} sessionStatus={sessionStatus ?? \"\"} onAnswer={onAnswer} />\n )}\n\n {hasPhaseData && showAskQuestion && (\n <AskUserQuestionBlock data={latestAskQuestion.data} answered={false} toolCallId={latestAskQuestion.toolCallId} sessionStatus={sessionStatus ?? \"\"} onAnswer={onAnswer} />\n )}\n\n </div>\n )\n}\n","import {\n CheckSquare,\n ChevronRight,\n GitBranch,\n List,\n Workflow,\n} from \"lucide-react\"\nimport { useCallback, useMemo, useState } from \"react\"\nimport { cn } from \"../../../lib/utils\"\nimport type { PlanNode } from \"../types\"\nimport { PlanMindMap } from \"./PlanMindMap\"\nimport { PlanStatusIcon } from \"./PlanStatusIcon\"\n\ntype ViewMode = \"mindmap\" | \"tree\"\n\n/** Collect node ids up to (and including) a given depth. */\nfunction collectIdsToDepth(node: PlanNode, maxDepth: number, out: Set<string>) {\n if (node.depth > maxDepth) return\n out.add(node.id)\n for (const child of node.children ?? []) collectIdsToDepth(child, maxDepth, out)\n}\n\ninterface Props {\n root: PlanNode\n notes: string[]\n active: boolean\n}\n\n/** Recursively fingerprint the full tree so key changes on any structural/label change. */\nfunction treeFinger(node: PlanNode): string {\n const children = node.children ?? []\n if (children.length === 0) return node.label\n return `${node.label}[${children.map(treeFinger).join(\",\")}]`\n}\n\nexport function PlanTree({ root, notes, active }: Props) {\n return <PlanTreeContent key={treeFinger(root)} root={root} notes={notes ?? []} active={active} />\n}\n\nfunction PlanTreeContent({ root, notes, active }: Props) {\n const [viewMode, setViewMode] = useState<ViewMode>(\"mindmap\")\n\n // Compute default expanded set: root + depth-1 children\n const defaultExpanded = useMemo(() => {\n const ids = new Set<string>()\n collectIdsToDepth(root, 1, ids)\n return ids\n }, [root])\n\n const [expandedIds, setExpandedIds] = useState<Set<string>>(defaultExpanded)\n\n const toggle = useCallback((id: string) => {\n setExpandedIds((prev) => {\n const next = new Set(prev)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n return next\n })\n }, [])\n\n return (\n <div className={cn(!active && \"pointer-events-none opacity-0\")}>\n <div className=\"flex flex-col gap-3\">\n <div className=\"flex items-center justify-end\">\n <div className=\"flex items-center gap-0.5 rounded-lg border border-[hsl(var(--border))] p-0.5\">\n <button\n type=\"button\"\n onClick={() => setViewMode(\"mindmap\")}\n className={cn(\n \"rounded-md p-1.5 transition-colors\",\n viewMode === \"mindmap\"\n ? \"bg-[hsl(var(--accent))] text-[hsl(var(--foreground))]\"\n : \"text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))]\",\n )}\n title=\"思维导图\"\n >\n <GitBranch size={14} />\n </button>\n <button\n type=\"button\"\n onClick={() => setViewMode(\"tree\")}\n className={cn(\n \"rounded-md p-1.5 transition-colors\",\n viewMode === \"tree\"\n ? \"bg-[hsl(var(--accent))] text-[hsl(var(--foreground))]\"\n : \"text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))]\",\n )}\n title=\"列表视图\"\n >\n <List size={14} />\n </button>\n </div>\n </div>\n\n <div className=\"rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card)/0.5)] px-3 py-3\">\n {viewMode === \"mindmap\" ? (\n <PlanMindMap root={root} expandedIds={expandedIds} onToggle={toggle} />\n ) : (\n <TreeNode node={root} />\n )}\n </div>\n\n {notes.length > 0 && (\n <div className=\"rounded-xl border border-[hsl(var(--border)/0.5)] bg-[hsl(var(--card)/0.5)] px-4 py-3 text-sm text-[hsl(var(--muted-foreground))]\">\n {notes.map((note, i) => (\n <p key={i} className=\"py-0.5\">\n <span className=\"mr-1.5 text-[hsl(var(--primary)/0.6)]\">{i + 1}.</span>\n {note}\n </p>\n ))}\n </div>\n )}\n </div>\n </div>\n )\n}\n\nfunction TreeNode({ node }: { node: PlanNode }) {\n const children = node.children ?? []\n const hasChildren = children.length > 0\n\n return (\n <div>\n <div\n className=\"group flex min-w-0 items-center gap-2 rounded-md px-2 py-2 hover:bg-[hsl(var(--accent)/0.5)]\"\n style={{ paddingLeft: `${node.depth * 24 + 10}px` }}\n >\n {hasChildren ? (\n <ChevronRight\n size={16}\n className=\"shrink-0 rotate-90 text-[hsl(var(--muted-foreground)/0.6)]\"\n />\n ) : (\n <span className=\"w-4 shrink-0\" />\n )}\n\n <PlanStatusIcon status={node.status} />\n\n {node.skillRef ? (\n <Workflow size={15} className=\"shrink-0 text-[hsl(var(--primary))]\" />\n ) : (\n <CheckSquare size={15} className=\"shrink-0 text-[hsl(var(--muted-foreground))]\" />\n )}\n\n <span className=\"min-w-0 flex-1 truncate text-[15px] font-medium text-[hsl(var(--foreground))]\">\n {node.label}\n </span>\n\n {node.skillRef && (\n <span className=\"ml-auto max-w-[160px] shrink-0 truncate rounded bg-[hsl(var(--primary)/0.1)] px-2 py-0.5 text-sm font-medium text-[hsl(var(--primary)/0.8)]\">\n {node.skillRef}\n </span>\n )}\n </div>\n\n {hasChildren && (\n <div className=\"relative\">\n <div\n className=\"absolute bottom-1 top-0 w-px bg-[hsl(var(--border)/0.4)]\"\n style={{ left: `${node.depth * 24 + 18}px` }}\n />\n {children.map((child) => (\n <TreeNode key={child.id} node={child} />\n ))}\n </div>\n )}\n </div>\n )\n}\n","import { ChevronRight, Workflow } from \"lucide-react\"\nimport type { ReactNode } from \"react\"\nimport { cn } from \"../../../lib/utils\"\nimport type { PlanNode } from \"../types\"\nimport { PlanStatusIcon } from \"./PlanStatusIcon\"\n\ninterface Props {\n root: PlanNode\n expandedIds: Set<string>\n onToggle: (id: string) => void\n}\n\nexport function PlanMindMap({ root, expandedIds, onToggle }: Props) {\n return (\n <div className=\"overflow-x-auto py-2\">\n <MindMapSubtree node={root} expandedIds={expandedIds} onToggle={onToggle} isRoot />\n </div>\n )\n}\n\nfunction MindMapSubtree({\n node,\n expandedIds,\n onToggle,\n isRoot = false,\n}: {\n node: PlanNode\n expandedIds: Set<string>\n onToggle: (id: string) => void\n isRoot?: boolean\n}) {\n const children = node.children ?? []\n const hasChildren = children.length > 0\n const isExpanded = expandedIds.has(node.id)\n const visibleChildren = hasChildren && isExpanded ? children : []\n\n return (\n <div className=\"flex items-center\">\n {/* Node bubble */}\n <div\n role={hasChildren ? \"button\" : undefined}\n tabIndex={hasChildren ? 0 : undefined}\n aria-expanded={hasChildren ? isExpanded : undefined}\n onClick={hasChildren ? () => onToggle(node.id) : undefined}\n onKeyDown={\n hasChildren\n ? (e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault()\n onToggle(node.id)\n }\n }\n : undefined\n }\n className={cn(\n \"relative z-10 shrink-0 rounded-lg border px-3 py-1.5 text-sm font-medium whitespace-nowrap select-none\",\n hasChildren && \"cursor-pointer\",\n isRoot\n ? \"border-[hsl(var(--primary))] bg-[hsl(var(--primary)/0.15)] text-[hsl(var(--primary))]\"\n : node.skillRef\n ? \"border-[hsl(var(--primary)/0.4)] bg-[hsl(var(--primary)/0.08)] text-[hsl(var(--foreground))]\"\n : \"border-[hsl(var(--border))] bg-[hsl(var(--card))] text-[hsl(var(--foreground))]\",\n )}\n >\n <span className=\"flex items-center gap-1.5\">\n <PlanStatusIcon status={node.status} size={14} />\n {node.skillRef && <Workflow size={12} className=\"text-[hsl(var(--primary))]\" />}\n {node.label}\n {hasChildren && (\n <ChevronRight\n size={14}\n className={cn(\n \"text-[hsl(var(--muted-foreground))] transition-transform duration-150\",\n isExpanded && \"rotate-90\",\n )}\n />\n )}\n {hasChildren && !isExpanded && (\n <span className=\"ml-0.5 rounded-full bg-[hsl(var(--muted))] px-1.5 py-px text-[10px] text-[hsl(var(--muted-foreground))]\">\n +{children.length}\n </span>\n )}\n </span>\n </div>\n\n {/* Connector + Children */}\n {visibleChildren.length > 0 && (\n <>\n {/* Horizontal line from node to vertical rail */}\n <div className=\"h-px w-6 shrink-0 bg-[hsl(var(--border))]\" />\n\n <VerticalRail count={visibleChildren.length}>\n {visibleChildren.map((child) => (\n <div key={child.id} className=\"flex items-center\">\n {/* Horizontal branch line */}\n <div className=\"h-px w-4 shrink-0 bg-[hsl(var(--border))]\" />\n <MindMapSubtree node={child} expandedIds={expandedIds} onToggle={onToggle} />\n </div>\n ))}\n </VerticalRail>\n </>\n )}\n </div>\n )\n}\n\n/**\n * Draws a vertical rail from the center of the first child to the center\n * of the last child. Uses absolute-positioned segments per row:\n * - first: top 50% → bottom 0\n * - middle: top 0 → bottom 0\n * - last: top 0 → bottom 50%\n */\nfunction VerticalRail({ count, children }: { count: number; children: ReactNode[] }) {\n if (count <= 1) {\n return <div className=\"flex flex-col\">{children}</div>\n }\n\n return (\n <div className=\"flex flex-col\">\n {children.map((child, i) => (\n <div key={i} className={cn(\"relative\", i > 0 && \"pt-1.5\")}>\n <div\n className=\"absolute left-0 w-px bg-[hsl(var(--border))]\"\n style={{\n top: i === 0 ? \"50%\" : 0,\n bottom: i === count - 1 ? \"50%\" : 0,\n }}\n />\n {child}\n </div>\n ))}\n </div>\n )\n}\n","import { CheckCircle2, Circle, Loader2, XCircle } from \"lucide-react\"\nimport type { PlanNode } from \"../types\"\n\nexport function PlanStatusIcon({\n status,\n size = 16,\n}: {\n status: PlanNode[\"status\"]\n size?: number\n}) {\n if (status === \"pending\") {\n return (\n <Circle\n size={size}\n className=\"shrink-0 text-[hsl(var(--muted-foreground))] transition-transform duration-300\"\n />\n )\n }\n\n if (status === \"running\") {\n return (\n <Loader2\n size={size}\n className=\"shrink-0 animate-spin text-[hsl(var(--primary))] transition-transform duration-300\"\n />\n )\n }\n\n if (status === \"done\") {\n return (\n <CheckCircle2\n size={size}\n className=\"shrink-0 scale-105 text-green-500 transition-transform duration-300\"\n />\n )\n }\n\n return (\n <XCircle\n size={size}\n className=\"shrink-0 text-destructive transition-transform duration-300\"\n />\n )\n}\n","import { BookOpen, Link2 } from \"lucide-react\"\nimport { cn } from \"../../../lib/utils\"\nimport type { SkillInfo } from \"../types\"\n\ninterface Props {\n skills: SkillInfo[]\n active: boolean\n}\n\nfunction planSkillDisplayName(skill: SkillInfo) {\n return skill.displayName?.trim() || skill.skillId\n}\n\n/** Extract numbered steps from markdown content (e.g. \"1. foo\\n2. bar\") */\nfunction extractSteps(content: string): string[] {\n return content\n .split(\"\\n\")\n .filter((line) => /^\\d+\\.\\s/.test(line.trim()))\n .map((line) => line.trim().replace(/^\\d+\\.\\s*/, \"\"))\n .slice(0, 5)\n}\n\nexport function SkillAnalysis({ skills: rawSkills, active }: Props) {\n const skills = Array.isArray(rawSkills) ? rawSkills : []\n return (\n <div\n className={cn(\n \"transition-opacity duration-500\",\n active ? \"opacity-100\" : \"pointer-events-none opacity-0\",\n )}\n >\n <div className=\"columns-2 gap-4\">\n {skills.map((skill) => {\n const steps = skill.content ? extractSteps(skill.content) : []\n return (\n <div\n key={skill.skillId}\n className=\"mb-4 break-inside-avoid overflow-hidden rounded-xl border border-[hsl(var(--primary)/0.4)] bg-[hsl(var(--card))] shadow-lg shadow-[hsl(var(--primary)/0.05)] transition-all duration-500\"\n >\n <div className=\"flex items-center gap-2 px-4 py-3\">\n <BookOpen size={15} className=\"shrink-0 text-[hsl(var(--primary))]\" />\n <span className=\"min-w-0 truncate text-[15px] font-semibold text-[hsl(var(--foreground))]\">\n {planSkillDisplayName(skill)}\n </span>\n </div>\n\n <div className=\"border-t border-[hsl(var(--border)/0.5)] px-4 py-2.5\">\n <p className=\"text-sm leading-relaxed text-[hsl(var(--muted-foreground))]\">\n {skill.description}\n </p>\n </div>\n\n <div className=\"border-t border-[hsl(var(--border)/0.5)] px-4 py-2.5\">\n {skill.references && skill.references.length > 0 && (\n <div className=\"mb-2 flex flex-wrap gap-1.5\">\n {skill.references.map((ref, refIdx) => (\n <span\n key={`${refIdx}-${ref}`}\n className=\"inline-flex items-center gap-1 rounded-md bg-[hsl(var(--primary)/0.1)] px-2 py-0.5 text-xs text-[hsl(var(--primary))]\"\n >\n <Link2 size={10} />\n {ref}\n </span>\n ))}\n </div>\n )}\n {steps.length > 0 && (\n <ol className=\"list-inside list-decimal space-y-0.5 text-sm leading-relaxed text-[hsl(var(--muted-foreground)/0.8)]\">\n {steps.map((step, idx) => (\n <li key={idx}>{step}</li>\n ))}\n </ol>\n )}\n </div>\n </div>\n )\n })}\n </div>\n </div>\n )\n}\n","import { CheckCircle2, Search, Sparkles } from \"lucide-react\"\nimport { useMemo } from \"react\"\nimport { cn } from \"../../../lib/utils\"\nimport type { SkillCatalogItem, SkillInfo } from \"../types\"\n\ninterface Props {\n intent: string\n searchResults: SkillInfo[]\n selectedSkills: SkillInfo[]\n allSkillNames: SkillCatalogItem[]\n active: boolean\n}\n\n/** Stable pseudo-random size class for word cloud variety */\nfunction sizeClass(name: string): string {\n const hash = name.split(\"\").reduce((acc, c) => acc + c.charCodeAt(0), 0)\n const sizes = [\"text-xs\", \"text-sm\", \"text-[15px]\"]\n return sizes[hash % sizes.length]\n}\n\nfunction planSkillDisplayName(skill: { skillId: string; displayName?: string }) {\n return skill.displayName?.trim() || skill.skillId\n}\n\nexport function SkillDiscovery({\n intent,\n searchResults: rawSearchResults,\n selectedSkills: rawSelectedSkills,\n allSkillNames: rawAllSkillNames,\n active,\n}: Props) {\n const searchResults = Array.isArray(rawSearchResults) ? rawSearchResults : []\n const selectedSkills = Array.isArray(rawSelectedSkills) ? rawSelectedSkills : []\n const allSkillNames = Array.isArray(rawAllSkillNames) ? rawAllSkillNames : []\n const searchNames = useMemo(() => new Set(searchResults.map((s) => s.skillId)), [searchResults])\n const selectedNames = useMemo(\n () => new Set(selectedSkills.map((s) => s.skillId)),\n [selectedSkills],\n )\n\n const cloudItems = useMemo(() => {\n const bgItems = allSkillNames\n .filter((skill) => !searchNames.has(skill.skillId))\n .map((skill) => ({\n name: planSkillDisplayName(skill),\n key: `bg:${skill.skillId}`,\n isSearch: false,\n isSelected: false,\n }))\n const searchItems = searchResults.map((s) => ({\n name: planSkillDisplayName(s),\n key: `search:${s.skillId}`,\n isSearch: true,\n isSelected: selectedNames.has(s.skillId),\n }))\n\n const result = [...bgItems]\n for (let i = 0; i < searchItems.length; i++) {\n const insertAt = Math.round(((i + 1) / (searchItems.length + 1)) * result.length)\n result.splice(insertAt, 0, searchItems[i])\n }\n return result\n }, [allSkillNames, searchNames, searchResults, selectedNames])\n\n return (\n <div\n className={cn(\n \"flex h-full flex-col gap-6 transition-opacity duration-500\",\n active ? \"opacity-100\" : \"pointer-events-none opacity-0\",\n )}\n >\n <div className=\"flex shrink-0 max-w-md self-center flex-col items-center gap-2.5 rounded-2xl border border-[hsl(var(--primary)/0.4)] bg-[hsl(var(--primary)/0.08)] px-6 py-5 text-center shadow-lg shadow-[hsl(var(--primary)/0.1)]\">\n <Sparkles size={20} className=\"text-[hsl(var(--primary))]\" />\n <p className=\"break-words text-[15px] leading-relaxed text-[hsl(var(--foreground))]\">\n {intent}\n </p>\n </div>\n\n <div className=\"flex min-h-0 flex-1 flex-wrap content-start items-start justify-center gap-x-4 gap-y-3 overflow-y-auto px-6 pb-6\">\n {cloudItems.map((item) => {\n if (item.isSearch && item.isSelected) {\n return (\n <span\n key={item.key}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-[hsl(var(--primary)/0.5)] bg-[hsl(var(--primary)/0.12)] px-3 py-1.5 text-[15px] font-medium text-[hsl(var(--primary))] shadow-md shadow-[hsl(var(--primary)/0.15)] transition-all duration-500\"\n >\n <CheckCircle2 size={14} className=\"shrink-0\" />\n {item.name}\n </span>\n )\n }\n\n if (item.isSearch) {\n return (\n <span\n key={item.key}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-[hsl(var(--foreground)/0.3)] bg-[hsl(var(--foreground)/0.08)] px-3 py-1.5 text-[15px] font-medium text-[hsl(var(--foreground))] transition-all duration-500\"\n >\n <Search size={14} className=\"shrink-0\" />\n {item.name}\n </span>\n )\n }\n\n return (\n <span\n key={item.key}\n className={cn(\n \"select-none font-medium text-[hsl(var(--foreground)/0.45)] transition-all duration-500\",\n sizeClass(item.name),\n )}\n >\n {item.name}\n </span>\n )\n })}\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":["BookOpen","GitBranch","Search","useMemo","useState","ChevronRight","Workflow","jsx","jsx","jsxs","ChevronRight","Workflow","jsx","jsxs","CheckCircle2","useMemo","jsx","jsxs","planSkillDisplayName","useMemo","CheckCircle2","Fragment","jsx","jsxs","Search","BookOpen","GitBranch","useMemo","useState"]}
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { a as SessionInfo } from '../../../session-CT8Y2KHr.js';
2
+ import { a as SessionInfo } from '../../../session-CNnotR90.js';
3
3
  import 'arktype/internal/variants/object.ts';
4
4
  import 'arktype/internal/variants/string.ts';
5
5
 
@@ -1,18 +1,17 @@
1
1
  import {
2
2
  useSession
3
- } from "../../../chunk-TYM7KL2L.js";
3
+ } from "../../../chunk-VJY6RLYU.js";
4
4
  import {
5
5
  checkoutSession,
6
6
  getSessionCheckpoints,
7
7
  useChatStore,
8
8
  useSessionStore
9
- } from "../../../chunk-IMMRWXI7.js";
10
- import "../../../chunk-J3XVFPOV.js";
11
- import "../../../chunk-7F6UP5LP.js";
9
+ } from "../../../chunk-WVXXQ3KM.js";
10
+ import "../../../chunk-M45K3554.js";
12
11
  import {
13
12
  cn
14
- } from "../../../chunk-7LEKQI47.js";
15
- import "../../../chunk-JCJFFJ42.js";
13
+ } from "../../../chunk-QODAKTG5.js";
14
+ import "../../../chunk-J3XVFPOV.js";
16
15
  import "../../../chunk-PZ5AY32C.js";
17
16
 
18
17
  // src/react/components/session/SessionDetail.tsx
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/react/components/session/SessionDetail.tsx","../../../../src/react/components/session/SessionList.tsx","../../../../src/react/components/session/SessionListItem.tsx","../../../../src/react/components/session/StatusBadge.tsx","../../../../src/react/components/session/session-utils.ts"],"sourcesContent":["import * as sessionsApi from \"../../api/sessions\"\nimport { cn } from \"../../lib/utils\"\nimport type { SessionInfo } from \"../../schemas/session\"\nimport { useChatStore } from \"../../stores/chat-store\"\nimport { useSessionStore } from \"../../stores/session-store\"\nimport * as Tooltip from \"@radix-ui/react-tooltip\"\nimport { useQuery, useQueryClient } from \"@tanstack/react-query\"\nimport { HelpCircle } from \"lucide-react\"\nimport { useEffect, useMemo, useRef, useState } from \"react\"\n\ntype CheckpointTree = Awaited<ReturnType<typeof sessionsApi.getSessionCheckpoints>>\ntype CheckpointNode = CheckpointTree[\"nodes\"][number]\n\nconst ROW_HEIGHT = 32\nconst SVG_WIDTH = 44\n\ninterface LayoutNode {\n id: string\n column: number\n row: number\n parentRow: number | null\n parentColumn: number | null\n isActive: boolean\n isCurrent: boolean\n isVirtual: boolean\n preview: string\n content: string\n}\n\ninterface LayoutGraph {\n nodes: LayoutNode[]\n hasCycle: boolean\n maxColumn: number\n maxRow: number\n}\n\nexport function SessionDetailTrigger({\n onClick,\n showReplayDot = false,\n}: {\n onClick: () => void\n showReplayDot?: boolean\n}) {\n return (\n <div className=\"flex items-center gap-1.5\">\n <button\n type=\"button\"\n onClick={onClick}\n className=\"flex items-center gap-1.5 text-[10px] font-medium tracking-[0.18em] text-[hsl(var(--muted-foreground))] uppercase transition-colors hover:text-[hsl(var(--foreground))]\"\n >\n <span>历史回溯</span>\n <HelpCircle size={12} />\n </button>\n {showReplayDot ? (\n <Tooltip.Provider delayDuration={150}>\n <Tooltip.Root>\n <Tooltip.Trigger asChild>\n <span\n className=\"h-[5px] w-[5px] shrink-0 rounded-full bg-amber-400\"\n aria-label=\"当前属于回放模式\"\n />\n </Tooltip.Trigger>\n <Tooltip.Portal>\n <Tooltip.Content\n side=\"top\"\n className=\"z-[60] rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--popover))] px-2 py-1 text-[11px] text-[hsl(var(--popover-foreground))] shadow-lg\"\n >\n 当前属于回放模式\n <Tooltip.Arrow className=\"fill-[hsl(var(--popover))]\" />\n </Tooltip.Content>\n </Tooltip.Portal>\n </Tooltip.Root>\n </Tooltip.Provider>\n ) : null}\n </div>\n )\n}\n\nexport function SessionDetail({ session }: { session: SessionInfo }) {\n const [pendingNodeId, setPendingNodeId] = useState<string | null>(null)\n const isStreaming = useChatStore((state) => state.isStreaming[session.id] ?? false)\n const setRewindDraft = useSessionStore((state) => state.setRewindDraft)\n const setActiveSession = useSessionStore((state) => state.setActiveSession)\n const queryClient = useQueryClient()\n const { data: tree } = useQuery({\n queryKey: [\"checkpoints\", session.id],\n queryFn: ({ signal }) => sessionsApi.getSessionCheckpoints(session.id, { signal }),\n })\n const prevStreamingRef = useRef(isStreaming)\n useEffect(() => {\n if (prevStreamingRef.current && !isStreaming) {\n void queryClient.invalidateQueries({ queryKey: [\"checkpoints\", session.id] })\n }\n prevStreamingRef.current = isStreaming\n }, [isStreaming, queryClient, session.id])\n\n const hasHistory = (tree?.nodes.length ?? 0) > 0\n const layout = useMemo(() => buildLayoutNodes(tree), [tree])\n const nodeMap = useMemo(\n () => new Map((tree?.nodes ?? []).map((node) => [node.id, node])),\n [tree],\n )\n const isBusy = isStreaming || pendingNodeId !== null\n const graphHeight = Math.max((layout.maxRow + 1) * ROW_HEIGHT, ROW_HEIGHT)\n const graphWidth = Math.max(SVG_WIDTH, getColumnX(layout.maxColumn) + 12)\n\n async function checkoutNode(node: CheckpointNode, position: \"before\" | \"turn_end\") {\n if (isBusy) {\n return\n }\n\n setPendingNodeId(node.id)\n\n try {\n const result = await sessionsApi.checkoutSession(session.id, node.id, position)\n if (result.position === \"before\" && result.content.trim()) {\n setRewindDraft(session.id, result.content)\n } else {\n // turn_end: clear input by setting empty string (null = no-op in ChatInput)\n setRewindDraft(session.id, \"\")\n }\n setActiveSession(session.id)\n await queryClient.invalidateQueries({ queryKey: [\"checkpoints\", session.id] })\n } finally {\n setPendingNodeId(null)\n }\n }\n\n async function handleVirtualClick(node: LayoutNode) {\n if (isBusy || !node.isVirtual) return\n const leafId = node.content\n if (!leafId) return\n if (node.isActive) return\n const sourceNode = nodeMap.get(leafId)\n if (!sourceNode) return\n await checkoutNode(sourceNode, \"turn_end\")\n }\n\n async function handleNodeSelect(node: LayoutNode) {\n if (isBusy) {\n return\n }\n\n const sourceNode = nodeMap.get(node.id)\n if (!sourceNode) {\n return\n }\n\n await checkoutNode(sourceNode, \"before\")\n }\n\n if (!hasHistory) return null\n\n return (\n <Tooltip.Provider delayDuration={200}>\n <div className=\"flex max-h-52 justify-center overflow-x-auto overflow-y-auto\">\n <div className=\"relative\" style={{ height: graphHeight, width: graphWidth }}>\n <svg\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute left-0 top-0 z-10 overflow-visible\"\n width={graphWidth}\n height={graphHeight}\n viewBox={`0 0 ${graphWidth} ${graphHeight}`}\n fill=\"none\"\n >\n {layout.nodes.map((node) => {\n if (node.parentRow == null || node.parentColumn == null) {\n return null\n }\n\n const childStroke = node.isActive\n ? \"hsl(var(--primary))\"\n : \"hsl(var(--muted-foreground))\"\n\n return (\n <path\n key={`path-${node.id}`}\n d={buildEdgePath(\n getColumnX(node.parentColumn),\n getRowY(node.parentRow),\n getColumnX(node.column),\n getRowY(node.row),\n )}\n stroke={childStroke}\n strokeOpacity={node.isActive ? 0.95 : 0.45}\n strokeWidth={node.isActive ? 1.8 : 1.4}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeDasharray={node.isVirtual ? \"3 3\" : undefined}\n />\n )\n })}\n </svg>\n\n <div className=\"relative z-0 h-full\">\n {layout.nodes.map((node) => {\n const isPendingNode = pendingNodeId === node.id\n const color = node.isActive\n ? \"hsl(var(--primary))\"\n : \"hsl(var(--muted-foreground))\"\n const previewText = node.isVirtual\n ? isPendingNode\n ? \"切换中...\"\n : \"\"\n : isPendingNode\n ? \"切换中...\"\n : node.preview\n const shouldShowTooltip = !node.isVirtual || Boolean(previewText)\n const button = (\n <button\n type=\"button\"\n onClick={() =>\n void (node.isVirtual ? handleVirtualClick(node) : handleNodeSelect(node))\n }\n disabled={isBusy}\n aria-current={!node.isVirtual && node.isCurrent ? \"step\" : undefined}\n aria-label={node.isVirtual ? \"切换到该分支\" : node.preview}\n className={cn(\n \"absolute z-20 h-8 w-6 overflow-visible\",\n isBusy ? \"cursor-not-allowed opacity-60\" : \"cursor-pointer\",\n )}\n style={{\n top: node.row * ROW_HEIGHT,\n left: getColumnX(node.column) - 12,\n }}\n >\n <span\n aria-hidden=\"true\"\n className=\"absolute left-0 top-0 h-8 w-6\"\n >\n <svg\n aria-hidden=\"true\"\n role=\"img\"\n className=\"pointer-events-none absolute left-0 top-0 h-full w-full overflow-visible\"\n width={24}\n height={ROW_HEIGHT}\n viewBox={`0 0 24 ${ROW_HEIGHT}`}\n fill=\"none\"\n >\n {node.isVirtual ? (\n <circle\n cx={12}\n cy={ROW_HEIGHT / 2}\n r={3.5}\n fill=\"none\"\n stroke={color}\n strokeWidth={1.2}\n strokeDasharray=\"2 2\"\n opacity={0.7}\n />\n ) : (\n <g>\n {node.isCurrent ? (\n <circle\n cx={12}\n cy={ROW_HEIGHT / 2}\n r={9}\n fill={color}\n opacity={0.18}\n />\n ) : null}\n <circle\n cx={12}\n cy={ROW_HEIGHT / 2}\n r={node.isCurrent ? 5.5 : 4}\n fill={color}\n />\n </g>\n )}\n </svg>\n </span>\n </button>\n )\n\n if (!shouldShowTooltip) {\n return <div key={node.id}>{button}</div>\n }\n\n return (\n <Tooltip.Root key={node.id}>\n <Tooltip.Trigger asChild>{button}</Tooltip.Trigger>\n <Tooltip.Portal>\n <Tooltip.Content\n side=\"right\"\n sideOffset={8}\n className={cn(\n \"rounded-md border border-border bg-popover px-2 py-1 text-xs text-foreground shadow-md\",\n !node.isVirtual && node.isCurrent && \"font-semibold\",\n )}\n >\n {previewText}\n </Tooltip.Content>\n </Tooltip.Portal>\n </Tooltip.Root>\n )\n })}\n </div>\n </div>\n </div>\n </Tooltip.Provider>\n )\n}\n\nfunction buildLayoutNodes(tree: CheckpointTree | undefined): LayoutGraph {\n if (!tree || tree.nodes.length === 0) {\n return { nodes: [], hasCycle: false, maxColumn: 0, maxRow: 0 }\n }\n\n const nodeMap = new Map(tree.nodes.map((node) => [node.id, node]))\n const order = new Map(tree.nodes.map((node, index) => [node.id, index]))\n const childrenMap = new Map<string | null, CheckpointNode[]>()\n\n for (const node of tree.nodes) {\n const parentId = node.parent_id && nodeMap.has(node.parent_id) ? node.parent_id : null\n const siblings = childrenMap.get(parentId) ?? []\n siblings.push(node)\n childrenMap.set(parentId, siblings)\n }\n\n const activeIds = new Set<string>()\n const activeVisited = new Set<string>()\n const leafId = tree.leaf_id\n let current = tree.leaf_id\n\n while (current && nodeMap.has(current) && !activeVisited.has(current)) {\n activeIds.add(current)\n activeVisited.add(current)\n current = nodeMap.get(current)?.parent_id ?? null\n }\n\n const layoutNodes: LayoutNode[] = []\n const placed = new Set<string>()\n const visiting = new Set<string>()\n let nextColumn = 1\n let maxColumn = 0\n let maxRow = 0\n let hasCycle = false\n\n const rootSort = (a: CheckpointNode, b: CheckpointNode) =>\n (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0)\n\n const childSort = (a: CheckpointNode, b: CheckpointNode) =>\n (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0)\n\n const allocateColumn = () => {\n const fresh = nextColumn\n nextColumn += 1\n return fresh\n }\n\n function walk(node: CheckpointNode, parent: LayoutNode | null, column: number, row: number) {\n if (visiting.has(node.id)) {\n hasCycle = true\n return\n }\n\n if (placed.has(node.id)) {\n return\n }\n\n visiting.add(node.id)\n maxColumn = Math.max(maxColumn, column)\n maxRow = Math.max(maxRow, row)\n\n const layoutNode: LayoutNode = {\n id: node.id,\n column,\n row,\n parentRow: parent?.row ?? null,\n parentColumn: parent?.column ?? null,\n isActive: activeIds.has(node.id),\n isCurrent: node.id === leafId,\n isVirtual: false,\n preview: formatPreview(node.content_preview),\n content: node.content,\n }\n\n layoutNodes.push(layoutNode)\n placed.add(node.id)\n\n const children = [...(childrenMap.get(node.id) ?? [])].sort(childSort)\n\n if (children.length === 0) {\n const virtualRow = row + 1\n maxRow = Math.max(maxRow, virtualRow)\n layoutNodes.push({\n id: `__virtual__${node.id}`,\n column,\n row: virtualRow,\n parentRow: layoutNode.row,\n parentColumn: layoutNode.column,\n isActive: activeIds.has(node.id),\n isCurrent: false,\n isVirtual: true,\n preview: \"\",\n content: node.id,\n })\n } else {\n for (const [index, child] of children.entries()) {\n if (visiting.has(child.id)) {\n hasCycle = true\n continue\n }\n\n const childColumn = index === 0 ? column : allocateColumn()\n walk(child, layoutNode, childColumn, row + 1)\n }\n }\n\n visiting.delete(node.id)\n }\n\n const roots = [...(childrenMap.get(null) ?? [])].sort(rootSort)\n for (const [index, root] of roots.entries()) {\n const rootColumn = index === 0 ? 0 : allocateColumn()\n walk(root, null, rootColumn, 0)\n }\n\n for (const node of [...tree.nodes].sort(rootSort)) {\n if (!placed.has(node.id)) {\n hasCycle = true\n const rootColumn = layoutNodes.length === 0 ? 0 : allocateColumn()\n walk(node, null, rootColumn, 0)\n }\n }\n\n return {\n nodes: layoutNodes,\n hasCycle,\n maxColumn,\n maxRow,\n }\n}\n\nfunction formatPreview(preview: string): string {\n const normalized = preview.replace(/\\s+/g, \" \").trim()\n return normalized.length > 0 ? normalized : \"(空消息)\"\n}\n\nfunction getColumnX(column: number): number {\n return 12 + column * 24\n}\n\nfunction getRowY(row: number): number {\n return row * ROW_HEIGHT + ROW_HEIGHT / 2\n}\n\nfunction buildEdgePath(fromX: number, fromY: number, toX: number, toY: number): string {\n if (fromX === toX || fromY === toY) {\n return `M ${fromX} ${fromY} L ${toX} ${toY}`\n }\n\n // Branch line: horizontal from parent to child column, then vertical down\n const r = Math.min(5, Math.abs(toX - fromX), Math.abs(toY - fromY))\n const dx = toX > fromX ? 1 : -1\n\n return [\n `M ${fromX} ${fromY}`,\n `H ${toX - dx * r}`,\n `A ${r} ${r} 0 0 ${dx > 0 ? 1 : 0} ${toX} ${fromY + r}`,\n `V ${toY}`,\n ].join(\" \")\n}\n","import { Plus } from \"lucide-react\"\nimport { useState } from \"react\"\nimport type { SessionInfo } from \"../../schemas/session\"\nimport { useSession } from \"../../hooks/use-session\"\nimport { SessionListItem } from \"./SessionListItem\"\nimport { shouldShowSessionInHistory } from \"./session-utils\"\n\nexport interface SessionListProps {\n sessions: SessionInfo[]\n /** Called after a new session is created; defaults to no-op. */\n onSessionCreated?: (sessionId: string) => void\n /** Called when user selects a session. */\n onSessionSelect: (sessionId: string) => void\n}\n\nexport function SessionList({ sessions, onSessionCreated, onSessionSelect }: SessionListProps) {\n const { createSession, activeSessionId } = useSession()\n const [error, setError] = useState<string | null>(null)\n\n const handleCreateSession = async () => {\n setError(null)\n try {\n const sessionId = await createSession()\n onSessionCreated?.(sessionId)\n onSessionSelect(sessionId)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n setError(`创建对话失败: ${message}`)\n setTimeout(() => setError(null), 5000)\n }\n }\n\n return (\n <div className=\"flex flex-col pt-1\">\n <button\n type=\"button\"\n onClick={handleCreateSession}\n className=\"mx-2 mt-1.5 flex items-center gap-2 rounded-md border border-dashed border-[hsl(var(--border))] px-3 py-2 text-sm text-[hsl(var(--muted-foreground))] transition-all hover:border-[hsl(var(--ring))] hover:text-[hsl(var(--primary))]\"\n >\n <Plus size={13} />\n 新建会话\n </button>\n {error ? (\n <p className=\"mx-2 mt-2 rounded-lg bg-[hsl(var(--destructive)/0.1)] px-3 py-2 text-sm text-[hsl(var(--destructive))]\">\n {error}\n </p>\n ) : null}\n <SessionListEntries\n sessions={sessions}\n activeSessionId={activeSessionId}\n onSessionSelect={onSessionSelect}\n />\n </div>\n )\n}\n\nfunction SessionListEntries({\n sessions,\n activeSessionId,\n onSessionSelect,\n}: {\n sessions: SessionInfo[]\n activeSessionId: string | null\n onSessionSelect: (sessionId: string) => void\n}) {\n return (\n <div className=\"mt-2 flex flex-col gap-0.5 px-1.5\">\n {sessions.filter(shouldShowSessionInHistory).map((session) => (\n <SessionListItem\n key={session.id}\n session={session}\n active={session.id === activeSessionId}\n onClick={() => onSessionSelect(session.id)}\n />\n ))}\n </div>\n )\n}\n","import { Loader2 } from \"lucide-react\"\nimport { cn } from \"../../lib/utils\"\nimport type { SessionInfo } from \"../../schemas/session\"\nimport { StatusBadge } from \"./StatusBadge\"\nimport { getDisplaySessionStatus, getSessionLabel, isReplaySession } from \"./session-utils\"\n\ninterface Props {\n session: SessionInfo\n active: boolean\n onClick: () => void\n}\n\nexport function SessionListItem({ session, active, onClick }: Props) {\n const isReplay = isReplaySession(session)\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(\n \"flex w-full flex-col gap-1 rounded-md border-l-2 px-3 py-2 text-left text-sm transition-all hover:bg-[hsl(var(--accent))]\",\n active ? \"border-l-[hsl(var(--primary))] bg-[hsl(var(--accent))]\" : \"border-l-transparent\",\n )}\n >\n <div className=\"flex items-center gap-2\">\n {session.status === \"running\" && (\n <Loader2 size={11} className=\"shrink-0 animate-spin text-blue-400\" />\n )}\n <span className=\"truncate text-[13px] font-medium leading-snug\">{getSessionLabel(session)}</span>\n {isReplay ? (\n <span\n className=\"h-[5px] w-[5px] shrink-0 rounded-full bg-amber-400\"\n title=\"当前属于回放模式\"\n aria-label=\"当前属于回放模式\"\n />\n ) : null}\n </div>\n <div className=\"flex items-center gap-2\">\n <StatusBadge status={getDisplaySessionStatus(session)} />\n <span className=\"font-mono text-[10px] text-[hsl(var(--muted-foreground))]\">\n {session.id.slice(0, 8)}\n </span>\n </div>\n </button>\n )\n}\n","import { cn } from \"../../lib/utils\"\n\nconst statusConfig: Record<string, { className: string; label: string }> = {\n created: {\n className: \"bg-[hsl(var(--muted))] text-[hsl(var(--muted-foreground))]\",\n label: \"已创建\",\n },\n running: { className: \"bg-blue-500/15 text-blue-400\", label: \"运行中\" },\n completed: { className: \"bg-emerald-500/15 text-emerald-400\", label: \"已完成\" },\n failed: {\n className: \"bg-[hsl(var(--destructive)/0.15)] text-[hsl(var(--destructive))]\",\n label: \"失败\",\n },\n interrupted: { className: \"bg-amber-500/15 text-amber-400\", label: \"已中断\" },\n waiting_for_input: { className: \"bg-violet-500/15 text-violet-400\", label: \"等待输入\" },\n pending: {\n className: \"bg-[hsl(var(--muted))] text-[hsl(var(--muted-foreground))]\",\n label: \"待处理\",\n },\n in_progress: { className: \"bg-blue-500/15 text-blue-400\", label: \"进行中\" },\n done: { className: \"bg-emerald-500/15 text-emerald-400\", label: \"完成\" },\n info: {\n className: \"bg-[hsl(var(--muted))] text-[hsl(var(--muted-foreground))]\",\n label: \"信息\",\n },\n error: {\n className: \"bg-[hsl(var(--destructive)/0.15)] text-[hsl(var(--destructive))]\",\n label: \"错误\",\n },\n skipped: {\n className: \"bg-[hsl(var(--muted)/0.5)] text-[hsl(var(--muted-foreground)/0.6)]\",\n label: \"已跳过\",\n },\n example: {\n className: \"bg-[hsl(var(--muted))] text-[hsl(var(--muted-foreground))]\",\n label: \"示例\",\n },\n}\n\nconst defaultConfig = {\n className: \"bg-[hsl(var(--muted))] text-[hsl(var(--muted-foreground))]\",\n label: \"\",\n}\n\nexport function StatusBadge({ status }: { status: string }) {\n const config = statusConfig[status] ?? defaultConfig\n return (\n <span\n className={cn(\n \"inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium tracking-wide\",\n config.className,\n )}\n >\n {config.label || status}\n </span>\n )\n}\n","import type { SessionInfo } from \"../../schemas/session\"\n\nexport type SessionGroupKey = \"today\" | \"yesterday\" | \"week\" | \"older\"\n\nexport const SESSION_GROUPS: SessionGroupKey[] = [\"today\", \"yesterday\", \"week\", \"older\"]\n\nexport const SESSION_GROUP_LABELS: Record<SessionGroupKey, string> = {\n today: \"今天\",\n yesterday: \"昨天\",\n week: \"本周\",\n older: \"更早\",\n}\n\nexport const RELATIVE_TIME_FORMATTER = new Intl.RelativeTimeFormat(\"zh-CN\", {\n numeric: \"auto\",\n})\n\nexport function getSessionTimestamp(session: SessionInfo) {\n const value = Date.parse(session.updated_at || session.created_at)\n return Number.isNaN(value) ? 0 : value\n}\n\nexport function getSessionLabel(session: SessionInfo, fallback = \"未命名对话\") {\n const normalized = session.intent?.trim()\n return normalized ? normalized : fallback\n}\n\nexport function shouldShowSessionInHistory(session: SessionInfo) {\n return !(session.status === \"created\" && !session.intent.trim())\n}\n\nexport function isReplaySession(session: SessionInfo) {\n return session.replay_state?.status === \"replay\"\n}\n\nexport function getDisplaySessionStatus(session: SessionInfo): SessionInfo[\"status\"] {\n if (\n session.replay_state?.status === \"autonomous\" &&\n session.replay_state.autonomous_reason === \"completed\"\n ) {\n return \"completed\"\n }\n return session.status\n}\n\nexport function startOfDay(date: Date) {\n const copy = new Date(date)\n copy.setHours(0, 0, 0, 0)\n return copy\n}\n\nexport function startOfWeek(date: Date) {\n const copy = startOfDay(date)\n const day = copy.getDay()\n const diff = day === 0 ? 6 : day - 1\n copy.setDate(copy.getDate() - diff)\n return copy\n}\n\nexport function getSessionGroup(timestamp: number, now = new Date()): SessionGroupKey {\n if (!timestamp) {\n return \"older\"\n }\n\n const sessionDate = new Date(timestamp)\n const today = startOfDay(now)\n const yesterday = new Date(today)\n yesterday.setDate(yesterday.getDate() - 1)\n const thisWeek = startOfWeek(now)\n\n if (sessionDate >= today) {\n return \"today\"\n }\n\n if (sessionDate >= yesterday) {\n return \"yesterday\"\n }\n\n if (sessionDate >= thisWeek) {\n return \"week\"\n }\n\n return \"older\"\n}\n\nexport function formatRelativeTime(timestamp: number, now = Date.now()) {\n if (!timestamp) {\n return \"时间未知\"\n }\n\n const diffSeconds = Math.round((timestamp - now) / 1000)\n const absSeconds = Math.abs(diffSeconds)\n\n if (absSeconds < 60) {\n return \"刚刚\"\n }\n\n const units: Array<[Intl.RelativeTimeFormatUnit, number]> = [\n [\"minute\", 60],\n [\"hour\", 60 * 60],\n [\"day\", 60 * 60 * 24],\n [\"week\", 60 * 60 * 24 * 7],\n [\"month\", 60 * 60 * 24 * 30],\n [\"year\", 60 * 60 * 24 * 365],\n ]\n\n for (let index = 0; index < units.length; index += 1) {\n const [unit, threshold] = units[index]\n const nextThreshold = units[index + 1]?.[1]\n\n if (!nextThreshold || absSeconds < nextThreshold) {\n return RELATIVE_TIME_FORMATTER.format(Math.round(diffSeconds / threshold), unit)\n }\n }\n\n return RELATIVE_TIME_FORMATTER.format(Math.round(diffSeconds / (60 * 60 * 24 * 365)), \"year\")\n}\n\nexport function getStatusMeta(status: SessionInfo[\"status\"]) {\n switch (status) {\n case \"running\":\n return {\n dotClass: \"bg-emerald-400\",\n toneClass: \"border-emerald-500/20 bg-emerald-500/8 text-emerald-300\",\n label: \"运行中\",\n }\n case \"failed\":\n return {\n dotClass: \"bg-rose-400\",\n toneClass: \"border-rose-500/20 bg-rose-500/8 text-rose-300\",\n label: \"异常\",\n }\n case \"waiting_for_input\":\n return {\n dotClass: \"bg-violet-400\",\n toneClass: \"border-violet-500/20 bg-violet-500/8 text-violet-300\",\n label: \"待补充\",\n }\n case \"completed\":\n return {\n dotClass: \"bg-sky-400\",\n toneClass: \"border-sky-500/20 bg-sky-500/8 text-sky-300\",\n label: \"已完成\",\n }\n case \"interrupted\":\n return {\n dotClass: \"bg-amber-400\",\n toneClass: \"border-amber-500/20 bg-amber-500/8 text-amber-300\",\n label: \"已中断\",\n }\n default:\n return {\n dotClass: \"bg-[hsl(var(--muted-foreground))]\",\n toneClass:\n \"border-[hsl(var(--border))] bg-[hsl(var(--accent))] text-[hsl(var(--muted-foreground))]\",\n label: \"准备中\",\n }\n }\n}\n"],"mappings":"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","names":["useState","jsx","jsx","jsxs","jsx","jsxs","useState"]}
1
+ {"version":3,"sources":["../../../../src/react/components/session/SessionDetail.tsx","../../../../src/react/components/session/SessionList.tsx","../../../../src/react/components/session/SessionListItem.tsx","../../../../src/react/components/session/StatusBadge.tsx","../../../../src/react/components/session/session-utils.ts"],"sourcesContent":["import * as sessionsApi from \"../../api/sessions\"\nimport { cn } from \"../../lib/utils\"\nimport type { SessionInfo } from \"../../schemas/session\"\nimport { useChatStore } from \"../../stores/chat-store\"\nimport { useSessionStore } from \"../../stores/session-store\"\nimport * as Tooltip from \"@radix-ui/react-tooltip\"\nimport { useQuery, useQueryClient } from \"@tanstack/react-query\"\nimport { HelpCircle } from \"lucide-react\"\nimport { useEffect, useMemo, useRef, useState } from \"react\"\n\ntype CheckpointTree = Awaited<ReturnType<typeof sessionsApi.getSessionCheckpoints>>\ntype CheckpointNode = CheckpointTree[\"nodes\"][number]\n\nconst ROW_HEIGHT = 32\nconst SVG_WIDTH = 44\n\ninterface LayoutNode {\n id: string\n column: number\n row: number\n parentRow: number | null\n parentColumn: number | null\n isActive: boolean\n isCurrent: boolean\n isVirtual: boolean\n preview: string\n content: string\n}\n\ninterface LayoutGraph {\n nodes: LayoutNode[]\n hasCycle: boolean\n maxColumn: number\n maxRow: number\n}\n\nexport function SessionDetailTrigger({\n onClick,\n showReplayDot = false,\n}: {\n onClick: () => void\n showReplayDot?: boolean\n}) {\n return (\n <div className=\"flex items-center gap-1.5\">\n <button\n type=\"button\"\n onClick={onClick}\n className=\"flex items-center gap-1.5 text-[10px] font-medium tracking-[0.18em] text-[hsl(var(--muted-foreground))] uppercase transition-colors hover:text-[hsl(var(--foreground))]\"\n >\n <span>历史回溯</span>\n <HelpCircle size={12} />\n </button>\n {showReplayDot ? (\n <Tooltip.Provider delayDuration={150}>\n <Tooltip.Root>\n <Tooltip.Trigger asChild>\n <span\n className=\"h-[5px] w-[5px] shrink-0 rounded-full bg-amber-400\"\n aria-label=\"当前属于回放模式\"\n />\n </Tooltip.Trigger>\n <Tooltip.Portal>\n <Tooltip.Content\n side=\"top\"\n className=\"z-[60] rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--popover))] px-2 py-1 text-[11px] text-[hsl(var(--popover-foreground))] shadow-lg\"\n >\n 当前属于回放模式\n <Tooltip.Arrow className=\"fill-[hsl(var(--popover))]\" />\n </Tooltip.Content>\n </Tooltip.Portal>\n </Tooltip.Root>\n </Tooltip.Provider>\n ) : null}\n </div>\n )\n}\n\nexport function SessionDetail({ session }: { session: SessionInfo }) {\n const [pendingNodeId, setPendingNodeId] = useState<string | null>(null)\n const isStreaming = useChatStore((state) => state.isStreaming[session.id] ?? false)\n const setRewindDraft = useSessionStore((state) => state.setRewindDraft)\n const setActiveSession = useSessionStore((state) => state.setActiveSession)\n const queryClient = useQueryClient()\n const { data: tree } = useQuery({\n queryKey: [\"checkpoints\", session.id],\n queryFn: ({ signal }) => sessionsApi.getSessionCheckpoints(session.id, { signal }),\n })\n const prevStreamingRef = useRef(isStreaming)\n useEffect(() => {\n if (prevStreamingRef.current && !isStreaming) {\n void queryClient.invalidateQueries({ queryKey: [\"checkpoints\", session.id] })\n }\n prevStreamingRef.current = isStreaming\n }, [isStreaming, queryClient, session.id])\n\n const hasHistory = (tree?.nodes.length ?? 0) > 0\n const layout = useMemo(() => buildLayoutNodes(tree), [tree])\n const nodeMap = useMemo(\n () => new Map((tree?.nodes ?? []).map((node) => [node.id, node])),\n [tree],\n )\n const isBusy = isStreaming || pendingNodeId !== null\n const graphHeight = Math.max((layout.maxRow + 1) * ROW_HEIGHT, ROW_HEIGHT)\n const graphWidth = Math.max(SVG_WIDTH, getColumnX(layout.maxColumn) + 12)\n\n async function checkoutNode(node: CheckpointNode, position: \"before\" | \"turn_end\") {\n if (isBusy) {\n return\n }\n\n setPendingNodeId(node.id)\n\n try {\n const result = await sessionsApi.checkoutSession(session.id, node.id, position)\n if (result.position === \"before\" && result.content.trim()) {\n setRewindDraft(session.id, result.content)\n } else {\n // turn_end: clear input by setting empty string (null = no-op in ChatInput)\n setRewindDraft(session.id, \"\")\n }\n setActiveSession(session.id)\n await queryClient.invalidateQueries({ queryKey: [\"checkpoints\", session.id] })\n } finally {\n setPendingNodeId(null)\n }\n }\n\n async function handleVirtualClick(node: LayoutNode) {\n if (isBusy || !node.isVirtual) return\n const leafId = node.content\n if (!leafId) return\n if (node.isActive) return\n const sourceNode = nodeMap.get(leafId)\n if (!sourceNode) return\n await checkoutNode(sourceNode, \"turn_end\")\n }\n\n async function handleNodeSelect(node: LayoutNode) {\n if (isBusy) {\n return\n }\n\n const sourceNode = nodeMap.get(node.id)\n if (!sourceNode) {\n return\n }\n\n await checkoutNode(sourceNode, \"before\")\n }\n\n if (!hasHistory) return null\n\n return (\n <Tooltip.Provider delayDuration={200}>\n <div className=\"flex max-h-52 justify-center overflow-x-auto overflow-y-auto\">\n <div className=\"relative\" style={{ height: graphHeight, width: graphWidth }}>\n <svg\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute left-0 top-0 z-10 overflow-visible\"\n width={graphWidth}\n height={graphHeight}\n viewBox={`0 0 ${graphWidth} ${graphHeight}`}\n fill=\"none\"\n >\n {layout.nodes.map((node) => {\n if (node.parentRow == null || node.parentColumn == null) {\n return null\n }\n\n const childStroke = node.isActive\n ? \"hsl(var(--primary))\"\n : \"hsl(var(--muted-foreground))\"\n\n return (\n <path\n key={`path-${node.id}`}\n d={buildEdgePath(\n getColumnX(node.parentColumn),\n getRowY(node.parentRow),\n getColumnX(node.column),\n getRowY(node.row),\n )}\n stroke={childStroke}\n strokeOpacity={node.isActive ? 0.95 : 0.45}\n strokeWidth={node.isActive ? 1.8 : 1.4}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeDasharray={node.isVirtual ? \"3 3\" : undefined}\n />\n )\n })}\n </svg>\n\n <div className=\"relative z-0 h-full\">\n {layout.nodes.map((node) => {\n const isPendingNode = pendingNodeId === node.id\n const color = node.isActive\n ? \"hsl(var(--primary))\"\n : \"hsl(var(--muted-foreground))\"\n const previewText = node.isVirtual\n ? isPendingNode\n ? \"切换中...\"\n : \"\"\n : isPendingNode\n ? \"切换中...\"\n : node.preview\n const shouldShowTooltip = !node.isVirtual || Boolean(previewText)\n const button = (\n <button\n type=\"button\"\n onClick={() =>\n void (node.isVirtual ? handleVirtualClick(node) : handleNodeSelect(node))\n }\n disabled={isBusy}\n aria-current={!node.isVirtual && node.isCurrent ? \"step\" : undefined}\n aria-label={node.isVirtual ? \"切换到该分支\" : node.preview}\n className={cn(\n \"absolute z-20 h-8 w-6 overflow-visible\",\n isBusy ? \"cursor-not-allowed opacity-60\" : \"cursor-pointer\",\n )}\n style={{\n top: node.row * ROW_HEIGHT,\n left: getColumnX(node.column) - 12,\n }}\n >\n <span\n aria-hidden=\"true\"\n className=\"absolute left-0 top-0 h-8 w-6\"\n >\n <svg\n aria-hidden=\"true\"\n role=\"img\"\n className=\"pointer-events-none absolute left-0 top-0 h-full w-full overflow-visible\"\n width={24}\n height={ROW_HEIGHT}\n viewBox={`0 0 24 ${ROW_HEIGHT}`}\n fill=\"none\"\n >\n {node.isVirtual ? (\n <circle\n cx={12}\n cy={ROW_HEIGHT / 2}\n r={3.5}\n fill=\"none\"\n stroke={color}\n strokeWidth={1.2}\n strokeDasharray=\"2 2\"\n opacity={0.7}\n />\n ) : (\n <g>\n {node.isCurrent ? (\n <circle\n cx={12}\n cy={ROW_HEIGHT / 2}\n r={9}\n fill={color}\n opacity={0.18}\n />\n ) : null}\n <circle\n cx={12}\n cy={ROW_HEIGHT / 2}\n r={node.isCurrent ? 5.5 : 4}\n fill={color}\n />\n </g>\n )}\n </svg>\n </span>\n </button>\n )\n\n if (!shouldShowTooltip) {\n return <div key={node.id}>{button}</div>\n }\n\n return (\n <Tooltip.Root key={node.id}>\n <Tooltip.Trigger asChild>{button}</Tooltip.Trigger>\n <Tooltip.Portal>\n <Tooltip.Content\n side=\"right\"\n sideOffset={8}\n className={cn(\n \"rounded-md border border-border bg-popover px-2 py-1 text-xs text-foreground shadow-md\",\n !node.isVirtual && node.isCurrent && \"font-semibold\",\n )}\n >\n {previewText}\n </Tooltip.Content>\n </Tooltip.Portal>\n </Tooltip.Root>\n )\n })}\n </div>\n </div>\n </div>\n </Tooltip.Provider>\n )\n}\n\nfunction buildLayoutNodes(tree: CheckpointTree | undefined): LayoutGraph {\n if (!tree || tree.nodes.length === 0) {\n return { nodes: [], hasCycle: false, maxColumn: 0, maxRow: 0 }\n }\n\n const nodeMap = new Map(tree.nodes.map((node) => [node.id, node]))\n const order = new Map(tree.nodes.map((node, index) => [node.id, index]))\n const childrenMap = new Map<string | null, CheckpointNode[]>()\n\n for (const node of tree.nodes) {\n const parentId = node.parent_id && nodeMap.has(node.parent_id) ? node.parent_id : null\n const siblings = childrenMap.get(parentId) ?? []\n siblings.push(node)\n childrenMap.set(parentId, siblings)\n }\n\n const activeIds = new Set<string>()\n const activeVisited = new Set<string>()\n const leafId = tree.leaf_id\n let current = tree.leaf_id\n\n while (current && nodeMap.has(current) && !activeVisited.has(current)) {\n activeIds.add(current)\n activeVisited.add(current)\n current = nodeMap.get(current)?.parent_id ?? null\n }\n\n const layoutNodes: LayoutNode[] = []\n const placed = new Set<string>()\n const visiting = new Set<string>()\n let nextColumn = 1\n let maxColumn = 0\n let maxRow = 0\n let hasCycle = false\n\n const rootSort = (a: CheckpointNode, b: CheckpointNode) =>\n (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0)\n\n const childSort = (a: CheckpointNode, b: CheckpointNode) =>\n (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0)\n\n const allocateColumn = () => {\n const fresh = nextColumn\n nextColumn += 1\n return fresh\n }\n\n function walk(node: CheckpointNode, parent: LayoutNode | null, column: number, row: number) {\n if (visiting.has(node.id)) {\n hasCycle = true\n return\n }\n\n if (placed.has(node.id)) {\n return\n }\n\n visiting.add(node.id)\n maxColumn = Math.max(maxColumn, column)\n maxRow = Math.max(maxRow, row)\n\n const layoutNode: LayoutNode = {\n id: node.id,\n column,\n row,\n parentRow: parent?.row ?? null,\n parentColumn: parent?.column ?? null,\n isActive: activeIds.has(node.id),\n isCurrent: node.id === leafId,\n isVirtual: false,\n preview: formatPreview(node.content_preview),\n content: node.content,\n }\n\n layoutNodes.push(layoutNode)\n placed.add(node.id)\n\n const children = [...(childrenMap.get(node.id) ?? [])].sort(childSort)\n\n if (children.length === 0) {\n const virtualRow = row + 1\n maxRow = Math.max(maxRow, virtualRow)\n layoutNodes.push({\n id: `__virtual__${node.id}`,\n column,\n row: virtualRow,\n parentRow: layoutNode.row,\n parentColumn: layoutNode.column,\n isActive: activeIds.has(node.id),\n isCurrent: false,\n isVirtual: true,\n preview: \"\",\n content: node.id,\n })\n } else {\n for (const [index, child] of children.entries()) {\n if (visiting.has(child.id)) {\n hasCycle = true\n continue\n }\n\n const childColumn = index === 0 ? column : allocateColumn()\n walk(child, layoutNode, childColumn, row + 1)\n }\n }\n\n visiting.delete(node.id)\n }\n\n const roots = [...(childrenMap.get(null) ?? [])].sort(rootSort)\n for (const [index, root] of roots.entries()) {\n const rootColumn = index === 0 ? 0 : allocateColumn()\n walk(root, null, rootColumn, 0)\n }\n\n for (const node of [...tree.nodes].sort(rootSort)) {\n if (!placed.has(node.id)) {\n hasCycle = true\n const rootColumn = layoutNodes.length === 0 ? 0 : allocateColumn()\n walk(node, null, rootColumn, 0)\n }\n }\n\n return {\n nodes: layoutNodes,\n hasCycle,\n maxColumn,\n maxRow,\n }\n}\n\nfunction formatPreview(preview: string): string {\n const normalized = preview.replace(/\\s+/g, \" \").trim()\n return normalized.length > 0 ? normalized : \"(空消息)\"\n}\n\nfunction getColumnX(column: number): number {\n return 12 + column * 24\n}\n\nfunction getRowY(row: number): number {\n return row * ROW_HEIGHT + ROW_HEIGHT / 2\n}\n\nfunction buildEdgePath(fromX: number, fromY: number, toX: number, toY: number): string {\n if (fromX === toX || fromY === toY) {\n return `M ${fromX} ${fromY} L ${toX} ${toY}`\n }\n\n // Branch line: horizontal from parent to child column, then vertical down\n const r = Math.min(5, Math.abs(toX - fromX), Math.abs(toY - fromY))\n const dx = toX > fromX ? 1 : -1\n\n return [\n `M ${fromX} ${fromY}`,\n `H ${toX - dx * r}`,\n `A ${r} ${r} 0 0 ${dx > 0 ? 1 : 0} ${toX} ${fromY + r}`,\n `V ${toY}`,\n ].join(\" \")\n}\n","import { Plus } from \"lucide-react\"\nimport { useState } from \"react\"\nimport type { SessionInfo } from \"../../schemas/session\"\nimport { useSession } from \"../../hooks/use-session\"\nimport { SessionListItem } from \"./SessionListItem\"\nimport { shouldShowSessionInHistory } from \"./session-utils\"\n\nexport interface SessionListProps {\n sessions: SessionInfo[]\n /** Called after a new session is created; defaults to no-op. */\n onSessionCreated?: (sessionId: string) => void\n /** Called when user selects a session. */\n onSessionSelect: (sessionId: string) => void\n}\n\nexport function SessionList({ sessions, onSessionCreated, onSessionSelect }: SessionListProps) {\n const { createSession, activeSessionId } = useSession()\n const [error, setError] = useState<string | null>(null)\n\n const handleCreateSession = async () => {\n setError(null)\n try {\n const sessionId = await createSession()\n onSessionCreated?.(sessionId)\n onSessionSelect(sessionId)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n setError(`创建对话失败: ${message}`)\n setTimeout(() => setError(null), 5000)\n }\n }\n\n return (\n <div className=\"flex flex-col pt-1\">\n <button\n type=\"button\"\n onClick={handleCreateSession}\n className=\"mx-2 mt-1.5 flex items-center gap-2 rounded-md border border-dashed border-[hsl(var(--border))] px-3 py-2 text-sm text-[hsl(var(--muted-foreground))] transition-all hover:border-[hsl(var(--ring))] hover:text-[hsl(var(--primary))]\"\n >\n <Plus size={13} />\n 新建会话\n </button>\n {error ? (\n <p className=\"mx-2 mt-2 rounded-lg bg-[hsl(var(--destructive)/0.1)] px-3 py-2 text-sm text-[hsl(var(--destructive))]\">\n {error}\n </p>\n ) : null}\n <SessionListEntries\n sessions={sessions}\n activeSessionId={activeSessionId}\n onSessionSelect={onSessionSelect}\n />\n </div>\n )\n}\n\nfunction SessionListEntries({\n sessions,\n activeSessionId,\n onSessionSelect,\n}: {\n sessions: SessionInfo[]\n activeSessionId: string | null\n onSessionSelect: (sessionId: string) => void\n}) {\n return (\n <div className=\"mt-2 flex flex-col gap-0.5 px-1.5\">\n {sessions.filter(shouldShowSessionInHistory).map((session) => (\n <SessionListItem\n key={session.id}\n session={session}\n active={session.id === activeSessionId}\n onClick={() => onSessionSelect(session.id)}\n />\n ))}\n </div>\n )\n}\n","import { Loader2 } from \"lucide-react\"\nimport { cn } from \"../../lib/utils\"\nimport type { SessionInfo } from \"../../schemas/session\"\nimport { StatusBadge } from \"./StatusBadge\"\nimport { getDisplaySessionStatus, getSessionLabel, isReplaySession } from \"./session-utils\"\n\ninterface Props {\n session: SessionInfo\n active: boolean\n onClick: () => void\n}\n\nexport function SessionListItem({ session, active, onClick }: Props) {\n const isReplay = isReplaySession(session)\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(\n \"flex w-full flex-col gap-1 rounded-md border-l-2 px-3 py-2 text-left text-sm transition-all hover:bg-[hsl(var(--accent))]\",\n active ? \"border-l-[hsl(var(--primary))] bg-[hsl(var(--accent))]\" : \"border-l-transparent\",\n )}\n >\n <div className=\"flex items-center gap-2\">\n {session.status === \"running\" && (\n <Loader2 size={11} className=\"shrink-0 animate-spin text-blue-400\" />\n )}\n <span className=\"truncate text-[13px] font-medium leading-snug\">{getSessionLabel(session)}</span>\n {isReplay ? (\n <span\n className=\"h-[5px] w-[5px] shrink-0 rounded-full bg-amber-400\"\n title=\"当前属于回放模式\"\n aria-label=\"当前属于回放模式\"\n />\n ) : null}\n </div>\n <div className=\"flex items-center gap-2\">\n <StatusBadge status={getDisplaySessionStatus(session)} />\n <span className=\"font-mono text-[10px] text-[hsl(var(--muted-foreground))]\">\n {session.id.slice(0, 8)}\n </span>\n </div>\n </button>\n )\n}\n","import { cn } from \"../../lib/utils\"\n\nconst statusConfig: Record<string, { className: string; label: string }> = {\n created: {\n className: \"bg-[hsl(var(--muted))] text-[hsl(var(--muted-foreground))]\",\n label: \"已创建\",\n },\n running: { className: \"bg-blue-500/15 text-blue-400\", label: \"运行中\" },\n completed: { className: \"bg-emerald-500/15 text-emerald-400\", label: \"已完成\" },\n failed: {\n className: \"bg-[hsl(var(--destructive)/0.15)] text-[hsl(var(--destructive))]\",\n label: \"失败\",\n },\n interrupted: { className: \"bg-amber-500/15 text-amber-400\", label: \"已中断\" },\n waiting_for_input: { className: \"bg-violet-500/15 text-violet-400\", label: \"等待输入\" },\n pending: {\n className: \"bg-[hsl(var(--muted))] text-[hsl(var(--muted-foreground))]\",\n label: \"待处理\",\n },\n in_progress: { className: \"bg-blue-500/15 text-blue-400\", label: \"进行中\" },\n done: { className: \"bg-emerald-500/15 text-emerald-400\", label: \"完成\" },\n info: {\n className: \"bg-[hsl(var(--muted))] text-[hsl(var(--muted-foreground))]\",\n label: \"信息\",\n },\n error: {\n className: \"bg-[hsl(var(--destructive)/0.15)] text-[hsl(var(--destructive))]\",\n label: \"错误\",\n },\n skipped: {\n className: \"bg-[hsl(var(--muted)/0.5)] text-[hsl(var(--muted-foreground)/0.6)]\",\n label: \"已跳过\",\n },\n example: {\n className: \"bg-[hsl(var(--muted))] text-[hsl(var(--muted-foreground))]\",\n label: \"示例\",\n },\n}\n\nconst defaultConfig = {\n className: \"bg-[hsl(var(--muted))] text-[hsl(var(--muted-foreground))]\",\n label: \"\",\n}\n\nexport function StatusBadge({ status }: { status: string }) {\n const config = statusConfig[status] ?? defaultConfig\n return (\n <span\n className={cn(\n \"inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium tracking-wide\",\n config.className,\n )}\n >\n {config.label || status}\n </span>\n )\n}\n","import type { SessionInfo } from \"../../schemas/session\"\n\nexport type SessionGroupKey = \"today\" | \"yesterday\" | \"week\" | \"older\"\n\nexport const SESSION_GROUPS: SessionGroupKey[] = [\"today\", \"yesterday\", \"week\", \"older\"]\n\nexport const SESSION_GROUP_LABELS: Record<SessionGroupKey, string> = {\n today: \"今天\",\n yesterday: \"昨天\",\n week: \"本周\",\n older: \"更早\",\n}\n\nexport const RELATIVE_TIME_FORMATTER = new Intl.RelativeTimeFormat(\"zh-CN\", {\n numeric: \"auto\",\n})\n\nexport function getSessionTimestamp(session: SessionInfo) {\n const value = Date.parse(session.updated_at || session.created_at)\n return Number.isNaN(value) ? 0 : value\n}\n\nexport function getSessionLabel(session: SessionInfo, fallback = \"未命名对话\") {\n const normalized = session.intent?.trim()\n return normalized ? normalized : fallback\n}\n\nexport function shouldShowSessionInHistory(session: SessionInfo) {\n return !(session.status === \"created\" && !session.intent.trim())\n}\n\nexport function isReplaySession(session: SessionInfo) {\n return session.replay_state?.status === \"replay\"\n}\n\nexport function getDisplaySessionStatus(session: SessionInfo): SessionInfo[\"status\"] {\n if (\n session.replay_state?.status === \"autonomous\" &&\n session.replay_state.autonomous_reason === \"completed\"\n ) {\n return \"completed\"\n }\n return session.status\n}\n\nexport function startOfDay(date: Date) {\n const copy = new Date(date)\n copy.setHours(0, 0, 0, 0)\n return copy\n}\n\nexport function startOfWeek(date: Date) {\n const copy = startOfDay(date)\n const day = copy.getDay()\n const diff = day === 0 ? 6 : day - 1\n copy.setDate(copy.getDate() - diff)\n return copy\n}\n\nexport function getSessionGroup(timestamp: number, now = new Date()): SessionGroupKey {\n if (!timestamp) {\n return \"older\"\n }\n\n const sessionDate = new Date(timestamp)\n const today = startOfDay(now)\n const yesterday = new Date(today)\n yesterday.setDate(yesterday.getDate() - 1)\n const thisWeek = startOfWeek(now)\n\n if (sessionDate >= today) {\n return \"today\"\n }\n\n if (sessionDate >= yesterday) {\n return \"yesterday\"\n }\n\n if (sessionDate >= thisWeek) {\n return \"week\"\n }\n\n return \"older\"\n}\n\nexport function formatRelativeTime(timestamp: number, now = Date.now()) {\n if (!timestamp) {\n return \"时间未知\"\n }\n\n const diffSeconds = Math.round((timestamp - now) / 1000)\n const absSeconds = Math.abs(diffSeconds)\n\n if (absSeconds < 60) {\n return \"刚刚\"\n }\n\n const units: Array<[Intl.RelativeTimeFormatUnit, number]> = [\n [\"minute\", 60],\n [\"hour\", 60 * 60],\n [\"day\", 60 * 60 * 24],\n [\"week\", 60 * 60 * 24 * 7],\n [\"month\", 60 * 60 * 24 * 30],\n [\"year\", 60 * 60 * 24 * 365],\n ]\n\n for (let index = 0; index < units.length; index += 1) {\n const [unit, threshold] = units[index]\n const nextThreshold = units[index + 1]?.[1]\n\n if (!nextThreshold || absSeconds < nextThreshold) {\n return RELATIVE_TIME_FORMATTER.format(Math.round(diffSeconds / threshold), unit)\n }\n }\n\n return RELATIVE_TIME_FORMATTER.format(Math.round(diffSeconds / (60 * 60 * 24 * 365)), \"year\")\n}\n\nexport function getStatusMeta(status: SessionInfo[\"status\"]) {\n switch (status) {\n case \"running\":\n return {\n dotClass: \"bg-emerald-400\",\n toneClass: \"border-emerald-500/20 bg-emerald-500/8 text-emerald-300\",\n label: \"运行中\",\n }\n case \"failed\":\n return {\n dotClass: \"bg-rose-400\",\n toneClass: \"border-rose-500/20 bg-rose-500/8 text-rose-300\",\n label: \"异常\",\n }\n case \"waiting_for_input\":\n return {\n dotClass: \"bg-violet-400\",\n toneClass: \"border-violet-500/20 bg-violet-500/8 text-violet-300\",\n label: \"待补充\",\n }\n case \"completed\":\n return {\n dotClass: \"bg-sky-400\",\n toneClass: \"border-sky-500/20 bg-sky-500/8 text-sky-300\",\n label: \"已完成\",\n }\n case \"interrupted\":\n return {\n dotClass: \"bg-amber-400\",\n toneClass: \"border-amber-500/20 bg-amber-500/8 text-amber-300\",\n label: \"已中断\",\n }\n default:\n return {\n dotClass: \"bg-[hsl(var(--muted-foreground))]\",\n toneClass:\n \"border-[hsl(var(--border))] bg-[hsl(var(--accent))] text-[hsl(var(--muted-foreground))]\",\n label: \"准备中\",\n }\n }\n}\n"],"mappings":"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","names":["useState","jsx","jsx","jsxs","jsx","jsxs","useState"]}
@@ -1,11 +1,11 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
- import { l as listDir } from '../../../sessions-DI9DVun7.js';
4
- import '../../../blade-client-CseN7OW9.js';
3
+ import { l as listDir } from '../../../sessions-BvfLGbjw.js';
4
+ import '../../../blade-client-qTOovekU.js';
5
5
  import 'arktype/internal/variants/object.ts';
6
6
  import 'arktype/internal/variants/string.ts';
7
7
  import '../../../projection-BWYEFYNn.js';
8
- import '../../../session-CT8Y2KHr.js';
8
+ import '../../../session-CNnotR90.js';
9
9
  import 'socket.io-client';
10
10
 
11
11
  interface WorkspaceFileEntry {
@@ -5,7 +5,7 @@ import {
5
5
  } from "../../../chunk-H62LH2AG.js";
6
6
  import {
7
7
  resolveSessionFilePreviewTarget
8
- } from "../../../chunk-2QYV43YP.js";
8
+ } from "../../../chunk-WPLEMYL7.js";
9
9
  import {
10
10
  apiFetchText,
11
11
  copyFile,
@@ -19,13 +19,12 @@ import {
19
19
  useChatStore,
20
20
  useSessionStore,
21
21
  useUiStore
22
- } from "../../../chunk-IMMRWXI7.js";
23
- import "../../../chunk-J3XVFPOV.js";
24
- import "../../../chunk-7F6UP5LP.js";
22
+ } from "../../../chunk-WVXXQ3KM.js";
23
+ import "../../../chunk-M45K3554.js";
25
24
  import {
26
25
  cn
27
- } from "../../../chunk-7LEKQI47.js";
28
- import "../../../chunk-JCJFFJ42.js";
26
+ } from "../../../chunk-QODAKTG5.js";
27
+ import "../../../chunk-J3XVFPOV.js";
29
28
  import "../../../chunk-PZ5AY32C.js";
30
29
 
31
30
  // src/react/components/workspace/WorkspaceFilesPanel.tsx