@blade-hq/agent-kit 1.0.25 → 1.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-M45K3554.js → chunk-34GDDOWY.js} +5 -3
- package/dist/chunk-34GDDOWY.js.map +1 -0
- package/dist/chunk-7LEKQI47.js +32 -0
- package/dist/chunk-7LEKQI47.js.map +1 -0
- package/dist/{chunk-WPLEMYL7.js → chunk-C2FKVGJU.js} +2 -2
- package/dist/{chunk-4D4EXLVT.js → chunk-DQCXSPHP.js} +2 -2
- package/dist/{chunk-QODAKTG5.js → chunk-JCJFFJ42.js} +2 -31
- package/dist/chunk-JCJFFJ42.js.map +1 -0
- package/dist/{chunk-VJY6RLYU.js → chunk-JU5SL4HP.js} +2 -2
- package/dist/chunk-M72OL7ZJ.js +23 -0
- package/dist/chunk-M72OL7ZJ.js.map +1 -0
- package/dist/{chunk-WVXXQ3KM.js → chunk-SBASG3M2.js} +132 -102
- package/dist/chunk-SBASG3M2.js.map +1 -0
- package/dist/{chunk-XCIDE3JW.js → chunk-TE6G6NVX.js} +7 -7
- package/dist/{chunk-3I4ZURKH.js → chunk-X2NJKKXR.js} +15 -15
- package/dist/client/auth.d.ts +8 -0
- package/dist/client/blade-client.d.ts +80 -0
- package/dist/client/index.d.ts +22 -15348
- package/dist/client/index.js +1 -1
- package/dist/client/resources/api-keys.d.ts +28 -0
- package/dist/client/resources/auth.d.ts +26 -0
- package/dist/client/resources/env-buckets.d.ts +20 -0
- package/dist/client/resources/gis.d.ts +8 -0
- package/dist/client/resources/headless.d.ts +33 -0
- package/dist/client/resources/memories.d.ts +63 -0
- package/dist/client/resources/models.d.ts +23 -0
- package/dist/client/resources/published-apps.d.ts +8 -0
- package/dist/client/resources/registry.d.ts +58 -0
- package/dist/client/resources/runs.d.ts +8 -0
- package/dist/client/resources/scenarios.d.ts +49 -0
- package/dist/client/resources/sessions.d.ts +253 -0
- package/dist/client/resources/skills.d.ts +38 -0
- package/dist/client/resources/solutions.d.ts +31 -0
- package/dist/client/resources/user-preferences.d.ts +26 -0
- package/dist/client/rest.d.ts +19 -0
- package/dist/client/socket.d.ts +9 -0
- package/dist/client/types/index.d.ts +8 -0
- package/dist/client/types/rest.d.ts +15335 -0
- package/dist/client/types/sdk-profile.d.ts +47 -0
- package/dist/client/types/socket-events.d.ts +503 -0
- package/dist/react/api/api-keys.d.ts +6 -0
- package/dist/react/api/auth.d.ts +7 -0
- package/dist/react/api/client.d.ts +8 -0
- package/dist/react/api/env-buckets.d.ts +10 -0
- package/dist/react/api/gis-api.d.ts +4 -0
- package/dist/react/api/memories.d.ts +14 -0
- package/dist/react/api/models.d.ts +11 -0
- package/dist/react/api/partner-skill.d.ts +2 -0
- package/dist/react/api/prod-solution.d.ts +456 -0
- package/dist/react/api/published-apps.d.ts +21 -0
- package/dist/react/api/published-apps.js +14 -0
- package/dist/react/api/published-apps.js.map +1 -0
- package/dist/react/api/registry.d.ts +46 -0
- package/dist/react/api/scenarios.d.ts +9 -0
- package/dist/react/api/scheduled-tasks.d.ts +24 -0
- package/dist/react/api/session-skill.d.ts +2 -0
- package/dist/react/api/sessions.d.ts +109 -0
- package/dist/react/api/sessions.js +93 -0
- package/dist/react/api/sessions.js.map +1 -0
- package/dist/react/api/skills.d.ts +27 -0
- package/dist/react/api/socket.d.ts +5 -0
- package/dist/react/api/solutions.d.ts +11 -0
- package/dist/react/api/user-preferences.d.ts +8 -0
- package/dist/react/asr/VoiceWaveform.d.ts +10 -0
- package/dist/react/asr/use-tiptap-voice-input.d.ts +29 -0
- package/dist/react/asr/use-voice-input.d.ts +17 -0
- package/dist/react/asr/voice-input-support.d.ts +5 -0
- package/dist/react/bootstrap.d.ts +4 -0
- package/dist/react/cards/register.d.ts +1 -2
- package/dist/react/cards/register.js +3 -2
- package/dist/react/cards/register.js.map +1 -1
- package/dist/react/components/ai-elements/file-tree.d.ts +26 -0
- package/dist/react/components/ai-elements/reasoning.d.ts +32 -0
- package/dist/react/components/ai-elements/shimmer.d.ts +11 -0
- package/dist/react/components/card/CardCodeBlock.d.ts +5 -0
- package/dist/react/components/card/CardContext.d.ts +7 -0
- package/dist/react/components/card/CardRenderer.d.ts +7 -0
- package/dist/react/components/card/CardStates.d.ts +8 -0
- package/dist/react/components/card/cards/attraction-card.d.ts +2 -0
- package/dist/react/components/card/cards/cite-card.d.ts +10 -0
- package/dist/react/components/card/cards/comprehensive-analysis-card.d.ts +2 -0
- package/dist/react/components/card/cards/conflict-detection-card.d.ts +4 -0
- package/dist/react/components/card/cards/counter.d.ts +2 -0
- package/dist/react/components/card/cards/damage-effect-card.d.ts +4 -0
- package/dist/react/components/card/cards/destination-card.d.ts +2 -0
- package/dist/react/components/card/cards/diff-card.d.ts +2 -0
- package/dist/react/components/card/cards/execution-order-card.d.ts +2 -0
- package/dist/react/components/card/cards/experience-card-with-options.d.ts +4 -0
- package/dist/react/components/card/cards/flight-card.d.ts +2 -0
- package/dist/react/components/card/cards/hotel-card.d.ts +2 -0
- package/dist/react/components/card/cards/kill-chain-card.d.ts +2 -0
- package/dist/react/components/card/cards/kill-chain-types.d.ts +157 -0
- package/dist/react/components/card/cards/map-card.d.ts +2 -0
- package/dist/react/components/card/cards/order-status-card.d.ts +2 -0
- package/dist/react/components/card/cards/patch-card.d.ts +15 -0
- package/dist/react/components/card/cards/product-recommendation-card.d.ts +2 -0
- package/dist/react/components/card/cards/reflection-optimization-card.d.ts +2 -0
- package/dist/react/components/card/cards/resolution-modifications-card.d.ts +2 -0
- package/dist/react/components/card/cards/resolution-summary-card.d.ts +2 -0
- package/dist/react/components/card/cards/restaurant-card.d.ts +2 -0
- package/dist/react/components/card/cards/shopping-list-card.d.ts +2 -0
- package/dist/react/components/card/cards/simulation-event-card.d.ts +4 -0
- package/dist/react/components/card/cards/survival-effect-card.d.ts +4 -0
- package/dist/react/components/card/cards/travel-itinerary-card.d.ts +2 -0
- package/dist/react/components/card/register.d.ts +1 -0
- package/dist/react/components/chat/AgentLoopBlock.d.ts +8 -0
- package/dist/react/components/chat/AskUserQuestionBlock.d.ts +32 -0
- package/dist/react/components/chat/AssistantTurnBlock.d.ts +28 -0
- package/dist/react/components/chat/AttachmentPreviewDialog.d.ts +26 -0
- package/dist/react/components/chat/BackgroundTasksPill.d.ts +3 -0
- package/dist/react/components/chat/ChatInput.d.ts +94 -0
- package/dist/react/components/chat/ChatView.d.ts +16 -0
- package/dist/react/components/chat/CompactionCard.d.ts +6 -0
- package/dist/react/components/chat/ConnectionBanner.d.ts +1 -0
- package/dist/react/components/chat/FileCompletionMenu.d.ts +13 -0
- package/dist/react/components/chat/FileSizeLimitDialog.d.ts +9 -0
- package/dist/react/components/chat/ImageLightbox.d.ts +11 -0
- package/dist/react/components/chat/MessageActions.d.ts +6 -0
- package/dist/react/components/chat/MessageContextPills.d.ts +6 -0
- package/dist/react/components/chat/MessageFileAttachmentList.d.ts +13 -0
- package/dist/react/components/chat/MessageList.d.ts +13 -0
- package/dist/react/components/chat/ProgressCircle.d.ts +12 -0
- package/dist/react/components/chat/RenderErrorBoundary.d.ts +19 -0
- package/dist/react/components/chat/ResourceIframe.d.ts +5 -0
- package/dist/react/components/chat/Shimmer.d.ts +6 -0
- package/dist/react/components/chat/SkillCompletionMenu.d.ts +9 -0
- package/dist/react/components/chat/SkillStatusBar.d.ts +8 -0
- package/dist/react/components/chat/StickyStatusBar.d.ts +10 -0
- package/dist/react/components/chat/TextAttachmentPills.d.ts +10 -0
- package/dist/react/components/chat/ThinkingToggle.d.ts +7 -0
- package/dist/react/components/chat/ToolCallBlock.d.ts +18 -0
- package/dist/react/components/chat/TurnNavRail.d.ts +11 -0
- package/dist/react/components/chat/UserMessageBubble.d.ts +20 -0
- package/dist/react/components/chat/WhatIfUserBubble.d.ts +13 -0
- package/dist/react/components/chat/customization.d.ts +82 -0
- package/dist/react/components/chat/display-utils.d.ts +35 -0
- package/dist/react/components/chat/extensions/file-mention.d.ts +12 -0
- package/dist/react/components/chat/extensions/skill-mention.d.ts +25 -0
- package/dist/react/components/chat/index.d.ts +16 -115
- package/dist/react/components/chat/index.js +8 -7
- package/dist/react/components/chat/tool-renderers/BashRenderer.d.ts +2 -0
- package/dist/react/components/chat/tool-renderers/FileEditRenderer.d.ts +2 -0
- package/dist/react/components/chat/tool-renderers/FileReadRenderer.d.ts +2 -0
- package/dist/react/components/chat/tool-renderers/SearchRenderer.d.ts +2 -0
- package/dist/react/components/chat/tool-renderers/SubmitResultRenderer.d.ts +2 -0
- package/dist/react/components/chat/tool-renderers/registry.d.ts +9 -0
- package/dist/react/components/chat/tool-renderers/shared.d.ts +26 -0
- package/dist/react/components/chat/whatif-quote-context.d.ts +15 -0
- package/dist/react/components/markdown/ExternalLinkDialog.d.ts +8 -0
- package/dist/react/components/markdown/FileCardComponent.d.ts +10 -0
- package/dist/react/components/markdown/MarkdownContent.d.ts +19 -0
- package/dist/react/components/model/ModelSelector.d.ts +9 -0
- package/dist/react/components/plan/PlanSummaryCard.d.ts +8 -0
- package/dist/react/components/plan/PlanVisualization.d.ts +13 -0
- package/dist/react/components/plan/debug-log.d.ts +21 -0
- package/dist/react/components/plan/extract-plan-messages.d.ts +2 -0
- package/dist/react/components/plan/index.d.ts +6 -110
- package/dist/react/components/plan/index.js +7 -6
- package/dist/react/components/plan/index.js.map +1 -1
- package/dist/react/components/plan/parse-plan-messages.d.ts +10 -0
- package/dist/react/components/plan/parse-plan-tree.d.ts +16 -0
- package/dist/react/components/plan/phases/PlanMindMap.d.ts +8 -0
- package/dist/react/components/plan/phases/PlanStatusIcon.d.ts +5 -0
- package/dist/react/components/plan/phases/PlanTree.d.ts +8 -0
- package/dist/react/components/plan/phases/SkillAnalysis.d.ts +7 -0
- package/dist/react/components/plan/phases/SkillDiscovery.d.ts +10 -0
- package/dist/react/components/plan/types.d.ts +56 -0
- package/dist/react/components/session/SessionDetail.d.ts +8 -0
- package/dist/react/components/session/SessionList.d.ts +9 -0
- package/dist/react/components/session/SessionListItem.d.ts +8 -0
- package/dist/react/components/session/StatusBadge.d.ts +3 -0
- package/dist/react/components/session/index.d.ts +5 -53
- package/dist/react/components/session/index.js +6 -5
- package/dist/react/components/session/index.js.map +1 -1
- package/dist/react/components/session/session-utils.d.ts +19 -0
- package/dist/react/components/ui/collapsible.d.ts +5 -0
- package/dist/react/components/workspace/FileTree.d.ts +21 -0
- package/dist/react/components/workspace/WorkspaceFilesPanel.d.ts +30 -0
- package/dist/react/components/workspace/file-icon-assets.d.ts +3 -0
- package/dist/react/components/workspace/index.d.ts +2 -59
- package/dist/react/components/workspace/index.js +6 -5
- package/dist/react/components/workspace/index.js.map +1 -1
- package/dist/react/context.d.ts +2 -0
- package/dist/react/devtools/bridge-devtools/BridgeDevtoolsFab.d.ts +1 -0
- package/dist/react/devtools/bridge-devtools/index.d.ts +3 -36
- package/dist/react/devtools/bridge-devtools/mount.d.ts +1 -0
- package/dist/react/devtools/bridge-devtools/store.d.ts +15 -0
- package/dist/react/devtools/bridge-devtools/tap.d.ts +5 -0
- package/dist/react/devtools/bridge-devtools/types.d.ts +29 -0
- package/dist/react/hooks/use-background-tasks.d.ts +7 -0
- package/dist/react/hooks/use-card-state.d.ts +1 -0
- package/dist/react/hooks/use-chat.d.ts +13 -0
- package/dist/react/hooks/use-check-skill-file.d.ts +4 -0
- package/dist/react/hooks/use-check-solution-file.d.ts +4 -0
- package/dist/react/hooks/use-context-stats.d.ts +7 -0
- package/dist/react/hooks/use-gis.d.ts +17 -0
- package/dist/react/hooks/use-global-skill-stats.d.ts +6 -0
- package/dist/react/hooks/use-input-history.d.ts +7 -0
- package/dist/react/hooks/use-model-preferences.d.ts +17 -0
- package/dist/react/hooks/use-registry.d.ts +53 -0
- package/dist/react/hooks/use-resolved-model.d.ts +5 -0
- package/dist/react/hooks/use-session.d.ts +10 -0
- package/dist/react/hooks/use-skill-stats.d.ts +7 -0
- package/dist/react/hooks/use-skills.d.ts +6 -0
- package/dist/react/hooks/use-token-pressure.d.ts +6 -0
- package/dist/react/index.d.ts +121 -2034
- package/dist/react/index.js +47 -52
- package/dist/react/index.js.map +1 -1
- package/dist/react/lib/analytics.d.ts +7 -0
- package/dist/react/lib/attachment-upload.d.ts +10 -0
- package/dist/react/lib/card-registry.d.ts +35 -0
- package/dist/react/lib/chat.d.ts +48 -0
- package/dist/react/lib/code-highlight.d.ts +9 -0
- package/dist/react/lib/html-element-selection.d.ts +140 -0
- package/dist/react/lib/html-source-locator.d.ts +16 -0
- package/dist/react/lib/open-session-file.d.ts +2 -0
- package/dist/react/lib/parent-bridge.d.ts +22 -0
- package/dist/react/lib/preview-dispatch.d.ts +24 -0
- package/dist/react/lib/resource-bridge.d.ts +11 -0
- package/dist/react/lib/session-file-preview.d.ts +8 -0
- package/dist/react/lib/step-ranges.d.ts +42 -0
- package/dist/react/lib/tool-preview.d.ts +2 -0
- package/dist/react/lib/ui-meta.d.ts +9 -0
- package/dist/react/lib/utils.d.ts +3 -0
- package/dist/react/lib/whatif-prompt.d.ts +45 -0
- package/dist/react/projection/builder.d.ts +59 -0
- package/dist/react/projection/helpers.d.ts +34 -0
- package/dist/react/projection/index.d.ts +2 -0
- package/dist/react/projection/state.d.ts +22 -0
- package/dist/react/provider.d.ts +8 -0
- package/dist/react/routes.d.ts +1 -0
- package/dist/react/schemas/background.d.ts +16 -0
- package/dist/react/schemas/event.d.ts +51 -0
- package/dist/react/schemas/gis.d.ts +50 -0
- package/dist/{AskUserQuestionBlock---kOTouk.d.ts → react/schemas/message.d.ts} +15 -48
- package/dist/react/schemas/partner-skill.d.ts +46 -0
- package/dist/{projection-BWYEFYNn.d.ts → react/schemas/projection.d.ts} +12 -10
- package/dist/react/schemas/published-apps.d.ts +38 -0
- package/dist/react/schemas/scheduled-task.d.ts +32 -0
- package/dist/react/schemas/session.d.ts +121 -0
- package/dist/react/schemas/skill.d.ts +50 -0
- package/dist/react/schemas/studio/agent.d.ts +12 -0
- package/dist/react/schemas/studio/database.d.ts +39 -0
- package/dist/react/schemas/studio/env.d.ts +7 -0
- package/dist/react/schemas/studio/knowledge.d.ts +18 -0
- package/dist/react/schemas/studio/resource-base.d.ts +7 -0
- package/dist/react/schemas/studio/scene.d.ts +12 -0
- package/dist/react/schemas/studio/tool.d.ts +25 -0
- package/dist/react/schemas/task.d.ts +12 -0
- package/dist/react/sockets/event-bridge.d.ts +115 -0
- package/dist/react/sockets/socket-state.d.ts +4 -0
- package/dist/react/stores/answer-callback-store.d.ts +9 -0
- package/dist/react/stores/auth-store.d.ts +38 -0
- package/dist/react/stores/background-store.d.ts +13 -0
- package/dist/react/stores/card-state-store.d.ts +10 -0
- package/dist/react/stores/chat-store.d.ts +34 -0
- package/dist/react/stores/client-aware.d.ts +7 -0
- package/dist/react/stores/connection-store.d.ts +14 -0
- package/dist/react/stores/gis-store.d.ts +19 -0
- package/dist/react/stores/index.d.ts +14 -0
- package/dist/react/stores/runtime-features-store.d.ts +21 -0
- package/dist/react/stores/runtime-store.d.ts +18 -0
- package/dist/react/stores/session-store.d.ts +44 -0
- package/dist/react/stores/task-store.d.ts +9 -0
- package/dist/react/stores/ui-bridge-store.d.ts +32 -0
- package/dist/react/stores/ui-store.d.ts +69 -0
- package/dist/react/types/index.d.ts +7 -0
- package/dist/react/types/solution.d.ts +101 -0
- package/package.json +41 -11
- package/dist/SkillStatusBar-U6fbQxMu.d.ts +0 -340
- package/dist/blade-client-qTOovekU.d.ts +0 -1609
- package/dist/chunk-M45K3554.js.map +0 -1
- package/dist/chunk-QODAKTG5.js.map +0 -1
- package/dist/chunk-WVXXQ3KM.js.map +0 -1
- package/dist/session-CNnotR90.d.ts +0 -227
- package/dist/sessions-BvfLGbjw.d.ts +0 -177
- /package/dist/{chunk-WPLEMYL7.js.map → chunk-C2FKVGJU.js.map} +0 -0
- /package/dist/{chunk-4D4EXLVT.js.map → chunk-DQCXSPHP.js.map} +0 -0
- /package/dist/{chunk-VJY6RLYU.js.map → chunk-JU5SL4HP.js.map} +0 -0
- /package/dist/{chunk-XCIDE3JW.js.map → chunk-TE6G6NVX.js.map} +0 -0
- /package/dist/{chunk-3I4ZURKH.js.map → chunk-X2NJKKXR.js.map} +0 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SessionInfo } from "../../schemas/session.js";
|
|
2
|
+
export declare function SessionDetailTrigger({ onClick, showReplayDot, }: {
|
|
3
|
+
onClick: () => void;
|
|
4
|
+
showReplayDot?: boolean;
|
|
5
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export declare function SessionDetail({ session }: {
|
|
7
|
+
session: SessionInfo;
|
|
8
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SessionInfo } from "../../schemas/session.js";
|
|
2
|
+
export interface SessionListProps {
|
|
3
|
+
sessions: SessionInfo[];
|
|
4
|
+
/** Called after a new session is created; defaults to no-op. */
|
|
5
|
+
onSessionCreated?: (sessionId: string) => void;
|
|
6
|
+
/** Called when user selects a session. */
|
|
7
|
+
onSessionSelect: (sessionId: string) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function SessionList({ sessions, onSessionCreated, onSessionSelect }: SessionListProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SessionInfo } from "../../schemas/session.js";
|
|
2
|
+
interface Props {
|
|
3
|
+
session: SessionInfo;
|
|
4
|
+
active: boolean;
|
|
5
|
+
onClick: () => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function SessionListItem({ session, active, onClick }: Props): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
|
@@ -1,53 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
declare function SessionDetailTrigger({ onClick, showReplayDot, }: {
|
|
7
|
-
onClick: () => void;
|
|
8
|
-
showReplayDot?: boolean;
|
|
9
|
-
}): react_jsx_runtime.JSX.Element;
|
|
10
|
-
declare function SessionDetail({ session }: {
|
|
11
|
-
session: SessionInfo;
|
|
12
|
-
}): react_jsx_runtime.JSX.Element | null;
|
|
13
|
-
|
|
14
|
-
interface SessionListProps {
|
|
15
|
-
sessions: SessionInfo[];
|
|
16
|
-
/** Called after a new session is created; defaults to no-op. */
|
|
17
|
-
onSessionCreated?: (sessionId: string) => void;
|
|
18
|
-
/** Called when user selects a session. */
|
|
19
|
-
onSessionSelect: (sessionId: string) => void;
|
|
20
|
-
}
|
|
21
|
-
declare function SessionList({ sessions, onSessionCreated, onSessionSelect }: SessionListProps): react_jsx_runtime.JSX.Element;
|
|
22
|
-
|
|
23
|
-
interface Props {
|
|
24
|
-
session: SessionInfo;
|
|
25
|
-
active: boolean;
|
|
26
|
-
onClick: () => void;
|
|
27
|
-
}
|
|
28
|
-
declare function SessionListItem({ session, active, onClick }: Props): react_jsx_runtime.JSX.Element;
|
|
29
|
-
|
|
30
|
-
declare function StatusBadge({ status }: {
|
|
31
|
-
status: string;
|
|
32
|
-
}): react_jsx_runtime.JSX.Element;
|
|
33
|
-
|
|
34
|
-
type SessionGroupKey = "today" | "yesterday" | "week" | "older";
|
|
35
|
-
declare const SESSION_GROUPS: SessionGroupKey[];
|
|
36
|
-
declare const SESSION_GROUP_LABELS: Record<SessionGroupKey, string>;
|
|
37
|
-
declare const RELATIVE_TIME_FORMATTER: Intl.RelativeTimeFormat;
|
|
38
|
-
declare function getSessionTimestamp(session: SessionInfo): number;
|
|
39
|
-
declare function getSessionLabel(session: SessionInfo, fallback?: string): string;
|
|
40
|
-
declare function shouldShowSessionInHistory(session: SessionInfo): boolean;
|
|
41
|
-
declare function isReplaySession(session: SessionInfo): boolean;
|
|
42
|
-
declare function getDisplaySessionStatus(session: SessionInfo): SessionInfo["status"];
|
|
43
|
-
declare function startOfDay(date: Date): Date;
|
|
44
|
-
declare function startOfWeek(date: Date): Date;
|
|
45
|
-
declare function getSessionGroup(timestamp: number, now?: Date): SessionGroupKey;
|
|
46
|
-
declare function formatRelativeTime(timestamp: number, now?: number): string;
|
|
47
|
-
declare function getStatusMeta(status: SessionInfo["status"]): {
|
|
48
|
-
dotClass: string;
|
|
49
|
-
toneClass: string;
|
|
50
|
-
label: string;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export { RELATIVE_TIME_FORMATTER, SESSION_GROUPS, SESSION_GROUP_LABELS, SessionDetail, SessionDetailTrigger, type SessionGroupKey, SessionList, SessionListItem, type SessionListProps, StatusBadge, formatRelativeTime, getDisplaySessionStatus, getSessionGroup, getSessionLabel, getSessionTimestamp, getStatusMeta, isReplaySession, shouldShowSessionInHistory, startOfDay, startOfWeek };
|
|
1
|
+
export { SessionDetail, SessionDetailTrigger } from "./SessionDetail.js";
|
|
2
|
+
export { SessionList, type SessionListProps } from "./SessionList.js";
|
|
3
|
+
export { SessionListItem } from "./SessionListItem.js";
|
|
4
|
+
export { StatusBadge } from "./StatusBadge.js";
|
|
5
|
+
export * from "./session-utils.js";
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
useSession
|
|
3
|
-
} from "../../../chunk-
|
|
3
|
+
} from "../../../chunk-JU5SL4HP.js";
|
|
4
4
|
import {
|
|
5
5
|
checkoutSession,
|
|
6
6
|
getSessionCheckpoints,
|
|
7
7
|
useChatStore,
|
|
8
8
|
useSessionStore
|
|
9
|
-
} from "../../../chunk-
|
|
10
|
-
import "../../../chunk-
|
|
9
|
+
} from "../../../chunk-SBASG3M2.js";
|
|
10
|
+
import "../../../chunk-J3XVFPOV.js";
|
|
11
|
+
import "../../../chunk-34GDDOWY.js";
|
|
11
12
|
import {
|
|
12
13
|
cn
|
|
13
|
-
} from "../../../chunk-
|
|
14
|
-
import "../../../chunk-
|
|
14
|
+
} from "../../../chunk-7LEKQI47.js";
|
|
15
|
+
import "../../../chunk-JCJFFJ42.js";
|
|
15
16
|
import "../../../chunk-PZ5AY32C.js";
|
|
16
17
|
|
|
17
18
|
// 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"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SessionInfo } from "../../schemas/session.js";
|
|
2
|
+
export type SessionGroupKey = "today" | "yesterday" | "week" | "older";
|
|
3
|
+
export declare const SESSION_GROUPS: SessionGroupKey[];
|
|
4
|
+
export declare const SESSION_GROUP_LABELS: Record<SessionGroupKey, string>;
|
|
5
|
+
export declare const RELATIVE_TIME_FORMATTER: Intl.RelativeTimeFormat;
|
|
6
|
+
export declare function getSessionTimestamp(session: SessionInfo): number;
|
|
7
|
+
export declare function getSessionLabel(session: SessionInfo, fallback?: string): string;
|
|
8
|
+
export declare function shouldShowSessionInHistory(session: SessionInfo): boolean;
|
|
9
|
+
export declare function isReplaySession(session: SessionInfo): boolean;
|
|
10
|
+
export declare function getDisplaySessionStatus(session: SessionInfo): SessionInfo["status"];
|
|
11
|
+
export declare function startOfDay(date: Date): Date;
|
|
12
|
+
export declare function startOfWeek(date: Date): Date;
|
|
13
|
+
export declare function getSessionGroup(timestamp: number, now?: Date): SessionGroupKey;
|
|
14
|
+
export declare function formatRelativeTime(timestamp: number, now?: number): string;
|
|
15
|
+
export declare function getStatusMeta(status: SessionInfo["status"]): {
|
|
16
|
+
dotClass: string;
|
|
17
|
+
toneClass: string;
|
|
18
|
+
label: string;
|
|
19
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Collapsible as CollapsiblePrimitive } from "radix-ui";
|
|
2
|
+
declare function Collapsible({ ...props }: React.ComponentProps<typeof CollapsiblePrimitive.Root>): import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
declare function CollapsibleTrigger({ ...props }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
declare function CollapsibleContent({ ...props }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export { Collapsible, CollapsibleTrigger, CollapsibleContent };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as sessionsApi from "../../api/sessions.js";
|
|
2
|
+
import "./file-icon-assets.js";
|
|
3
|
+
type FileEntry = Awaited<ReturnType<typeof sessionsApi.listDir>>[number];
|
|
4
|
+
type ListDirFn = (sessionId: string, dirPath: string) => Promise<FileEntry[]>;
|
|
5
|
+
interface FileTreeProps {
|
|
6
|
+
sessionId: string | null;
|
|
7
|
+
checkActiveSession?: boolean;
|
|
8
|
+
enableEditor?: boolean;
|
|
9
|
+
expandedDirs?: Set<string>;
|
|
10
|
+
defaultExpandedDirs?: Set<string>;
|
|
11
|
+
onExpandedDirsChange?: (dirs: Set<string>) => void;
|
|
12
|
+
rootPath?: string;
|
|
13
|
+
readOnly?: boolean;
|
|
14
|
+
onShareFile?: (path: string, name: string) => Promise<void>;
|
|
15
|
+
allowDelete?: boolean;
|
|
16
|
+
onOpenFile?: (path: string, name: string) => Promise<void>;
|
|
17
|
+
listDir?: ListDirFn;
|
|
18
|
+
queryKeyScope?: readonly unknown[];
|
|
19
|
+
}
|
|
20
|
+
export declare function FileTree({ sessionId, checkActiveSession, enableEditor, expandedDirs: controlledExpandedDirs, defaultExpandedDirs, onExpandedDirsChange, rootPath, readOnly, onShareFile, allowDelete, onOpenFile, listDir, queryKeyScope, }: FileTreeProps): import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
interface WorkspaceFileEntry {
|
|
3
|
+
name: string;
|
|
4
|
+
path: string;
|
|
5
|
+
is_dir: boolean;
|
|
6
|
+
created_at: number;
|
|
7
|
+
tags?: string[];
|
|
8
|
+
}
|
|
9
|
+
interface WorkspaceFilesPanelProps {
|
|
10
|
+
sessionId: string | null;
|
|
11
|
+
enableEditor?: boolean;
|
|
12
|
+
className?: string;
|
|
13
|
+
treeContainerClassName?: string;
|
|
14
|
+
title?: string;
|
|
15
|
+
rootPath?: string;
|
|
16
|
+
readOnly?: boolean;
|
|
17
|
+
expandedDirs?: Set<string>;
|
|
18
|
+
onExpandedDirsChange?: (dirs: Set<string>) => void;
|
|
19
|
+
onShareFile?: (path: string, name: string) => Promise<void>;
|
|
20
|
+
onSync?: () => Promise<void>;
|
|
21
|
+
allowDelete?: boolean;
|
|
22
|
+
/** Optional slot above the file tree (e.g. phase progress in host app). */
|
|
23
|
+
topSlot?: ReactNode;
|
|
24
|
+
/** Custom file open handler; used when enableEditor is false if provided. */
|
|
25
|
+
onOpenFile?: (path: string, name: string) => Promise<void>;
|
|
26
|
+
listDir?: (sessionId: string, dirPath: string) => Promise<WorkspaceFileEntry[]>;
|
|
27
|
+
queryKeyScope?: readonly unknown[];
|
|
28
|
+
}
|
|
29
|
+
export declare function WorkspaceFilesPanel({ sessionId, enableEditor, className, treeContainerClassName, title, rootPath, readOnly, expandedDirs: controlledExpandedDirs, onExpandedDirsChange, onShareFile, onSync, allowDelete, topSlot, onOpenFile, listDir, queryKeyScope, }: WorkspaceFilesPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
30
|
+
export {};
|
|
@@ -1,59 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { l as listDir } from '../../../sessions-BvfLGbjw.js';
|
|
4
|
-
import '../../../blade-client-qTOovekU.js';
|
|
5
|
-
import 'arktype/internal/variants/object.ts';
|
|
6
|
-
import 'arktype/internal/variants/string.ts';
|
|
7
|
-
import '../../../projection-BWYEFYNn.js';
|
|
8
|
-
import '../../../session-CNnotR90.js';
|
|
9
|
-
import 'socket.io-client';
|
|
10
|
-
|
|
11
|
-
interface WorkspaceFileEntry {
|
|
12
|
-
name: string;
|
|
13
|
-
path: string;
|
|
14
|
-
is_dir: boolean;
|
|
15
|
-
created_at: number;
|
|
16
|
-
tags?: string[];
|
|
17
|
-
}
|
|
18
|
-
interface WorkspaceFilesPanelProps {
|
|
19
|
-
sessionId: string | null;
|
|
20
|
-
enableEditor?: boolean;
|
|
21
|
-
className?: string;
|
|
22
|
-
treeContainerClassName?: string;
|
|
23
|
-
title?: string;
|
|
24
|
-
rootPath?: string;
|
|
25
|
-
readOnly?: boolean;
|
|
26
|
-
expandedDirs?: Set<string>;
|
|
27
|
-
onExpandedDirsChange?: (dirs: Set<string>) => void;
|
|
28
|
-
onShareFile?: (path: string, name: string) => Promise<void>;
|
|
29
|
-
onSync?: () => Promise<void>;
|
|
30
|
-
allowDelete?: boolean;
|
|
31
|
-
/** Optional slot above the file tree (e.g. phase progress in host app). */
|
|
32
|
-
topSlot?: ReactNode;
|
|
33
|
-
/** Custom file open handler; used when enableEditor is false if provided. */
|
|
34
|
-
onOpenFile?: (path: string, name: string) => Promise<void>;
|
|
35
|
-
listDir?: (sessionId: string, dirPath: string) => Promise<WorkspaceFileEntry[]>;
|
|
36
|
-
queryKeyScope?: readonly unknown[];
|
|
37
|
-
}
|
|
38
|
-
declare function WorkspaceFilesPanel({ sessionId, enableEditor, className, treeContainerClassName, title, rootPath, readOnly, expandedDirs: controlledExpandedDirs, onExpandedDirsChange, onShareFile, onSync, allowDelete, topSlot, onOpenFile, listDir, queryKeyScope, }: WorkspaceFilesPanelProps): react_jsx_runtime.JSX.Element;
|
|
39
|
-
|
|
40
|
-
type FileEntry = Awaited<ReturnType<typeof listDir>>[number];
|
|
41
|
-
type ListDirFn = (sessionId: string, dirPath: string) => Promise<FileEntry[]>;
|
|
42
|
-
interface FileTreeProps {
|
|
43
|
-
sessionId: string | null;
|
|
44
|
-
checkActiveSession?: boolean;
|
|
45
|
-
enableEditor?: boolean;
|
|
46
|
-
expandedDirs?: Set<string>;
|
|
47
|
-
defaultExpandedDirs?: Set<string>;
|
|
48
|
-
onExpandedDirsChange?: (dirs: Set<string>) => void;
|
|
49
|
-
rootPath?: string;
|
|
50
|
-
readOnly?: boolean;
|
|
51
|
-
onShareFile?: (path: string, name: string) => Promise<void>;
|
|
52
|
-
allowDelete?: boolean;
|
|
53
|
-
onOpenFile?: (path: string, name: string) => Promise<void>;
|
|
54
|
-
listDir?: ListDirFn;
|
|
55
|
-
queryKeyScope?: readonly unknown[];
|
|
56
|
-
}
|
|
57
|
-
declare function FileTree({ sessionId, checkActiveSession, enableEditor, expandedDirs: controlledExpandedDirs, defaultExpandedDirs, onExpandedDirsChange, rootPath, readOnly, onShareFile, allowDelete, onOpenFile, listDir, queryKeyScope, }: FileTreeProps): react_jsx_runtime.JSX.Element;
|
|
58
|
-
|
|
59
|
-
export { FileTree, WorkspaceFilesPanel };
|
|
1
|
+
export { WorkspaceFilesPanel } from "./WorkspaceFilesPanel.js";
|
|
2
|
+
export { FileTree } from "./FileTree.js";
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "../../../chunk-H62LH2AG.js";
|
|
6
6
|
import {
|
|
7
7
|
resolveSessionFilePreviewTarget
|
|
8
|
-
} from "../../../chunk-
|
|
8
|
+
} from "../../../chunk-C2FKVGJU.js";
|
|
9
9
|
import {
|
|
10
10
|
apiFetchText,
|
|
11
11
|
copyFile,
|
|
@@ -19,12 +19,13 @@ import {
|
|
|
19
19
|
useChatStore,
|
|
20
20
|
useSessionStore,
|
|
21
21
|
useUiStore
|
|
22
|
-
} from "../../../chunk-
|
|
23
|
-
import "../../../chunk-
|
|
22
|
+
} from "../../../chunk-SBASG3M2.js";
|
|
23
|
+
import "../../../chunk-J3XVFPOV.js";
|
|
24
|
+
import "../../../chunk-34GDDOWY.js";
|
|
24
25
|
import {
|
|
25
26
|
cn
|
|
26
|
-
} from "../../../chunk-
|
|
27
|
-
import "../../../chunk-
|
|
27
|
+
} from "../../../chunk-7LEKQI47.js";
|
|
28
|
+
import "../../../chunk-JCJFFJ42.js";
|
|
28
29
|
import "../../../chunk-PZ5AY32C.js";
|
|
29
30
|
|
|
30
31
|
// src/react/components/workspace/WorkspaceFilesPanel.tsx
|