@blade-hq/agent-kit 1.0.30 → 1.0.32

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 (42) hide show
  1. package/dist/{chunk-7OEW3P7R.js → chunk-E7FQV4IX.js} +56 -35
  2. package/dist/chunk-E7FQV4IX.js.map +1 -0
  3. package/dist/{chunk-6G5LCDOS.js → chunk-EGGBOVVF.js} +2 -2
  4. package/dist/{chunk-L4C2TY6S.js → chunk-F4Y7SUBC.js} +2 -2
  5. package/dist/{chunk-GAVSC2AW.js → chunk-FK4CV6R2.js} +46 -2
  6. package/dist/chunk-FK4CV6R2.js.map +1 -0
  7. package/dist/{chunk-WOKDHXS7.js → chunk-IDVNG3YJ.js} +37 -12
  8. package/dist/chunk-IDVNG3YJ.js.map +1 -0
  9. package/dist/{chunk-3XDPNPE3.js → chunk-IGMLETZX.js} +1001 -713
  10. package/dist/chunk-IGMLETZX.js.map +1 -0
  11. package/dist/{chunk-MJPVAXJN.js → chunk-OICNN4K4.js} +2 -2
  12. package/dist/client/index.js +1 -1
  13. package/dist/client/types/rest.d.ts +65 -136
  14. package/dist/react/api/published-apps.js +3 -3
  15. package/dist/react/api/sessions.js +2 -2
  16. package/dist/react/components/chat/FileDeliveryCards.d.ts +11 -0
  17. package/dist/react/components/chat/MessageList.d.ts +1 -0
  18. package/dist/react/components/chat/PlanningToggle.d.ts +7 -0
  19. package/dist/react/components/chat/ResourceIframe.d.ts +1 -1
  20. package/dist/react/components/chat/UserMessageBubble.d.ts +1 -1
  21. package/dist/react/components/chat/index.d.ts +1 -0
  22. package/dist/react/components/chat/index.js +7 -5
  23. package/dist/react/components/plan/index.js +4 -4
  24. package/dist/react/components/session/index.js +3 -3
  25. package/dist/react/components/workspace/index.js +61 -42
  26. package/dist/react/components/workspace/index.js.map +1 -1
  27. package/dist/react/hooks/use-model-preferences.d.ts +2 -0
  28. package/dist/react/index.d.ts +1 -1
  29. package/dist/react/index.js +9 -7
  30. package/dist/react/index.js.map +1 -1
  31. package/dist/react/lib/ui-meta.d.ts +1 -0
  32. package/dist/react/stores/ui-store.d.ts +5 -0
  33. package/dist/react/types/solution.d.ts +1 -0
  34. package/dist/style.css +1 -1
  35. package/package.json +1 -1
  36. package/dist/chunk-3XDPNPE3.js.map +0 -1
  37. package/dist/chunk-7OEW3P7R.js.map +0 -1
  38. package/dist/chunk-GAVSC2AW.js.map +0 -1
  39. package/dist/chunk-WOKDHXS7.js.map +0 -1
  40. /package/dist/{chunk-6G5LCDOS.js.map → chunk-EGGBOVVF.js.map} +0 -0
  41. /package/dist/{chunk-L4C2TY6S.js.map → chunk-F4Y7SUBC.js.map} +0 -0
  42. /package/dist/{chunk-MJPVAXJN.js.map → chunk-OICNN4K4.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getSessionFilePath,
3
3
  resolveSessionFilePreviewTarget
4
- } from "./chunk-MJPVAXJN.js";
4
+ } from "./chunk-OICNN4K4.js";
5
5
  import {
6
6
  CardJSON,
7
7
  cardRegistry
@@ -11,7 +11,7 @@ import {
11
11
  formatToolName,
12
12
  getAuthedUrl,
13
13
  useUiStore
14
- } from "./chunk-WOKDHXS7.js";
14
+ } from "./chunk-IDVNG3YJ.js";
15
15
  import {
16
16
  cn,
17
17
  copyToClipboard
@@ -852,8 +852,11 @@ function CodeBlockPre({ children, node: _node, ...props }) {
852
852
  const preRef = useRef(null);
853
853
  const [copied, setCopied] = useState4(false);
854
854
  const [hasCodeNode, setHasCodeNode] = useState4(false);
855
+ const [language, setLanguage] = useState4("");
855
856
  useEffect3(() => {
856
- setHasCodeNode(!!preRef.current?.querySelector("code"));
857
+ const codeEl = preRef.current?.querySelector("code");
858
+ setHasCodeNode(!!codeEl);
859
+ setLanguage(codeEl?.className.match(/language-(\S+)/)?.[1] ?? "");
857
860
  }, []);
858
861
  const getRawCode = () => preRef.current?.querySelector("code")?.textContent ?? "";
859
862
  const handleCopy = async () => {
@@ -875,37 +878,55 @@ function CodeBlockPre({ children, node: _node, ...props }) {
875
878
  a.click();
876
879
  URL.revokeObjectURL(url);
877
880
  };
878
- return /* @__PURE__ */ jsxs5("div", { className: "relative group", children: [
879
- /* @__PURE__ */ jsx6("pre", { ref: preRef, ...props, children }),
880
- hasCodeNode && /* @__PURE__ */ jsxs5("div", { className: "absolute top-2 right-2 flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity", children: [
881
- /* @__PURE__ */ jsxs5(
882
- "button",
883
- {
884
- type: "button",
885
- onClick: handleCopy,
886
- className: cn(
887
- "flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[11px] transition-colors",
888
- copied ? "text-[hsl(var(--primary))]" : "text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))] hover:bg-[hsl(var(--accent))]"
889
- ),
890
- children: [
891
- copied ? /* @__PURE__ */ jsx6(Check2, { size: 12 }) : /* @__PURE__ */ jsx6(Copy2, { size: 12 }),
892
- /* @__PURE__ */ jsx6("span", { children: copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236" })
893
- ]
894
- }
895
- ),
896
- /* @__PURE__ */ jsxs5(
897
- "button",
898
- {
899
- type: "button",
900
- onClick: handleDownload,
901
- className: "flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[11px] transition-colors text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))] hover:bg-[hsl(var(--accent))]",
902
- children: [
903
- /* @__PURE__ */ jsx6(Download2, { size: 12 }),
904
- /* @__PURE__ */ jsx6("span", { children: "\u4E0B\u8F7D" })
905
- ]
906
- }
907
- )
908
- ] })
881
+ if (!hasCodeNode) {
882
+ return /* @__PURE__ */ jsx6("div", { className: "relative", children: /* @__PURE__ */ jsx6("pre", { ref: preRef, ...props, children }) });
883
+ }
884
+ return /* @__PURE__ */ jsxs5("div", { className: "not-prose my-3 overflow-hidden rounded-xl border border-[hsl(var(--border))]", children: [
885
+ /* @__PURE__ */ jsxs5("div", { className: "flex h-[34px] items-center justify-between border-b border-[hsl(var(--border))] bg-[hsl(var(--muted))/0.5] pl-3.5 pr-1.5", children: [
886
+ /* @__PURE__ */ jsx6("span", { className: "font-mono text-[12px] text-[hsl(var(--muted-foreground))]", children: language || "code" }),
887
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-0.5", children: [
888
+ /* @__PURE__ */ jsxs5(
889
+ "button",
890
+ {
891
+ type: "button",
892
+ onClick: handleCopy,
893
+ className: cn(
894
+ "flex h-6 items-center gap-1 rounded-md px-1.5 text-[11px] transition-colors",
895
+ copied ? "text-[hsl(var(--primary))]" : "text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]"
896
+ ),
897
+ children: [
898
+ copied ? /* @__PURE__ */ jsx6(Check2, { size: 12 }) : /* @__PURE__ */ jsx6(Copy2, { size: 12 }),
899
+ /* @__PURE__ */ jsx6("span", { children: copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236" })
900
+ ]
901
+ }
902
+ ),
903
+ /* @__PURE__ */ jsxs5(
904
+ "button",
905
+ {
906
+ type: "button",
907
+ onClick: handleDownload,
908
+ className: "flex h-6 items-center gap-1 rounded-md px-1.5 text-[11px] text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
909
+ children: [
910
+ /* @__PURE__ */ jsx6(Download2, { size: 12 }),
911
+ /* @__PURE__ */ jsx6("span", { children: "\u4E0B\u8F7D" })
912
+ ]
913
+ }
914
+ )
915
+ ] })
916
+ ] }),
917
+ /* @__PURE__ */ jsx6(
918
+ "pre",
919
+ {
920
+ ref: preRef,
921
+ ...props,
922
+ className: cn(
923
+ props.className,
924
+ // 原型:13.5px/1.7 等宽、浅底;覆盖 prose 的继承字号与主题里手写的 pre 样式。
925
+ "m-0! overflow-x-auto! rounded-none! border-0! bg-[hsl(var(--muted))/0.25]! px-4! py-3.5! font-mono text-[13.5px]! leading-[1.7]! [&_code]:bg-transparent! [&_code]:p-0! [&_code]:font-mono [&_code]:text-[13.5px]! [&_code]:text-[hsl(var(--foreground))]"
926
+ ),
927
+ children
928
+ }
929
+ )
909
930
  ] });
910
931
  }
911
932
  function isExternalImageSrc(src) {
@@ -2044,4 +2065,4 @@ export {
2044
2065
  PlanSummaryCard,
2045
2066
  extractLatestPlanMessages
2046
2067
  };
2047
- //# sourceMappingURL=chunk-7OEW3P7R.js.map
2068
+ //# sourceMappingURL=chunk-E7FQV4IX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react/lib/code-highlight.ts","../src/react/components/card/CardContext.tsx","../src/react/components/card/CardCodeBlock.tsx","../src/react/components/card/CardRenderer.tsx","../src/react/components/card/CardStates.tsx","../src/react/components/markdown/MarkdownContent.tsx","../src/react/components/markdown/ExternalLinkDialog.tsx","../src/react/components/markdown/FileCardComponent.tsx","../src/react/components/chat/AskUserQuestionBlock.tsx","../src/react/components/plan/parse-plan-tree.ts","../src/react/components/plan/parse-plan-messages.ts","../src/react/components/plan/PlanSummaryCard.tsx","../src/react/components/plan/extract-plan-messages.ts"],"sourcesContent":["import { useEffect, useMemo, useState } from \"react\"\n\nconst DARK_THEME = \"github-dark-default\"\nconst LIGHT_THEME = \"github-light-default\"\n\nconst SUPPORTED_LANGUAGES = [\n \"python\",\n \"javascript\",\n \"typescript\",\n \"tsx\",\n \"jsx\",\n \"yaml\",\n \"markdown\",\n \"bash\",\n \"json\",\n \"go\",\n \"rust\",\n \"css\",\n \"html\",\n] as const\n\nexport type SupportedCodeLanguage = (typeof SUPPORTED_LANGUAGES)[number]\n\nconst LANGUAGE_ALIASES: Record<string, SupportedCodeLanguage> = {\n bash: \"bash\",\n css: \"css\",\n go: \"go\",\n golang: \"go\",\n htm: \"html\",\n html: \"html\",\n javascript: \"javascript\",\n js: \"javascript\",\n json: \"json\",\n jsonc: \"json\",\n jsx: \"jsx\",\n markdown: \"markdown\",\n md: \"markdown\",\n py: \"python\",\n python: \"python\",\n rs: \"rust\",\n rust: \"rust\",\n scss: \"css\",\n sh: \"bash\",\n shell: \"bash\",\n ts: \"typescript\",\n tsx: \"tsx\",\n typescript: \"typescript\",\n yaml: \"yaml\",\n yml: \"yaml\",\n zsh: \"bash\",\n}\n\nconst FILE_EXTENSION_ALIASES: Record<string, SupportedCodeLanguage> = {\n \".bash\": \"bash\",\n \".css\": \"css\",\n \".go\": \"go\",\n \".htm\": \"html\",\n \".html\": \"html\",\n \".js\": \"javascript\",\n \".json\": \"json\",\n \".jsonc\": \"json\",\n \".jsx\": \"jsx\",\n \".md\": \"markdown\",\n \".mdx\": \"markdown\",\n \".py\": \"python\",\n \".rs\": \"rust\",\n \".scss\": \"css\",\n \".sh\": \"bash\",\n \".ts\": \"typescript\",\n \".tsx\": \"tsx\",\n \".yaml\": \"yaml\",\n \".yml\": \"yaml\",\n \".zsh\": \"bash\",\n}\n\ntype CodeHighlighter = {\n codeToHtml: (\n code: string,\n options: {\n lang: SupportedCodeLanguage\n themes: { light: string; dark: string }\n defaultColor?: false\n },\n ) => string\n}\n\nlet highlighterPromise: Promise<CodeHighlighter> | null = null\n\nconst CACHE_MAX_SIZE = 200\nconst highlightCache = new Map<string, Promise<string | null>>()\n\nexport function normalizeCodeLanguage(language?: string | null): SupportedCodeLanguage | null {\n if (!language) return null\n\n return LANGUAGE_ALIASES[language.trim().toLowerCase()] ?? null\n}\n\nexport function getCodeLanguageFromFilename(filePath?: string | null): SupportedCodeLanguage | null {\n if (!filePath) return null\n\n const dotIndex = filePath.lastIndexOf(\".\")\n if (dotIndex < 0) return null\n\n return FILE_EXTENSION_ALIASES[filePath.slice(dotIndex).toLowerCase()] ?? null\n}\n\nexport function useHighlightedCodeHtml(code: string, language?: string | null) {\n const normalizedLanguage = useMemo(() => normalizeCodeLanguage(language), [language])\n const [highlightedHtml, setHighlightedHtml] = useState<string | null>(null)\n\n useEffect(() => {\n let cancelled = false\n\n setHighlightedHtml(null)\n\n if (!normalizedLanguage) {\n return () => {\n cancelled = true\n }\n }\n\n void highlightCodeToInnerHtml(code, normalizedLanguage).then((result) => {\n if (!cancelled) {\n setHighlightedHtml(result)\n }\n })\n\n return () => {\n cancelled = true\n }\n }, [code, normalizedLanguage])\n\n return { highlightedHtml, language: normalizedLanguage }\n}\n\nasync function highlightCodeToInnerHtml(code: string, language: SupportedCodeLanguage) {\n const cacheKey = `${language}\\u0000${code}`\n const cached = highlightCache.get(cacheKey)\n\n if (cached) {\n return cached\n }\n\n const request = loadCodeHighlighter()\n .then((highlighter) => {\n const html = highlighter.codeToHtml(code, {\n lang: language,\n themes: { light: LIGHT_THEME, dark: DARK_THEME },\n defaultColor: false,\n })\n return extractInnerCodeHtml(html)\n })\n .catch(() => {\n highlightCache.delete(cacheKey)\n return null\n })\n\n if (highlightCache.size >= CACHE_MAX_SIZE) {\n const oldest = highlightCache.keys().next().value\n if (oldest !== undefined) highlightCache.delete(oldest)\n }\n highlightCache.set(cacheKey, request)\n return request\n}\n\nasync function loadCodeHighlighter(): Promise<CodeHighlighter> {\n if (!highlighterPromise) {\n highlighterPromise = Promise.all([\n import(\"shiki/core\"),\n import(\"shiki/engine/javascript\"),\n import(\"@shikijs/langs/bash\"),\n import(\"@shikijs/langs/css\"),\n import(\"@shikijs/langs/go\"),\n import(\"@shikijs/langs/html\"),\n import(\"@shikijs/langs/javascript\"),\n import(\"@shikijs/langs/json\"),\n import(\"@shikijs/langs/jsx\"),\n import(\"@shikijs/langs/markdown\"),\n import(\"@shikijs/langs/python\"),\n import(\"@shikijs/langs/rust\"),\n import(\"@shikijs/langs/tsx\"),\n import(\"@shikijs/langs/typescript\"),\n import(\"@shikijs/langs/yaml\"),\n import(\"@shikijs/themes/github-dark-default\"),\n import(\"@shikijs/themes/github-light-default\"),\n ]).then(\n ([\n core,\n engine,\n bash,\n css,\n go,\n html,\n javascript,\n json,\n jsx,\n markdown,\n python,\n rust,\n tsx,\n typescript,\n yaml,\n darkTheme,\n lightTheme,\n ]) =>\n core.createHighlighterCore({\n engine: engine.createJavaScriptRegexEngine(),\n langs: [\n bash.default,\n css.default,\n go.default,\n html.default,\n javascript.default,\n json.default,\n jsx.default,\n markdown.default,\n python.default,\n rust.default,\n tsx.default,\n typescript.default,\n yaml.default,\n ],\n themes: [darkTheme.default, lightTheme.default],\n }),\n ).catch((err) => {\n highlighterPromise = null\n throw err\n })\n }\n\n return highlighterPromise as Promise<CodeHighlighter>\n}\n\nfunction extractInnerCodeHtml(html: string) {\n const match = html.match(/<code[^>]*>([\\s\\S]*)<\\/code><\\/pre>\\s*$/)\n return match?.[1] ?? null\n}\n","import { createContext, useContext } from \"react\"\n\nexport interface CardContextValue {\n sendMessage?: (content: string) => Promise<void>\n sessionId?: string\n messageId?: string\n}\n\nexport const CardContext = createContext<CardContextValue>({})\n\nexport const useCardContext = () => useContext(CardContext)\n","import type { JSX } from \"react\"\nimport { useIsCodeFenceIncomplete } from \"streamdown\"\nimport type { ExtraProps } from \"streamdown\"\nimport { CardJSON } from \"../../lib/card-registry\"\nimport { normalizeCodeLanguage, useHighlightedCodeHtml } from \"../../lib/code-highlight\"\nimport { CardRenderer } from \"./CardRenderer\"\n\ntype CodeProps = JSX.IntrinsicElements[\"code\"] & ExtraProps\n\nexport function CardCodeBlock({ className, children, node, ...props }: CodeProps) {\n const isIncomplete = useIsCodeFenceIncomplete()\n const match = /language-(\\S+)/.exec(className || \"\")\n const lang = match?.[1]\n const isInline = !className\n const raw = String(children ?? \"\")\n const normalizedLang = normalizeCodeLanguage(lang)\n const { highlightedHtml } = useHighlightedCodeHtml(raw, normalizedLang)\n\n if (!isInline && CardJSON.isCardsLanguage(lang)) {\n return (\n <CardRenderer\n raw={raw}\n blockPosition={node?.position?.start?.line}\n isCodeFenceIncomplete={isIncomplete}\n />\n )\n }\n\n if (!isInline && highlightedHtml) {\n return (\n <code\n className={className}\n {...props}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: syntax highlighting output is generated locally\n dangerouslySetInnerHTML={{ __html: highlightedHtml }}\n />\n )\n }\n\n return (\n <code className={className} {...props}>\n {children}\n </code>\n )\n}\n","import { Component, type ErrorInfo, type ReactNode } from \"react\"\nimport { type Card, CardJSON, cardRegistry } from \"../../lib/card-registry\"\nimport { useUiStore } from \"../../stores/ui-store\"\nimport { useCardContext } from \"./CardContext\"\nimport { CardErrorState, CardLoadingState, CardWarningState } from \"./CardStates\"\n\ninterface Props {\n raw: string\n blockPosition?: number\n isCodeFenceIncomplete?: boolean\n}\n\nfunction looksIncomplete(text: string): boolean {\n const t = text.trim()\n if (!t) return true\n const openBraces = (t.match(/{/g) || []).length\n const closeBraces = (t.match(/}/g) || []).length\n const openBrackets = (t.match(/\\[/g) || []).length\n const closeBrackets = (t.match(/]/g) || []).length\n const quotes = (t.match(/\"/g) || []).length\n\n return (\n (!t.endsWith(\"}\") && !t.endsWith(\"]\")) ||\n openBraces !== closeBraces ||\n openBrackets !== closeBrackets ||\n t.endsWith(\",\") ||\n t.endsWith(\":\") ||\n quotes % 2 !== 0\n )\n}\n\ninterface ErrorBoundaryProps {\n fallback: ReactNode\n children: ReactNode\n}\n\ninterface ErrorBoundaryState {\n hasError: boolean\n}\n\nclass CardErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\n state: ErrorBoundaryState = { hasError: false }\n\n static getDerivedStateFromError(): ErrorBoundaryState {\n return { hasError: true }\n }\n\n componentDidCatch(error: Error, info: ErrorInfo) {\n console.error(\"Card render error:\", error, info)\n }\n\n render() {\n if (this.state.hasError) return this.props.fallback\n return this.props.children\n }\n}\n\nfunction OpenInPreviewButton({ card }: { card: Card }) {\n const pushArtifact = useUiStore((s) => s.pushArtifact)\n\n return (\n <button\n type=\"button\"\n onClick={() =>\n pushArtifact({\n type: \"card\",\n content: JSON.stringify(card, null, 2),\n title: card.title || card.type,\n key: `card-${card.id}`,\n })\n }\n className=\"absolute right-2 top-2 rounded bg-[hsl(var(--accent))] px-1.5 py-0.5 text-[10px] text-[hsl(var(--muted-foreground))] opacity-0 transition-opacity group-hover/card:opacity-100 hover:text-[hsl(var(--foreground))]\"\n >\n 预览\n </button>\n )\n}\n\nexport function CardRenderer({ raw, blockPosition, isCodeFenceIncomplete }: Props) {\n const { sessionId, messageId, sendMessage } = useCardContext()\n const trimmed = raw.trim()\n\n if (!trimmed) return <CardLoadingState content=\"\" />\n\n // If code fence is still streaming, show loading\n if (isCodeFenceIncomplete) {\n return <CardLoadingState content={trimmed} />\n }\n\n const parsed = CardJSON.safeParseJSON(trimmed)\n\n if (!parsed.ok) {\n if (looksIncomplete(trimmed)) {\n return <CardLoadingState content={trimmed} />\n }\n return <CardErrorState content={trimmed} message={parsed.error} />\n }\n\n const cards = CardJSON.toCardArray(parsed.value)\n if (!cards) {\n return <CardWarningState content={trimmed} message=\"JSON 格式正确但不符合卡片结构\" />\n }\n\n const cardsWithIds = cards.map((c, i) => {\n if (c.id) return c\n return {\n ...c,\n id: `${messageId || \"msg\"}-block-${blockPosition ?? 0}-card-${i}`,\n }\n })\n\n return (\n <>\n {cardsWithIds.map((card) => {\n const CardComponent = cardRegistry.get(card.type)\n if (!CardComponent) {\n return (\n <CardWarningState\n key={card.id}\n content={JSON.stringify(card, null, 2)}\n message={`未知的卡片类型: ${card.type}`}\n />\n )\n }\n return (\n <div key={card.id} className=\"group/card relative my-4\">\n <CardErrorBoundary\n fallback={\n <CardErrorState\n content={JSON.stringify(card, null, 2)}\n message=\"卡片渲染出错\"\n />\n }\n >\n <CardComponent card={card} sendMessage={sendMessage} sessionId={sessionId} />\n <OpenInPreviewButton card={card} />\n </CardErrorBoundary>\n </div>\n )\n })}\n </>\n )\n}\n","interface CardStateProps {\n content: string\n message?: string\n}\n\nexport function CardLoadingState({ content }: CardStateProps) {\n return (\n <div className=\"my-4 rounded-md border border-[hsl(var(--primary)/0.2)] bg-[hsl(var(--primary)/0.05)] p-4\">\n <div className=\"mb-2 flex items-center gap-2\">\n <div className=\"h-4 w-4 animate-spin rounded-full border-2 border-[hsl(var(--primary))] border-t-transparent\" />\n <p className=\"text-sm text-[hsl(var(--primary))]\">正在加载卡片数据...</p>\n </div>\n <details className=\"mt-2\">\n <summary className=\"cursor-pointer text-xs text-[hsl(var(--primary)/0.7)]\">查看接收中的数据</summary>\n <pre className=\"mt-1 whitespace-pre-wrap rounded bg-[hsl(var(--primary)/0.1)] p-2 font-mono text-xs text-[hsl(var(--primary)/0.8)]\">\n {content}\n </pre>\n </details>\n </div>\n )\n}\n\nexport function CardErrorState({ content, message }: CardStateProps) {\n return (\n <div className=\"my-4 rounded-md border border-red-500/20 bg-red-500/5 p-4\">\n <p className=\"mb-2 text-sm text-red-400\">{message || \"卡片数据解析失败\"}</p>\n <details className=\"mt-2\">\n <summary className=\"cursor-pointer text-xs text-red-400/70 hover:underline\">\n 查看原始代码块\n </summary>\n <pre className=\"mt-2 overflow-x-auto whitespace-pre-wrap rounded bg-red-500/10 p-3 font-mono text-xs text-red-400/80\">\n {content}\n </pre>\n </details>\n </div>\n )\n}\n\nexport function CardWarningState({ content, message }: CardStateProps) {\n return (\n <div className=\"my-4 rounded-md border border-yellow-500/20 bg-yellow-500/5 p-4\">\n <p className=\"mb-2 text-sm text-yellow-400\">{message || \"数据格式不符合卡片要求\"}</p>\n <details className=\"mt-2\">\n <summary className=\"cursor-pointer text-xs text-yellow-400/70\">查看原始数据</summary>\n <pre className=\"mt-1 whitespace-pre-wrap rounded bg-yellow-500/10 p-2 font-mono text-xs text-yellow-400/80\">\n {content}\n </pre>\n </details>\n </div>\n )\n}\n","import { mermaid } from \"@streamdown/mermaid\"\nimport { useQuery } from \"@tanstack/react-query\"\nimport { Check, Copy, Download, X } from \"lucide-react\"\nimport {\n type ComponentProps,\n type ComponentPropsWithRef,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\"\nimport { createPortal } from \"react-dom\"\nimport { type ExtraProps, Streamdown, defaultRehypePlugins } from \"streamdown\"\nimport { apiFetch, getAuthedUrl } from \"../../api/client\"\nimport { cn, copyToClipboard } from \"../../lib/utils\"\nimport { useUiStore } from \"../../stores/ui-store\"\nimport { CardCodeBlock } from \"../card/CardCodeBlock\"\nimport { ExternalLinkDialog } from \"./ExternalLinkDialog\"\nimport { FileCardComponent } from \"./FileCardComponent\"\n\ntype StreamdownProps = ComponentProps<typeof Streamdown>\n\nconst LINK_SAFETY_CONFIG: NonNullable<StreamdownProps[\"linkSafety\"]> = {\n enabled: true,\n renderModal: (props) => <ExternalLinkDialog {...props} />,\n}\n\n/** 在会话的沙盒浏览器(「浏览器」面板)中打开链接:新建归属本会话的标签页,\n * 并把右侧面板切到「浏览器」标签——不然新标签开在用户看不见的地方,等于白点。\n * 失败静默(浏览器镜像未启用等),不打断用户。\n *\n * 注意:这里不看 rightPanelAutoJump——那个开关管的是\"agent 后台操作浏览器时\n * 要不要自动跟过去围观\",跟这里不是一回事:用户点\"在浏览器中打开\"是**直接的\n * 前台操作**,就是奔着看这个新标签去的,不该被\"后台自动跳转\"开关拦下来只留一个\n * 未读点。*/\nasync function openInSandboxBrowser(sessionId: string, url: string): Promise<void> {\n try {\n await apiFetch(`/api/sessions/${encodeURIComponent(sessionId)}/browser/tabs`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ url }),\n })\n const uiStore = useUiStore.getState()\n uiStore.clearRightPanelTabUnread(\"browser\")\n uiStore.setActiveRightTab(\"browser\")\n } catch (error) {\n console.warn(\"open in sandbox browser failed\", error)\n }\n}\n\nconst STREAMDOWN_PLUGINS = { mermaid } satisfies NonNullable<StreamdownProps[\"plugins\"]>\n\nconst SYSTEM_REMINDER_TAG = \"system-reminder\"\nconst TOOL_CALL_TAG = \"blade-malformed-tool-call\"\nconst FILE_CARD_TAG = \"blade-file-card\"\nconst AGENT_WORKSPACE_DIR_NAME = \"智能助手工作空间\"\nconst CUSTOM_ALLOWED_TAGS: NonNullable<StreamdownProps[\"allowedTags\"]> = {\n [SYSTEM_REMINDER_TAG]: [],\n [TOOL_CALL_TAG]: [\"data-key\", \"data-raw\"],\n [FILE_CARD_TAG]: [\"data-rel-path\", \"data-name\"],\n}\nconst HIDDEN_SYSTEM_REMINDER_COMPONENTS = {\n [SYSTEM_REMINDER_TAG]: () => null,\n} as NonNullable<StreamdownProps[\"components\"]>\nconst TOOL_CALL_BLOCK_RE = /<tool_call>\\s*[\\s\\S]*?\\s*<\\/tool_call>/gi\nconst malformedToolCallContent = new Map<string, string>()\n\ntype SanitizeSchema = {\n tagNames?: string[]\n attributes?: Record<string, unknown>\n [key: string]: unknown\n}\n\nconst sanitizePlugin = defaultRehypePlugins.sanitize\nconst sanitizeFn = Array.isArray(sanitizePlugin) ? sanitizePlugin[0] : sanitizePlugin\nconst sanitizeSchema = (\n Array.isArray(sanitizePlugin) ? sanitizePlugin[1] : {}\n) as SanitizeSchema\nconst hardenFn = Array.isArray(defaultRehypePlugins.harden)\n ? defaultRehypePlugins.harden[0]\n : defaultRehypePlugins.harden\n\nfunction buildSanitizeAttributes(\n allowedTags: NonNullable<StreamdownProps[\"allowedTags\"]>,\n): Record<string, string[]> {\n return Object.fromEntries(\n Object.entries(allowedTags).map(([tag, attributes]) => [\n tag,\n [\n ...new Set(\n attributes.flatMap((attribute) => [\n attribute,\n attribute.replace(/-([a-z])/g, (_, letter: string) => letter.toUpperCase()),\n ]),\n ),\n ],\n ]),\n )\n}\n\nfunction buildRehypePlugins(\n allowedTags: NonNullable<StreamdownProps[\"allowedTags\"]>,\n): NonNullable<StreamdownProps[\"rehypePlugins\"]> {\n return Object.values({\n ...defaultRehypePlugins,\n sanitize: [\n sanitizeFn,\n {\n ...sanitizeSchema,\n tagNames: [...(sanitizeSchema.tagNames ?? []), ...Object.keys(allowedTags)],\n attributes: {\n ...(sanitizeSchema.attributes ?? {}),\n ...buildSanitizeAttributes(allowedTags),\n },\n },\n ],\n harden: [\n hardenFn,\n {\n allowedImagePrefixes: [\"*\"],\n allowedLinkPrefixes: [\"*\"],\n allowedProtocols: [\"*\"],\n defaultOrigin: \"http://localhost\",\n allowDataImages: true,\n },\n ],\n }) as NonNullable<StreamdownProps[\"rehypePlugins\"]>\n}\n\ntype PreProps = ComponentPropsWithRef<\"pre\"> & ExtraProps\n\ntype ToolCallProps = ComponentPropsWithRef<\"span\"> &\n ExtraProps & {\n \"data-key\"?: string\n \"data-raw\"?: string\n dataKey?: string\n dataRaw?: string\n }\n\nfunction InlineToolCallBlock({\n children,\n node,\n \"data-key\": dataKeyAttribute,\n \"data-raw\": dataRawAttribute,\n dataKey,\n dataRaw,\n ...props\n}: ToolCallProps) {\n const rawText =\n resolveCollapsedContent({\n dataKeyAttribute,\n dataRawAttribute,\n dataKey,\n dataRaw,\n node,\n children,\n }) || extractText(children).trim()\n const [open, setOpen] = useState(false)\n\n return (\n <span\n {...props}\n className=\"not-prose relative inline-flex align-baseline\"\n >\n <button\n type=\"button\"\n onClick={() => setOpen(true)}\n className=\"inline-flex items-center rounded-full bg-[hsl(var(--muted))]/40 px-2 py-0.5 text-[10px] leading-none text-[hsl(var(--muted-foreground))]/70 transition-colors hover:bg-[hsl(var(--muted))]/60 hover:text-[hsl(var(--muted-foreground))] focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none\"\n aria-label=\"查看折叠的内容\"\n aria-expanded={open}\n >\n 折叠的内容\n </button>\n {open\n ? createPortal(\n <div\n className=\"fixed inset-0 z-[70] flex items-center justify-center bg-black/10 p-6\"\n role=\"presentation\"\n tabIndex={-1}\n onClick={(event) => {\n if (event.target === event.currentTarget) {\n setOpen(false)\n }\n }}\n onKeyDown={(event) => {\n if (event.key === \"Escape\") {\n setOpen(false)\n }\n }}\n >\n <div\n className=\"m-0 flex max-h-[min(520px,calc(100vh-48px))] w-[min(760px,calc(100vw-48px))] flex-col overflow-hidden rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--popover))] text-left text-[13px] leading-6 text-[hsl(var(--popover-foreground))] shadow-xl\"\n aria-label=\"折叠的内容\"\n >\n <div className=\"flex items-center justify-between gap-3 border-b border-[hsl(var(--border))] px-4 py-2\">\n <span className=\"text-xs font-medium text-[hsl(var(--muted-foreground))]\">\n 折叠的内容\n </span>\n <button\n type=\"button\"\n onClick={() => setOpen(false)}\n className=\"inline-flex h-6 w-6 items-center justify-center rounded-md text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))] focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none\"\n aria-label=\"关闭折叠的内容\"\n >\n <X size={14} aria-hidden=\"true\" />\n </button>\n </div>\n <pre className=\"m-0 overflow-auto px-4 py-3 font-mono text-[12px] leading-5 whitespace-pre-wrap text-[hsl(var(--popover-foreground))]\">\n {rawText || children}\n </pre>\n </div>\n </div>,\n document.body,\n )\n : null}\n </span>\n )\n}\n\nfunction extractText(value: unknown): string {\n if (typeof value === \"string\" || typeof value === \"number\") return String(value)\n if (Array.isArray(value)) return value.map(extractText).join(\"\")\n if (value && typeof value === \"object\" && \"props\" in value) {\n const props = (value as { props?: { children?: unknown } }).props\n return extractText(props?.children)\n }\n return \"\"\n}\n\nexport function resolveCollapsedContent({\n dataKeyAttribute,\n dataRawAttribute,\n dataKey,\n dataRaw,\n node,\n children,\n}: {\n dataKeyAttribute?: string\n dataRawAttribute?: string\n dataKey?: string\n dataRaw?: string\n node?: ExtraProps[\"node\"]\n children?: unknown\n}): string {\n const nodeProperties =\n node && typeof node === \"object\" && \"properties\" in node\n ? (node.properties as Record<string, unknown>)\n : undefined\n const key =\n dataKeyAttribute ??\n dataKey ??\n stringValue(nodeProperties?.[\"data-key\"]) ??\n stringValue(nodeProperties?.dataKey) ??\n extractText(children).trim()\n const cached = key ? malformedToolCallContent.get(key) : undefined\n if (cached) return cached\n\n const raw =\n dataRawAttribute ??\n dataRaw ??\n stringValue(nodeProperties?.[\"data-raw\"]) ??\n stringValue(nodeProperties?.dataRaw) ??\n \"\"\n return decodeCollapsedContent(raw) || extractText(children).trim()\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined\n}\n\nfunction CodeBlockPre({ children, node: _node, ...props }: PreProps) {\n const preRef = useRef<HTMLPreElement>(null)\n const [copied, setCopied] = useState(false)\n const [hasCodeNode, setHasCodeNode] = useState(false)\n const [language, setLanguage] = useState(\"\")\n\n useEffect(() => {\n const codeEl = preRef.current?.querySelector(\"code\")\n setHasCodeNode(!!codeEl)\n setLanguage(codeEl?.className.match(/language-(\\S+)/)?.[1] ?? \"\")\n }, [])\n\n const getRawCode = () => preRef.current?.querySelector(\"code\")?.textContent ?? \"\"\n\n const handleCopy = async () => {\n const ok = await copyToClipboard(getRawCode())\n if (ok) {\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n }\n }\n\n const handleDownload = () => {\n const codeEl = preRef.current?.querySelector(\"code\")\n const text = codeEl?.textContent ?? \"\"\n const ext = codeEl?.className.match(/language-(\\S+)/)?.[1] ?? \"txt\"\n const blob = new Blob([text], { type: \"text/plain\" })\n const url = URL.createObjectURL(blob)\n const a = document.createElement(\"a\")\n a.href = url\n a.download = `code.${ext}`\n a.click()\n URL.revokeObjectURL(url)\n }\n\n // 无 code 子节点(如 mermaid 等特殊 pre)时保持原样,不套代码块外壳。\n if (!hasCodeNode) {\n return (\n <div className=\"relative\">\n <pre ref={preRef} {...props}>\n {children}\n </pre>\n </div>\n )\n }\n\n // 原型样式:常驻头部栏(语言标签 + 复制/下载),代码区浅底。\n return (\n <div className=\"not-prose my-3 overflow-hidden rounded-xl border border-[hsl(var(--border))]\">\n <div className=\"flex h-[34px] items-center justify-between border-b border-[hsl(var(--border))] bg-[hsl(var(--muted))/0.5] pl-3.5 pr-1.5\">\n <span className=\"font-mono text-[12px] text-[hsl(var(--muted-foreground))]\">\n {language || \"code\"}\n </span>\n <div className=\"flex items-center gap-0.5\">\n <button\n type=\"button\"\n onClick={handleCopy}\n className={cn(\n \"flex h-6 items-center gap-1 rounded-md px-1.5 text-[11px] transition-colors\",\n copied\n ? \"text-[hsl(var(--primary))]\"\n : \"text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]\",\n )}\n >\n {copied ? <Check size={12} /> : <Copy size={12} />}\n <span>{copied ? \"已复制\" : \"复制\"}</span>\n </button>\n <button\n type=\"button\"\n onClick={handleDownload}\n className=\"flex h-6 items-center gap-1 rounded-md px-1.5 text-[11px] text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]\"\n >\n <Download size={12} />\n <span>下载</span>\n </button>\n </div>\n </div>\n <pre\n ref={preRef}\n {...props}\n className={cn(\n props.className,\n // 原型:13.5px/1.7 等宽、浅底;覆盖 prose 的继承字号与主题里手写的 pre 样式。\n \"m-0! overflow-x-auto! rounded-none! border-0! bg-[hsl(var(--muted))/0.25]! px-4! py-3.5! font-mono text-[13.5px]! leading-[1.7]! [&_code]:bg-transparent! [&_code]:p-0! [&_code]:font-mono [&_code]:text-[13.5px]! [&_code]:text-[hsl(var(--foreground))]\",\n )}\n >\n {children}\n </pre>\n </div>\n )\n}\n\nfunction isExternalImageSrc(src: string): boolean {\n if (!src) return false\n if (src.startsWith(\"data:\") || src.startsWith(\"blob:\")) return true\n if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(src)) return true\n if (src.startsWith(\"/\")) return true\n return false\n}\n\nfunction decodeMarkdownPath(src: string): string {\n try {\n return decodeURIComponent(src)\n } catch {\n return src\n }\n}\n\nconst MARKDOWN_IMAGE_PATTERN =\n /!\\[((?:\\\\.|[^\\]\\\\])*)\\]\\(\\s*(?:<([^>\\n]+)>|([^\\s)]+))(\\s+(?:\"[^\"]*\"|'[^']*'|\\([^)]*\\)))?\\s*\\)/g\nconst MEDIA_LINE_RE = /^[ \\t]*[`\"']?MEDIA:[ \\t]*(\\S+?)[`\"']?[ \\t]*$/gm\n\nfunction resolveSessionImageMarkdown(children: string, sessionId: string): string {\n return children.replace(\n MARKDOWN_IMAGE_PATTERN,\n (match, alt: string, angleSrc: string | undefined, plainSrc: string | undefined, title = \"\") => {\n const src = angleSrc ?? plainSrc\n if (!src || isExternalImageSrc(src)) {\n return match\n }\n\n const resolved = getAuthedUrl(\n `/api/sessions/${encodeURIComponent(sessionId)}/files/${encodeURIComponent(decodeMarkdownPath(src))}`,\n )\n return `![${alt}](<${resolved}>${title})`\n },\n )\n}\n\nfunction stripWorkspacePrefix(path: string, sessionId: string): string | null {\n const sessionRoot = `/root/${AGENT_WORKSPACE_DIR_NAME}/${sessionId}`\n if (path === sessionRoot || path === `${sessionRoot}/`) {\n return null\n }\n let relPath: string\n if (path.startsWith(`${sessionRoot}/`)) {\n relPath = path.slice(sessionRoot.length + 1)\n } else if (!path.startsWith(\"/\")) {\n relPath = path.replace(/^\\.\\//, \"\")\n } else {\n return null\n }\n if (!relPath || relPath.startsWith(\"../\") || relPath.includes(\"/../\")) {\n return null\n }\n return relPath\n}\n\nfunction basename(path: string): string {\n return path.split(\"/\").filter(Boolean).pop() || path\n}\n\nfunction escapeAttribute(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n}\n\nexport function collapseMediaTags(children: string, sessionId: string): string {\n return children.replace(MEDIA_LINE_RE, (match, absPath: string) => {\n const relPath = stripWorkspacePrefix(absPath, sessionId)\n if (!relPath) {\n return match\n }\n const name = basename(relPath)\n return `<${FILE_CARD_TAG} data-rel-path=\"${encodeURIComponent(relPath)}\" data-name=\"${escapeAttribute(name)}\">${escapeAttribute(name)}</${FILE_CARD_TAG}>`\n })\n}\n\nexport function collapseInlineToolCalls(children: string): string {\n return children.replace(\n TOOL_CALL_BLOCK_RE,\n (match) => {\n const key = malformedToolCallKey(match)\n malformedToolCallContent.set(key, match)\n return `<${TOOL_CALL_TAG} data-key=\"${key}\">${key}</${TOOL_CALL_TAG}>`\n },\n )\n}\n\nfunction malformedToolCallKey(value: string): string {\n let hash = 0\n for (let index = 0; index < value.length; index += 1) {\n hash = (hash * 31 + value.charCodeAt(index)) | 0\n }\n return `malformed-tool-call-${Math.abs(hash).toString(36)}-${value.length.toString(36)}`\n}\n\nfunction decodeCollapsedContent(value: string | undefined): string {\n if (!value) return \"\"\n try {\n return decodeURIComponent(value)\n } catch {\n return value\n }\n}\n\ntype MarkdownContentProps = StreamdownProps & {\n /** 当提供时,markdown 中相对路径的 <img> src 会解析为 session 工作区文件 URL */\n sessionId?: string\n}\n\nexport function MarkdownContent({\n allowedTags,\n children,\n components,\n mode,\n plugins,\n sessionId,\n ...props\n}: MarkdownContentProps) {\n const resolvedChildren = useMemo(\n () => {\n if (typeof children !== \"string\") return children\n const withResolvedImages = sessionId ? resolveSessionImageMarkdown(children, sessionId) : children\n const withMediaCards = sessionId ? collapseMediaTags(withResolvedImages, sessionId) : withResolvedImages\n return collapseInlineToolCalls(withMediaCards)\n },\n [children, sessionId],\n )\n const resolvedAllowedTags = useMemo(\n () => ({\n ...(allowedTags ?? {}),\n ...CUSTOM_ALLOWED_TAGS,\n }),\n [allowedTags],\n )\n const resolvedComponents = useMemo(\n () => ({\n code: CardCodeBlock,\n pre: CodeBlockPre,\n ...(components ?? {}),\n ...HIDDEN_SYSTEM_REMINDER_COMPONENTS,\n [TOOL_CALL_TAG]: InlineToolCallBlock,\n [FILE_CARD_TAG]: FileCardComponent,\n }),\n [components],\n )\n const resolvedRehypePlugins = useMemo(\n () => buildRehypePlugins(resolvedAllowedTags),\n [resolvedAllowedTags],\n )\n const resolvedPlugins = useMemo(\n () => ({\n ...STREAMDOWN_PLUGINS,\n ...(plugins ?? {}),\n }),\n [plugins],\n )\n // 浏览器镜像是否可用(要求探测真的成功,不是\"非 404\"这种宽松判定):这个按钮\n // 点了就直接 POST /tabs,503(沙盒未创建/browserd 未启动)时那次请求一样会失败,\n // 跟 RightPanel 判断\"要不要显示标签\"不是同一个问题——RightPanel 的标签打开后\n // 自己有加载态可以等 browserd 起来,这个按钮是一次性动作,等不到就该先不出现。\n const { data: hasBrowserMirror = false } = useQuery({\n queryKey: [\"browser-mirror-ready\", sessionId],\n queryFn: async () => {\n const resp = await apiFetch<unknown>(`/api/sessions/${sessionId}/browser/health`, {\n method: \"GET\",\n }).then(\n () => true,\n () => false,\n )\n return resp\n },\n enabled: Boolean(sessionId),\n staleTime: 60_000,\n })\n\n // 有会话上下文且浏览器镜像可用时,外链弹窗多一个「在浏览器中打开」——开进本会话的沙盒浏览器\n const linkSafety = useMemo<NonNullable<StreamdownProps[\"linkSafety\"]>>(\n () =>\n sessionId && hasBrowserMirror\n ? {\n enabled: true,\n renderModal: (modalProps) => (\n <ExternalLinkDialog\n {...modalProps}\n onOpenInternal={() => openInSandboxBrowser(sessionId, modalProps.url)}\n />\n ),\n }\n : LINK_SAFETY_CONFIG,\n [sessionId, hasBrowserMirror],\n )\n\n return (\n <Streamdown\n {...props}\n className={cn(\"break-words [&_button[data-streamdown=link]]:max-w-full\", props.className)}\n linkSafety={linkSafety}\n mode={mode ?? \"static\"}\n rehypePlugins={resolvedRehypePlugins}\n allowedTags={resolvedAllowedTags}\n components={resolvedComponents}\n plugins={resolvedPlugins}\n >\n {resolvedChildren}\n </Streamdown>\n )\n}\n","import { Check, Copy, ExternalLink, Monitor, X } from \"lucide-react\"\nimport { useEffect, useState } from \"react\"\nimport { createPortal } from \"react-dom\"\nimport { copyToClipboard } from \"../../lib/utils\"\n\ninterface Props {\n isOpen: boolean\n onClose: () => void\n onConfirm: () => void\n url: string\n /** 在会话的沙盒浏览器(「浏览器」面板)中打开链接;不传则不显示该按钮 */\n onOpenInternal?: () => void | Promise<void>\n}\n\nexport function ExternalLinkDialog({ isOpen, onClose, onConfirm, url, onOpenInternal }: Props) {\n const [copied, setCopied] = useState(false)\n\n useEffect(() => {\n if (!isOpen) return\n const handleKey = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") onClose()\n }\n window.addEventListener(\"keydown\", handleKey)\n return () => window.removeEventListener(\"keydown\", handleKey)\n }, [isOpen, onClose])\n\n useEffect(() => {\n if (!isOpen) setCopied(false)\n }, [isOpen])\n\n if (!isOpen) return null\n\n const handleCopy = async () => {\n const ok = await copyToClipboard(url)\n if (ok) {\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n }\n }\n\n return createPortal(\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4\"\n onClick={onClose}\n onKeyDown={(event) => {\n if (event.key === \"Escape\") onClose()\n }}\n // biome-ignore lint/a11y/useSemanticElements: 外层 div 作为可点击关闭的 backdrop\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"external-link-dialog-title\"\n >\n <div\n className=\"w-full max-w-md overflow-hidden rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--background))] shadow-2xl\"\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => event.stopPropagation()}\n >\n <div className=\"flex items-start justify-between gap-3 px-5 pt-5\">\n <div className=\"flex items-center gap-2\">\n <ExternalLink size={20} className=\"text-[hsl(var(--foreground))]\" />\n <h3\n id=\"external-link-dialog-title\"\n className=\"text-lg font-semibold text-[hsl(var(--foreground))]\"\n >\n 打开外部链接?\n </h3>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n title=\"关闭\"\n className=\"flex h-7 w-7 items-center justify-center rounded-md text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]\"\n >\n <X size={14} />\n </button>\n </div>\n <div className=\"px-5 pt-2 pb-4\">\n <p className=\"text-sm text-[hsl(var(--muted-foreground))]\">即将访问外部网站:</p>\n <div className=\"mt-3 break-all rounded-md bg-[hsl(var(--muted))] p-3 font-mono text-sm text-[hsl(var(--foreground))]\">\n {url}\n </div>\n </div>\n <div className=\"flex justify-end gap-2 px-5 pb-5\">\n <button\n type=\"button\"\n onClick={handleCopy}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--background))] px-3 py-1.5 text-sm font-medium text-[hsl(var(--foreground))] transition-colors hover:bg-[hsl(var(--accent))]\"\n >\n {copied ? <Check size={14} /> : <Copy size={14} />}\n <span>{copied ? \"已复制\" : \"复制链接\"}</span>\n </button>\n {onOpenInternal && (\n <button\n type=\"button\"\n onClick={() => {\n void onOpenInternal()\n onClose()\n }}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--background))] px-3 py-1.5 text-sm font-medium text-[hsl(var(--foreground))] transition-colors hover:bg-[hsl(var(--accent))]\"\n >\n <Monitor size={14} />\n <span>在浏览器中打开</span>\n </button>\n )}\n <button\n type=\"button\"\n onClick={() => {\n onConfirm()\n onClose()\n }}\n className=\"inline-flex items-center gap-1.5 rounded-md bg-[hsl(var(--primary))] px-3 py-1.5 text-sm font-semibold text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90\"\n >\n <ExternalLink size={14} />\n <span>打开链接</span>\n </button>\n </div>\n </div>\n </div>,\n document.body,\n )\n}\n","import {\n Archive,\n Download,\n File,\n FileCode2,\n FileSpreadsheet,\n FileText,\n Film,\n Image,\n Loader2,\n Music,\n} from \"lucide-react\"\nimport { type ComponentPropsWithRef, useState } from \"react\"\nimport type { ExtraProps } from \"streamdown\"\nimport { getAuthedUrl } from \"../../api/client\"\nimport { getSessionFilePath, resolveSessionFilePreviewTarget } from \"../../lib/session-file-preview\"\nimport { cn } from \"../../lib/utils\"\nimport { useUiStore } from \"../../stores/ui-store\"\nimport { useCardContext } from \"../card/CardContext\"\n\ntype FileCardProps = ComponentPropsWithRef<\"span\"> &\n ExtraProps & {\n \"data-rel-path\"?: string\n \"data-name\"?: string\n dataRelPath?: string\n dataName?: string\n }\n\nconst IMAGE_EXTS = new Set([\"png\", \"jpg\", \"jpeg\", \"gif\", \"svg\", \"webp\", \"ico\", \"bmp\"])\nconst SHEET_EXTS = new Set([\"xlsx\", \"xls\", \"xlsm\", \"xlsb\", \"csv\"])\nconst TEXT_EXTS = new Set([\"txt\", \"md\", \"markdown\", \"pdf\", \"doc\", \"docx\", \"rtf\"])\nconst CODE_EXTS = new Set([\"js\", \"jsx\", \"ts\", \"tsx\", \"py\", \"go\", \"json\", \"yaml\", \"yml\", \"html\", \"css\"])\nconst VIDEO_EXTS = new Set([\"mp4\", \"webm\", \"mov\", \"mkv\", \"avi\"])\nconst AUDIO_EXTS = new Set([\"mp3\", \"wav\", \"ogg\", \"m4a\", \"flac\"])\nconst ARCHIVE_EXTS = new Set([\"zip\", \"tar\", \"gz\", \"tgz\", \"rar\", \"7z\"])\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined\n}\n\nfunction decodeAttribute(value: string | undefined): string {\n if (!value) return \"\"\n try {\n return decodeURIComponent(value)\n } catch {\n return value\n }\n}\n\nfunction isSafeRelPath(p: string): boolean {\n if (!p || p.startsWith(\"/\")) return false\n const segments = p.split(\"/\")\n return segments.every((s) => s !== \"..\" && s !== \".\")\n}\n\nfunction basename(path: string): string {\n return path.split(\"/\").filter(Boolean).pop() || path\n}\n\nfunction getExt(name: string): string {\n return name.split(\".\").pop()?.toLowerCase() ?? \"\"\n}\n\nfunction getFileIcon(name: string) {\n const ext = getExt(name)\n if (IMAGE_EXTS.has(ext)) return Image\n if (SHEET_EXTS.has(ext)) return FileSpreadsheet\n if (TEXT_EXTS.has(ext)) return FileText\n if (CODE_EXTS.has(ext)) return FileCode2\n if (VIDEO_EXTS.has(ext)) return Film\n if (AUDIO_EXTS.has(ext)) return Music\n if (ARCHIVE_EXTS.has(ext)) return Archive\n return File\n}\n\nfunction extractChildrenText(children: unknown): string {\n if (typeof children === \"string\") return children\n if (Array.isArray(children)) return children.map(extractChildrenText).join(\"\")\n if (children && typeof children === \"object\" && \"props\" in children) {\n return extractChildrenText((children as { props?: { children?: unknown } }).props?.children)\n }\n return \"\"\n}\n\nexport function FileCardComponent({\n node,\n \"data-rel-path\": dataRelPathAttribute,\n \"data-name\": dataNameAttribute,\n dataRelPath,\n dataName,\n children,\n className,\n ...props\n}: FileCardProps) {\n const nodeProperties =\n node && typeof node === \"object\" && \"properties\" in node\n ? (node.properties as Record<string, unknown>)\n : undefined\n const childrenText = extractChildrenText(children)\n const relPath = decodeAttribute(\n dataRelPathAttribute ??\n dataRelPath ??\n stringValue(nodeProperties?.[\"data-rel-path\"]) ??\n stringValue(nodeProperties?.dataRelPath),\n ) || decodeAttribute(childrenText || undefined)\n const name =\n decodeAttribute(\n dataNameAttribute ??\n dataName ??\n stringValue(nodeProperties?.[\"data-name\"]) ??\n stringValue(nodeProperties?.dataName),\n ) || basename(relPath)\n const { sessionId } = useCardContext()\n const [opening, setOpening] = useState(false)\n const Icon = getFileIcon(name)\n const disabled = !sessionId || !relPath || !isSafeRelPath(relPath)\n\n const handleOpen = async () => {\n if (disabled || opening) return\n setOpening(true)\n try {\n const target = await resolveSessionFilePreviewTarget(sessionId, relPath, name)\n const uiStore = useUiStore.getState()\n uiStore.pushArtifact(target)\n uiStore.setActiveRightTab(\"preview\")\n } finally {\n setOpening(false)\n }\n }\n\n const handleDownload = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.stopPropagation()\n if (disabled) return\n const a = document.createElement(\"a\")\n a.href = getAuthedUrl(getSessionFilePath(sessionId, relPath))\n a.download = name\n a.click()\n }\n\n return (\n <span\n {...props}\n className={cn(\"not-prose my-2 flex max-w-full items-stretch\", className)}\n >\n <button\n type=\"button\"\n onClick={handleOpen}\n disabled={disabled || opening}\n className=\"flex min-w-0 flex-1 items-center gap-3 rounded-l-lg border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-2.5 text-left text-[hsl(var(--card-foreground))] shadow-sm transition-colors hover:border-[hsl(var(--primary))]/45 hover:bg-[hsl(var(--accent))]/45 focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none disabled:cursor-not-allowed disabled:opacity-60\"\n aria-label={`打开文件:${name}`}\n >\n <span className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-md bg-[hsl(var(--muted))] text-[hsl(var(--primary))]\">\n {opening ? <Loader2 size={18} className=\"animate-spin\" /> : <Icon size={18} />}\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium leading-5\">{name}</span>\n <span className=\"block truncate text-xs leading-4 text-[hsl(var(--muted-foreground))]\">\n 点击预览文件\n </span>\n </span>\n </button>\n <button\n type=\"button\"\n onClick={handleDownload}\n disabled={disabled}\n className=\"flex w-11 shrink-0 items-center justify-center rounded-r-lg border border-l-0 border-[hsl(var(--border))] bg-[hsl(var(--card))] text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))] focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none disabled:cursor-not-allowed disabled:opacity-60\"\n aria-label={`下载文件:${name}`}\n title=\"下载\"\n >\n <Download size={16} />\n </button>\n </span>\n )\n}\n","import { Check, Loader2, MessageSquareMore } from \"lucide-react\"\nimport { useEffect, useMemo, useState } from \"react\"\nimport { cn } from \"../../lib/utils\"\nimport { MarkdownContent } from \"../markdown/MarkdownContent\"\n\ninterface OptionItem {\n label: string\n description: string\n}\n\ninterface QuestionItem {\n question: string\n options: OptionItem[]\n multiSelect?: boolean\n}\n\ninterface SourceLoopInfo {\n loop_name: string\n description: string\n}\n\nexport interface AskUserQuestionData {\n questions: QuestionItem[]\n source_loop?: SourceLoopInfo | null\n}\n\nexport type AskUserAnswerData = {\n selections: Record<number, number[]>\n custom: Record<number, string>\n}\n\ninterface Props {\n data: AskUserQuestionData\n answered: boolean\n toolCallId: string\n sessionStatus: string\n answerData?: AskUserAnswerData | undefined\n onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void\n}\n\nexport function AskUserQuestionBlock({\n data,\n answered,\n toolCallId,\n sessionStatus,\n answerData,\n onAnswer,\n}: Props) {\n // Per-question state: selected option indices or custom text\n const [selections, setSelections] = useState<Map<number, Set<number>>>(new Map())\n const [customTexts, setCustomTexts] = useState<Map<number, string>>(new Map())\n const [usingCustom, setUsingCustom] = useState<Set<number>>(new Set())\n const [submitted, setSubmitted] = useState(false)\n\n useEffect(() => {\n if (sessionStatus === \"failed\" || sessionStatus === \"interrupted\") {\n setSubmitted(false)\n }\n }, [sessionStatus])\n\n const displayAnswerState = useMemo(() => {\n if (!(answered && answerData)) {\n return {\n selections,\n customTexts,\n usingCustom,\n }\n }\n\n const nextSelections = new Map<number, Set<number>>()\n const nextCustomTexts = new Map<number, string>()\n const nextUsingCustom = new Set<number>()\n\n for (const [questionKey, optionIndexes] of Object.entries(answerData.selections)) {\n nextSelections.set(Number(questionKey), new Set(optionIndexes))\n }\n\n for (const [questionKey, text] of Object.entries(answerData.custom)) {\n const qIdx = Number(questionKey)\n nextCustomTexts.set(qIdx, text)\n nextUsingCustom.add(qIdx)\n }\n\n return {\n selections: nextSelections,\n customTexts: nextCustomTexts,\n usingCustom: nextUsingCustom,\n }\n }, [answerData, answered, customTexts, selections, usingCustom])\n\n const displaySelections = displayAnswerState.selections\n const displayCustomTexts = displayAnswerState.customTexts\n const displayUsingCustom = displayAnswerState.usingCustom\n\n const toggleOption = (qIdx: number, optIdx: number, multi: boolean) => {\n if (answered || submitted) return\n setSelections((prev) => {\n const next = new Map(prev)\n const current = new Set(next.get(qIdx) ?? [])\n if (multi) {\n if (current.has(optIdx)) current.delete(optIdx)\n else current.add(optIdx)\n } else {\n current.clear()\n current.add(optIdx)\n }\n next.set(qIdx, current)\n return next\n })\n // Clear custom for this question\n setUsingCustom((prev) => {\n const next = new Set(prev)\n next.delete(qIdx)\n return next\n })\n }\n\n const handleCustomFocus = (qIdx: number) => {\n if (answered || submitted) return\n setSelections((prev) => {\n const next = new Map(prev)\n next.delete(qIdx)\n return next\n })\n setUsingCustom((prev) => new Set(prev).add(qIdx))\n }\n\n const setCustomText = (qIdx: number, text: string) => {\n if (answered || submitted) return\n setCustomTexts((prev) => new Map(prev).set(qIdx, text))\n }\n\n const getAnswer = (qIdx: number): string | null => {\n const q = data.questions[qIdx]\n if (usingCustom.has(qIdx)) {\n const text = (customTexts.get(qIdx) ?? \"\").trim()\n return text || null\n }\n const sel = selections.get(qIdx)\n if (!sel || sel.size === 0) return null\n return [...sel]\n .sort()\n .map((i) => q.options[i].label)\n .join(\", \")\n }\n\n const allAnswered = data.questions.every((_, i) => getAnswer(i) !== null)\n\n const handleSubmit = () => {\n if (answered || submitted || !allAnswered || !onAnswer) return\n\n const nextAnswerData: AskUserAnswerData = {\n selections: Object.fromEntries(\n Array.from(selections.entries()).map(([qIdx, optionIndexes]) => [\n qIdx,\n Array.from(optionIndexes).sort((a, b) => a - b),\n ]),\n ) as Record<number, number[]>,\n custom: Object.fromEntries(\n Array.from(usingCustom)\n .map((qIdx) => [qIdx, (customTexts.get(qIdx) ?? \"\").trim()] as const)\n .filter(([, text]) => text.length > 0),\n ) as Record<number, string>,\n }\n\n const parts = data.questions.map((q, i) => `- ${q.question} -> ${getAnswer(i)}`)\n const text = `关于需要确认的问题,用户的回答如下:\\n${parts.join(\"\\n\")}`\n setSubmitted(true)\n onAnswer(text, toolCallId, nextAnswerData)\n }\n\n return (\n <div\n className={cn(\n \"ml-4 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))]\",\n answered\n ? \"max-w-2xl space-y-3 p-3 text-xs text-[hsl(var(--muted-foreground))] opacity-80\"\n : \"max-w-lg space-y-5 p-4 text-sm\",\n )}\n >\n {data.source_loop?.description && (\n <div className=\"rounded-lg bg-[hsl(var(--muted)/0.35)] px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]\">\n 子智能体「{data.source_loop.description}」在等待你的回答\n </div>\n )}\n {data.questions.map((q, qIdx) => (\n <QuestionCard\n key={q.question}\n question={q}\n qIdx={qIdx}\n answered={answered}\n selected={displaySelections.get(qIdx) ?? new Set()}\n isCustom={displayUsingCustom.has(qIdx)}\n customText={displayCustomTexts.get(qIdx) ?? \"\"}\n onToggle={toggleOption}\n onCustomFocus={handleCustomFocus}\n onCustomChange={setCustomText}\n />\n ))}\n\n {!answered && !submitted && onAnswer && (\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={!allAnswered}\n className=\"w-full rounded-lg bg-[hsl(var(--primary))] px-4 py-2 text-xs font-semibold text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-60\"\n >\n {allAnswered ? \"确认\" : \"请先选择一个选项\"}\n </button>\n )}\n\n {submitted && !answered && (\n <button\n type=\"button\"\n disabled\n className=\"flex w-full items-center justify-center gap-2 rounded-lg bg-[hsl(var(--primary))] px-4 py-2 text-xs font-semibold text-[hsl(var(--primary-foreground))] opacity-80\"\n >\n <Loader2 size={14} className=\"animate-spin\" />\n 确认中\n </button>\n )}\n </div>\n )\n}\n\nfunction QuestionCard({\n question,\n qIdx,\n answered,\n selected,\n isCustom,\n customText,\n onToggle,\n onCustomFocus,\n onCustomChange,\n}: {\n question: QuestionItem\n qIdx: number\n answered: boolean\n selected: Set<number>\n isCustom: boolean\n customText: string\n onToggle: (qIdx: number, optIdx: number, multi: boolean) => void\n onCustomFocus: (qIdx: number) => void\n onCustomChange: (qIdx: number, text: string) => void\n}) {\n const multi = question.multiSelect ?? false\n\n return (\n <div>\n <div className={cn(\"flex items-start gap-2\", answered ? \"mb-2\" : \"mb-3\")}>\n <MessageSquareMore\n size={answered ? 12 : 13}\n className=\"mt-0.5 shrink-0 text-[hsl(var(--primary))]\"\n />\n <div\n className={cn(\n \"min-w-0 flex-1 font-medium text-[hsl(var(--foreground))]\",\n answered ? \"text-xs\" : \"text-sm\",\n )}\n >\n <MarkdownContent\n className={cn(\n \"prose prose-sm prose-invert max-w-none [&_li>p]:inline [&_ol]:my-1 [&_p]:my-1 [&_p:first-child]:mt-0 [&_p:last-child]:mb-0 [&_ul]:my-1\",\n answered ? \"text-xs\" : \"text-sm\",\n )}\n controls={{ code: true }}\n >\n {question.question}\n </MarkdownContent>\n </div>\n </div>\n\n <div className={cn(\"flex flex-col pl-5\", answered ? \"gap-1\" : \"gap-1.5\")}>\n {question.options.map((opt, optIdx) => {\n const isSel = selected.has(optIdx)\n return (\n <button\n key={opt.label}\n type=\"button\"\n disabled={answered}\n onClick={() => onToggle(qIdx, optIdx, multi)}\n className={cn(\n \"flex items-start gap-2.5 rounded-lg border text-left transition-all\",\n answered ? \"px-2.5 py-1.5\" : \"px-3 py-2.5\",\n isSel && !answered\n ? \"border-[hsl(var(--primary)/0.8)] bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))]\"\n : isSel\n ? \"border-[hsl(var(--primary)/0.45)] bg-[hsl(var(--primary)/0.08)] text-[hsl(var(--foreground))]\"\n : \"border-[hsl(var(--border))] bg-[hsl(var(--muted)/0.2)]\",\n !answered && !isSel && \"hover:border-[hsl(var(--ring)/0.4)] hover:bg-[hsl(var(--accent))]\",\n answered && \"cursor-default opacity-70\",\n )}\n >\n {multi && (\n <div\n className={cn(\n \"mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors\",\n isSel && !answered\n ? \"border-[hsl(var(--primary-foreground)/0.6)] bg-[hsl(var(--primary-foreground)/0.2)]\"\n : isSel\n ? \"border-[hsl(var(--primary)/0.45)] bg-[hsl(var(--primary)/0.12)]\"\n : \"border-[hsl(var(--border))]\",\n )}\n >\n {isSel && (\n <Check\n size={9}\n className={\n answered\n ? \"text-[hsl(var(--primary))]\"\n : \"text-[hsl(var(--primary-foreground))]\"\n }\n />\n )}\n </div>\n )}\n <div className=\"min-w-0\">\n <div className={cn(\"font-medium\", answered ? \"text-xs\" : \"text-[13px]\")}>\n {opt.label}\n </div>\n {opt.description && (\n <div\n className={cn(\n \"mt-0.5\",\n answered ? \"text-[11px]\" : \"text-xs\",\n isSel && !answered ? \"opacity-75\" : \"text-[hsl(var(--muted-foreground))]\",\n )}\n >\n {opt.description}\n </div>\n )}\n </div>\n </button>\n )\n })}\n\n {/* \"Other\" inline input */}\n {answered && !isCustom ? null : (\n <div\n className={cn(\n \"flex items-center gap-2 rounded-lg border transition-all\",\n answered ? \"px-2.5 py-1.5\" : \"px-3 py-2.5\",\n isCustom\n ? \"border-[hsl(var(--ring)/0.6)] bg-[hsl(var(--accent))]\"\n : \"border-[hsl(var(--border))] hover:border-[hsl(var(--ring)/0.3)] hover:bg-[hsl(var(--accent))]\",\n answered && \"cursor-default opacity-70\",\n )}\n >\n <span className=\"shrink-0 text-xs text-[hsl(var(--muted-foreground))]\">其他:</span>\n <input\n type=\"text\"\n value={customText}\n disabled={answered}\n onChange={(e) => onCustomChange(qIdx, e.target.value)}\n onFocus={() => onCustomFocus(qIdx)}\n aria-label=\"自定义回答\"\n placeholder=\"输入你的答案...\"\n className={cn(\n \"min-w-0 flex-1 bg-transparent text-[hsl(var(--foreground))] outline-none placeholder:text-[hsl(var(--muted-foreground)/0.5)]\",\n answered ? \"text-xs\" : \"text-sm\",\n )}\n />\n </div>\n )}\n </div>\n </div>\n )\n}\n\nexport function parseAskUserQuestion(\n toolResult: string | null | undefined,\n): AskUserQuestionData | null {\n if (!toolResult) return null\n try {\n const parsed = JSON.parse(toolResult)\n let questions = parsed?.questions\n // 容错:LLM 偶尔将 questions 输出为 JSON 字符串而非数组\n if (typeof questions === \"string\") {\n try {\n questions = JSON.parse(questions)\n } catch {\n return null\n }\n }\n if (Array.isArray(questions) && questions.length > 0) {\n const normalized = questions.map(normalizeQuestionItem)\n if (normalized.every((question): question is QuestionItem => question !== null)) {\n return { ...parsed, questions: normalized } as AskUserQuestionData\n }\n }\n } catch {\n // not JSON\n }\n return null\n}\n\nfunction normalizeQuestionItem(value: unknown): QuestionItem | null {\n if (!value || typeof value !== \"object\") return null\n const item = value as {\n question?: unknown\n options?: unknown\n multiSelect?: unknown\n multi_select?: unknown\n }\n if (typeof item.question !== \"string\" || !Array.isArray(item.options)) return null\n const options = item.options.map(normalizeOptionItem)\n if (!options.every((option): option is OptionItem => option !== null)) return null\n return {\n question: item.question,\n options,\n multiSelect: item.multiSelect === true || item.multi_select === true,\n }\n}\n\nfunction normalizeOptionItem(value: unknown): OptionItem | null {\n if (typeof value === \"string\") return { label: value, description: \"\" }\n if (!value || typeof value !== \"object\") return null\n const option = value as { label?: unknown; description?: unknown }\n if (typeof option.label !== \"string\") return null\n return {\n label: option.label,\n description: typeof option.description === \"string\" ? option.description : \"\",\n }\n}\n","import { load } from \"js-yaml\"\nimport type { PlanNode } from \"./types\"\n\ninterface PlanStep {\n label: string\n skill?: string\n id?: string\n status?: string\n children?: PlanStep[]\n}\n\ninterface PlanDocument {\n title: string\n objective: string\n steps: PlanStep[]\n notes?: string[]\n}\n\ninterface ParsedPlanResult {\n plan: { root: PlanNode; notes: string[] } | null\n error: string | null\n}\n\nexport type PlanStatusMap = Record<string, PlanNode[\"status\"]>\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === \"string\" && value.trim().length > 0\n}\n\nfunction isPlanStep(value: unknown): value is PlanStep {\n if (!value || typeof value !== \"object\") return false\n const step = value as Record<string, unknown>\n if (!isNonEmptyString(step.label)) return false\n if (\"skill\" in step && step.skill !== undefined && !isNonEmptyString(step.skill)) return false\n if (\"children\" in step && !Array.isArray(step.children)) return false\n\n const children = Array.isArray(step.children) ? step.children : []\n if (children.length > 0 && !isNonEmptyString(step.skill)) return false\n return children.every((child) => isPlanStep(child))\n}\n\nfunction isPlanDocument(value: unknown): value is PlanDocument {\n if (!value || typeof value !== \"object\") return false\n const doc = value as Record<string, unknown>\n if (!isNonEmptyString(doc.title) || !isNonEmptyString(doc.objective)) return false\n if (!Array.isArray(doc.steps) || doc.steps.length === 0) return false\n if (!doc.steps.every((step) => isPlanStep(step))) return false\n if (\"notes\" in doc) {\n if (!Array.isArray(doc.notes)) return false\n if (!doc.notes.every((note) => isNonEmptyString(note))) return false\n }\n return true\n}\n\nfunction getPlanDocumentError(value: unknown): string {\n if (!value || typeof value !== \"object\") return \"PLAN.yaml 顶层结构必须是对象\"\n\n const doc = value as Record<string, unknown>\n if (!isNonEmptyString(doc.title)) return \"PLAN.yaml 缺少非空 title\"\n if (!isNonEmptyString(doc.objective)) return \"PLAN.yaml 缺少非空 objective\"\n if (!Array.isArray(doc.steps) || doc.steps.length === 0) return \"PLAN.yaml 缺少非空 steps\"\n if (!doc.steps.every((step) => isPlanStep(step))) {\n return \"PLAN.yaml 步骤结构无效,请检查 label / skill / children\"\n }\n if (\"notes\" in doc) {\n if (!Array.isArray(doc.notes) || !doc.notes.every((note) => isNonEmptyString(note))) {\n return \"PLAN.yaml notes 必须是非空字符串列表\"\n }\n }\n return \"PLAN.yaml 结构无效\"\n}\n\nfunction toPlanStatus(value: unknown): PlanNode[\"status\"] {\n if (!isNonEmptyString(value)) return \"pending\"\n const normalized = value.trim().toLowerCase()\n return normalized === \"pending\" || normalized === \"running\" || normalized === \"done\" || normalized === \"failed\"\n ? normalized\n : \"pending\"\n}\n\nexport function parsePlanTree(content: string): { root: PlanNode; notes: string[] } | null {\n return parsePlanTreeResult(content).plan\n}\n\nexport function applyPlanStatusesById(root: PlanNode, statuses: PlanStatusMap): PlanNode {\n const nextStatus = statuses[root.id] ?? root.status\n const children = Array.isArray(root.children) ? root.children : []\n return {\n ...root,\n status: nextStatus,\n children: children.map((child) => applyPlanStatusesById(child, statuses)),\n }\n}\n\nexport function parsePlanTreeResult(content: string): ParsedPlanResult {\n if (!content.trim()) {\n return { plan: null, error: null }\n }\n\n let parsed: unknown\n try {\n parsed = load(content)\n } catch (error) {\n return {\n plan: null,\n error: error instanceof Error ? `PLAN.yaml YAML 语法错误:${error.message}` : \"PLAN.yaml YAML 语法错误\",\n }\n }\n\n if (!isPlanDocument(parsed)) {\n return { plan: null, error: getPlanDocumentError(parsed) }\n }\n\n const createNode = (step: PlanStep, depth: number, fallbackId: string): PlanNode => {\n const children = Array.isArray(step.children) ? step.children : []\n return {\n id: isNonEmptyString(step.id) ? step.id.trim() : fallbackId,\n label: step.label.trim(),\n skillRef: isNonEmptyString(step.skill) ? step.skill.trim() : null,\n status: toPlanStatus(step.status),\n children: children.map((child, index) => createNode(child, depth + 1, `${fallbackId}.${index + 1}`)),\n depth,\n }\n }\n\n const root: PlanNode = {\n id: \"plan-root\",\n label: parsed.title.trim(),\n skillRef: null,\n status: \"pending\",\n children: parsed.steps.map((step, index) => createNode(step, 1, `${index + 1}`)),\n depth: 0,\n }\n\n const notes = [parsed.objective.trim(), ...(parsed.notes ?? []).map((note) => note.trim())]\n\n return { plan: { root, notes }, error: null }\n}\n","import type { ChatMessage } from \"../../schemas/message\"\nimport { parseAskUserQuestion } from \"../chat/AskUserQuestionBlock\"\nimport { formatToolName } from \"../chat/display-utils\"\nimport { applyPlanStatusesById, parsePlanTreeResult, type PlanStatusMap } from \"./parse-plan-tree\"\nimport type { PlanData, SkillInfo } from \"./types\"\n\nfunction resultAsString(result: unknown): string | null {\n if (typeof result === \"string\") return result\n return null\n}\n\nconst PAUSE_TOOLS = new Set([\"AskUserQuestion\", \"ExitPlanMode\"])\nconst READ_FILE_TOOLS = new Set([\"Read\"])\nconst PLAN_WRITE_TOOLS = new Set([\"Write\"])\nconst PLAN_EDIT_TOOLS = new Set([\"Edit\"])\n\nfunction isPlanYamlPath(value: unknown): value is string {\n return typeof value === \"string\" && (value === \"PLAN.yaml\" || value.endsWith(\"/PLAN.yaml\"))\n}\n\nfunction getToolPath(args: Record<string, unknown>): unknown {\n return args.file_path ?? args.path\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n}\n\nfunction applyReplaceEdit(\n content: string,\n oldText: string,\n newText: string,\n replaceAll: boolean,\n): string | null {\n if (!oldText) {\n return null\n }\n if (content.includes(oldText)) {\n return replaceAll ? content.split(oldText).join(newText) : content.replace(oldText, newText)\n }\n\n const pattern = oldText\n .split(/(\\s+)/u)\n .filter((part) => part.length > 0)\n .map((part) => (/\\s+/u.test(part) ? \"\\\\s+\" : escapeRegExp(part)))\n .join(\"\")\n if (!pattern) {\n return null\n }\n const matches = [...content.matchAll(new RegExp(pattern, \"gu\"))]\n if (matches.length !== 1) {\n return null\n }\n const match = matches[0]\n const start = match.index\n const end = start + match[0].length\n return `${content.slice(0, start)}${newText}${content.slice(end)}`\n}\n\nfunction getSkillId(payload: { skill_id?: string; name?: string } | null | undefined): string {\n if (!payload) {\n return \"\"\n }\n if (typeof payload.skill_id === \"string\" && payload.skill_id) {\n return payload.skill_id\n }\n if (typeof payload.name === \"string\" && payload.name) {\n return payload.name\n }\n return \"\"\n}\n\nfunction getSkillDisplayName(\n payload: { display_name?: string; skill_id?: string; name?: string } | null | undefined,\n): string | undefined {\n if (!payload || typeof payload.display_name !== \"string\") {\n return undefined\n }\n const displayName = payload.display_name.trim()\n if (!displayName) {\n return undefined\n }\n const skillId = getSkillId(payload)\n return displayName === skillId ? undefined : displayName\n}\n\nfunction parseModeChange(message: ChatMessage): { from: string; to: string } | null {\n if (message.kind !== \"mode_change\" || typeof message.content !== \"string\") {\n return null\n }\n try {\n const parsed = JSON.parse(message.content) as { from?: unknown; to?: unknown }\n if (typeof parsed.from === \"string\" && typeof parsed.to === \"string\") {\n return { from: parsed.from, to: parsed.to }\n }\n } catch {}\n return null\n}\n\nfunction isPlanningBoundaryMessage(message: ChatMessage): boolean {\n const modeChange = parseModeChange(message)\n if (!modeChange) {\n return false\n }\n return modeChange.to === \"planning\" || modeChange.from === \"planning\"\n}\n\n/**\n * Extract structured plan data from planning phase messages.\n *\n * Expects messages between planning-mode mode_change markers containing:\n * - ReadSkill tool calls (技能调研:成功结果 = 选定技能,歧义 candidates = 候选列表)\n * - Write tool call to PLAN.yaml with plan YAML\n */\nexport function parsePlanMessages(allMessages: ChatMessage[]): PlanData {\n const messages = Array.isArray(allMessages) ? allMessages : []\n // Extract intent from the first ReadSkill query\n let intent = \"\"\n for (const msg of messages) {\n if (!msg.tool_calls) continue\n const readSkillTc = msg.tool_calls.find((tc) => tc.name === \"ReadSkill\")\n if (readSkillTc) {\n try {\n intent = JSON.parse(readSkillTc.arguments).skill ?? \"\"\n } catch {}\n if (intent) break\n }\n }\n\n const plannerMsgs = messages.filter(\n (message) => !isPlanningBoundaryMessage(message),\n )\n const searchResults: SkillInfo[] = []\n const searchMap = new Map<string, SkillInfo>()\n const selectedSkills: SkillInfo[] = []\n const selectedSet = new Set<string>()\n const askQuestions: PlanData[\"askQuestions\"] = []\n const readFiles: PlanData[\"readFiles\"] = []\n let lastPauseTool: PlanData[\"lastPauseTool\"] = null\n let planContent = \"\"\n let planContentPriority = 0\n let latestStatuses: PlanStatusMap = {}\n\n const setPlanContent = (nextContent: unknown, priority: number) => {\n if (typeof nextContent !== \"string\" || !nextContent.trim()) {\n return\n }\n if (priority < planContentPriority) {\n return\n }\n planContent = nextContent\n planContentPriority = priority\n }\n\n const applyPlanEdit = (args: Record<string, unknown>) => {\n if (Array.isArray(args.edits)) {\n for (const rawEdit of args.edits) {\n if (!rawEdit || typeof rawEdit !== \"object\" || Array.isArray(rawEdit)) {\n continue\n }\n const edit = rawEdit as Record<string, unknown>\n const oldText = typeof edit.old_text === \"string\" ? edit.old_text : \"\"\n const newText = typeof edit.new_text === \"string\" ? edit.new_text : \"\"\n if (!planContent) {\n continue\n }\n planContent = applyReplaceEdit(planContent, oldText, newText, edit.all === true) ?? planContent\n }\n return\n }\n\n const oldString = typeof args.old_string === \"string\" ? args.old_string : \"\"\n const newString = typeof args.new_string === \"string\" ? args.new_string : \"\"\n if (!planContent || !oldString || !planContent.includes(oldString)) {\n return\n }\n planContent = planContent.replace(oldString, newString)\n }\n\n const maybeParsePlanStatus = (msg: ChatMessage) => {\n if (msg.kind !== \"plan_status\") return\n if (typeof msg.content !== \"string\" || !msg.content.trim()) return\n try {\n const data = JSON.parse(msg.content) as { plan_yaml?: unknown; statuses?: unknown }\n setPlanContent(data.plan_yaml, 3)\n if (data.statuses && typeof data.statuses === \"object\" && !Array.isArray(data.statuses)) {\n latestStatuses = Object.fromEntries(\n Object.entries(data.statuses)\n .filter((entry): entry is [string, string] => typeof entry[0] === \"string\" && typeof entry[1] === \"string\")\n .map(([stepId, status]) => [stepId, normalizePlanStatus(status)]),\n )\n }\n } catch {}\n }\n\n for (const msg of plannerMsgs) {\n maybeParsePlanStatus(msg)\n if (!msg.tool_calls) continue\n for (const tc of msg.tool_calls) {\n if (formatToolName(tc.name) === \"ReadSkill\" && resultAsString(tc.result)) {\n try {\n const data = JSON.parse(resultAsString(tc.result)!) as {\n skill_id?: string\n name?: string\n display_name?: string\n description?: string\n content?: string\n candidates?: Array<{\n skill_id?: string\n name?: string\n display_name?: string\n description?: string\n }>\n }\n // 歧义结果:candidates 列表作为候选技能展示\n if (Array.isArray(data.candidates)) {\n for (const r of data.candidates) {\n const skillId = getSkillId(r)\n if (!skillId || searchMap.has(skillId)) continue\n const skill: SkillInfo = {\n skillId,\n displayName: getSkillDisplayName(r),\n description: r.description ?? \"\",\n }\n searchMap.set(skillId, skill)\n searchResults.push(skill)\n }\n continue\n }\n const skillId = getSkillId(data)\n if (!skillId || selectedSet.has(skillId)) continue\n let existing = searchMap.get(skillId)\n if (!existing) {\n existing = {\n skillId,\n displayName: getSkillDisplayName(data),\n description: data.description ?? \"\",\n }\n searchMap.set(skillId, existing)\n searchResults.push(existing)\n }\n existing.displayName ??= getSkillDisplayName(data)\n existing.content = data.content\n existing.references = extractRefs(data.content ?? \"\")\n selectedSkills.push(existing)\n selectedSet.add(skillId)\n } catch {}\n }\n if (tc.name === \"AskUserQuestion\" && resultAsString(tc.result)) {\n const data = parseAskUserQuestion(resultAsString(tc.result))\n if (data) {\n askQuestions.push({ toolCallId: tc.id, data })\n }\n }\n if (READ_FILE_TOOLS.has(tc.name) && tc.arguments) {\n try {\n const args = JSON.parse(tc.arguments) as Record<string, unknown>\n const path = getToolPath(args)\n if (typeof path === \"string\" && path) {\n readFiles.push({ path, status: tc.status ?? \"done\" })\n }\n } catch {}\n }\n if (\n PLAN_WRITE_TOOLS.has(tc.name) &&\n tc.arguments &&\n tc.status === \"done\" &&\n !(typeof tc.result === \"string\" && tc.result.startsWith(\"错误\"))\n ) {\n try {\n const args = JSON.parse(tc.arguments) as {\n file_path?: unknown\n path?: unknown\n content?: unknown\n }\n if (isPlanYamlPath(getToolPath(args as Record<string, unknown>)) && typeof args.content === \"string\") {\n setPlanContent(args.content, 1)\n }\n } catch {}\n }\n if (\n PLAN_EDIT_TOOLS.has(tc.name) &&\n tc.arguments &&\n tc.status === \"done\" &&\n !(typeof tc.result === \"string\" && tc.result.startsWith(\"错误\"))\n ) {\n try {\n const args = JSON.parse(tc.arguments) as {\n file_path?: unknown\n path?: unknown\n old_string?: unknown\n new_string?: unknown\n }\n if (isPlanYamlPath(args.path) || isPlanYamlPath(args.file_path)) {\n applyPlanEdit(args as Record<string, unknown>)\n }\n } catch {}\n }\n // Track the last pause-triggering tool across the whole phase.\n // Multi-round planning produces multiple pauses (e.g. AskUserQuestion\n // then ExitPlanMode); the UI needs the most recent one.\n if (PAUSE_TOOLS.has(tc.name) && tc.status === \"done\") {\n lastPauseTool = tc.name as PlanData[\"lastPauseTool\"]\n }\n if (tc.name === \"ExitPlanMode\" && resultAsString(tc.result)) {\n try {\n const data = JSON.parse(resultAsString(tc.result)!) as { plan?: unknown }\n setPlanContent(data.plan, 2)\n } catch {}\n }\n }\n }\n\n const { plan: parsedPlan, error: parseError } = parsePlanTreeResult(planContent)\n const plan =\n parsedPlan == null\n ? null\n : {\n ...parsedPlan,\n root: applyPlanStatusesById(parsedPlan.root, latestStatuses),\n }\n\n return {\n intent,\n searchResults,\n selectedSkills,\n plan,\n hasPlanContent: planContent.trim().length > 0,\n parseError,\n askQuestions,\n readFiles,\n lastPauseTool,\n }\n}\n\nfunction normalizePlanStatus(value: string): \"pending\" | \"running\" | \"done\" | \"failed\" {\n const normalized = value.trim().toLowerCase()\n return normalized === \"running\" || normalized === \"done\" || normalized === \"failed\"\n ? normalized\n : \"pending\"\n}\n\nfunction extractRefs(content: string): string[] {\n const seen = new Set<string>()\n const refs: string[] = []\n for (const m of content.matchAll(/\\[\\[([^\\]]+)\\]\\]/g)) {\n const ref = m[1].trim()\n if (ref && !seen.has(ref)) {\n seen.add(ref)\n refs.push(ref)\n }\n }\n return refs\n}\n","import { CheckCircle2, ChevronRight, PencilLine, Play, Sparkles } from \"lucide-react\"\nimport { useMemo, useState } from \"react\"\nimport { cn } from \"../../lib/utils\"\nimport type { ChatMessage } from \"../../schemas/message\"\nimport { useUiStore } from \"../../stores/ui-store\"\nimport { parsePlanMessages } from \"./parse-plan-messages\"\n\ninterface Props {\n messages: ChatMessage[]\n sessionStatus?: string\n onConfirmPlan?: (action: \"execute\" | \"revise\", text?: string) => void\n}\n\ntype SummaryState =\n | { kind: \"complete\"; label: string }\n | { kind: \"failed\"; label: string }\n | { kind: \"interrupted\"; label: string }\n | { kind: \"progress\"; label: string; dots: string }\n\nexport function PlanSummaryCard({\n messages,\n sessionStatus,\n onConfirmPlan,\n}: Props) {\n const data = useMemo(() => parsePlanMessages(messages), [messages])\n const rightPanelCollapsed = useUiStore((state) => state.rightPanelCollapsed)\n const toggleRightPanel = useUiStore((state) => state.toggleRightPanel)\n const setActiveRightTab = useUiStore((state) => state.setActiveRightTab)\n const summaryState = useMemo(() => getSummaryState(data, sessionStatus), [data, sessionStatus])\n const stepCount = useMemo(() => countPlanSteps(data.plan), [data.plan])\n const isWaitingForInput = sessionStatus === \"waiting_for_input\"\n const canConfirm =\n Boolean(onConfirmPlan) &&\n isWaitingForInput &&\n data.lastPauseTool === \"ExitPlanMode\"\n\n const openPlanPanel = () => {\n if (rightPanelCollapsed) {\n toggleRightPanel()\n }\n setActiveRightTab(\"situation\")\n }\n\n return (\n <div className=\"flex w-full flex-col gap-4 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card)/0.55)] p-4\">\n <button\n type=\"button\"\n onClick={openPlanPanel}\n className=\"flex w-full flex-col gap-4 text-left transition-colors hover:text-[hsl(var(--foreground))]\"\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0 space-y-2\">\n <div className=\"flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]\">\n <Sparkles size={12} />\n <span>规划摘要</span>\n </div>\n <div className=\"truncate text-base font-medium text-[hsl(var(--foreground))]\">\n {data.intent || \"当前规划\"}\n </div>\n <div className=\"flex flex-wrap items-center gap-2 text-xs\">\n {summaryState.kind === \"progress\" ? (\n <>\n <span className=\"rounded-full bg-[hsl(var(--accent))] px-2.5 py-1 text-[hsl(var(--foreground))]\">\n {summaryState.label}\n </span>\n <span className=\"font-mono tracking-[0.25em] text-[hsl(var(--muted-foreground))]\">\n {summaryState.dots}\n </span>\n </>\n ) : (\n <span\n className={cn(\n \"rounded-full px-2.5 py-1\",\n summaryState.kind === \"complete\" &&\n \"bg-[hsl(var(--primary)/0.12)] text-[hsl(var(--primary))]\",\n summaryState.kind === \"failed\" &&\n \"bg-[hsl(var(--destructive)/0.12)] text-[hsl(var(--destructive))]\",\n summaryState.kind === \"interrupted\" && \"bg-orange-500/12 text-orange-300\",\n )}\n >\n {summaryState.label}\n </span>\n )}\n </div>\n </div>\n <ChevronRight\n size={16}\n className=\"mt-1 shrink-0 text-[hsl(var(--muted-foreground))]\"\n aria-hidden=\"true\"\n />\n </div>\n\n {summaryState.kind === \"complete\" && (\n <div className=\"flex flex-wrap items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]\">\n <span className=\"rounded-full border border-[hsl(var(--border))] px-2.5 py-1\">\n {data.selectedSkills.length} 个技能\n </span>\n <span className=\"rounded-full border border-[hsl(var(--border))] px-2.5 py-1\">\n {stepCount} 个步骤\n </span>\n <span className=\"inline-flex items-center gap-1 text-[hsl(var(--muted-foreground))]\">\n <CheckCircle2 size={12} />\n 右侧查看详情\n </span>\n </div>\n )}\n </button>\n\n {canConfirm && <PlanConfirmationPanel onConfirmPlan={onConfirmPlan} />}\n </div>\n )\n}\n\nfunction PlanConfirmationPanel({\n onConfirmPlan,\n}: {\n onConfirmPlan?: (action: \"execute\" | \"revise\", text?: string) => void\n}) {\n const [isEditing, setIsEditing] = useState(false)\n const [revisionText, setRevisionText] = useState(\"\")\n\n const submitRevision = () => {\n const trimmed = revisionText.trim()\n if (!trimmed) return\n onConfirmPlan?.(\"revise\", trimmed)\n setRevisionText(\"\")\n setIsEditing(false)\n }\n\n return (\n <div className=\"space-y-3 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--background)/0.45)] p-3\">\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() => onConfirmPlan?.(\"execute\")}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-[hsl(var(--primary))] px-3 py-2 text-sm font-medium text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90\"\n >\n <Play size={14} />\n 开始执行\n </button>\n <button\n type=\"button\"\n onClick={() => setIsEditing((value) => !value)}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-[hsl(var(--border))] px-3 py-2 text-sm text-[hsl(var(--foreground))] transition-colors hover:bg-[hsl(var(--accent))]\"\n >\n <PencilLine size={14} />\n 修改\n </button>\n </div>\n\n {isEditing && (\n <div className=\"space-y-2\">\n <textarea\n value={revisionText}\n onChange={(event) => setRevisionText(event.target.value)}\n placeholder=\"输入修改建议...\"\n className=\"min-h-24 w-full resize-y rounded-lg border border-[hsl(var(--border))] bg-transparent px-3 py-2 text-sm text-[hsl(var(--foreground))] outline-none placeholder:text-[hsl(var(--muted-foreground))]\"\n />\n <div className=\"flex justify-end\">\n <button\n type=\"button\"\n disabled={!revisionText.trim()}\n onClick={submitRevision}\n className=\"rounded-lg bg-[hsl(var(--primary))] px-3 py-1.5 text-xs font-medium text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:opacity-30\"\n >\n 提交修改意见\n </button>\n </div>\n </div>\n )}\n </div>\n )\n}\n\nfunction getSummaryState(\n data: ReturnType<typeof parsePlanMessages>,\n sessionStatus?: string,\n): SummaryState {\n if (sessionStatus === \"failed\") {\n return { kind: \"failed\", label: \"出错\" }\n }\n if (sessionStatus === \"interrupted\") {\n return { kind: \"interrupted\", label: \"已中断\" }\n }\n if (data.parseError) {\n return { kind: \"failed\", label: \"解析失败\" }\n }\n if (data.hasPlanContent || data.plan != null) {\n return { kind: \"complete\", label: \"已生成\" }\n }\n if (data.selectedSkills.length > 0) {\n return { kind: \"progress\", label: \"技能分析中\", dots: \"●●○\" }\n }\n if (data.searchResults.length > 0) {\n return { kind: \"progress\", label: \"技能发现中\", dots: \"●○○\" }\n }\n return { kind: \"progress\", label: \"规划准备中\", dots: \"○○○\" }\n}\n\nfunction countPlanSteps(plan: ReturnType<typeof parsePlanMessages>[\"plan\"]): number {\n if (!plan) return 0\n\n const countNode = (node: (typeof plan.root)[\"children\"][number] | typeof plan.root): number => {\n const children = Array.isArray(node.children) ? node.children : []\n return 1 + children.reduce((total, child) => total + countNode(child), 0)\n }\n\n if (plan.root.id === \"plan-root\") {\n const children = Array.isArray(plan.root.children) ? plan.root.children : []\n return children.reduce((total, child) => total + countNode(child), 0)\n }\n\n return countNode(plan.root)\n}\n","import type { ChatMessage } from \"../../schemas/message\"\n\nfunction parseModeChange(message: ChatMessage): { from: string; to: string } | null {\n if (message.kind !== \"mode_change\" || typeof message.content !== \"string\") {\n return null\n }\n try {\n const parsed = JSON.parse(message.content) as { from?: unknown; to?: unknown }\n if (typeof parsed.from === \"string\" && typeof parsed.to === \"string\") {\n return { from: parsed.from, to: parsed.to }\n }\n } catch {}\n return null\n}\n\nfunction isPlanningEnter(message: ChatMessage): boolean {\n const modeChange = parseModeChange(message)\n return modeChange?.to === \"planning\"\n}\n\nfunction isPlanningExit(message: ChatMessage): boolean {\n const modeChange = parseModeChange(message)\n return modeChange?.from === \"planning\"\n}\n\nexport function extractLatestPlanMessages(messages: ChatMessage[]): ChatMessage[] {\n const safeMessages = Array.isArray(messages) ? messages : []\n let enterIndex = -1\n let exitIndex = -1\n\n for (let i = safeMessages.length - 1; i >= 0; i -= 1) {\n const message = safeMessages[i]\n if (isPlanningExit(message) && exitIndex === -1) {\n exitIndex = i\n continue\n }\n if (isPlanningEnter(message)) {\n enterIndex = i\n break\n }\n }\n\n if (enterIndex === -1) {\n return []\n }\n\n return safeMessages\n .slice(enterIndex + 1)\n .filter((message, offset) => {\n const absoluteIndex = enterIndex + 1 + offset\n if (isPlanningEnter(message) || isPlanningExit(message)) {\n return false\n }\n if (exitIndex !== -1 && absoluteIndex > exitIndex) {\n return message.kind === \"plan_status\"\n }\n return true\n })\n}\n"],"mappings":"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","names":["jsx","jsx","jsxs","jsx","Check","Copy","Download","X","useEffect","useMemo","useState","createPortal","useEffect","useState","jsx","jsxs","useState","useEffect","useState","jsx","jsxs","useState","jsx","jsxs","useState","createPortal","X","stringValue","useEffect","Check","Copy","Download","basename","useMemo","Check","Loader2","useEffect","useMemo","useState","jsx","jsxs","useState","useEffect","useMemo","text","Loader2","Check","skillId","useMemo","useState","Fragment","jsx","jsxs","useMemo","useState","parseModeChange"]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getClient
3
- } from "./chunk-WOKDHXS7.js";
3
+ } from "./chunk-IDVNG3YJ.js";
4
4
  import {
5
5
  __export
6
6
  } from "./chunk-PZ5AY32C.js";
@@ -20,4 +20,4 @@ export {
20
20
  unpublishApp,
21
21
  published_apps_exports
22
22
  };
23
- //# sourceMappingURL=chunk-6G5LCDOS.js.map
23
+ //# sourceMappingURL=chunk-EGGBOVVF.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  useSessionStore
3
- } from "./chunk-WOKDHXS7.js";
3
+ } from "./chunk-IDVNG3YJ.js";
4
4
 
5
5
  // src/react/hooks/use-session.ts
6
6
  function useSession() {
@@ -27,4 +27,4 @@ function useSession() {
27
27
  export {
28
28
  useSession
29
29
  };
30
- //# sourceMappingURL=chunk-L4C2TY6S.js.map
30
+ //# sourceMappingURL=chunk-F4Y7SUBC.js.map
@@ -1636,6 +1636,7 @@ function projectHistory(entries) {
1636
1636
  const toolOwners = /* @__PURE__ */ new Map();
1637
1637
  const latestAssistantByLoop = /* @__PURE__ */ new Map();
1638
1638
  const pendingChildPauses = /* @__PURE__ */ new Map();
1639
+ const answeredToolCallIds = /* @__PURE__ */ new Set();
1639
1640
  let sequence = 0;
1640
1641
  for (const entry of entries) {
1641
1642
  const kind = String(entry.kind ?? "");
@@ -1679,6 +1680,7 @@ function projectHistory(entries) {
1679
1680
  };
1680
1681
  turns.push(turn);
1681
1682
  if (role === "assistant") latestAssistantByLoop.set(loopId, turn);
1683
+ if (role === "user") latestAssistantByLoop.delete(loopId);
1682
1684
  for (const toolCall of toolCalls) toolOwners.set(toolCall.id, turn);
1683
1685
  continue;
1684
1686
  }
@@ -1754,6 +1756,7 @@ function projectHistory(entries) {
1754
1756
  } else if (kind === "ask_user_answer") {
1755
1757
  const data = entry.data ?? {};
1756
1758
  const toolCallId = String(data.tool_call_id ?? "");
1759
+ if (toolCallId) answeredToolCallIds.add(toolCallId);
1757
1760
  const pending = pendingChildPauses.get(toolCallId);
1758
1761
  if (pending) {
1759
1762
  setToolCallStatus(latestAssistantByLoop.get(pending.childLoopId), toolCallId, "done", null, null);
@@ -1780,8 +1783,46 @@ function projectHistory(entries) {
1780
1783
  );
1781
1784
  }
1782
1785
  }
1786
+ const rootTurn = latestAssistantByLoop.get("root");
1787
+ if (rootTurn) {
1788
+ for (const toolCall of rootTurn.tool_calls) {
1789
+ if (answeredToolCallIds.has(toolCall.id)) continue;
1790
+ const normalizedName = toolCall.tool_name.split(":").pop();
1791
+ if (normalizedName !== "AskUserQuestion") continue;
1792
+ if (toolCall.status === "error" || toolCall.status === "cancelled") continue;
1793
+ applyAskUserPauseToTurn(
1794
+ rootTurn,
1795
+ {
1796
+ name: toolCall.tool_name,
1797
+ tool_call_id: toolCall.id,
1798
+ arguments: buildAskUserPauseArguments(toolCall)
1799
+ },
1800
+ toolCall.id,
1801
+ "",
1802
+ "",
1803
+ (name) => name
1804
+ );
1805
+ }
1806
+ }
1783
1807
  return turns;
1784
1808
  }
1809
+ function buildAskUserPauseArguments(toolCall) {
1810
+ const argumentsPayload = parseToolArguments(toolCall.arguments);
1811
+ if (typeof toolCall.result !== "string") return argumentsPayload;
1812
+ const resultPayload = parseToolArguments(toolCall.result);
1813
+ if (Array.isArray(resultPayload.questions)) {
1814
+ return { ...argumentsPayload, questions: resultPayload.questions };
1815
+ }
1816
+ return argumentsPayload;
1817
+ }
1818
+ function parseToolArguments(value) {
1819
+ try {
1820
+ const parsed = JSON.parse(value);
1821
+ return isRecord2(parsed) ? parsed : {};
1822
+ } catch {
1823
+ return {};
1824
+ }
1825
+ }
1785
1826
  function buildToolCalls(value) {
1786
1827
  if (!Array.isArray(value)) return [];
1787
1828
  return value.filter(isRecord2).map((raw) => {
@@ -1798,9 +1839,12 @@ function buildToolCalls(value) {
1798
1839
  });
1799
1840
  }
1800
1841
  function buildBlocks(message, toolCalls) {
1842
+ const displayContent = message.role === "user" ? message._display_content : void 0;
1801
1843
  const stored = message._blocks;
1802
1844
  const blocks = [];
1803
- if (Array.isArray(stored)) {
1845
+ if (displayContent !== void 0) {
1846
+ blocks.push({ type: "text", content: displayContent });
1847
+ } else if (Array.isArray(stored)) {
1804
1848
  for (const raw of stored) {
1805
1849
  if (!isRecord2(raw)) continue;
1806
1850
  const type3 = String(raw.type ?? "");
@@ -2903,4 +2947,4 @@ export {
2903
2947
  createSocket,
2904
2948
  BladeClient
2905
2949
  };
2906
- //# sourceMappingURL=chunk-GAVSC2AW.js.map
2950
+ //# sourceMappingURL=chunk-FK4CV6R2.js.map