@deepseek-ai/dsh-client-ui-workspace 0.0.1-rc.1

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/lib/index.js ADDED
@@ -0,0 +1,11 @@
1
+ //#region lib/types/index.js
2
+ /**
3
+ * Workspace picker plugin, node half. Pure UI plugin: the empty apply exists
4
+ * so the plugin appears in the host cordis.yml / Loader (load and lifecycle
5
+ * follow the host; the browser half ships via exports["./client"], discovered
6
+ * through the package.json dsh.client declaration).
7
+ */
8
+ /** Host plugin body — no host-side behavior for the workspace picker plugin. */
9
+ function apply() {}
10
+ //#endregion
11
+ export { apply };
@@ -0,0 +1,25 @@
1
+ //#region lib/types/invariant.js
2
+ /**
3
+ * Package-owned invariant companion for `@deepseek-ai/dsh-client-ui-workspace`.
4
+ * @module @deepseek-ai/dsh-client-ui-workspace/invariant
5
+ */
6
+ const PACKAGE_NAME = "@deepseek-ai/dsh-client-ui-workspace";
7
+ /** Cordis companion plugin name. */
8
+ const name = "client-ui-workspace-invariant";
9
+ /** Service required before the companion can reserve package ownership. */
10
+ const inject = ["invariants"];
11
+ /**
12
+ * No runtime invariant: a pure-consumer plugin registering presentational
13
+ * components into two host-declared slots plus its locale dictionaries — its
14
+ * inject face is stateless RPC wrappers plus a create-and-open call; it
15
+ * emits no cordis events and owns no cross-plugin mutable state.
16
+ */
17
+ const install = () => {};
18
+ /**
19
+ * Register this package's invariant companion.
20
+ * @param ctx - Cordis context carrying the invariant service.
21
+ * @returns the installed registration's disposer after setup succeeds.
22
+ */
23
+ const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
24
+ //#endregion
25
+ export { apply, inject, name };
@@ -0,0 +1,8 @@
1
+ import type { WorkspaceBrowserProps } from './contract/slots.ts';
2
+ /**
3
+ * Render the browsing region.
4
+ * @param props - composed slot props (shell owner share + store + injected actions).
5
+ * @returns the region element tree.
6
+ */
7
+ export declare function WorkspaceBrowser({ wide, expandSidebar, useSessions, useWorkspaces, useStore, actions, startSession, open, renameSession, forkSession, renameWorkspace, deleteWorkspace, archiveSession, insertSessionBefore, createWorkspace, searchSessions, searchResultLimit, useDirectoryFlow, renderSlot, t, }: WorkspaceBrowserProps): import("react").JSX.Element;
8
+ //# sourceMappingURL=WorkspaceBrowser.d.ts.map
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Workspace pick/add flow. WorkspacePickFlow is the reusable core (menu +
3
+ * path error dialog) consumed directly by WorkspaceBrowser (same package) and
4
+ * wrapped by WorkspacePicker for the conversation empty-state slot
5
+ * registration. Directory picking itself lives in the composed flow package's
6
+ * slot occupant (see the contract module doc): this core only opens the flow,
7
+ * adopts the picked path, and owns the error surface. Adding a workspace has
8
+ * exactly one route — pick a host directory, new or existing — because the
9
+ * occupant's own create-folder affordance already covers creating one.
10
+ */
11
+ import type { ReactNode, RefObject } from 'react';
12
+ import type { WorkspaceId, WorkspaceListState, WorkspaceView } from '@deepseek-ai/dsh-client-runtime/client';
13
+ import type { SnapshotSelectorHook } from '@deepseek-ai/dsh-client-ui-slots';
14
+ import type { DirectoryFlowOwnerProps, WorkspacePickerProps } from './contract/slots.ts';
15
+ /** Core flow props: the owner supplies popover control and pick semantics. */
16
+ export interface WorkspacePickFlowProps {
17
+ /** The standard locale seat, forwarded by whichever slot entry hosts the flow. */
18
+ t: WorkspacePickerProps['t'];
19
+ /** Popover visibility (anchor button toggle state, owner-local). */
20
+ open: boolean;
21
+ /** The anchor button element — the popover's placement anchor. */
22
+ anchorRef?: RefObject<HTMLElement | null> | undefined;
23
+ /** Selector hook over the workspace list (framework standard hook). */
24
+ useWorkspaces: <S>(selector: (state: WorkspaceListState) => S) => S;
25
+ /** Adopt a picked host directory as a real Workspace. */
26
+ createWorkspace: (input: {
27
+ path: string;
28
+ }) => Promise<WorkspaceView>;
29
+ /** Bound occupancy selector hook for this surface's directory-flow hole (empty leaves the surface with no add action). */
30
+ useDirectoryFlow: SnapshotSelectorHook<boolean>;
31
+ /** Render this surface's directory-flow hole with the owner conversation (the entry's narrowed renderSlot). */
32
+ renderDirectoryFlow: (owner: DirectoryFlowOwnerProps) => ReactNode;
33
+ /** A real Workspace was picked or created. */
34
+ onPick: (workspaceId: WorkspaceId) => void;
35
+ /** Close the popover (outside click / Escape / post-pick). */
36
+ onClose: () => void;
37
+ /** Only offer the add action, hide existing workspaces. */
38
+ addOnly?: boolean;
39
+ /** Menu opening direction relative to the anchor. */
40
+ side?: 'bottom' | 'top' | 'right';
41
+ /** Currently active workspace (trailing check in the picker list). */
42
+ selectedId?: WorkspaceId | undefined;
43
+ }
44
+ /**
45
+ * Render the pick menu plus the adoption error dialog.
46
+ * @param props - owner-controlled flow props.
47
+ * @returns menu + dialog elements.
48
+ */
49
+ export declare function WorkspacePickFlow({ t, open, anchorRef, useWorkspaces, createWorkspace, useDirectoryFlow, renderDirectoryFlow, onPick, onClose, addOnly, side, selectedId, }: WorkspacePickFlowProps): import("react").JSX.Element;
50
+ /**
51
+ * The conversation empty-state registration: adapts the owner share to the
52
+ * core flow (all state and semantics live in the flow / the owner).
53
+ * @param props - empty-state slot props (owner share + injected creation callback).
54
+ * @returns the flow element.
55
+ */
56
+ export declare function WorkspacePicker({ open, anchorRef, useWorkspaces, selectedId, onPick, onClose, createWorkspace, useDirectoryFlow, renderSlot, t, }: WorkspacePickerProps): import("react").JSX.Element;
57
+ //# sourceMappingURL=WorkspacePicker.d.ts.map
@@ -0,0 +1,149 @@
1
+ /**
2
+ * ui-workspace contracts. Two registrations share this package:
3
+ *
4
+ * - WorkspaceBrowser fills the sidebar shell's `sidebar.workspaces` hole —
5
+ * the whole browsing region (section header, search, grouped/flat session
6
+ * list, workspace dialogs). It registers this package's viewing store and
7
+ * consumes the shell's two-fact owner share (wide / expandSidebar).
8
+ * - WorkspacePicker fills the conversation empty-state hole (menu + error
9
+ * dialog shared with the browser).
10
+ *
11
+ * Each registration also declares one **directory-flow hole** (`single`
12
+ * kind): the slot a composed picker package's client half fills with its
13
+ * picking interaction — a renderless native-chooser driver or an in-app
14
+ * browsing dialog. ui-workspace owns the trigger (the "Add workspace…"
15
+ * entry, present only while the hole is occupied) and the adoption
16
+ * semantics (`createWorkspace({ path })`, the retryable error dialog,
17
+ * Choose again); the occupant owns everything between `open` and the picked path,
18
+ * including creating a new directory to hand back. That occupant-owned
19
+ * creation is why adding a workspace has a single route: an unoccupied hole
20
+ * leaves the surface with no add affordance at all.
21
+ * Two holes exist because the two menu surfaces are independent slot entries
22
+ * and a hole has exactly one declaring entry — they carry the same owner
23
+ * contract and the same occupant.
24
+ */
25
+ import type { HostObservable, PropsLocale, PropsRenderSlots, PropsRuntime, PropsStore, SnapshotSelectorHook } from '@deepseek-ai/dsh-client-ui-slots';
26
+ import type { SessionId, SessionSearchResultItem, WorkspaceId, WorkspaceView } from '@deepseek-ai/dsh-client-runtime/client';
27
+ import type { createWorkspaceViewStore } from '../stores.ts';
28
+ /**
29
+ * Owner share of the directory-flow holes: the complete conversation between
30
+ * the trigger surface and the picking interaction. The occupant reads `open`
31
+ * to run/render its interaction and reports exactly one outcome per open.
32
+ */
33
+ export interface DirectoryFlowOwnerProps {
34
+ /** True while a picking interaction is requested; flipping back to false withdraws the request. */
35
+ open: boolean;
36
+ /** True while the owner adopts a picked path (`createWorkspace` in flight); occupants disable their commit affordances. */
37
+ busy: boolean;
38
+ /** The operator picked a directory (absolute host path); the owner adopts it. */
39
+ onPicked: (path: string) => void;
40
+ /** The operator dismissed the interaction; the owner just closes the flow. */
41
+ onCancel: () => void;
42
+ /** The interaction itself failed (chooser missing, listing denied); the owner shows its error surface. */
43
+ onError: (message: string) => void;
44
+ }
45
+ declare module '@deepseek-ai/dsh-client-ui-slots' {
46
+ interface SlotMap {
47
+ /** Directory-flow hole under the conversation empty-state picker (declared by the WorkspacePicker entry). */
48
+ 'conversation.hero.workspace.directoryFlow': {
49
+ kind: 'single';
50
+ scope: 'root';
51
+ owner: DirectoryFlowOwnerProps;
52
+ };
53
+ /** Directory-flow hole under the sidebar browsing region (declared by the WorkspaceBrowser entry). */
54
+ 'sidebar.workspaces.directoryFlow': {
55
+ kind: 'single';
56
+ scope: 'root';
57
+ owner: DirectoryFlowOwnerProps;
58
+ };
59
+ }
60
+ }
61
+ /** The two directory-flow holes; a flow package's client half registers its one component into both. */
62
+ export type DirectoryFlowSlotName = 'conversation.hero.workspace.directoryFlow' | 'sidebar.workspaces.directoryFlow';
63
+ /**
64
+ * Directory-picking share both trigger surfaces consume. Occupancy rides the
65
+ * inject face's reserved `hooks` compartment: the renderer binds the source
66
+ * into the `useDirectoryFlow` selector hook, so an empty hole hides the
67
+ * "Add workspace…" entry reactively and the surface withdraws an open
68
+ * flow whose occupant unloaded mid-interaction (nobody is left to cancel).
69
+ */
70
+ export type DirectoryPickingInjected = {
71
+ hooks: {
72
+ /** True while this surface's directory-flow hole is occupied. */
73
+ directoryFlow: HostObservable<boolean>;
74
+ };
75
+ };
76
+ /** Component-side view of the picking share: the bound occupancy selector hook. */
77
+ export type DirectoryPickingHooks = {
78
+ /** Selector hook over this surface's directory-flow occupancy. */
79
+ useDirectoryFlow: SnapshotSelectorHook<boolean>;
80
+ };
81
+ /**
82
+ * Browser-private injected share (arrives via the register inject factory).
83
+ * Data reads use the global framework hooks; these are the Host actions the
84
+ * browsing region drives.
85
+ */
86
+ export type WorkspaceBrowserInjected = DirectoryPickingInjected & {
87
+ /**
88
+ * Start a New Session in a Workspace: reuse-or-create its blank session
89
+ * and open it; with no workspace, clear the selection into the New Session
90
+ * pure view state (the conversation.empty seat).
91
+ */
92
+ startSession: (workspaceId?: WorkspaceId) => void;
93
+ /** Open a real Session. */
94
+ open: (sessionId: SessionId) => void;
95
+ /**
96
+ * Search current visible conversation messages. The Host fixes the result
97
+ * bound; `hasMore` means the query needs narrowing.
98
+ */
99
+ searchSessions: (query: string, signal: AbortSignal) => Promise<{
100
+ items: readonly SessionSearchResultItem[];
101
+ hasMore: boolean;
102
+ }>;
103
+ /** Maximum number of merged rows rendered for one search. */
104
+ searchResultLimit: number;
105
+ /** Rename a Session (explicit user title; resolves on host acceptance). */
106
+ renameSession: (sessionId: SessionId, title: string) => Promise<void>;
107
+ /** Fork a Session at its last completed turn and open the child. */
108
+ forkSession: (sessionId: SessionId) => void;
109
+ /** Rename a Host Workspace (rejects on name conflict; resolves on durability). */
110
+ renameWorkspace: (workspaceId: WorkspaceId, title: string) => Promise<void>;
111
+ /** Delete only a Host Workspace registration; directory and Session logs remain. */
112
+ deleteWorkspace: (workspaceId: WorkspaceId) => Promise<void>;
113
+ /**
114
+ * Archive a Session into the registry-global set: hidden from grouping
115
+ * surfaces, log and accounting slot retained. Archiving the current
116
+ * session clears the selection into the New Session view state.
117
+ */
118
+ archiveSession: (sessionId: SessionId) => Promise<void>;
119
+ /**
120
+ * Reorder a session inside its Workspace account (DOM-insertBefore
121
+ * semantics: omitted anchor appends to the end). The view refreshes from
122
+ * the Host response/changed frame; failures leave the order unchanged.
123
+ */
124
+ insertSessionBefore: (workspaceId: WorkspaceId, sessionId: SessionId, beforeSessionId?: SessionId) => Promise<void>;
125
+ /** Adopt a picked host directory as a real Workspace before targeting a Session. */
126
+ createWorkspace: (input: {
127
+ path: string;
128
+ }) => Promise<WorkspaceView>;
129
+ };
130
+ /** Full browser props: shell owner share + viewing store + injected actions + the locale seat. */
131
+ export type WorkspaceBrowserProps = PropsRuntime<'sidebar.workspaces'> & PropsRenderSlots<'sidebar.workspaces.directoryFlow'> & PropsStore<ReturnType<typeof createWorkspaceViewStore>> & Omit<WorkspaceBrowserInjected, 'hooks'> & DirectoryPickingHooks & PropsLocale<'workspace'>;
132
+ /**
133
+ * Picker-private injected share. Pick semantics remain in the owner's onPick
134
+ * callback; this callback creates only the real Host Workspace. A type alias
135
+ * supplies the implicit index signature required by the registry.
136
+ */
137
+ export type WorkspacePickerInjected = DirectoryPickingInjected & {
138
+ /** Adopt a picked host directory as a real Workspace before targeting a Session. */
139
+ createWorkspace: (input: {
140
+ path: string;
141
+ }) => Promise<WorkspaceView>;
142
+ };
143
+ /**
144
+ * Full picker props: the owner share plus the creation callback and the
145
+ * locale seat. The two picker holes (blank-session hero / New-Session view)
146
+ * share one owner currency, so one composed type serves both registrations.
147
+ */
148
+ export type WorkspacePickerProps = PropsRuntime<'conversation.hero.workspace'> & PropsRenderSlots<'conversation.hero.workspace.directoryFlow'> & Omit<WorkspacePickerInjected, 'hooks'> & DirectoryPickingHooks & PropsLocale<'workspace'>;
149
+ //# sourceMappingURL=slots.d.ts.map
@@ -0,0 +1,27 @@
1
+ import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
2
+ import { type WorkspaceKey } from './locales.ts';
3
+ export type { DirectoryFlowOwnerProps, DirectoryFlowSlotName, DirectoryPickingHooks, DirectoryPickingInjected, WorkspaceBrowserInjected, WorkspaceBrowserProps, WorkspacePickerInjected, WorkspacePickerProps, } from './contract/slots.ts';
4
+ export type { WorkspaceKey } from './locales.ts';
5
+ declare module '@deepseek-ai/dsh-client-ui-slots' {
6
+ interface LocaleNamespaceMap {
7
+ /** The workspace browsing region and pick/create flow copy. */
8
+ workspace: WorkspaceKey;
9
+ }
10
+ }
11
+ /**
12
+ * Required services (cordis fiber inject). The target slots are declared by
13
+ * the ui-sidebar / ui-conversation applies, whose activation order relative
14
+ * to this one is NOT constrained: dsh.client.inject edges are informational
15
+ * (loading/prefetch metadata, never apply sequencing) and neither owner
16
+ * provides a waitable service. apply therefore depends on each slot
17
+ * declaration through `slots.inject()` instead of assuming order.
18
+ */
19
+ export declare const inject: string[];
20
+ /**
21
+ * Register the browser and picker once their slot declarations are on the
22
+ * ledger. Inject factories return plain callbacks; data reads use the
23
+ * framework's global hooks.
24
+ * @param ctx - client root context.
25
+ */
26
+ export declare function apply(ctx: ClientContext): void;
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,126 @@
1
+ /**
2
+ * `workspace` namespace dictionaries: the browsing region (section header,
3
+ * search, tree rows, dialogs) and the pick/add flow. Runtime failure
4
+ * messages (wire error strings) pass through untranslated by policy.
5
+ */
6
+ /** Simplified Chinese dictionary (the key-set source of truth). */
7
+ export declare const zh: {
8
+ 'group.ungrouped': string;
9
+ 'session.new': string;
10
+ 'section.workspaces': string;
11
+ 'section.sessions': string;
12
+ 'groupBy.label': string;
13
+ 'groupBy.workspace': string;
14
+ 'groupBy.flat': string;
15
+ 'empty.none': string;
16
+ 'empty.noMatches': string;
17
+ 'workspace.add': string;
18
+ 'search.sessions.aria': string;
19
+ 'search.placeholder': string;
20
+ 'search.clear': string;
21
+ 'search.results.aria': string;
22
+ 'search.pending': string;
23
+ 'search.unavailable': string;
24
+ 'search.noMatches': string;
25
+ 'search.hasMore': string;
26
+ 'menu.addWorkspace': string;
27
+ 'picker.loading': string;
28
+ 'conflict.named': string;
29
+ 'folderError.title': string;
30
+ 'folderError.retry': string;
31
+ rename: string;
32
+ 'rename.workspace.title': string;
33
+ 'rename.session.title': string;
34
+ 'field.workspaceName': string;
35
+ 'field.sessionName': string;
36
+ 'delete.workspace': string;
37
+ 'delete.desc': string;
38
+ 'delete.pending': string;
39
+ 'menu.fork': string;
40
+ 'menu.archiveSession': string;
41
+ 'sessions.count.one': string;
42
+ 'sessions.count.other': string;
43
+ 'actions.workspace.aria': string;
44
+ 'actions.session.aria': string;
45
+ 'actions.newSession.aria': string;
46
+ 'status.running': string;
47
+ 'status.subagentsRunning.one': string;
48
+ 'status.subagentsRunning.other': string;
49
+ 'status.idle': string;
50
+ 'status.waitingApproval': string;
51
+ 'status.planReview': string;
52
+ 'status.waitingAnswer': string;
53
+ 'status.completed': string;
54
+ 'hover.created': string;
55
+ 'hover.copied': string;
56
+ 'date.ymd': string;
57
+ 'time.now': string;
58
+ 'time.minutes': string;
59
+ 'time.hours': string;
60
+ 'time.days': string;
61
+ 'time.months': string;
62
+ 'time.years': string;
63
+ 'time.ago': string;
64
+ };
65
+ /** The workspace namespace key union. */
66
+ export type WorkspaceKey = keyof typeof zh;
67
+ /** English dictionary, checked complete against the zh key set. */
68
+ export declare const en: {
69
+ 'group.ungrouped': string;
70
+ 'session.new': string;
71
+ 'section.workspaces': string;
72
+ 'section.sessions': string;
73
+ 'groupBy.label': string;
74
+ 'groupBy.workspace': string;
75
+ 'groupBy.flat': string;
76
+ 'empty.none': string;
77
+ 'empty.noMatches': string;
78
+ 'workspace.add': string;
79
+ 'search.sessions.aria': string;
80
+ 'search.placeholder': string;
81
+ 'search.clear': string;
82
+ 'search.results.aria': string;
83
+ 'search.pending': string;
84
+ 'search.unavailable': string;
85
+ 'search.noMatches': string;
86
+ 'search.hasMore': string;
87
+ 'menu.addWorkspace': string;
88
+ 'picker.loading': string;
89
+ 'conflict.named': string;
90
+ 'folderError.title': string;
91
+ 'folderError.retry': string;
92
+ rename: string;
93
+ 'rename.workspace.title': string;
94
+ 'rename.session.title': string;
95
+ 'field.workspaceName': string;
96
+ 'field.sessionName': string;
97
+ 'delete.workspace': string;
98
+ 'delete.desc': string;
99
+ 'delete.pending': string;
100
+ 'menu.fork': string;
101
+ 'menu.archiveSession': string;
102
+ 'sessions.count.one': string;
103
+ 'sessions.count.other': string;
104
+ 'actions.workspace.aria': string;
105
+ 'actions.session.aria': string;
106
+ 'actions.newSession.aria': string;
107
+ 'status.running': string;
108
+ 'status.subagentsRunning.one': string;
109
+ 'status.subagentsRunning.other': string;
110
+ 'status.idle': string;
111
+ 'status.waitingApproval': string;
112
+ 'status.planReview': string;
113
+ 'status.waitingAnswer': string;
114
+ 'status.completed': string;
115
+ 'hover.created': string;
116
+ 'hover.copied': string;
117
+ 'date.ymd': string;
118
+ 'time.now': string;
119
+ 'time.minutes': string;
120
+ 'time.hours': string;
121
+ 'time.days': string;
122
+ 'time.months': string;
123
+ 'time.years': string;
124
+ 'time.ago': string;
125
+ };
126
+ //# sourceMappingURL=locales.d.ts.map
@@ -0,0 +1,90 @@
1
+ import type { WorkspaceBrowserProps } from '../contract/slots.ts';
2
+ import type { GroupNode, SearchResultNode, SessionNode } from '../tree.ts';
3
+ /** The standard locale seat, prop-passed from the browser root. */
4
+ type RowTranslate = WorkspaceBrowserProps['t'];
5
+ /**
6
+ * Project (workspace) header row: 54px, folder + title + session count;
7
+ * hover reveals the chevron and create button, and dwelling on a real
8
+ * Workspace shows its hover card (the ungrouped bucket has none).
9
+ * `containsCurrent` arrives on the node (derivation fact, no renderer scan).
10
+ * @param props.group - derived group node.
11
+ * @param props.onToggle - expand/collapse the group.
12
+ * @param props.onCreate - start a frontend Session inside this Workspace.
13
+ * @param props.t - the browser root's locale seat.
14
+ * @returns the row element.
15
+ */
16
+ export declare function ProjectRowItem({ group, onToggle, onCreate, actions, t }: {
17
+ group: GroupNode;
18
+ onToggle: () => void;
19
+ onCreate: () => void;
20
+ /** Real-Workspace actions; absent for the ungrouped bucket (no menu shown). */
21
+ actions?: {
22
+ rename: () => void;
23
+ delete: () => void;
24
+ } | undefined;
25
+ t: RowTranslate;
26
+ }): import("react").JSX.Element;
27
+ /**
28
+ * Session-row drag wiring supplied by the group owner (workspace groups only).
29
+ * `drop` reports the half of the row the pointer released on: 'before'
30
+ * inserts above this row, 'after' below it (the owner resolves the anchor).
31
+ */
32
+ export interface RowDragProps {
33
+ /** Start dragging this row. */
34
+ start: () => void;
35
+ /** A drag from the same group is in flight (rows show insert markers). */
36
+ active: boolean;
37
+ /** Current marker on this row: insert line above, below, or none. */
38
+ marker: 'before' | 'after' | null;
39
+ /** Report the hovered half while a same-group drag passes over this row. */
40
+ hover: (half: 'before' | 'after') => void;
41
+ drop: (half: 'before' | 'after') => void;
42
+ end: () => void;
43
+ }
44
+ /**
45
+ * One flat search result: title, Workspace context, and optional content
46
+ * excerpt. Search navigation opens the session only; it does not address an
47
+ * event inside the conversation.
48
+ * @param props.result - merged local/content search row.
49
+ * @param props.currentId - selected session id.
50
+ * @param props.onOpen - open the selected session.
51
+ * @param props.t - Workspace-browser translation seat.
52
+ * @returns the result button.
53
+ */
54
+ export declare function SearchResultItem({ result, currentId, onOpen, t }: {
55
+ result: SearchResultNode;
56
+ currentId: string | undefined;
57
+ onOpen: (id: SearchResultNode['id']) => void;
58
+ t: RowTranslate;
59
+ }): import("react").JSX.Element;
60
+ /**
61
+ * One top-level 34px session row: status dot (pending user interaction outranks
62
+ * own or descendant activity), title, relative time, and the row actions menu.
63
+ * @param props.node - derived session node.
64
+ * @param props.currentId - selected session id (row highlight).
65
+ * @param props.now - epoch ms for relative-time formatting.
66
+ * @param props.onOpen - open a session by id.
67
+ * @param props.onRename - open the session rename dialog (id + current title).
68
+ * @param props.onFork - fork a session at its last completed turn.
69
+ * @param props.onArchive - archive a session by id.
70
+ * @param props.drag - optional draggable-row wiring.
71
+ * @param props.t - the browser root's locale seat.
72
+ * @returns the session row.
73
+ */
74
+ export declare function SessionNodeItem({ node, currentId, now, onOpen, onRename, onFork, onArchive, drag, t }: {
75
+ node: SessionNode;
76
+ currentId: string | undefined;
77
+ now: number;
78
+ onOpen: (id: SessionNode['id']) => void;
79
+ /** Open the browser-owned session rename dialog (row menu action). */
80
+ onRename: (id: SessionNode['id'], currentTitle: string) => void;
81
+ /** Fork a session at its last completed turn (row menu action). */
82
+ onFork: (id: SessionNode['id']) => void;
83
+ /** Archive this session (row menu action; commits without a dialog). */
84
+ onArchive: (id: SessionNode['id']) => void;
85
+ /** Present only on draggable rows (workspace-group sessions outside search). */
86
+ drag?: RowDragProps | undefined;
87
+ t: RowTranslate;
88
+ }): import("react").JSX.Element;
89
+ export {};
90
+ //# sourceMappingURL=Rows.d.ts.map
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The workspace browser's viewing store: the session-list grouping mode,
3
+ * persisted across reloads. Module level exports the factory only (a
4
+ * module-level handle would pin the store identity across plugin reloads);
5
+ * register() receives the factory and the browser derives its PropsStore
6
+ * share from the return type.
7
+ */
8
+ import { type EngineStoreHandle } from '@deepseek-ai/dsh-client-runtime/client';
9
+ /** Session-list grouping mode: workspace sections or one flat recency list. */
10
+ export type WorkspaceGroupBy = 'workspace' | 'flat';
11
+ /** Workspace browser viewing state (grouping mode only; transient UI facts stay component-local). */
12
+ type WorkspaceViewState = {
13
+ groupBy: WorkspaceGroupBy;
14
+ };
15
+ /**
16
+ * Annotation twin of the actions literal below (the export needs a declared
17
+ * return type); drift fails assignability at the defineStore call.
18
+ */
19
+ type WorkspaceViewActions = {
20
+ setGroupBy: (draft: WorkspaceViewState, mode: WorkspaceGroupBy) => void;
21
+ };
22
+ /**
23
+ * Create the workspace browser viewing store handle.
24
+ * @returns the store handle (spec + type + identity + factory in one).
25
+ */
26
+ export declare function createWorkspaceViewStore(): EngineStoreHandle<WorkspaceViewState, WorkspaceViewActions>;
27
+ export {};
28
+ //# sourceMappingURL=stores.d.ts.map
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Derives the workspace browser tree from Host Workspace order and membership.
3
+ * Unassigned Sessions trail under Ungrouped; only the selected blank Session
4
+ * remains visible.
5
+ */
6
+ import { type PendingInteractionStatus, type SessionId, type SessionListState, type SessionSearchResultItem, type WorkspaceId, type WorkspaceView } from '@deepseek-ai/dsh-client-runtime/client';
7
+ /** Group key for Sessions outside every Workspace. */
8
+ export declare const UNGROUPED_KEY = "";
9
+ /** Display label for the ungrouped bucket row. */
10
+ export declare const UNGROUPED_LABEL = "Ungrouped";
11
+ /** One top-level session row in a group or the flat list. */
12
+ export interface SessionNode {
13
+ id: SessionId;
14
+ /** Stored display title; the renderer substitutes the localized New Session label for blank rows. */
15
+ title: string;
16
+ /** The provisional blank session (renderer shows the localized New Session title). */
17
+ blank: boolean;
18
+ /** The runtime Session list reports an interaction awaiting this user. */
19
+ pendingInteraction?: PendingInteractionStatus;
20
+ running: boolean;
21
+ /** Running descendants connected through uninterrupted subagent-origin lineage. */
22
+ runningSubagentCount: number;
23
+ /** Finished running while not selected and not yet opened (the green "done" reminder dot). */
24
+ completed: boolean;
25
+ updatedAt: number;
26
+ }
27
+ /** One workspace group section: header row facts + visible top-level session rows. */
28
+ export interface GroupNode {
29
+ /** Group key: the workspace id or {@link UNGROUPED_KEY}. */
30
+ key: string;
31
+ /** Backing Workspace id; absent only for the ungrouped bucket. */
32
+ workspaceId: WorkspaceId | undefined;
33
+ cwd: string | undefined;
34
+ /** Workspace creation time (epoch ms); absent only for the ungrouped bucket. */
35
+ createdAt: number | undefined;
36
+ label: string;
37
+ /** Total visible sessions in the group. */
38
+ sessionCount: number;
39
+ expanded: boolean;
40
+ /** The group contains the selected session (active folder tint; supplied here so the renderer never scans). */
41
+ containsCurrent: boolean;
42
+ /** Visible session rows (empty while the group is folded). */
43
+ sessions: readonly SessionNode[];
44
+ }
45
+ /** One flat search row combining list metadata with an optional content match. */
46
+ export interface SearchResultNode {
47
+ id: SessionId;
48
+ title: string;
49
+ workspace: string;
50
+ /** The runtime Session list reports an interaction awaiting this user. */
51
+ pendingInteraction?: PendingInteractionStatus;
52
+ running: boolean;
53
+ /** Running descendants connected through uninterrupted subagent-origin lineage. */
54
+ runningSubagentCount: number;
55
+ /** Finished running while not selected and not yet opened (the green "done" reminder dot). */
56
+ completed: boolean;
57
+ snippet?: string;
58
+ }
59
+ /** Bounded merged search projection plus the refine-query hint bit. */
60
+ export interface SearchResultSet {
61
+ items: readonly SearchResultNode[];
62
+ hasMore: boolean;
63
+ }
64
+ /** Viewing state consumed by the derivation. */
65
+ export interface TreeView {
66
+ expandedProjects: readonly string[];
67
+ }
68
+ /**
69
+ * Directory display label: basename of the path (both separators accepted).
70
+ * Ungrouped-bucket fallback for surfaces without a workspace title.
71
+ * @param cwd - directory path, or undefined for the ungrouped bucket.
72
+ * @returns basename, the raw cwd when it has no basename, or the ungrouped label.
73
+ */
74
+ export declare function projectLabel(cwd: string | undefined): string;
75
+ /**
76
+ * Derive the workspace browser groups with every session as a top-level row.
77
+ *
78
+ * Every group shows; sessions populate under expanded groups, preserving
79
+ * Host account order. Blank sessions are excluded except for the selected
80
+ * provisional New Session row; archived sessions are excluded everywhere.
81
+ * Content search lives outside this derivation
82
+ * (see {@link deriveSearchResults}).
83
+ * @param list - sessions list snapshot (`current` feeds containsCurrent).
84
+ * @param workspaces - real workspaces in stable Host order.
85
+ * @param archivedSessionIds - registry-global archive set.
86
+ * @param view - local expansion arrays.
87
+ * @returns group sections in render order.
88
+ */
89
+ export declare function deriveGroups(list: SessionListState, workspaces: readonly WorkspaceView[], archivedSessionIds: readonly SessionId[], view: TreeView): GroupNode[];
90
+ /**
91
+ * Derive the flat session list ("In one list" mode): every session — fork
92
+ * children included — as a top-level row, strictly newest-first. No grouping,
93
+ * no parent/child adjacency. Content search lives outside this derivation
94
+ * (see {@link deriveSearchResults}).
95
+ * @param list - sessions list snapshot.
96
+ * @param archivedSessionIds - registry-global archive set.
97
+ * @returns flat rows in render order.
98
+ */
99
+ export declare function deriveFlat(list: SessionListState, archivedSessionIds: readonly SessionId[]): SessionNode[];
100
+ /** Relative-time bucket of a session row's trailing label. */
101
+ export type RelativeTimeUnit = 'now' | 'minutes' | 'hours' | 'days' | 'months' | 'years';
102
+ /** Structured relative time: the bucket plus its magnitude (0 for 'now'). */
103
+ export interface RelativeTime {
104
+ unit: RelativeTimeUnit;
105
+ n: number;
106
+ }
107
+ /**
108
+ * Merge immediate title/Workspace substring matches with ranked Host content
109
+ * matches. Local rows lead newest-first, content-only rows retain backend
110
+ * order, and duplicate sessions receive the backend snippet in place.
111
+ * @param list - session metadata authority.
112
+ * @param workspaces - Workspace membership and display labels.
113
+ * @param query - caller text; surrounding whitespace is ignored.
114
+ * @param archivedSessionIds - registry-global archive set (members never match).
115
+ * @param content - ranked Host content-search page.
116
+ * @param limit - protocol-owned maximum merged row count.
117
+ * @returns bounded deduplicated flat rows and a refine-query hint bit.
118
+ */
119
+ export declare function deriveSearchResults(list: SessionListState, workspaces: readonly WorkspaceView[], query: string, archivedSessionIds: readonly SessionId[], content: {
120
+ items: readonly SessionSearchResultItem[];
121
+ hasMore: boolean;
122
+ }, limit: number): SearchResultSet;
123
+ /**
124
+ * Compact relative time for session rows, as a structured bucket the
125
+ * renderer localizes ("now"/"5min"/"3h"/"2d"/"4mo"/"1y" in en).
126
+ * @param updatedAt - epoch ms of the session's last activity.
127
+ * @param now - current epoch ms (injected for pure rendering).
128
+ * @returns the row's trailing time bucket and magnitude.
129
+ */
130
+ export declare function relativeTime(updatedAt: number, now: number): RelativeTime;
131
+ //# sourceMappingURL=tree.d.ts.map