@workerdeck/ui 2.0.0 → 2.1.0
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/README.md +4 -4
- package/build/{SessionPanel-CE5AVkg6.mjs → SessionPanel-DrMj8Yv0.mjs} +6 -73
- package/build/SessionPanel-DrMj8Yv0.mjs.map +1 -0
- package/build/{SessionPanel-CUpq2yO-.d.mts → SessionPanel-My98j9RZ.d.mts} +2 -3
- package/build/index.d.mts +2 -22
- package/build/index.mjs +2 -2
- package/build/scoped.css +0 -4
- package/build/workspace.d.mts +2 -3
- package/build/workspace.mjs +2 -3
- package/build/workspace.mjs.map +1 -1
- package/package.json +4 -4
- package/src/components/agent/SessionPanel.tsx +1 -9
- package/src/components/agent/SessionWorkspace.tsx +0 -3
- package/src/index.ts +0 -1
- package/build/SessionPanel-CE5AVkg6.mjs.map +0 -1
- package/src/components/agent/held-sends.tsx +0 -73
|
@@ -99,7 +99,6 @@ interface SessionPanelProps {
|
|
|
99
99
|
stickyPrompt?: boolean;
|
|
100
100
|
transcriptDensity?: TranscriptDensity;
|
|
101
101
|
transcriptFont?: TranscriptFont;
|
|
102
|
-
midTurnSend?: 'fold' | 'hold';
|
|
103
102
|
controlsSurface?: 'internal' | 'external' | 'status';
|
|
104
103
|
onControls?: (controls: SessionControls | undefined) => void;
|
|
105
104
|
focusComposerOnClick?: boolean;
|
|
@@ -142,7 +141,7 @@ type SessionVitals = {
|
|
|
142
141
|
itemCount: number;
|
|
143
142
|
totalCostUsd: number;
|
|
144
143
|
};
|
|
145
|
-
declare function SessionPanel({ client, sessionId, header, panelSurface, statusSurface, statusPlacement, onOpenPanel, onVitals, transcriptVariant, transcriptDensity, transcriptFont,
|
|
144
|
+
declare function SessionPanel({ client, sessionId, header, panelSurface, statusSurface, statusPlacement, onOpenPanel, onVitals, transcriptVariant, transcriptDensity, transcriptFont, affordances, terminalMetrics, scrubber, bookmarks, onToggleBookmark, reveal, subagents, openSubagent, onSubagentChange, stickyPrompt, controlsSurface, onControls, focusComposerOnClick, unseen, readOnly, toolHost, clientTools, cacheTranscript, emptyState, onLinkClick, fontSize, className }: SessionPanelProps): import("react").JSX.Element;
|
|
146
145
|
//#endregion
|
|
147
146
|
export { permissionModeChoices as C, PermissionModeSelectProps as S, useAffordances as _, SessionVitals as a, PermissionModeMeta as b, TranscriptDensityProvider as c, TranscriptVariantProvider as d, useTranscriptDensity as f, WithActions as g, TerminalAffordances as h, SessionSurfacePanel as i, TranscriptFont as l, CopyAction as m, SessionPanel as n, TerminalMetrics as o, useTranscriptVariant as p, SessionPanelProps as r, TranscriptDensity as s, SessionControls as t, TranscriptVariant as u, PERMISSION_MODES as v, permissionModeMeta as w, PermissionModeSelect as x, PermissionModeChoice as y };
|
|
148
|
-
//# sourceMappingURL=SessionPanel-
|
|
147
|
+
//# sourceMappingURL=SessionPanel-My98j9RZ.d.mts.map
|
package/build/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as formatCountdown, c as formatRateLimitWindowLong, d as friendlyModel, f as rateLimitWindowSeconds, i as formatCost, l as formatRelativeTime, n as formatAgoPrecise, o as formatDuration, p as toolInputPreview, r as formatBytes, s as formatRateLimitWindow, u as formatTokens } from "./format-TVRJzYUj.mjs";
|
|
2
|
-
import { C as permissionModeChoices, S as PermissionModeSelectProps, _ as useAffordances, a as SessionVitals, b as PermissionModeMeta, c as TranscriptDensityProvider, d as TranscriptVariantProvider, f as useTranscriptDensity, g as WithActions, h as TerminalAffordances, i as SessionSurfacePanel, l as TranscriptFont, m as CopyAction, n as SessionPanel, o as TerminalMetrics, p as useTranscriptVariant, r as SessionPanelProps, s as TranscriptDensity, t as SessionControls, u as TranscriptVariant, v as PERMISSION_MODES, w as permissionModeMeta, x as PermissionModeSelect, y as PermissionModeChoice } from "./SessionPanel-
|
|
2
|
+
import { C as permissionModeChoices, S as PermissionModeSelectProps, _ as useAffordances, a as SessionVitals, b as PermissionModeMeta, c as TranscriptDensityProvider, d as TranscriptVariantProvider, f as useTranscriptDensity, g as WithActions, h as TerminalAffordances, i as SessionSurfacePanel, l as TranscriptFont, m as CopyAction, n as SessionPanel, o as TerminalMetrics, p as useTranscriptVariant, r as SessionPanelProps, s as TranscriptDensity, t as SessionControls, u as TranscriptVariant, v as PERMISSION_MODES, w as permissionModeMeta, x as PermissionModeSelect, y as PermissionModeChoice } from "./SessionPanel-My98j9RZ.mjs";
|
|
3
3
|
import { ButtonHTMLAttributes, FunctionComponent, HTMLAttributes, InputHTMLAttributes, ReactElement, ReactNode, Ref, RefObject, TextareaHTMLAttributes } from "react";
|
|
4
4
|
import { VariantProps } from "class-variance-authority";
|
|
5
5
|
import { ClassValue } from "clsx";
|
|
@@ -832,26 +832,6 @@ declare function ToolTitleProvider({ value, children }: {
|
|
|
832
832
|
}): import("react").JSX.Element;
|
|
833
833
|
declare function useToolTitle(name: string): string | undefined;
|
|
834
834
|
//#endregion
|
|
835
|
-
//#region src/components/agent/held-sends.d.ts
|
|
836
|
-
type HeldSend = {
|
|
837
|
-
text: string;
|
|
838
|
-
attachmentIds: string[];
|
|
839
|
-
};
|
|
840
|
-
type HeldSends = {
|
|
841
|
-
held: HeldSend[];
|
|
842
|
-
submit: (text: string, attachmentIds: string[]) => void;
|
|
843
|
-
flush: () => void;
|
|
844
|
-
};
|
|
845
|
-
declare function useHeldSends(options: {
|
|
846
|
-
hold: boolean;
|
|
847
|
-
busy: boolean;
|
|
848
|
-
send: (text: string, attachmentIds: string[]) => void;
|
|
849
|
-
}): HeldSends;
|
|
850
|
-
declare function HeldSendsBar({ held, onSendNow }: {
|
|
851
|
-
held: HeldSend[];
|
|
852
|
-
onSendNow: () => void;
|
|
853
|
-
}): import("react").JSX.Element | null;
|
|
854
|
-
//#endregion
|
|
855
835
|
//#region src/components/agent/FileCard.d.ts
|
|
856
836
|
type FileDeliveredItem = Extract<TranscriptItem, {
|
|
857
837
|
kind: 'file_delivered';
|
|
@@ -1210,5 +1190,5 @@ declare function copyText(value: string): Promise<boolean>;
|
|
|
1210
1190
|
declare function toolIcon(toolName: string): LucideIcon;
|
|
1211
1191
|
declare function isMutatingTool(toolName: string): boolean;
|
|
1212
1192
|
//#endregion
|
|
1213
|
-
export { AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger, Badge, type BadgeProps, Band, Blank, Button, type ButtonProps, Card, CardContent, CardHeader, CardTitle, type ChipSegment, CodeBlock, type CodeBlockProps, Composer, type ComposerFileMatch, type ComposerHandle, type ComposerProps, ContextDialog, type ContextDialogProps, ContextRing, Conversation, ConversationContent, type ConversationProps, ConversationScrollButton, CopyAction, CopyButton, type CopyButtonProps, Dialog, DialogBody, DialogClose, DialogContent, DialogHeader, DialogRow, DialogTrigger, Empty, EmptyKey, EngineIcon, FileCard, type FileCardProps, type FileDeliveredItem,
|
|
1193
|
+
export { AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger, Badge, type BadgeProps, Band, Blank, Button, type ButtonProps, Card, CardContent, CardHeader, CardTitle, type ChipSegment, CodeBlock, type CodeBlockProps, Composer, type ComposerFileMatch, type ComposerHandle, type ComposerProps, ContextDialog, type ContextDialogProps, ContextRing, Conversation, ConversationContent, type ConversationProps, ConversationScrollButton, CopyAction, CopyButton, type CopyButtonProps, Dialog, DialogBody, DialogClose, DialogContent, DialogHeader, DialogRow, DialogTrigger, Empty, EmptyKey, EngineIcon, FileCard, type FileCardProps, type FileDeliveredItem, HostFilesDialog, type HostFilesDialogProps, Ink, Input, Loader, McpDialog, type McpDialogProps, Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Message, MessageContent, type MessageProps, ModelSelect, type ModelSelectProps, PERMISSION_MODES, type PermissionModeChoice, type PermissionModeMeta, PermissionModeSelect, type PermissionModeSelectProps, PermissionPrompt, type PermissionPromptProps, ProgressRing, type ProgressRingProps, ProjectIcon, PromptArea, type PromptAreaHandle, type PromptAreaProps, PromptTokenText, QUESTION_BEHAVIORS, type QuestionBehaviorMeta, QuestionPrompt, type QuestionPromptProps, Reasoning, type ReasoningProps, Response, type ResponseProps, Row, type RowProps, STATUS_META, type Segment, Select, SelectContent, SelectItem, SelectItemText, SelectTrigger, SelectValue, SessionBrowser, type SessionBrowserProps, type SessionControls, SessionEmptyState, type SessionEmptyStateProps, SessionInfoDialog, type SessionInfoDialogProps, SessionItem, type SessionItemProps, SessionList, SessionListItem, type SessionListItemProps, type SessionListProps, SessionPanel, type SessionPanelProps, SessionStatusIcon, type SessionSurfacePanel, type SessionVitals, SkillsDialog, type SkillsDialogProps, Spinner, Splitter, type SplitterProps, StatusBar, type StatusBarProps, type Step, StepRow, StepToggle, SubagentStrip, TaskList, type TaskListProps, TasksDialog, type TasksDialogProps, type TerminalAffordances, TerminalDiff, TerminalItemView, TerminalMarkdown, type TerminalMarkdownProps, type TerminalMetrics, TerminalPermissionPrompt, type TerminalPermissionPromptProps, TerminalQuestionPrompt, type TerminalQuestionPromptProps, TerminalStatusLine, type TerminalStatusLineProps, TerminalSurface, type TerminalSurfaceProps, TerminalTranscript, type TerminalTranscriptProps, type TextSegment, Textarea, Tip, Toaster, type Tone, ToolCallCard, type ToolCallCardProps, type ToolCallItem, ToolTitleProvider, TooltipContent, TooltipProvider, Transcript, type TranscriptDensity, TranscriptDensityProvider, type TranscriptFont, type TranscriptProps, type TranscriptVariant, TranscriptVariantProvider, type TriggerConfig, type TriggerSuggestion, UsageDialog, type UsageDialogProps, UsageMeters, WithActions, badgeVariants, buttonVariants, cn, commandTrigger, copyText, engineMark, formatAgoPrecise, formatBytes, formatCost, formatCountdown, formatDuration, formatRateLimitWindow, formatRateLimitWindowLong, formatRelativeTime, formatTokens, friendlyModel, getChipsByTrigger, hashtagTrigger, isMutatingTool, isSegmentsEmpty, mentionTrigger, parseUserQuestions, permissionModeChoices, permissionModeMeta, plainTextToSegments, previewPatch, rateLimitWindowSeconds, rowShapeClass, runningSteps, segmentsToPlainText, sessionSteps, skillPrompt, toast, toolIcon, toolInputPreview, useAffordances, useMinuteClock, usePromptAreaState, useToolTitle, useTranscriptDensity, useTranscriptVariant, vendorMarkClass, vendorTextClass };
|
|
1214
1194
|
//# sourceMappingURL=index.d.mts.map
|
package/build/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as Ink, A as PERMISSION_MODES, At as DialogHeader, B as TaskList, Bt as SelectItem, C as TerminalPermissionPrompt, Ct as Tip, D as SubagentStrip, Dt as DialogBody, E as parseUserQuestions, Et as Dialog, F as SkillsDialog, Ft as MenuItem, G as TerminalSurface, Gt as Input, H as contextNote, Ht as SelectTrigger, I as McpDialog, It as MenuSeparator, J as TerminalMarkdown, Jt as Button, K as ToolTitleProvider, Kt as Badge, L as HostFilesDialog, Lt as MenuTrigger, M as permissionModeChoices, Mt as DialogTrigger, N as permissionModeMeta, Nt as Menu, O as PermissionPrompt, Ot as DialogClose, P as ModelSelect, Pt as MenuContent, Q as Blank, Rt as Select, S as TerminalQuestionPrompt, St as copyText, T as QuestionPrompt, Tt as TooltipProvider, U as Composer, Ut as SelectValue, V as ContextDialog, Vt as SelectItemText, W as skillPrompt, Wt as PortalScope, X as previewPatch, Xt as cn, Y as TerminalDiff, Yt as buttonVariants, Z as Band, _ as ConversationContent, _t as ProgressRing, a as Transcript, at as toolIcon, b as STATUS_META, bt as Spinner, c as PromptTokenText, ct as useTranscriptDensity, d as FileCard, dt as hashtagTrigger, et as Row, f as TerminalItemView, ft as mentionTrigger, g as Conversation, gt as segmentsToPlainText, h as Loader, ht as plainTextToSegments, i as useMinuteClock, it as isMutatingTool, j as PermissionModeSelect, jt as DialogRow, k as Response, kt as DialogContent, l as Message, lt as useTranscriptVariant, m as SessionEmptyState, mt as PromptArea, n as UsageDialog, nt as WithActions, o as ToolCallCard, ot as TranscriptDensityProvider, p as TerminalTranscript, pt as usePromptAreaState, q as useToolTitle, qt as badgeVariants, r as UsageMeters, rt as useAffordances, s as Reasoning, st as TranscriptVariantProvider, t as SessionPanel, tt as CopyAction, u as MessageContent, ut as commandTrigger, v as ConversationScrollButton, vt as Splitter, w as QUESTION_BEHAVIORS, wt as TooltipContent, x as SessionInfoDialog, xt as CopyButton, y as StatusBar, yt as CodeBlock, z as TasksDialog, zt as SelectContent } from "./SessionPanel-DrMj8Yv0.mjs";
|
|
2
2
|
import { C as toolInputPreview, S as rateLimitWindowSeconds, _ as formatRateLimitWindow, b as formatTokens, c as tightestWindow, f as formatAgoPrecise, g as formatDuration, h as formatCountdown, i as meterSeverity, m as formatCost, o as modelLabel, p as formatBytes, r as meterColorClass, s as statusPresentation, t as contextSeverity, u as windowLabel, v as formatRateLimitWindowLong, x as friendlyModel, y as formatRelativeTime } from "./status-C4TAgVSc.mjs";
|
|
3
3
|
import { Fragment, forwardRef, useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1089,6 +1089,6 @@ function OneOfSelect({ label, value, options, onChange }) {
|
|
|
1089
1089
|
});
|
|
1090
1090
|
}
|
|
1091
1091
|
//#endregion
|
|
1092
|
-
export { AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger, Badge, Band, Blank, Button, Card, CardContent, CardHeader, CardTitle, CodeBlock, Composer, ContextDialog, ContextRing, Conversation, ConversationContent, ConversationScrollButton, CopyAction, CopyButton, Dialog, DialogBody, DialogClose, DialogContent, DialogHeader, DialogRow, DialogTrigger, Empty, EmptyKey, EngineIcon, FileCard,
|
|
1092
|
+
export { AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger, Badge, Band, Blank, Button, Card, CardContent, CardHeader, CardTitle, CodeBlock, Composer, ContextDialog, ContextRing, Conversation, ConversationContent, ConversationScrollButton, CopyAction, CopyButton, Dialog, DialogBody, DialogClose, DialogContent, DialogHeader, DialogRow, DialogTrigger, Empty, EmptyKey, EngineIcon, FileCard, HostFilesDialog, Ink, Input, Loader, McpDialog, Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Message, MessageContent, ModelSelect, PERMISSION_MODES, PermissionModeSelect, PermissionPrompt, ProgressRing, ProjectIcon, PromptArea, PromptTokenText, QUESTION_BEHAVIORS, QuestionPrompt, Reasoning, Response, Row, STATUS_META, Select, SelectContent, SelectItem, SelectItemText, SelectTrigger, SelectValue, SessionBrowser, SessionEmptyState, SessionInfoDialog, SessionItem, SessionList, SessionListItem, SessionPanel, SessionStatusIcon, SkillsDialog, Spinner, Splitter, StatusBar, StepRow, StepToggle, SubagentStrip, TaskList, TasksDialog, TerminalDiff, TerminalItemView, TerminalMarkdown, TerminalPermissionPrompt, TerminalQuestionPrompt, TerminalStatusLine, TerminalSurface, TerminalTranscript, Textarea, Tip, Toaster, ToolCallCard, ToolTitleProvider, TooltipContent, TooltipProvider, Transcript, TranscriptDensityProvider, TranscriptVariantProvider, UsageDialog, UsageMeters, WithActions, badgeVariants, buttonVariants, cn, commandTrigger, copyText, engineMark, formatAgoPrecise, formatBytes, formatCost, formatCountdown, formatDuration, formatRateLimitWindow, formatRateLimitWindowLong, formatRelativeTime, formatTokens, friendlyModel, getChipsByTrigger, hashtagTrigger, isMutatingTool, isSegmentsEmpty, mentionTrigger, parseUserQuestions, permissionModeChoices, permissionModeMeta, plainTextToSegments, previewPatch, rateLimitWindowSeconds, rowShapeClass, runningSteps, segmentsToPlainText, sessionSteps, skillPrompt, toast, toolIcon, toolInputPreview, useAffordances, useMinuteClock, usePromptAreaState, useToolTitle, useTranscriptDensity, useTranscriptVariant, vendorMarkClass, vendorTextClass };
|
|
1093
1093
|
|
|
1094
1094
|
//# sourceMappingURL=index.mjs.map
|
package/build/scoped.css
CHANGED
|
@@ -1670,10 +1670,6 @@
|
|
|
1670
1670
|
.wd-root .opacity-70 {
|
|
1671
1671
|
opacity: 70%;
|
|
1672
1672
|
}
|
|
1673
|
-
.wd-root .shadow {
|
|
1674
|
-
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
|
1675
|
-
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
1676
|
-
}
|
|
1677
1673
|
.wd-root .shadow-\(--shadow-lg\) {
|
|
1678
1674
|
--tw-shadow: var(--shadow-lg);
|
|
1679
1675
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
package/build/workspace.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as SessionPanelProps } from "./SessionPanel-
|
|
1
|
+
import { r as SessionPanelProps } from "./SessionPanel-My98j9RZ.mjs";
|
|
2
2
|
import { CSSProperties } from "react";
|
|
3
3
|
import { OpenFile, UseHostFileSearchResult, UseHostFileTreeResult } from "@workerdeck/react";
|
|
4
4
|
import { WorkerDeckClient } from "@workerdeck/client";
|
|
@@ -10,7 +10,6 @@ interface SessionWorkspaceProps {
|
|
|
10
10
|
transcriptVariant?: SessionPanelProps['transcriptVariant'];
|
|
11
11
|
transcriptDensity?: SessionPanelProps['transcriptDensity'];
|
|
12
12
|
transcriptFont?: SessionPanelProps['transcriptFont'];
|
|
13
|
-
midTurnSend?: SessionPanelProps['midTurnSend'];
|
|
14
13
|
scrubber?: SessionPanelProps['scrubber'];
|
|
15
14
|
bookmarks?: SessionPanelProps['bookmarks'];
|
|
16
15
|
onToggleBookmark?: SessionPanelProps['onToggleBookmark'];
|
|
@@ -34,7 +33,7 @@ interface SessionWorkspaceProps {
|
|
|
34
33
|
}) => void;
|
|
35
34
|
className?: string;
|
|
36
35
|
}
|
|
37
|
-
declare function SessionWorkspace({ client, sessionId, header, transcriptVariant, transcriptDensity, transcriptFont,
|
|
36
|
+
declare function SessionWorkspace({ client, sessionId, header, transcriptVariant, transcriptDensity, transcriptFont, scrubber, bookmarks, onToggleBookmark, stickyPrompt, openSubagent, reveal, subagents, onSubagentChange, statusPlacement, controlsSurface, fontSize, onLinkClick, unseen, readOnly, onVitals, defaultRailWidth, defaultRailCollapsed, onRailChange, className }: SessionWorkspaceProps): import("react").JSX.Element;
|
|
38
37
|
//#endregion
|
|
39
38
|
//#region src/components/agent/FileTree.d.ts
|
|
40
39
|
interface FileTreeProps {
|
package/build/workspace.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ct as Tip, Gt as Input, Jt as Button, R as EntryIcon, Tt as TooltipProvider, Xt as cn, bt as Spinner, t as SessionPanel, vt as Splitter } from "./SessionPanel-DrMj8Yv0.mjs";
|
|
2
2
|
import { p as formatBytes } from "./status-C4TAgVSc.mjs";
|
|
3
3
|
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
4
4
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -661,7 +661,7 @@ const RAIL_MIN = 180;
|
|
|
661
661
|
const RAIL_MAX = 520;
|
|
662
662
|
const AGENT_MIN = 220;
|
|
663
663
|
const EDITOR_MIN = 120;
|
|
664
|
-
function SessionWorkspace({ client, sessionId, header, transcriptVariant, transcriptDensity, transcriptFont,
|
|
664
|
+
function SessionWorkspace({ client, sessionId, header, transcriptVariant, transcriptDensity, transcriptFont, scrubber, bookmarks, onToggleBookmark, stickyPrompt, openSubagent, reveal, subagents, onSubagentChange, statusPlacement, controlsSurface, fontSize, onLinkClick, unseen, readOnly, onVitals, defaultRailWidth = 260, defaultRailCollapsed, onRailChange, className }) {
|
|
665
665
|
const { info } = useSessionInfo(client, sessionId);
|
|
666
666
|
const cwd = info?.cwd;
|
|
667
667
|
const tree = useHostFileTree(client, cwd);
|
|
@@ -785,7 +785,6 @@ function SessionWorkspace({ client, sessionId, header, transcriptVariant, transc
|
|
|
785
785
|
transcriptVariant,
|
|
786
786
|
transcriptDensity,
|
|
787
787
|
transcriptFont,
|
|
788
|
-
midTurnSend,
|
|
789
788
|
scrubber,
|
|
790
789
|
bookmarks,
|
|
791
790
|
onToggleBookmark,
|
package/build/workspace.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.mjs","names":[],"sources":["../src/components/agent/EditorTabs.tsx","../src/components/agent/FileTree.tsx","../src/components/agent/CodeEditor.tsx","../src/components/agent/FileViewer.tsx","../src/components/agent/use-path-links.ts","../src/components/agent/SessionWorkspace.tsx"],"sourcesContent":["import { useEffect, useRef, type MouseEvent as ReactMouseEvent } from 'react'\nimport { isDirty, type OpenFile } from '@workerdeck/react'\nimport { X } from 'lucide-react'\nimport { cn } from '../../lib/utils.ts'\nimport { Tip, TooltipProvider } from '../ui/Tooltip.tsx'\nimport { formatBytes } from '../../lib/format.ts'\n\nexport interface EditorTabsProps {\n files: OpenFile[]\n activePath?: string\n onActivate: (path: string) => void\n onClose: (path: string) => void\n className?: string\n}\n\nexport function EditorTabs({ files, activePath, onActivate, onClose, className }: EditorTabsProps) {\n return (\n <TooltipProvider delay={500} closeDelay={0}>\n <div\n data-slot=\"editor-tabs\"\n role=\"tablist\"\n aria-label=\"Open files\"\n className={cn('flex shrink-0 items-stretch overflow-x-auto border-b border-border bg-surface', className)}\n >\n {files.map((file) => (\n <Tab\n key={file.path}\n file={file}\n active={file.path === activePath}\n onActivate={() => onActivate(file.path)}\n onClose={() => onClose(file.path)}\n onArrow={(direction) => {\n const index = files.findIndex((f) => f.path === file.path)\n const next = files[index + direction]\n if (next) {\n onActivate(next.path)\n }\n }}\n />\n ))}\n </div>\n </TooltipProvider>\n )\n}\n\nfunction Tab({\n file,\n active,\n onActivate,\n onClose,\n onArrow,\n}: {\n file: OpenFile\n active: boolean\n onActivate: () => void\n onClose: () => void\n onArrow: (direction: 1 | -1) => void\n}) {\n const dirty = isDirty(file)\n const ref = useRef<HTMLDivElement>(null)\n useEffect(() => {\n if (active) {\n ref.current?.scrollIntoView({ block: 'nearest', inline: 'nearest' })\n }\n }, [active])\n\n const onAuxClick = (event: ReactMouseEvent) => {\n if (event.button !== 1) {\n return\n }\n event.preventDefault()\n onClose()\n }\n\n return (\n <Tip\n side=\"bottom\"\n render={\n <div\n ref={ref}\n role=\"tab\"\n tabIndex={active ? 0 : -1}\n aria-selected={active}\n onClick={onActivate}\n onAuxClick={onAuxClick}\n onKeyDown={(event) => {\n if (event.key === 'ArrowRight') {\n onArrow(1)\n } else if (event.key === 'ArrowLeft') {\n onArrow(-1)\n } else if (event.key === 'Enter' || event.key === ' ') {\n onActivate()\n } else {\n return\n }\n event.preventDefault()\n }}\n className={cn(\n 'group flex min-w-0 shrink-0 cursor-pointer items-center gap-1.5 border-r border-border px-3 py-1.5 transition-colors',\n 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent focus-visible:ring-inset',\n active ? 'bg-bg text-fg-1' : 'text-fg-3 hover:bg-surface-hover hover:text-fg-2',\n )}\n />\n }\n content={\n <span className=\"flex flex-col gap-0.5\">\n <span className=\"font-mono break-all\">{file.path}</span>\n {file.bytes !== undefined ? <span className=\"text-fg-4\">{formatBytes(file.bytes)}</span> : null}\n </span>\n }\n >\n <span className={cn('max-w-40 truncate font-mono text-label', dirty && 'italic')}>{file.name}</span>\n {file.status === 'error' ? <span className=\"shrink-0 text-danger\">!</span> : null}\n <button\n type=\"button\"\n aria-label={dirty ? `Close ${file.name} (unsaved changes)` : `Close ${file.name}`}\n onClick={(event) => {\n event.stopPropagation()\n onClose()\n }}\n className={cn(\n 'shrink-0 rounded p-0.5 text-fg-4 transition-opacity hover:bg-surface-hover hover:text-fg-1',\n active || dirty ? 'opacity-70' : 'opacity-0 group-hover:opacity-70 focus-visible:opacity-100',\n )}\n >\n <span className={cn('block', dirty && 'group-hover:hidden')}>\n {dirty ? <span className=\"block size-3 rounded-full bg-fg-2\" /> : <X className=\"size-3\" />}\n </span>\n {dirty ? (\n <span className=\"hidden group-hover:block\">\n <X className=\"size-3\" />\n </span>\n ) : null}\n </button>\n </Tip>\n )\n}\n","import { useEffect, useRef, useState, type CSSProperties, type ReactNode } from 'react'\nimport type { UseHostFileSearchResult, UseHostFileTreeResult } from '@workerdeck/react'\nimport type { HostFileMatch } from '@workerdeck/protocol'\nimport { ChevronRight, File, Folder, FolderOpen, PanelLeftClose, RefreshCw, Search, X } from 'lucide-react'\nimport { cn } from '../../lib/utils.ts'\nimport { Button } from '../ui/Button.tsx'\nimport { Input } from '../ui/Input.tsx'\nimport { Spinner } from '../ui/Spinner.tsx'\nimport { EntryIcon } from './EntryIcon.tsx'\n\nexport interface FileTreeProps {\n tree: UseHostFileTreeResult\n search?: UseHostFileSearchResult\n activePath?: string\n onOpenFile: (path: string) => void\n onCollapse?: () => void\n style?: CSSProperties\n className?: string\n}\n\nconst INDENT = 12\n\nexport function FileTree({ tree, search, activePath, onOpenFile, onCollapse, style, className }: FileTreeProps) {\n const [query, setQuery] = useState('')\n const [matches, setMatches] = useState<HostFileMatch[] | undefined>()\n const searching = query.trim().length > 0\n\n useEffect(() => {\n if (!search?.available) {\n return\n }\n const q = query.trim()\n if (!q) {\n setMatches(undefined)\n return\n }\n const controller = new AbortController()\n const timer = setTimeout(() => {\n void search.search(q, { limit: 60, signal: controller.signal }).then((found) => {\n if (!controller.signal.aborted) {\n setMatches(found)\n }\n })\n }, 150)\n return () => {\n controller.abort()\n clearTimeout(timer)\n }\n }, [search, query])\n\n return (\n <div data-slot=\"file-tree\" style={style} className={cn('flex min-h-0 min-w-0 flex-col bg-surface', className)}>\n <div className=\"flex items-center gap-1 px-2 pt-2\">\n {search?.available ? (\n <div className=\"relative min-w-0 flex-1\">\n <Search className=\"absolute top-1/2 left-2 size-3.5 -translate-y-1/2 text-fg-4\" />\n <Input\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search files…\"\n className=\"h-7 pr-7 pl-7 text-label\"\n spellCheck={false}\n />\n {searching ? (\n <button\n type=\"button\"\n onClick={() => setQuery('')}\n aria-label=\"Clear search\"\n className=\"absolute top-1/2 right-1.5 -translate-y-1/2 text-fg-4 transition-colors hover:text-fg-2\"\n >\n <X className=\"size-3.5\" />\n </button>\n ) : null}\n </div>\n ) : (\n <span className=\"min-w-0 flex-1 truncate px-1 text-label text-fg-4\">{tree.root}</span>\n )}\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label=\"Refresh the file tree\" onClick={() => tree.refresh()}>\n <RefreshCw className=\"size-3.5 text-fg-3\" />\n </Button>\n {onCollapse ? (\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label=\"Hide project files\" onClick={onCollapse}>\n <PanelLeftClose className=\"size-3.5 text-fg-3\" />\n </Button>\n ) : null}\n </div>\n\n <div className=\"min-h-0 flex-1 overflow-auto px-1 py-1\">\n {tree.error ? (\n <p className=\"px-2 py-3 text-body-sm text-danger\">{tree.error}</p>\n ) : searching ? (\n matches === undefined ? (\n <div className=\"py-6 text-center\">\n <Spinner className=\"size-4 text-fg-4\" />\n </div>\n ) : matches.length === 0 ? (\n <p className=\"px-2 py-6 text-center text-body-sm text-fg-4\">No matching files.</p>\n ) : (\n <ul>\n {matches.map((match) => (\n <li key={match.path}>\n <Row\n label={fileName(match.relative)}\n detail={directoryOf(match.relative)}\n title={match.relative}\n icon={<File className=\"size-3.5 shrink-0 text-fg-4\" />}\n active={match.path === activePath}\n onClick={() => onOpenFile(match.path)}\n />\n </li>\n ))}\n </ul>\n )\n ) : tree.loading ? (\n <div className=\"py-6 text-center\">\n <Spinner className=\"size-4 text-fg-4\" />\n </div>\n ) : tree.rows.length === 0 ? (\n <p className=\"px-2 py-6 text-center text-body-sm text-fg-4\">This project is empty.</p>\n ) : (\n <ul role=\"tree\" aria-label=\"Project files\">\n {tree.rows.map((row) => (\n <li key={row.entry.path} role=\"treeitem\" aria-expanded={row.expanded} aria-level={row.depth + 1}>\n <Row\n label={row.entry.name}\n indent={row.depth}\n active={row.entry.path === activePath}\n icon={\n row.entry.type === 'dir' ? (\n row.loading ? (\n <Spinner className=\"size-3.5 shrink-0 text-fg-4\" />\n ) : row.expanded ? (\n <FolderOpen className=\"size-3.5 shrink-0 text-accent\" />\n ) : (\n <Folder className=\"size-3.5 shrink-0 text-accent\" />\n )\n ) : (\n <EntryIcon type={row.entry.type} />\n )\n }\n chevron={\n row.entry.type === 'dir' ? (\n <ChevronRight className={cn('size-3 shrink-0 text-fg-4 transition-transform', row.expanded && 'rotate-90')} />\n ) : undefined\n }\n onClick={() => (row.entry.type === 'dir' ? tree.toggle(row.entry.path) : onOpenFile(row.entry.path))}\n />\n {row.truncated ? (\n <p className=\"truncate py-0.5 text-label text-fg-4\" style={{ paddingLeft: (row.depth + 1) * INDENT + 22 }}>\n More entries than the server will return — use search.\n </p>\n ) : null}\n </li>\n ))}\n </ul>\n )}\n </div>\n </div>\n )\n}\n\nfunction Row({\n label,\n detail,\n title,\n icon,\n chevron,\n indent = 0,\n active,\n onClick,\n}: {\n label: string\n detail?: string\n title?: string\n icon: ReactNode\n chevron?: ReactNode\n indent?: number\n active?: boolean\n onClick: () => void\n}) {\n const ref = useRef<HTMLButtonElement>(null)\n useEffect(() => {\n if (active) {\n ref.current?.scrollIntoView({ block: 'nearest' })\n }\n }, [active])\n\n return (\n <button\n ref={ref}\n type=\"button\"\n onClick={onClick}\n title={title ?? label}\n style={{ paddingLeft: indent * INDENT + 4 }}\n className={cn(\n 'flex w-full items-center gap-1 rounded py-1 pr-2 text-left transition-colors',\n active ? 'bg-surface-hover text-fg-1' : 'text-fg-2 hover:bg-surface-hover',\n )}\n >\n <span className=\"flex size-3 shrink-0 items-center justify-center\">{chevron}</span>\n {icon}\n <span className=\"shrink-0 truncate text-label\">{label}</span>\n {detail ? <span className=\"min-w-0 flex-1 truncate text-label text-fg-4\">{detail}</span> : null}\n </button>\n )\n}\n\nfunction fileName(relative: string): string {\n return relative.slice(relative.lastIndexOf('/') + 1)\n}\n\nfunction directoryOf(relative: string): string | undefined {\n const cut = relative.lastIndexOf('/')\n return cut === -1 ? undefined : relative.slice(0, cut)\n}\n","import { useEffect, useRef, useState } from 'react'\nimport type * as Monaco from 'monaco-editor'\nimport { cn } from '../../lib/utils.ts'\nimport { Spinner } from '../ui/Spinner.tsx'\n\nexport interface CodeEditorProps {\n path: string\n value: string\n onChange?: (value: string) => void\n onSave?: () => void\n readOnly?: boolean\n className?: string\n}\n\nexport function CodeEditor({ path, value, onChange, onSave, readOnly, className }: CodeEditorProps) {\n const host = useRef<HTMLDivElement>(null)\n const editor = useRef<Monaco.editor.IStandaloneCodeEditor | null>(null)\n const monaco = useRef<typeof Monaco | null>(null)\n const [ready, setReady] = useState(false)\n const theme = useDocumentTheme()\n\n const handlers = useRef({ onChange, onSave })\n handlers.current = { onChange, onSave }\n\n useEffect(() => {\n let disposed = false\n void loadMonaco().then((api) => {\n if (disposed || !host.current) {\n return\n }\n monaco.current = api\n const instance = api.editor.create(host.current, {\n value,\n language: languageOf(path),\n readOnly,\n automaticLayout: true,\n theme: monacoTheme(document.documentElement.getAttribute('data-theme')),\n minimap: { enabled: false },\n scrollBeyondLastLine: false,\n fontSize: 12,\n lineHeight: 20,\n fontFamily: 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace',\n renderLineHighlight: 'line',\n smoothScrolling: true,\n padding: { top: 8, bottom: 8 },\n scrollbar: { verticalScrollbarSize: 10, horizontalScrollbarSize: 10 },\n wordBasedSuggestions: 'off',\n quickSuggestions: false,\n })\n editor.current = instance\n instance.onDidChangeModelContent(() => {\n handlers.current.onChange?.(instance.getValue())\n })\n instance.addCommand(api.KeyMod.CtrlCmd | api.KeyCode.KeyS, () => {\n handlers.current.onSave?.()\n })\n setReady(true)\n })\n return () => {\n disposed = true\n // The editor, never its models: a model is keyed by path and outlives this mount, which is what restores a reopened tab's undo stack.\n editor.current?.dispose()\n editor.current = null\n setReady(false)\n }\n }, [])\n\n useEffect(() => {\n const api = monaco.current\n const instance = editor.current\n if (!api || !instance || !ready) {\n return\n }\n const uri = api.Uri.parse(`workerdeck://host${path}`)\n const model = api.editor.getModel(uri) ?? api.editor.createModel(value, languageOf(path), uri)\n if (instance.getModel() !== model) {\n instance.setModel(model)\n }\n }, [path, ready, value])\n\n useEffect(() => {\n const instance = editor.current\n if (!instance || !ready) {\n return\n }\n const model = instance.getModel()\n if (!model || model.getValue() === value) {\n return\n }\n model.pushEditOperations([], [{ range: model.getFullModelRange(), text: value }], () => null)\n }, [value, ready])\n\n useEffect(() => {\n if (ready) {\n editor.current?.updateOptions({ readOnly })\n }\n }, [readOnly, ready])\n\n useEffect(() => {\n if (ready) {\n monaco.current?.editor.setTheme(monacoTheme(theme))\n }\n }, [theme, ready])\n\n return (\n <div className={cn('relative min-h-0 min-w-0 flex-1', className)}>\n <div ref={host} className=\"absolute inset-0\" />\n {!ready ? (\n <div className=\"absolute inset-0 flex items-center justify-center bg-bg\">\n <Spinner className=\"size-4 text-fg-4\" />\n </div>\n ) : null}\n </div>\n )\n}\n\nfunction useDocumentTheme(): string | null {\n const [theme, setTheme] = useState<string | null>(() =>\n typeof document === 'undefined' ? null : document.documentElement.getAttribute('data-theme'),\n )\n useEffect(() => {\n const root = document.documentElement\n const sync = () => setTheme(root.getAttribute('data-theme'))\n sync()\n const observer = new MutationObserver(sync)\n observer.observe(root, { attributes: true, attributeFilter: ['data-theme'] })\n return () => observer.disconnect()\n }, [])\n return theme\n}\n\nfunction monacoTheme(theme: string | null): string {\n return theme === 'light' ? 'wd-light' : 'wd-dark'\n}\n\nlet monacoPromise: Promise<typeof Monaco> | undefined\nfunction loadMonaco(): Promise<typeof Monaco> {\n monacoPromise ??= (async () => {\n const api = await import('monaco-editor')\n api.editor.defineTheme('wd-dark', {\n base: 'vs-dark',\n inherit: true,\n rules: [],\n colors: { 'editor.background': '#00000000' },\n })\n api.editor.defineTheme('wd-light', {\n base: 'vs',\n inherit: true,\n rules: [],\n colors: { 'editor.background': '#00000000' },\n })\n return api\n })()\n return monacoPromise\n}\n\nfunction languageOf(path: string): string {\n const name = path.slice(path.lastIndexOf('/') + 1)\n const byName = FILENAME_LANGUAGES[name.toLowerCase()]\n if (byName) {\n return byName\n }\n const extension = name.slice(name.lastIndexOf('.') + 1).toLowerCase()\n return EXTENSION_LANGUAGES[extension] ?? 'plaintext'\n}\n\nconst FILENAME_LANGUAGES: Record<string, string> = {\n dockerfile: 'dockerfile',\n makefile: 'plaintext',\n '.gitignore': 'plaintext',\n '.env': 'shell',\n}\n\nconst EXTENSION_LANGUAGES: Record<string, string> = {\n ts: 'typescript',\n tsx: 'typescript',\n mts: 'typescript',\n cts: 'typescript',\n js: 'javascript',\n jsx: 'javascript',\n mjs: 'javascript',\n cjs: 'javascript',\n json: 'json',\n jsonc: 'json',\n md: 'markdown',\n mdx: 'markdown',\n css: 'css',\n scss: 'scss',\n less: 'less',\n html: 'html',\n htm: 'html',\n xml: 'xml',\n svg: 'xml',\n yml: 'yaml',\n yaml: 'yaml',\n toml: 'plaintext',\n sh: 'shell',\n bash: 'shell',\n zsh: 'shell',\n fish: 'shell',\n py: 'python',\n rb: 'ruby',\n rs: 'rust',\n go: 'go',\n swift: 'swift',\n java: 'java',\n kt: 'kotlin',\n c: 'c',\n h: 'c',\n cpp: 'cpp',\n cc: 'cpp',\n hpp: 'cpp',\n cs: 'csharp',\n php: 'php',\n sql: 'sql',\n graphql: 'graphql',\n gql: 'graphql',\n lua: 'lua',\n r: 'r',\n pl: 'perl',\n dart: 'dart',\n scala: 'scala',\n ini: 'ini',\n cfg: 'ini',\n conf: 'ini',\n txt: 'plaintext',\n log: 'plaintext',\n}\n","import type { ReactNode } from 'react'\nimport type { OpenFile } from '@workerdeck/react'\nimport { currentText, isDirty } from '@workerdeck/react'\nimport { FileWarning, TriangleAlert } from 'lucide-react'\nimport { cn } from '../../lib/utils.ts'\nimport { Button } from '../ui/Button.tsx'\nimport { Spinner } from '../ui/Spinner.tsx'\nimport { CodeEditor } from './CodeEditor.tsx'\n\nexport interface FileViewerProps {\n file: OpenFile | undefined\n canWrite?: boolean\n onChange?: (path: string, content: string) => void\n onSave?: (path: string) => void\n onRevert?: (path: string) => void\n onReload?: (path: string) => void\n onOverwrite?: (path: string) => void\n onDismissConflict?: (path: string) => void\n className?: string\n}\n\nexport function FileViewer({\n file,\n canWrite,\n onChange,\n onSave,\n onRevert,\n onReload,\n onOverwrite,\n onDismissConflict,\n className,\n}: FileViewerProps) {\n if (!file) {\n return null\n }\n\n return (\n <div data-slot=\"file-viewer\" className={cn('flex min-h-0 min-w-0 flex-1 flex-col bg-bg', className)}>\n {file.conflict ? (\n <div className=\"flex shrink-0 flex-wrap items-center gap-2 border-b border-warning/40 bg-warning-bg px-3 py-2\">\n <TriangleAlert className=\"size-3.5 shrink-0 text-warning\" />\n <span className=\"min-w-0 flex-1 text-body-sm text-warning\">This file changed on disk since you opened it.</span>\n <Button variant=\"outline\" size=\"xs\" onClick={() => onReload?.(file.path)}>\n Use the version on disk\n </Button>\n <Button variant=\"outline\" size=\"xs\" onClick={() => onOverwrite?.(file.path)}>\n Keep mine\n </Button>\n <Button variant=\"ghost\" size=\"xs\" onClick={() => onDismissConflict?.(file.path)}>\n Dismiss\n </Button>\n </div>\n ) : file.saveError ? (\n <div className=\"flex shrink-0 items-center gap-2 border-b border-danger/40 bg-danger-bg px-3 py-2\">\n <TriangleAlert className=\"size-3.5 shrink-0 text-danger\" />\n <span className=\"min-w-0 flex-1 text-body-sm text-danger\">{file.saveError}</span>\n <Button variant=\"ghost\" size=\"xs\" onClick={() => onDismissConflict?.(file.path)}>\n Dismiss\n </Button>\n </div>\n ) : null}\n\n {file.status === 'loading' ? (\n <Centred>\n <Spinner className=\"size-4 text-fg-4\" />\n </Centred>\n ) : file.status === 'error' ? (\n <Centred>\n <TriangleAlert className=\"size-4 text-danger\" />\n <p className=\"text-body-sm text-danger\">{file.error}</p>\n </Centred>\n ) : file.status === 'binary' ? (\n <Centred>\n <FileWarning className=\"size-4 text-fg-4\" />\n <p className=\"text-body-sm text-fg-4\">This file isn’t text.</p>\n <p className=\"text-label text-fg-4\">It can’t be edited here without corrupting it.</p>\n </Centred>\n ) : (\n <CodeEditor\n path={file.path}\n value={currentText(file)}\n readOnly={!canWrite}\n onChange={onChange ? (content) => onChange(file.path, content) : undefined}\n onSave={onSave ? () => onSave(file.path) : undefined}\n />\n )}\n\n {file.status === 'ready' && (file.saving || isDirty(file) || !canWrite) ? (\n <div className=\"flex shrink-0 items-center gap-2 border-t border-border px-3 py-1\">\n {file.saving ? (\n <>\n <Spinner className=\"size-3 text-fg-4\" />\n <span className=\"text-label text-fg-4\">Saving…</span>\n </>\n ) : !canWrite ? (\n <span className=\"text-label text-fg-4\">Read-only — this gateway doesn’t allow writes.</span>\n ) : (\n <>\n <span className=\"text-label text-fg-3\">Unsaved changes</span>\n <span className=\"flex-1\" />\n <Button variant=\"ghost\" size=\"xs\" onClick={() => onRevert?.(file.path)}>\n Revert\n </Button>\n <Button variant=\"outline\" size=\"xs\" onClick={() => onSave?.(file.path)}>\n Save\n <span className=\"ml-1 text-fg-4\">⌘S</span>\n </Button>\n </>\n )}\n </div>\n ) : null}\n </div>\n )\n}\n\nfunction Centred({ children }: { children: ReactNode }) {\n return <div className=\"flex min-h-0 flex-1 flex-col items-center justify-center gap-2 p-6\">{children}</div>\n}\n","import { useEffect, type RefObject } from 'react'\n\nexport type PathHit = { path: string; line?: number }\n\nconst LINKISH = 'wd-path-link'\n\nconst PATH_RE = /^(\\/[^\\s:'\"`()[\\]{}]+|[\\w.@~-]+(?:\\/[\\w.@~-]+)+)(?::(\\d+))?$/\nconst FILE_RE = /^([\\w.@-]+\\.[A-Za-z0-9]{1,10})(?::(\\d+))?$/\n\nconst COVERAGE = 0.6\n\nexport function matchPath(text: string, inCode: boolean): PathHit | undefined {\n const trimmed = text.trim()\n if (!trimmed || trimmed.endsWith('/')) {\n return undefined\n }\n const hit = PATH_RE.exec(trimmed) ?? (inCode ? FILE_RE.exec(trimmed) : null)\n if (!hit) {\n return undefined\n }\n return { path: hit[1]!, line: hit[2] ? Number(hit[2]) : undefined }\n}\n\nfunction hitFor(element: HTMLElement | undefined): PathHit | undefined {\n if (!element) {\n return undefined\n }\n const inCode = element.closest('code') !== null\n const text = element.textContent ?? ''\n const hit = matchPath(text, inCode)\n if (!hit) {\n return undefined\n }\n if (!inCode && hit.path.length < text.trim().length * COVERAGE) {\n return undefined\n }\n return hit\n}\n\nexport function usePathLinks({\n container,\n onOpen,\n enabled = true,\n ignore,\n}: {\n container: RefObject<HTMLElement | null>\n onOpen: (hit: PathHit) => void\n enabled?: boolean\n ignore?: string\n}) {\n useEffect(() => {\n const root = container.current\n if (!root || !enabled) {\n return\n }\n const excluded = (element: HTMLElement | undefined) =>\n ignore !== undefined && element?.closest(ignore) !== null && element !== undefined\n\n let marked: HTMLElement | undefined\n const unmark = () => {\n marked?.classList.remove(LINKISH)\n marked = undefined\n }\n\n const onClick = (event: MouseEvent) => {\n if (!event.metaKey && !event.ctrlKey) {\n return\n }\n const target = event.target instanceof HTMLElement ? event.target : undefined\n if (excluded(target)) {\n return\n }\n const hit = hitFor(target)\n if (!hit) {\n return\n }\n event.preventDefault()\n event.stopPropagation()\n unmark()\n onOpen(hit)\n }\n\n const onMove = (event: MouseEvent) => {\n if (!event.metaKey && !event.ctrlKey) {\n return unmark()\n }\n const element = event.target instanceof HTMLElement ? event.target : undefined\n if (element === marked) {\n return\n }\n unmark()\n if (!element || excluded(element) || !hitFor(element)) {\n return\n }\n marked = element\n element.classList.add(LINKISH)\n }\n\n const onKey = (event: KeyboardEvent) => {\n if (!event.metaKey && !event.ctrlKey) {\n unmark()\n }\n }\n\n root.addEventListener('click', onClick, true)\n root.addEventListener('mousemove', onMove)\n document.addEventListener('keydown', onKey)\n document.addEventListener('keyup', onKey)\n window.addEventListener('blur', unmark)\n return () => {\n unmark()\n root.removeEventListener('click', onClick, true)\n root.removeEventListener('mousemove', onMove)\n document.removeEventListener('keydown', onKey)\n document.removeEventListener('keyup', onKey)\n window.removeEventListener('blur', unmark)\n }\n }, [container, onOpen, enabled, ignore])\n}\n\nexport function resolveAgainstCwd(path: string, cwd: string | undefined): string {\n if (path.startsWith('/')) {\n return path\n }\n if (!cwd) {\n return path\n }\n return `${cwd.replace(/\\/$/, '')}/${path.replace(/^\\.\\//, '')}`\n}\n","import { useCallback, useEffect, useLayoutEffect, useRef, useState, type RefObject } from 'react'\nimport { createPortal } from 'react-dom'\nimport type { WorkerDeckClient } from '@workerdeck/client'\nimport { useHostFileRoots, useHostFileSearch, useHostFileTree, useOpenFiles, useSessionInfo, isDirty } from '@workerdeck/react'\nimport { PanelLeftOpen } from 'lucide-react'\nimport { cn } from '../../lib/utils.ts'\nimport { Button } from '../ui/Button.tsx'\nimport { Splitter } from '../ui/Splitter.tsx'\nimport { EditorTabs } from './EditorTabs.tsx'\nimport { FileTree } from './FileTree.tsx'\nimport { FileViewer } from './FileViewer.tsx'\nimport { SessionPanel, type SessionPanelProps } from './SessionPanel.tsx'\nimport { resolveAgainstCwd, usePathLinks } from './use-path-links.ts'\n\nexport interface SessionWorkspaceProps {\n client: WorkerDeckClient\n sessionId: string | undefined\n header?: SessionPanelProps['header']\n transcriptVariant?: SessionPanelProps['transcriptVariant']\n transcriptDensity?: SessionPanelProps['transcriptDensity']\n transcriptFont?: SessionPanelProps['transcriptFont']\n midTurnSend?: SessionPanelProps['midTurnSend']\n scrubber?: SessionPanelProps['scrubber']\n bookmarks?: SessionPanelProps['bookmarks']\n onToggleBookmark?: SessionPanelProps['onToggleBookmark']\n stickyPrompt?: SessionPanelProps['stickyPrompt']\n openSubagent?: SessionPanelProps['openSubagent']\n reveal?: SessionPanelProps['reveal']\n subagents?: SessionPanelProps['subagents']\n onSubagentChange?: SessionPanelProps['onSubagentChange']\n statusPlacement?: SessionPanelProps['statusPlacement']\n controlsSurface?: SessionPanelProps['controlsSurface']\n fontSize?: SessionPanelProps['fontSize']\n onLinkClick?: SessionPanelProps['onLinkClick']\n unseen?: SessionPanelProps['unseen']\n readOnly?: SessionPanelProps['readOnly']\n onVitals?: SessionPanelProps['onVitals']\n defaultRailWidth?: number\n defaultRailCollapsed?: boolean\n onRailChange?: (rail: { width: number; collapsed: boolean }) => void\n className?: string\n}\n\nconst RAIL_MIN = 180\nconst RAIL_MAX = 520\nconst AGENT_MIN = 220\nconst EDITOR_MIN = 120\n\nexport function SessionWorkspace({\n client,\n sessionId,\n header,\n transcriptVariant,\n transcriptDensity,\n transcriptFont,\n midTurnSend,\n scrubber,\n bookmarks,\n onToggleBookmark,\n stickyPrompt,\n openSubagent,\n reveal,\n subagents,\n onSubagentChange,\n statusPlacement,\n controlsSurface,\n fontSize,\n onLinkClick,\n unseen,\n readOnly,\n onVitals,\n defaultRailWidth = 260,\n defaultRailCollapsed,\n onRailChange,\n className,\n}: SessionWorkspaceProps) {\n const { info } = useSessionInfo(client, sessionId)\n const cwd = info?.cwd\n\n const tree = useHostFileTree(client, cwd)\n const search = useHostFileSearch(client, cwd)\n const files = useOpenFiles(client)\n const { canWrite } = useHostFileRoots(client)\n\n useEffect(() => {\n if (!files.hasUnsaved) {\n return\n }\n const warn = (event: BeforeUnloadEvent) => event.preventDefault()\n window.addEventListener('beforeunload', warn)\n return () => window.removeEventListener('beforeunload', warn)\n }, [files.hasUnsaved])\n\n const wide = useIsWide()\n const [railCollapsed, setRailCollapsed] = useState(defaultRailCollapsed ?? false)\n const [railWidth, setRailWidth] = useState(defaultRailWidth)\n const onRailChangeRef = useRef(onRailChange)\n onRailChangeRef.current = onRailChange\n useEffect(() => {\n onRailChangeRef.current?.({ width: railWidth, collapsed: railCollapsed })\n }, [railWidth, railCollapsed])\n const [editorHeight, setEditorHeight] = useState(360)\n\n const hasFiles = files.files.length > 0\n\n const overlayRail = !wide\n const railOpen = tree.available && !railCollapsed\n useEffect(() => {\n if (overlayRail) {\n setRailCollapsed(true)\n }\n }, [overlayRail])\n\n const closeTab = useCallback(\n (path: string) => {\n const file = files.files.find((f) => f.path === path)\n if (file && isDirty(file)) {\n const name = file.name\n if (!window.confirm(`${name} has unsaved changes. Close it and lose them?`)) {\n return\n }\n }\n files.close(path)\n },\n [files],\n )\n\n const column = useRef<HTMLDivElement>(null)\n const columnHeight = useElementHeight(column)\n const openPath = useCallback(({ path }: { path: string }) => files.open(resolveAgainstCwd(path, cwd)), [files.open, cwd])\n usePathLinks({\n container: column,\n onOpen: openPath,\n enabled: tree.available,\n ignore: '.monaco-editor',\n })\n const editorMax = Math.max(EDITOR_MIN, columnHeight - AGENT_MIN)\n\n const [topBar, setTopBar] = useState<HTMLDivElement | null>(null)\n const hoisted: SessionPanelProps['header'] =\n header === undefined || topBar === null\n ? undefined\n : typeof header === 'function'\n ? (slots) => createPortal(header(slots), topBar)\n : createPortal(header, topBar)\n\n return (\n <div data-slot=\"session-workspace\" className={cn('flex h-full min-h-0 w-full flex-col overflow-hidden bg-bg', className)}>\n {header !== undefined ? <div ref={setTopBar} className=\"shrink-0\" /> : null}\n <div className=\"relative flex min-h-0 flex-1\">\n {railOpen ? (\n <FileTree\n tree={tree}\n search={search}\n activePath={files.activePath}\n onOpenFile={files.open}\n onCollapse={() => setRailCollapsed(true)}\n style={{ width: overlayRail ? Math.min(railWidth, 320) : railWidth }}\n className={cn('shrink-0 border-r border-border', overlayRail && 'absolute inset-y-0 left-0 z-20 shadow-lg')}\n />\n ) : tree.available ? (\n <div className=\"flex w-8 shrink-0 flex-col items-center border-r border-border bg-surface pt-1.5\">\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label=\"Show project files\" onClick={() => setRailCollapsed(false)}>\n <PanelLeftOpen className=\"size-4 text-fg-3\" />\n </Button>\n </div>\n ) : null}\n {railOpen && !overlayRail ? (\n <Splitter\n orientation=\"vertical\"\n value={railWidth}\n onValueChange={setRailWidth}\n min={RAIL_MIN}\n max={RAIL_MAX}\n defaultValue={defaultRailWidth}\n aria-label=\"Resize the file tree\"\n />\n ) : null}\n\n <div ref={column} className=\"flex min-h-0 min-w-0 flex-1 flex-col\">\n {hasFiles ? (\n <div\n className=\"flex min-h-0 shrink-0 flex-col overflow-hidden\"\n style={{ height: Math.min(editorHeight, editorMax || editorHeight) }}\n >\n <EditorTabs files={files.files} activePath={files.activePath} onActivate={files.activate} onClose={closeTab} />\n <FileViewer\n file={files.active}\n canWrite={canWrite}\n onChange={files.edit}\n onSave={(path) => void files.save(path)}\n onRevert={files.revert}\n onReload={files.reload}\n onOverwrite={(path) => void files.overwrite(path)}\n onDismissConflict={files.dismissConflict}\n />\n </div>\n ) : null}\n {hasFiles ? (\n <Splitter\n orientation=\"horizontal\"\n value={Math.min(editorHeight, editorMax || editorHeight)}\n onValueChange={setEditorHeight}\n min={EDITOR_MIN}\n max={editorMax}\n aria-label=\"Resize the open file\"\n />\n ) : null}\n <SessionPanel\n client={client}\n sessionId={sessionId}\n header={hoisted}\n transcriptVariant={transcriptVariant}\n transcriptDensity={transcriptDensity}\n transcriptFont={transcriptFont}\n midTurnSend={midTurnSend}\n scrubber={scrubber}\n bookmarks={bookmarks}\n onToggleBookmark={onToggleBookmark}\n stickyPrompt={stickyPrompt}\n openSubagent={openSubagent}\n reveal={reveal}\n subagents={subagents}\n onSubagentChange={onSubagentChange}\n controlsSurface={controlsSurface}\n fontSize={fontSize}\n onLinkClick={onLinkClick}\n statusPlacement={statusPlacement}\n unseen={unseen}\n readOnly={readOnly}\n onVitals={onVitals}\n className=\"min-h-0 flex-1\"\n />\n </div>\n\n {overlayRail && railOpen ? (\n <button\n type=\"button\"\n aria-label=\"Close the file tree\"\n onClick={() => setRailCollapsed(true)}\n className=\"absolute inset-0 z-10 bg-black/30\"\n />\n ) : null}\n </div>\n </div>\n )\n}\n\nfunction useElementHeight(ref: RefObject<HTMLElement | null>): number {\n const [height, setHeight] = useState(0)\n useLayoutEffect(() => {\n const element = ref.current\n if (!element) {\n return\n }\n const observer = new ResizeObserver(([entry]) => {\n if (entry) {\n setHeight(entry.contentRect.height)\n }\n })\n observer.observe(element)\n return () => observer.disconnect()\n }, [ref])\n return height\n}\n\nfunction useIsWide(): boolean {\n const [wide, setWide] = useState(true)\n useEffect(() => {\n const query = window.matchMedia('(min-width: 768px)')\n const sync = () => setWide(query.matches)\n sync()\n query.addEventListener('change', sync)\n return () => query.removeEventListener('change', sync)\n }, [])\n return wide\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"workspace.mjs","names":[],"sources":["../src/components/agent/EditorTabs.tsx","../src/components/agent/FileTree.tsx","../src/components/agent/CodeEditor.tsx","../src/components/agent/FileViewer.tsx","../src/components/agent/use-path-links.ts","../src/components/agent/SessionWorkspace.tsx"],"sourcesContent":["import { useEffect, useRef, type MouseEvent as ReactMouseEvent } from 'react'\nimport { isDirty, type OpenFile } from '@workerdeck/react'\nimport { X } from 'lucide-react'\nimport { cn } from '../../lib/utils.ts'\nimport { Tip, TooltipProvider } from '../ui/Tooltip.tsx'\nimport { formatBytes } from '../../lib/format.ts'\n\nexport interface EditorTabsProps {\n files: OpenFile[]\n activePath?: string\n onActivate: (path: string) => void\n onClose: (path: string) => void\n className?: string\n}\n\nexport function EditorTabs({ files, activePath, onActivate, onClose, className }: EditorTabsProps) {\n return (\n <TooltipProvider delay={500} closeDelay={0}>\n <div\n data-slot=\"editor-tabs\"\n role=\"tablist\"\n aria-label=\"Open files\"\n className={cn('flex shrink-0 items-stretch overflow-x-auto border-b border-border bg-surface', className)}\n >\n {files.map((file) => (\n <Tab\n key={file.path}\n file={file}\n active={file.path === activePath}\n onActivate={() => onActivate(file.path)}\n onClose={() => onClose(file.path)}\n onArrow={(direction) => {\n const index = files.findIndex((f) => f.path === file.path)\n const next = files[index + direction]\n if (next) {\n onActivate(next.path)\n }\n }}\n />\n ))}\n </div>\n </TooltipProvider>\n )\n}\n\nfunction Tab({\n file,\n active,\n onActivate,\n onClose,\n onArrow,\n}: {\n file: OpenFile\n active: boolean\n onActivate: () => void\n onClose: () => void\n onArrow: (direction: 1 | -1) => void\n}) {\n const dirty = isDirty(file)\n const ref = useRef<HTMLDivElement>(null)\n useEffect(() => {\n if (active) {\n ref.current?.scrollIntoView({ block: 'nearest', inline: 'nearest' })\n }\n }, [active])\n\n const onAuxClick = (event: ReactMouseEvent) => {\n if (event.button !== 1) {\n return\n }\n event.preventDefault()\n onClose()\n }\n\n return (\n <Tip\n side=\"bottom\"\n render={\n <div\n ref={ref}\n role=\"tab\"\n tabIndex={active ? 0 : -1}\n aria-selected={active}\n onClick={onActivate}\n onAuxClick={onAuxClick}\n onKeyDown={(event) => {\n if (event.key === 'ArrowRight') {\n onArrow(1)\n } else if (event.key === 'ArrowLeft') {\n onArrow(-1)\n } else if (event.key === 'Enter' || event.key === ' ') {\n onActivate()\n } else {\n return\n }\n event.preventDefault()\n }}\n className={cn(\n 'group flex min-w-0 shrink-0 cursor-pointer items-center gap-1.5 border-r border-border px-3 py-1.5 transition-colors',\n 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent focus-visible:ring-inset',\n active ? 'bg-bg text-fg-1' : 'text-fg-3 hover:bg-surface-hover hover:text-fg-2',\n )}\n />\n }\n content={\n <span className=\"flex flex-col gap-0.5\">\n <span className=\"font-mono break-all\">{file.path}</span>\n {file.bytes !== undefined ? <span className=\"text-fg-4\">{formatBytes(file.bytes)}</span> : null}\n </span>\n }\n >\n <span className={cn('max-w-40 truncate font-mono text-label', dirty && 'italic')}>{file.name}</span>\n {file.status === 'error' ? <span className=\"shrink-0 text-danger\">!</span> : null}\n <button\n type=\"button\"\n aria-label={dirty ? `Close ${file.name} (unsaved changes)` : `Close ${file.name}`}\n onClick={(event) => {\n event.stopPropagation()\n onClose()\n }}\n className={cn(\n 'shrink-0 rounded p-0.5 text-fg-4 transition-opacity hover:bg-surface-hover hover:text-fg-1',\n active || dirty ? 'opacity-70' : 'opacity-0 group-hover:opacity-70 focus-visible:opacity-100',\n )}\n >\n <span className={cn('block', dirty && 'group-hover:hidden')}>\n {dirty ? <span className=\"block size-3 rounded-full bg-fg-2\" /> : <X className=\"size-3\" />}\n </span>\n {dirty ? (\n <span className=\"hidden group-hover:block\">\n <X className=\"size-3\" />\n </span>\n ) : null}\n </button>\n </Tip>\n )\n}\n","import { useEffect, useRef, useState, type CSSProperties, type ReactNode } from 'react'\nimport type { UseHostFileSearchResult, UseHostFileTreeResult } from '@workerdeck/react'\nimport type { HostFileMatch } from '@workerdeck/protocol'\nimport { ChevronRight, File, Folder, FolderOpen, PanelLeftClose, RefreshCw, Search, X } from 'lucide-react'\nimport { cn } from '../../lib/utils.ts'\nimport { Button } from '../ui/Button.tsx'\nimport { Input } from '../ui/Input.tsx'\nimport { Spinner } from '../ui/Spinner.tsx'\nimport { EntryIcon } from './EntryIcon.tsx'\n\nexport interface FileTreeProps {\n tree: UseHostFileTreeResult\n search?: UseHostFileSearchResult\n activePath?: string\n onOpenFile: (path: string) => void\n onCollapse?: () => void\n style?: CSSProperties\n className?: string\n}\n\nconst INDENT = 12\n\nexport function FileTree({ tree, search, activePath, onOpenFile, onCollapse, style, className }: FileTreeProps) {\n const [query, setQuery] = useState('')\n const [matches, setMatches] = useState<HostFileMatch[] | undefined>()\n const searching = query.trim().length > 0\n\n useEffect(() => {\n if (!search?.available) {\n return\n }\n const q = query.trim()\n if (!q) {\n setMatches(undefined)\n return\n }\n const controller = new AbortController()\n const timer = setTimeout(() => {\n void search.search(q, { limit: 60, signal: controller.signal }).then((found) => {\n if (!controller.signal.aborted) {\n setMatches(found)\n }\n })\n }, 150)\n return () => {\n controller.abort()\n clearTimeout(timer)\n }\n }, [search, query])\n\n return (\n <div data-slot=\"file-tree\" style={style} className={cn('flex min-h-0 min-w-0 flex-col bg-surface', className)}>\n <div className=\"flex items-center gap-1 px-2 pt-2\">\n {search?.available ? (\n <div className=\"relative min-w-0 flex-1\">\n <Search className=\"absolute top-1/2 left-2 size-3.5 -translate-y-1/2 text-fg-4\" />\n <Input\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search files…\"\n className=\"h-7 pr-7 pl-7 text-label\"\n spellCheck={false}\n />\n {searching ? (\n <button\n type=\"button\"\n onClick={() => setQuery('')}\n aria-label=\"Clear search\"\n className=\"absolute top-1/2 right-1.5 -translate-y-1/2 text-fg-4 transition-colors hover:text-fg-2\"\n >\n <X className=\"size-3.5\" />\n </button>\n ) : null}\n </div>\n ) : (\n <span className=\"min-w-0 flex-1 truncate px-1 text-label text-fg-4\">{tree.root}</span>\n )}\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label=\"Refresh the file tree\" onClick={() => tree.refresh()}>\n <RefreshCw className=\"size-3.5 text-fg-3\" />\n </Button>\n {onCollapse ? (\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label=\"Hide project files\" onClick={onCollapse}>\n <PanelLeftClose className=\"size-3.5 text-fg-3\" />\n </Button>\n ) : null}\n </div>\n\n <div className=\"min-h-0 flex-1 overflow-auto px-1 py-1\">\n {tree.error ? (\n <p className=\"px-2 py-3 text-body-sm text-danger\">{tree.error}</p>\n ) : searching ? (\n matches === undefined ? (\n <div className=\"py-6 text-center\">\n <Spinner className=\"size-4 text-fg-4\" />\n </div>\n ) : matches.length === 0 ? (\n <p className=\"px-2 py-6 text-center text-body-sm text-fg-4\">No matching files.</p>\n ) : (\n <ul>\n {matches.map((match) => (\n <li key={match.path}>\n <Row\n label={fileName(match.relative)}\n detail={directoryOf(match.relative)}\n title={match.relative}\n icon={<File className=\"size-3.5 shrink-0 text-fg-4\" />}\n active={match.path === activePath}\n onClick={() => onOpenFile(match.path)}\n />\n </li>\n ))}\n </ul>\n )\n ) : tree.loading ? (\n <div className=\"py-6 text-center\">\n <Spinner className=\"size-4 text-fg-4\" />\n </div>\n ) : tree.rows.length === 0 ? (\n <p className=\"px-2 py-6 text-center text-body-sm text-fg-4\">This project is empty.</p>\n ) : (\n <ul role=\"tree\" aria-label=\"Project files\">\n {tree.rows.map((row) => (\n <li key={row.entry.path} role=\"treeitem\" aria-expanded={row.expanded} aria-level={row.depth + 1}>\n <Row\n label={row.entry.name}\n indent={row.depth}\n active={row.entry.path === activePath}\n icon={\n row.entry.type === 'dir' ? (\n row.loading ? (\n <Spinner className=\"size-3.5 shrink-0 text-fg-4\" />\n ) : row.expanded ? (\n <FolderOpen className=\"size-3.5 shrink-0 text-accent\" />\n ) : (\n <Folder className=\"size-3.5 shrink-0 text-accent\" />\n )\n ) : (\n <EntryIcon type={row.entry.type} />\n )\n }\n chevron={\n row.entry.type === 'dir' ? (\n <ChevronRight className={cn('size-3 shrink-0 text-fg-4 transition-transform', row.expanded && 'rotate-90')} />\n ) : undefined\n }\n onClick={() => (row.entry.type === 'dir' ? tree.toggle(row.entry.path) : onOpenFile(row.entry.path))}\n />\n {row.truncated ? (\n <p className=\"truncate py-0.5 text-label text-fg-4\" style={{ paddingLeft: (row.depth + 1) * INDENT + 22 }}>\n More entries than the server will return — use search.\n </p>\n ) : null}\n </li>\n ))}\n </ul>\n )}\n </div>\n </div>\n )\n}\n\nfunction Row({\n label,\n detail,\n title,\n icon,\n chevron,\n indent = 0,\n active,\n onClick,\n}: {\n label: string\n detail?: string\n title?: string\n icon: ReactNode\n chevron?: ReactNode\n indent?: number\n active?: boolean\n onClick: () => void\n}) {\n const ref = useRef<HTMLButtonElement>(null)\n useEffect(() => {\n if (active) {\n ref.current?.scrollIntoView({ block: 'nearest' })\n }\n }, [active])\n\n return (\n <button\n ref={ref}\n type=\"button\"\n onClick={onClick}\n title={title ?? label}\n style={{ paddingLeft: indent * INDENT + 4 }}\n className={cn(\n 'flex w-full items-center gap-1 rounded py-1 pr-2 text-left transition-colors',\n active ? 'bg-surface-hover text-fg-1' : 'text-fg-2 hover:bg-surface-hover',\n )}\n >\n <span className=\"flex size-3 shrink-0 items-center justify-center\">{chevron}</span>\n {icon}\n <span className=\"shrink-0 truncate text-label\">{label}</span>\n {detail ? <span className=\"min-w-0 flex-1 truncate text-label text-fg-4\">{detail}</span> : null}\n </button>\n )\n}\n\nfunction fileName(relative: string): string {\n return relative.slice(relative.lastIndexOf('/') + 1)\n}\n\nfunction directoryOf(relative: string): string | undefined {\n const cut = relative.lastIndexOf('/')\n return cut === -1 ? undefined : relative.slice(0, cut)\n}\n","import { useEffect, useRef, useState } from 'react'\nimport type * as Monaco from 'monaco-editor'\nimport { cn } from '../../lib/utils.ts'\nimport { Spinner } from '../ui/Spinner.tsx'\n\nexport interface CodeEditorProps {\n path: string\n value: string\n onChange?: (value: string) => void\n onSave?: () => void\n readOnly?: boolean\n className?: string\n}\n\nexport function CodeEditor({ path, value, onChange, onSave, readOnly, className }: CodeEditorProps) {\n const host = useRef<HTMLDivElement>(null)\n const editor = useRef<Monaco.editor.IStandaloneCodeEditor | null>(null)\n const monaco = useRef<typeof Monaco | null>(null)\n const [ready, setReady] = useState(false)\n const theme = useDocumentTheme()\n\n const handlers = useRef({ onChange, onSave })\n handlers.current = { onChange, onSave }\n\n useEffect(() => {\n let disposed = false\n void loadMonaco().then((api) => {\n if (disposed || !host.current) {\n return\n }\n monaco.current = api\n const instance = api.editor.create(host.current, {\n value,\n language: languageOf(path),\n readOnly,\n automaticLayout: true,\n theme: monacoTheme(document.documentElement.getAttribute('data-theme')),\n minimap: { enabled: false },\n scrollBeyondLastLine: false,\n fontSize: 12,\n lineHeight: 20,\n fontFamily: 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace',\n renderLineHighlight: 'line',\n smoothScrolling: true,\n padding: { top: 8, bottom: 8 },\n scrollbar: { verticalScrollbarSize: 10, horizontalScrollbarSize: 10 },\n wordBasedSuggestions: 'off',\n quickSuggestions: false,\n })\n editor.current = instance\n instance.onDidChangeModelContent(() => {\n handlers.current.onChange?.(instance.getValue())\n })\n instance.addCommand(api.KeyMod.CtrlCmd | api.KeyCode.KeyS, () => {\n handlers.current.onSave?.()\n })\n setReady(true)\n })\n return () => {\n disposed = true\n // The editor, never its models: a model is keyed by path and outlives this mount, which is what restores a reopened tab's undo stack.\n editor.current?.dispose()\n editor.current = null\n setReady(false)\n }\n }, [])\n\n useEffect(() => {\n const api = monaco.current\n const instance = editor.current\n if (!api || !instance || !ready) {\n return\n }\n const uri = api.Uri.parse(`workerdeck://host${path}`)\n const model = api.editor.getModel(uri) ?? api.editor.createModel(value, languageOf(path), uri)\n if (instance.getModel() !== model) {\n instance.setModel(model)\n }\n }, [path, ready, value])\n\n useEffect(() => {\n const instance = editor.current\n if (!instance || !ready) {\n return\n }\n const model = instance.getModel()\n if (!model || model.getValue() === value) {\n return\n }\n model.pushEditOperations([], [{ range: model.getFullModelRange(), text: value }], () => null)\n }, [value, ready])\n\n useEffect(() => {\n if (ready) {\n editor.current?.updateOptions({ readOnly })\n }\n }, [readOnly, ready])\n\n useEffect(() => {\n if (ready) {\n monaco.current?.editor.setTheme(monacoTheme(theme))\n }\n }, [theme, ready])\n\n return (\n <div className={cn('relative min-h-0 min-w-0 flex-1', className)}>\n <div ref={host} className=\"absolute inset-0\" />\n {!ready ? (\n <div className=\"absolute inset-0 flex items-center justify-center bg-bg\">\n <Spinner className=\"size-4 text-fg-4\" />\n </div>\n ) : null}\n </div>\n )\n}\n\nfunction useDocumentTheme(): string | null {\n const [theme, setTheme] = useState<string | null>(() =>\n typeof document === 'undefined' ? null : document.documentElement.getAttribute('data-theme'),\n )\n useEffect(() => {\n const root = document.documentElement\n const sync = () => setTheme(root.getAttribute('data-theme'))\n sync()\n const observer = new MutationObserver(sync)\n observer.observe(root, { attributes: true, attributeFilter: ['data-theme'] })\n return () => observer.disconnect()\n }, [])\n return theme\n}\n\nfunction monacoTheme(theme: string | null): string {\n return theme === 'light' ? 'wd-light' : 'wd-dark'\n}\n\nlet monacoPromise: Promise<typeof Monaco> | undefined\nfunction loadMonaco(): Promise<typeof Monaco> {\n monacoPromise ??= (async () => {\n const api = await import('monaco-editor')\n api.editor.defineTheme('wd-dark', {\n base: 'vs-dark',\n inherit: true,\n rules: [],\n colors: { 'editor.background': '#00000000' },\n })\n api.editor.defineTheme('wd-light', {\n base: 'vs',\n inherit: true,\n rules: [],\n colors: { 'editor.background': '#00000000' },\n })\n return api\n })()\n return monacoPromise\n}\n\nfunction languageOf(path: string): string {\n const name = path.slice(path.lastIndexOf('/') + 1)\n const byName = FILENAME_LANGUAGES[name.toLowerCase()]\n if (byName) {\n return byName\n }\n const extension = name.slice(name.lastIndexOf('.') + 1).toLowerCase()\n return EXTENSION_LANGUAGES[extension] ?? 'plaintext'\n}\n\nconst FILENAME_LANGUAGES: Record<string, string> = {\n dockerfile: 'dockerfile',\n makefile: 'plaintext',\n '.gitignore': 'plaintext',\n '.env': 'shell',\n}\n\nconst EXTENSION_LANGUAGES: Record<string, string> = {\n ts: 'typescript',\n tsx: 'typescript',\n mts: 'typescript',\n cts: 'typescript',\n js: 'javascript',\n jsx: 'javascript',\n mjs: 'javascript',\n cjs: 'javascript',\n json: 'json',\n jsonc: 'json',\n md: 'markdown',\n mdx: 'markdown',\n css: 'css',\n scss: 'scss',\n less: 'less',\n html: 'html',\n htm: 'html',\n xml: 'xml',\n svg: 'xml',\n yml: 'yaml',\n yaml: 'yaml',\n toml: 'plaintext',\n sh: 'shell',\n bash: 'shell',\n zsh: 'shell',\n fish: 'shell',\n py: 'python',\n rb: 'ruby',\n rs: 'rust',\n go: 'go',\n swift: 'swift',\n java: 'java',\n kt: 'kotlin',\n c: 'c',\n h: 'c',\n cpp: 'cpp',\n cc: 'cpp',\n hpp: 'cpp',\n cs: 'csharp',\n php: 'php',\n sql: 'sql',\n graphql: 'graphql',\n gql: 'graphql',\n lua: 'lua',\n r: 'r',\n pl: 'perl',\n dart: 'dart',\n scala: 'scala',\n ini: 'ini',\n cfg: 'ini',\n conf: 'ini',\n txt: 'plaintext',\n log: 'plaintext',\n}\n","import type { ReactNode } from 'react'\nimport type { OpenFile } from '@workerdeck/react'\nimport { currentText, isDirty } from '@workerdeck/react'\nimport { FileWarning, TriangleAlert } from 'lucide-react'\nimport { cn } from '../../lib/utils.ts'\nimport { Button } from '../ui/Button.tsx'\nimport { Spinner } from '../ui/Spinner.tsx'\nimport { CodeEditor } from './CodeEditor.tsx'\n\nexport interface FileViewerProps {\n file: OpenFile | undefined\n canWrite?: boolean\n onChange?: (path: string, content: string) => void\n onSave?: (path: string) => void\n onRevert?: (path: string) => void\n onReload?: (path: string) => void\n onOverwrite?: (path: string) => void\n onDismissConflict?: (path: string) => void\n className?: string\n}\n\nexport function FileViewer({\n file,\n canWrite,\n onChange,\n onSave,\n onRevert,\n onReload,\n onOverwrite,\n onDismissConflict,\n className,\n}: FileViewerProps) {\n if (!file) {\n return null\n }\n\n return (\n <div data-slot=\"file-viewer\" className={cn('flex min-h-0 min-w-0 flex-1 flex-col bg-bg', className)}>\n {file.conflict ? (\n <div className=\"flex shrink-0 flex-wrap items-center gap-2 border-b border-warning/40 bg-warning-bg px-3 py-2\">\n <TriangleAlert className=\"size-3.5 shrink-0 text-warning\" />\n <span className=\"min-w-0 flex-1 text-body-sm text-warning\">This file changed on disk since you opened it.</span>\n <Button variant=\"outline\" size=\"xs\" onClick={() => onReload?.(file.path)}>\n Use the version on disk\n </Button>\n <Button variant=\"outline\" size=\"xs\" onClick={() => onOverwrite?.(file.path)}>\n Keep mine\n </Button>\n <Button variant=\"ghost\" size=\"xs\" onClick={() => onDismissConflict?.(file.path)}>\n Dismiss\n </Button>\n </div>\n ) : file.saveError ? (\n <div className=\"flex shrink-0 items-center gap-2 border-b border-danger/40 bg-danger-bg px-3 py-2\">\n <TriangleAlert className=\"size-3.5 shrink-0 text-danger\" />\n <span className=\"min-w-0 flex-1 text-body-sm text-danger\">{file.saveError}</span>\n <Button variant=\"ghost\" size=\"xs\" onClick={() => onDismissConflict?.(file.path)}>\n Dismiss\n </Button>\n </div>\n ) : null}\n\n {file.status === 'loading' ? (\n <Centred>\n <Spinner className=\"size-4 text-fg-4\" />\n </Centred>\n ) : file.status === 'error' ? (\n <Centred>\n <TriangleAlert className=\"size-4 text-danger\" />\n <p className=\"text-body-sm text-danger\">{file.error}</p>\n </Centred>\n ) : file.status === 'binary' ? (\n <Centred>\n <FileWarning className=\"size-4 text-fg-4\" />\n <p className=\"text-body-sm text-fg-4\">This file isn’t text.</p>\n <p className=\"text-label text-fg-4\">It can’t be edited here without corrupting it.</p>\n </Centred>\n ) : (\n <CodeEditor\n path={file.path}\n value={currentText(file)}\n readOnly={!canWrite}\n onChange={onChange ? (content) => onChange(file.path, content) : undefined}\n onSave={onSave ? () => onSave(file.path) : undefined}\n />\n )}\n\n {file.status === 'ready' && (file.saving || isDirty(file) || !canWrite) ? (\n <div className=\"flex shrink-0 items-center gap-2 border-t border-border px-3 py-1\">\n {file.saving ? (\n <>\n <Spinner className=\"size-3 text-fg-4\" />\n <span className=\"text-label text-fg-4\">Saving…</span>\n </>\n ) : !canWrite ? (\n <span className=\"text-label text-fg-4\">Read-only — this gateway doesn’t allow writes.</span>\n ) : (\n <>\n <span className=\"text-label text-fg-3\">Unsaved changes</span>\n <span className=\"flex-1\" />\n <Button variant=\"ghost\" size=\"xs\" onClick={() => onRevert?.(file.path)}>\n Revert\n </Button>\n <Button variant=\"outline\" size=\"xs\" onClick={() => onSave?.(file.path)}>\n Save\n <span className=\"ml-1 text-fg-4\">⌘S</span>\n </Button>\n </>\n )}\n </div>\n ) : null}\n </div>\n )\n}\n\nfunction Centred({ children }: { children: ReactNode }) {\n return <div className=\"flex min-h-0 flex-1 flex-col items-center justify-center gap-2 p-6\">{children}</div>\n}\n","import { useEffect, type RefObject } from 'react'\n\nexport type PathHit = { path: string; line?: number }\n\nconst LINKISH = 'wd-path-link'\n\nconst PATH_RE = /^(\\/[^\\s:'\"`()[\\]{}]+|[\\w.@~-]+(?:\\/[\\w.@~-]+)+)(?::(\\d+))?$/\nconst FILE_RE = /^([\\w.@-]+\\.[A-Za-z0-9]{1,10})(?::(\\d+))?$/\n\nconst COVERAGE = 0.6\n\nexport function matchPath(text: string, inCode: boolean): PathHit | undefined {\n const trimmed = text.trim()\n if (!trimmed || trimmed.endsWith('/')) {\n return undefined\n }\n const hit = PATH_RE.exec(trimmed) ?? (inCode ? FILE_RE.exec(trimmed) : null)\n if (!hit) {\n return undefined\n }\n return { path: hit[1]!, line: hit[2] ? Number(hit[2]) : undefined }\n}\n\nfunction hitFor(element: HTMLElement | undefined): PathHit | undefined {\n if (!element) {\n return undefined\n }\n const inCode = element.closest('code') !== null\n const text = element.textContent ?? ''\n const hit = matchPath(text, inCode)\n if (!hit) {\n return undefined\n }\n if (!inCode && hit.path.length < text.trim().length * COVERAGE) {\n return undefined\n }\n return hit\n}\n\nexport function usePathLinks({\n container,\n onOpen,\n enabled = true,\n ignore,\n}: {\n container: RefObject<HTMLElement | null>\n onOpen: (hit: PathHit) => void\n enabled?: boolean\n ignore?: string\n}) {\n useEffect(() => {\n const root = container.current\n if (!root || !enabled) {\n return\n }\n const excluded = (element: HTMLElement | undefined) =>\n ignore !== undefined && element?.closest(ignore) !== null && element !== undefined\n\n let marked: HTMLElement | undefined\n const unmark = () => {\n marked?.classList.remove(LINKISH)\n marked = undefined\n }\n\n const onClick = (event: MouseEvent) => {\n if (!event.metaKey && !event.ctrlKey) {\n return\n }\n const target = event.target instanceof HTMLElement ? event.target : undefined\n if (excluded(target)) {\n return\n }\n const hit = hitFor(target)\n if (!hit) {\n return\n }\n event.preventDefault()\n event.stopPropagation()\n unmark()\n onOpen(hit)\n }\n\n const onMove = (event: MouseEvent) => {\n if (!event.metaKey && !event.ctrlKey) {\n return unmark()\n }\n const element = event.target instanceof HTMLElement ? event.target : undefined\n if (element === marked) {\n return\n }\n unmark()\n if (!element || excluded(element) || !hitFor(element)) {\n return\n }\n marked = element\n element.classList.add(LINKISH)\n }\n\n const onKey = (event: KeyboardEvent) => {\n if (!event.metaKey && !event.ctrlKey) {\n unmark()\n }\n }\n\n root.addEventListener('click', onClick, true)\n root.addEventListener('mousemove', onMove)\n document.addEventListener('keydown', onKey)\n document.addEventListener('keyup', onKey)\n window.addEventListener('blur', unmark)\n return () => {\n unmark()\n root.removeEventListener('click', onClick, true)\n root.removeEventListener('mousemove', onMove)\n document.removeEventListener('keydown', onKey)\n document.removeEventListener('keyup', onKey)\n window.removeEventListener('blur', unmark)\n }\n }, [container, onOpen, enabled, ignore])\n}\n\nexport function resolveAgainstCwd(path: string, cwd: string | undefined): string {\n if (path.startsWith('/')) {\n return path\n }\n if (!cwd) {\n return path\n }\n return `${cwd.replace(/\\/$/, '')}/${path.replace(/^\\.\\//, '')}`\n}\n","import { useCallback, useEffect, useLayoutEffect, useRef, useState, type RefObject } from 'react'\nimport { createPortal } from 'react-dom'\nimport type { WorkerDeckClient } from '@workerdeck/client'\nimport { useHostFileRoots, useHostFileSearch, useHostFileTree, useOpenFiles, useSessionInfo, isDirty } from '@workerdeck/react'\nimport { PanelLeftOpen } from 'lucide-react'\nimport { cn } from '../../lib/utils.ts'\nimport { Button } from '../ui/Button.tsx'\nimport { Splitter } from '../ui/Splitter.tsx'\nimport { EditorTabs } from './EditorTabs.tsx'\nimport { FileTree } from './FileTree.tsx'\nimport { FileViewer } from './FileViewer.tsx'\nimport { SessionPanel, type SessionPanelProps } from './SessionPanel.tsx'\nimport { resolveAgainstCwd, usePathLinks } from './use-path-links.ts'\n\nexport interface SessionWorkspaceProps {\n client: WorkerDeckClient\n sessionId: string | undefined\n header?: SessionPanelProps['header']\n transcriptVariant?: SessionPanelProps['transcriptVariant']\n transcriptDensity?: SessionPanelProps['transcriptDensity']\n transcriptFont?: SessionPanelProps['transcriptFont']\n scrubber?: SessionPanelProps['scrubber']\n bookmarks?: SessionPanelProps['bookmarks']\n onToggleBookmark?: SessionPanelProps['onToggleBookmark']\n stickyPrompt?: SessionPanelProps['stickyPrompt']\n openSubagent?: SessionPanelProps['openSubagent']\n reveal?: SessionPanelProps['reveal']\n subagents?: SessionPanelProps['subagents']\n onSubagentChange?: SessionPanelProps['onSubagentChange']\n statusPlacement?: SessionPanelProps['statusPlacement']\n controlsSurface?: SessionPanelProps['controlsSurface']\n fontSize?: SessionPanelProps['fontSize']\n onLinkClick?: SessionPanelProps['onLinkClick']\n unseen?: SessionPanelProps['unseen']\n readOnly?: SessionPanelProps['readOnly']\n onVitals?: SessionPanelProps['onVitals']\n defaultRailWidth?: number\n defaultRailCollapsed?: boolean\n onRailChange?: (rail: { width: number; collapsed: boolean }) => void\n className?: string\n}\n\nconst RAIL_MIN = 180\nconst RAIL_MAX = 520\nconst AGENT_MIN = 220\nconst EDITOR_MIN = 120\n\nexport function SessionWorkspace({\n client,\n sessionId,\n header,\n transcriptVariant,\n transcriptDensity,\n transcriptFont,\n scrubber,\n bookmarks,\n onToggleBookmark,\n stickyPrompt,\n openSubagent,\n reveal,\n subagents,\n onSubagentChange,\n statusPlacement,\n controlsSurface,\n fontSize,\n onLinkClick,\n unseen,\n readOnly,\n onVitals,\n defaultRailWidth = 260,\n defaultRailCollapsed,\n onRailChange,\n className,\n}: SessionWorkspaceProps) {\n const { info } = useSessionInfo(client, sessionId)\n const cwd = info?.cwd\n\n const tree = useHostFileTree(client, cwd)\n const search = useHostFileSearch(client, cwd)\n const files = useOpenFiles(client)\n const { canWrite } = useHostFileRoots(client)\n\n useEffect(() => {\n if (!files.hasUnsaved) {\n return\n }\n const warn = (event: BeforeUnloadEvent) => event.preventDefault()\n window.addEventListener('beforeunload', warn)\n return () => window.removeEventListener('beforeunload', warn)\n }, [files.hasUnsaved])\n\n const wide = useIsWide()\n const [railCollapsed, setRailCollapsed] = useState(defaultRailCollapsed ?? false)\n const [railWidth, setRailWidth] = useState(defaultRailWidth)\n const onRailChangeRef = useRef(onRailChange)\n onRailChangeRef.current = onRailChange\n useEffect(() => {\n onRailChangeRef.current?.({ width: railWidth, collapsed: railCollapsed })\n }, [railWidth, railCollapsed])\n const [editorHeight, setEditorHeight] = useState(360)\n\n const hasFiles = files.files.length > 0\n\n const overlayRail = !wide\n const railOpen = tree.available && !railCollapsed\n useEffect(() => {\n if (overlayRail) {\n setRailCollapsed(true)\n }\n }, [overlayRail])\n\n const closeTab = useCallback(\n (path: string) => {\n const file = files.files.find((f) => f.path === path)\n if (file && isDirty(file)) {\n const name = file.name\n if (!window.confirm(`${name} has unsaved changes. Close it and lose them?`)) {\n return\n }\n }\n files.close(path)\n },\n [files],\n )\n\n const column = useRef<HTMLDivElement>(null)\n const columnHeight = useElementHeight(column)\n const openPath = useCallback(({ path }: { path: string }) => files.open(resolveAgainstCwd(path, cwd)), [files.open, cwd])\n usePathLinks({\n container: column,\n onOpen: openPath,\n enabled: tree.available,\n ignore: '.monaco-editor',\n })\n const editorMax = Math.max(EDITOR_MIN, columnHeight - AGENT_MIN)\n\n const [topBar, setTopBar] = useState<HTMLDivElement | null>(null)\n const hoisted: SessionPanelProps['header'] =\n header === undefined || topBar === null\n ? undefined\n : typeof header === 'function'\n ? (slots) => createPortal(header(slots), topBar)\n : createPortal(header, topBar)\n\n return (\n <div data-slot=\"session-workspace\" className={cn('flex h-full min-h-0 w-full flex-col overflow-hidden bg-bg', className)}>\n {header !== undefined ? <div ref={setTopBar} className=\"shrink-0\" /> : null}\n <div className=\"relative flex min-h-0 flex-1\">\n {railOpen ? (\n <FileTree\n tree={tree}\n search={search}\n activePath={files.activePath}\n onOpenFile={files.open}\n onCollapse={() => setRailCollapsed(true)}\n style={{ width: overlayRail ? Math.min(railWidth, 320) : railWidth }}\n className={cn('shrink-0 border-r border-border', overlayRail && 'absolute inset-y-0 left-0 z-20 shadow-lg')}\n />\n ) : tree.available ? (\n <div className=\"flex w-8 shrink-0 flex-col items-center border-r border-border bg-surface pt-1.5\">\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label=\"Show project files\" onClick={() => setRailCollapsed(false)}>\n <PanelLeftOpen className=\"size-4 text-fg-3\" />\n </Button>\n </div>\n ) : null}\n {railOpen && !overlayRail ? (\n <Splitter\n orientation=\"vertical\"\n value={railWidth}\n onValueChange={setRailWidth}\n min={RAIL_MIN}\n max={RAIL_MAX}\n defaultValue={defaultRailWidth}\n aria-label=\"Resize the file tree\"\n />\n ) : null}\n\n <div ref={column} className=\"flex min-h-0 min-w-0 flex-1 flex-col\">\n {hasFiles ? (\n <div\n className=\"flex min-h-0 shrink-0 flex-col overflow-hidden\"\n style={{ height: Math.min(editorHeight, editorMax || editorHeight) }}\n >\n <EditorTabs files={files.files} activePath={files.activePath} onActivate={files.activate} onClose={closeTab} />\n <FileViewer\n file={files.active}\n canWrite={canWrite}\n onChange={files.edit}\n onSave={(path) => void files.save(path)}\n onRevert={files.revert}\n onReload={files.reload}\n onOverwrite={(path) => void files.overwrite(path)}\n onDismissConflict={files.dismissConflict}\n />\n </div>\n ) : null}\n {hasFiles ? (\n <Splitter\n orientation=\"horizontal\"\n value={Math.min(editorHeight, editorMax || editorHeight)}\n onValueChange={setEditorHeight}\n min={EDITOR_MIN}\n max={editorMax}\n aria-label=\"Resize the open file\"\n />\n ) : null}\n <SessionPanel\n client={client}\n sessionId={sessionId}\n header={hoisted}\n transcriptVariant={transcriptVariant}\n transcriptDensity={transcriptDensity}\n transcriptFont={transcriptFont}\n scrubber={scrubber}\n bookmarks={bookmarks}\n onToggleBookmark={onToggleBookmark}\n stickyPrompt={stickyPrompt}\n openSubagent={openSubagent}\n reveal={reveal}\n subagents={subagents}\n onSubagentChange={onSubagentChange}\n controlsSurface={controlsSurface}\n fontSize={fontSize}\n onLinkClick={onLinkClick}\n statusPlacement={statusPlacement}\n unseen={unseen}\n readOnly={readOnly}\n onVitals={onVitals}\n className=\"min-h-0 flex-1\"\n />\n </div>\n\n {overlayRail && railOpen ? (\n <button\n type=\"button\"\n aria-label=\"Close the file tree\"\n onClick={() => setRailCollapsed(true)}\n className=\"absolute inset-0 z-10 bg-black/30\"\n />\n ) : null}\n </div>\n </div>\n )\n}\n\nfunction useElementHeight(ref: RefObject<HTMLElement | null>): number {\n const [height, setHeight] = useState(0)\n useLayoutEffect(() => {\n const element = ref.current\n if (!element) {\n return\n }\n const observer = new ResizeObserver(([entry]) => {\n if (entry) {\n setHeight(entry.contentRect.height)\n }\n })\n observer.observe(element)\n return () => observer.disconnect()\n }, [ref])\n return height\n}\n\nfunction useIsWide(): boolean {\n const [wide, setWide] = useState(true)\n useEffect(() => {\n const query = window.matchMedia('(min-width: 768px)')\n const sync = () => setWide(query.matches)\n sync()\n query.addEventListener('change', sync)\n return () => query.removeEventListener('change', sync)\n }, [])\n return wide\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workerdeck/ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Styled agent-control component library for WorkerDeck: session panel, transcript with streaming, tool-call cards, permission prompts, session list, composer. Tailwind v4 + Base UI + cva. Pairs with the headless @workerdeck/react layer.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
"streamdown": "^2.6.0",
|
|
40
40
|
"tailwind-merge": "^3.6.0",
|
|
41
41
|
"use-stick-to-bottom": "^1.1.6",
|
|
42
|
-
"@workerdeck/
|
|
43
|
-
"@workerdeck/
|
|
44
|
-
"@workerdeck/
|
|
42
|
+
"@workerdeck/protocol": "2.1.0",
|
|
43
|
+
"@workerdeck/react": "2.1.0",
|
|
44
|
+
"@workerdeck/client": "2.1.0"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"monaco-editor": "^0.56.0",
|
|
@@ -50,7 +50,6 @@ import { BookmarkProvider, type BookmarkHandle, type TerminalAffordances } from
|
|
|
50
50
|
import { SessionInfoDialog } from './SessionInfoDialog.tsx'
|
|
51
51
|
import { StatusBar } from './StatusBar.tsx'
|
|
52
52
|
import { Transcript } from './Transcript.tsx'
|
|
53
|
-
import { HeldSendsBar, useHeldSends } from './held-sends.tsx'
|
|
54
53
|
import { ToolResultFetchProvider } from './tool-result-fetch.tsx'
|
|
55
54
|
import { ToolTitleProvider } from './tool-titles.tsx'
|
|
56
55
|
import { ToolResultImageProvider, useToolResultImages } from './tool-result-image.tsx'
|
|
@@ -116,9 +115,6 @@ export interface SessionPanelProps {
|
|
|
116
115
|
stickyPrompt?: boolean
|
|
117
116
|
transcriptDensity?: TranscriptDensity
|
|
118
117
|
transcriptFont?: TranscriptFont
|
|
119
|
-
// 'fold' sends a mid-turn message straight through, and the engine folds it into the running
|
|
120
|
-
// turn (catch-up mode). 'hold' keeps it here until the turn ends.
|
|
121
|
-
midTurnSend?: 'fold' | 'hold'
|
|
122
118
|
controlsSurface?: 'internal' | 'external' | 'status'
|
|
123
119
|
onControls?: (controls: SessionControls | undefined) => void
|
|
124
120
|
focusComposerOnClick?: boolean
|
|
@@ -194,7 +190,6 @@ export function SessionPanel({
|
|
|
194
190
|
transcriptVariant = 'cards',
|
|
195
191
|
transcriptDensity = 'comfortable',
|
|
196
192
|
transcriptFont = 'sans',
|
|
197
|
-
midTurnSend = 'fold',
|
|
198
193
|
affordances,
|
|
199
194
|
terminalMetrics,
|
|
200
195
|
scrubber = false,
|
|
@@ -416,8 +411,6 @@ export function SessionPanel({
|
|
|
416
411
|
return [{ name: 'model', description: 'Switch the model for this session', argumentHint: '<model>' }, ...state.commands]
|
|
417
412
|
}, [state.commands])
|
|
418
413
|
|
|
419
|
-
const heldSends = useHeldSends({ hold: midTurnSend === 'hold', busy: busy && !ended, send })
|
|
420
|
-
|
|
421
414
|
const handleSend = (text: string, attachmentIds: string[]) => {
|
|
422
415
|
if (attachmentIds.length === 0) {
|
|
423
416
|
const modelCommand = /^\/model\s+(\S+)$/.exec(text)
|
|
@@ -432,7 +425,7 @@ export function SessionPanel({
|
|
|
432
425
|
}
|
|
433
426
|
setCaughtUp(true)
|
|
434
427
|
repinTranscript.current?.()
|
|
435
|
-
|
|
428
|
+
send(text, attachmentIds)
|
|
436
429
|
}
|
|
437
430
|
|
|
438
431
|
const actionsMenu = (
|
|
@@ -691,7 +684,6 @@ export function SessionPanel({
|
|
|
691
684
|
) : null}
|
|
692
685
|
{readOnly || subagentId !== undefined ? null : (
|
|
693
686
|
<>
|
|
694
|
-
<HeldSendsBar held={heldSends.held} onSendNow={heldSends.flush} />
|
|
695
687
|
<Composer
|
|
696
688
|
ref={composerRef}
|
|
697
689
|
onSend={handleSend}
|
|
@@ -19,7 +19,6 @@ export interface SessionWorkspaceProps {
|
|
|
19
19
|
transcriptVariant?: SessionPanelProps['transcriptVariant']
|
|
20
20
|
transcriptDensity?: SessionPanelProps['transcriptDensity']
|
|
21
21
|
transcriptFont?: SessionPanelProps['transcriptFont']
|
|
22
|
-
midTurnSend?: SessionPanelProps['midTurnSend']
|
|
23
22
|
scrubber?: SessionPanelProps['scrubber']
|
|
24
23
|
bookmarks?: SessionPanelProps['bookmarks']
|
|
25
24
|
onToggleBookmark?: SessionPanelProps['onToggleBookmark']
|
|
@@ -53,7 +52,6 @@ export function SessionWorkspace({
|
|
|
53
52
|
transcriptVariant,
|
|
54
53
|
transcriptDensity,
|
|
55
54
|
transcriptFont,
|
|
56
|
-
midTurnSend,
|
|
57
55
|
scrubber,
|
|
58
56
|
bookmarks,
|
|
59
57
|
onToggleBookmark,
|
|
@@ -213,7 +211,6 @@ export function SessionWorkspace({
|
|
|
213
211
|
transcriptVariant={transcriptVariant}
|
|
214
212
|
transcriptDensity={transcriptDensity}
|
|
215
213
|
transcriptFont={transcriptFont}
|
|
216
|
-
midTurnSend={midTurnSend}
|
|
217
214
|
scrubber={scrubber}
|
|
218
215
|
bookmarks={bookmarks}
|
|
219
216
|
onToggleBookmark={onToggleBookmark}
|
package/src/index.ts
CHANGED
|
@@ -75,7 +75,6 @@ export { Reasoning, type ReasoningProps } from './components/agent/Reasoning.tsx
|
|
|
75
75
|
export { Loader } from './components/agent/Loader.tsx'
|
|
76
76
|
export { ToolCallCard, type ToolCallCardProps, type ToolCallItem } from './components/agent/ToolCallCard.tsx'
|
|
77
77
|
export { ToolTitleProvider, useToolTitle } from './components/agent/tool-titles.tsx'
|
|
78
|
-
export { HeldSendsBar, useHeldSends, type HeldSend, type HeldSends } from './components/agent/held-sends.tsx'
|
|
79
78
|
export { FileCard, type FileCardProps, type FileDeliveredItem } from './components/agent/FileCard.tsx'
|
|
80
79
|
export { PermissionPrompt, type PermissionPromptProps } from './components/agent/PermissionPrompt.tsx'
|
|
81
80
|
export {
|