@umialpha/dsh-client-ui-workspace-groups 0.0.0-stage → 0.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/LICENSE +21 -0
- package/README.i18n.yaml +73 -0
- package/README.md +233 -2
- package/README.zh.md +234 -0
- package/THIRD_PARTY_NOTICES.md +25 -0
- package/lib/client.js +5151 -0
- package/lib/index.js +11 -0
- package/lib/types/client/WorkspacePicker.d.ts +59 -0
- package/lib/types/client/contract/slots.d.ts +473 -0
- package/lib/types/client/index.d.ts +39 -0
- package/lib/types/client/locales.d.ts +246 -0
- package/lib/types/client/navigation.d.ts +157 -0
- package/lib/types/client/pin-order.d.ts +31 -0
- package/lib/types/client/rows/AnimatedRows.d.ts +44 -0
- package/lib/types/client/rows/Rows.d.ts +112 -0
- package/lib/types/client/rows/WorkspaceBrowser.d.ts +8 -0
- package/lib/types/client/session-actions/ArchiveSession.d.ts +23 -0
- package/lib/types/client/session-actions/ForkSession.d.ts +9 -0
- package/lib/types/client/session-actions/PinSession.d.ts +14 -0
- package/lib/types/client/session-actions/RenameSession.d.ts +18 -0
- package/lib/types/client/session-actions/RowActionToast.d.ts +8 -0
- package/lib/types/client/session-actions/derived.d.ts +12 -0
- package/lib/types/client/shortcuts.d.ts +46 -0
- package/lib/types/client/stores.d.ts +56 -0
- package/lib/types/client/tree.d.ts +203 -0
- package/lib/types/index.d.ts +9 -0
- package/package.json +115 -3
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,59 @@
|
|
|
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, WorkspaceSnapshot, WorkspaceView } from '@deepseek-ai/dsh-api-workspace-controller/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: WorkspaceSnapshot) => 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
|
+
/** Report the picking interaction and adoption occupancy. */
|
|
38
|
+
onBusyChange?: (busy: boolean) => void;
|
|
39
|
+
/** Only offer the add action, hide existing workspaces. */
|
|
40
|
+
addOnly?: boolean;
|
|
41
|
+
/** Menu opening direction relative to the anchor. */
|
|
42
|
+
side?: 'bottom' | 'top' | 'right';
|
|
43
|
+
/** Currently active workspace (trailing check in the picker list). */
|
|
44
|
+
selectedId?: WorkspaceId | undefined;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Render the pick menu plus the adoption error dialog.
|
|
48
|
+
* @param props - owner-controlled flow props.
|
|
49
|
+
* @returns menu + dialog elements.
|
|
50
|
+
*/
|
|
51
|
+
export declare function WorkspacePickFlow({ t, open, anchorRef, useWorkspaces, createWorkspace, useDirectoryFlow, renderDirectoryFlow, onPick, onClose, addOnly, onBusyChange, side, selectedId, }: WorkspacePickFlowProps): import("react").JSX.Element;
|
|
52
|
+
/**
|
|
53
|
+
* The conversation empty-state registration: adapts the owner share to the
|
|
54
|
+
* core flow (all state and semantics live in the flow / the owner).
|
|
55
|
+
* @param props - empty-state slot props (owner share + injected creation callback).
|
|
56
|
+
* @returns the flow element.
|
|
57
|
+
*/
|
|
58
|
+
export declare function WorkspacePicker({ open, anchorRef, useWorkspaces, selectedId, onPick, onClose, createWorkspace, useDirectoryFlow, renderSlot, t, }: WorkspacePickerProps): import("react").JSX.Element;
|
|
59
|
+
//# sourceMappingURL=WorkspacePicker.d.ts.map
|
|
@@ -0,0 +1,473 @@
|
|
|
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
|
+
* Both registrations declare a **directory-flow hole** (`single` kind): the
|
|
12
|
+
* 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
|
+
* WorkspaceBrowser also declares the two **Session row action lists**: every
|
|
26
|
+
* row of a Session's "..." menu is an entry of
|
|
27
|
+
* `sidebar.workspaces.session.menu.item`, and every hover button at the row's
|
|
28
|
+
* end is an entry of `sidebar.workspaces.session.row.action`. The shipped
|
|
29
|
+
* actions — pin, rename, fork, archive — are ordinary entries this package
|
|
30
|
+
* registers from `apply`, each carrying its own behavior in its own inject
|
|
31
|
+
* face and reading its own Host state through hooks that face injects, so a
|
|
32
|
+
* client plugin's action lands beside them by `order` and needs nothing from
|
|
33
|
+
* the browser beyond the row identity.
|
|
34
|
+
*
|
|
35
|
+
* The browser entry additionally declares two `list` seats per Session row
|
|
36
|
+
* (`sidebar.session.row.leading` / `sidebar.session.row.hover`) for ambient
|
|
37
|
+
* row decorations. Both take the row's Session identity and nothing else: a
|
|
38
|
+
* session-scoped seat would force a Session binding, which would activate and
|
|
39
|
+
* retain every listed Session.
|
|
40
|
+
*/
|
|
41
|
+
import type { HostObservable, InjectFace, PropsHooks, PropsLocale, PropsRenderSlots, PropsRuntime, PropsStore, SlotHookFactory } from '@deepseek-ai/dsh-client-ui-slots';
|
|
42
|
+
import type { SessionSearchResultItem } from '@deepseek-ai/dsh-api-session-controller/client';
|
|
43
|
+
import type { RemoteHostFacts } from '@deepseek-ai/dsh-api-remotes/client';
|
|
44
|
+
import type { SessionActivity, WorkspaceId, WorkspaceView } from '@deepseek-ai/dsh-api-workspace-controller/client';
|
|
45
|
+
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
46
|
+
import type { ShortcutCatalogEntry } from '@deepseek-ai/dsh-client-shortcuts/client';
|
|
47
|
+
import type { WorkspaceShortcutState } from '../shortcuts.ts';
|
|
48
|
+
import type { StartSessionOptions } from '../navigation.ts';
|
|
49
|
+
import type { createWorkspaceViewStore } from '../stores.ts';
|
|
50
|
+
/**
|
|
51
|
+
* Owner share of the directory-flow holes: the complete conversation between
|
|
52
|
+
* the trigger surface and the picking interaction. The occupant reads `open`
|
|
53
|
+
* to run/render its interaction and reports exactly one outcome per open.
|
|
54
|
+
*/
|
|
55
|
+
export interface DirectoryFlowOwnerProps {
|
|
56
|
+
/** True while a picking interaction is requested; flipping back to false withdraws the request. */
|
|
57
|
+
open: boolean;
|
|
58
|
+
/** True while the owner adopts a picked path (`createWorkspace` in flight); occupants disable their commit affordances. */
|
|
59
|
+
busy: boolean;
|
|
60
|
+
/** The operator picked a directory (absolute host path); the owner adopts it. */
|
|
61
|
+
onPicked: (path: string) => void;
|
|
62
|
+
/** The operator dismissed the interaction; the owner just closes the flow. */
|
|
63
|
+
onCancel: () => void;
|
|
64
|
+
/** The interaction itself failed (chooser missing, listing denied); the owner shows its error surface. */
|
|
65
|
+
onError: (message: string) => void;
|
|
66
|
+
}
|
|
67
|
+
/** Owner share of one Session row action occurrence: the row the action belongs to. */
|
|
68
|
+
export interface SessionRowOwnerProps {
|
|
69
|
+
/** Session the row shows. */
|
|
70
|
+
sessionId: SessionId;
|
|
71
|
+
/** Row display title: persisted title, or empty when the Session has none. */
|
|
72
|
+
displayTitle: string;
|
|
73
|
+
}
|
|
74
|
+
/** The row menu's open state as its owner holds it: the `useState` pair. */
|
|
75
|
+
export type MenuOpenState = readonly [open: boolean, setOpen: (open: boolean) => void];
|
|
76
|
+
/**
|
|
77
|
+
* Hook every row-menu entry receives. Rows only render while the menu is
|
|
78
|
+
* open, so an entry reads it for the setter: `setOpen(false)` dismisses the
|
|
79
|
+
* menu the entry sits in — the same state the owner's `onClose` sets.
|
|
80
|
+
*/
|
|
81
|
+
export type UseMenuOpenState = () => MenuOpenState;
|
|
82
|
+
/**
|
|
83
|
+
* Bind the row's render occurrence into the entries' `useMenuOpenState` hook:
|
|
84
|
+
* the owner supplies its open-state pair as the occurrence's `hookContext`,
|
|
85
|
+
* and the hook hands that pair back.
|
|
86
|
+
* @param _standard - framework standard props (unused).
|
|
87
|
+
* @param state - the menu's open-state pair from the render occurrence.
|
|
88
|
+
* @returns the hook the entry calls.
|
|
89
|
+
*/
|
|
90
|
+
export declare const menuOpenStateFactory: SlotHookFactory<'sidebar.workspaces.session.menu.item', UseMenuOpenState>;
|
|
91
|
+
/**
|
|
92
|
+
* Owner share of the two Session-row schedule seats. Both receive only the
|
|
93
|
+
* row's Session identity: the occupant reads that Session's own scheduled
|
|
94
|
+
* tasks, and reading them activates nothing.
|
|
95
|
+
*/
|
|
96
|
+
export interface SessionRowScheduleOwnerProps {
|
|
97
|
+
/** Session this row shows; the occupant addresses its own data by this id. */
|
|
98
|
+
readonly sessionId: SessionId;
|
|
99
|
+
}
|
|
100
|
+
/** Optional global Pinned-area share owned by WorkspaceBrowser. */
|
|
101
|
+
export interface WorkspaceSessionGroupsOwnerProps {
|
|
102
|
+
/** Session currently dragged from the tree or flat list, or null otherwise. */
|
|
103
|
+
activeSessionDrag: {
|
|
104
|
+
/** Session offered to the optional Pinned area. */
|
|
105
|
+
sessionId: SessionId;
|
|
106
|
+
/** Claim this drop synchronously so the source Session list cannot commit a reorder. */
|
|
107
|
+
claimDrop: () => void;
|
|
108
|
+
} | null;
|
|
109
|
+
}
|
|
110
|
+
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
111
|
+
interface SlotMap {
|
|
112
|
+
/** Directory-flow hole under the conversation empty-state picker (declared by the WorkspacePicker entry). */
|
|
113
|
+
'conversation.hero.workspace.directoryFlow': {
|
|
114
|
+
kind: 'single';
|
|
115
|
+
scope: 'root';
|
|
116
|
+
owner: DirectoryFlowOwnerProps;
|
|
117
|
+
};
|
|
118
|
+
/** Directory-flow hole under the sidebar browsing region (declared by the WorkspaceBrowser entry). */
|
|
119
|
+
'sidebar.workspaces.directoryFlow': {
|
|
120
|
+
kind: 'single';
|
|
121
|
+
scope: 'root';
|
|
122
|
+
owner: DirectoryFlowOwnerProps;
|
|
123
|
+
};
|
|
124
|
+
/** Optional global Pinned area rendered before the sibling Workspace section header. */
|
|
125
|
+
'sidebar.workspaces.sessionGroups': {
|
|
126
|
+
kind: 'single';
|
|
127
|
+
scope: 'root';
|
|
128
|
+
owner: WorkspaceSessionGroupsOwnerProps;
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Leading decoration of one Session row, in the 16px cell before the title
|
|
132
|
+
* that the row's own state dot otherwise occupies. A higher-priority state
|
|
133
|
+
* (a pending interaction, a new message, live activity) replaces the seat
|
|
134
|
+
* with that dot for the same row, so an occupant here never renders beside
|
|
135
|
+
* a status dot and is mounted only by a row whose primary state is idle.
|
|
136
|
+
* An archived row keeps that cell blank — neither its status dot nor this
|
|
137
|
+
* seat renders there, and its live status appears on the hover card only.
|
|
138
|
+
*/
|
|
139
|
+
'sidebar.session.row.leading': {
|
|
140
|
+
kind: 'list';
|
|
141
|
+
scope: 'root';
|
|
142
|
+
owner: SessionRowScheduleOwnerProps;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Section of the Session row's hover card between its relative time and
|
|
146
|
+
* its trailing status line. Mounted only while that card is open.
|
|
147
|
+
*/
|
|
148
|
+
'sidebar.session.row.hover': {
|
|
149
|
+
kind: 'list';
|
|
150
|
+
scope: 'root';
|
|
151
|
+
owner: SessionRowScheduleOwnerProps;
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* The rows of one Session's "..." menu, in ascending `order`. ui-workspace
|
|
155
|
+
* registers the shipped rows here — `pin` (100), `rename` (200), `fork`
|
|
156
|
+
* (300), `archive` (400) — so a plugin row is placed by its own `order`
|
|
157
|
+
* among them. Use a package-namespaced `id`; reusing a shipped id at
|
|
158
|
+
* another `priority` shadows that row. Each entry renders one
|
|
159
|
+
* `role="menuitem"` `<button>` (the shipped rows use ui-primitives'
|
|
160
|
+
* `MenuItemButton`, which adds the host styling and `separatorBefore`),
|
|
161
|
+
* decides its own visibility from its own state, and dismisses the menu
|
|
162
|
+
* through the injected `useMenuOpenState` hook after acting; the list's
|
|
163
|
+
* keyboard walk and focus return read the DOM, so any such button joins
|
|
164
|
+
* them. Labels come from the contributing package's locale namespace.
|
|
165
|
+
* @example
|
|
166
|
+
* return {
|
|
167
|
+
* inject: ['slots'],
|
|
168
|
+
* apply(ctx) {
|
|
169
|
+
* const copyLabel = 'Copy Session ID' // Localize in the contributing package.
|
|
170
|
+
* ctx.slots.inject('sidebar.workspaces.session.menu.item', () => ctx.slots.register(
|
|
171
|
+
* { name: 'sidebar.workspaces.session.menu.item', id: 'copy-session-id', order: 500 },
|
|
172
|
+
* ({ sessionId, useMenuOpenState }) => {
|
|
173
|
+
* const [, setMenuOpen] = useMenuOpenState()
|
|
174
|
+
* return React.createElement(
|
|
175
|
+
* 'button',
|
|
176
|
+
* { type: 'button', role: 'menuitem', onClick: () => { setMenuOpen(false); void navigator.clipboard.writeText(sessionId) } },
|
|
177
|
+
* copyLabel,
|
|
178
|
+
* )
|
|
179
|
+
* },
|
|
180
|
+
* ))
|
|
181
|
+
* },
|
|
182
|
+
* }
|
|
183
|
+
*/
|
|
184
|
+
'sidebar.workspaces.session.menu.item': {
|
|
185
|
+
kind: 'list';
|
|
186
|
+
scope: 'root';
|
|
187
|
+
owner: SessionRowOwnerProps;
|
|
188
|
+
hookContext: MenuOpenState;
|
|
189
|
+
inject: {
|
|
190
|
+
hooks: {
|
|
191
|
+
menuOpenState: SlotHookFactory<'sidebar.workspaces.session.menu.item', UseMenuOpenState>;
|
|
192
|
+
shortcuts: HostObservable<readonly ShortcutCatalogEntry[]>;
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* The hover buttons at the end of one Session row, in ascending `order`,
|
|
198
|
+
* after the "..." menu trigger. ui-workspace registers `archive` (100) and
|
|
199
|
+
* `pin` (200) here. An entry renders one icon button (or nothing, when its
|
|
200
|
+
* action does not apply to the row) and owns the action it performs. Clicks
|
|
201
|
+
* inside the strip stay in the strip, so the button needs no propagation
|
|
202
|
+
* handling to keep the row from opening.
|
|
203
|
+
*/
|
|
204
|
+
'sidebar.workspaces.session.row.action': {
|
|
205
|
+
kind: 'list';
|
|
206
|
+
scope: 'root';
|
|
207
|
+
owner: SessionRowOwnerProps;
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/** The two directory-flow holes; a flow package's client half registers its one component into both. */
|
|
212
|
+
export type DirectoryFlowSlotName = 'conversation.hero.workspace.directoryFlow' | 'sidebar.workspaces.directoryFlow';
|
|
213
|
+
/**
|
|
214
|
+
* Directory-picking share both trigger surfaces consume. Occupancy rides the
|
|
215
|
+
* inject face's reserved `hooks` compartment: the renderer binds the source
|
|
216
|
+
* into the `useDirectoryFlow` selector hook, so an empty hole hides the
|
|
217
|
+
* "Add workspace…" entry reactively and the surface withdraws an open
|
|
218
|
+
* flow whose occupant unloaded mid-interaction (nobody is left to cancel).
|
|
219
|
+
*/
|
|
220
|
+
export type DirectoryPickingInjected = {
|
|
221
|
+
hooks: {
|
|
222
|
+
/** True while this surface's directory-flow hole is occupied. */
|
|
223
|
+
directoryFlow: HostObservable<boolean>;
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
/** Component-side view of the picking share: the bound occupancy selector hook. */
|
|
227
|
+
export type DirectoryPickingHooks = PropsHooks<DirectoryPickingInjected['hooks']>;
|
|
228
|
+
/**
|
|
229
|
+
* Browser-private injected share (arrives via the register inject factory).
|
|
230
|
+
* Data reads use the global framework hooks; these are the Host actions the
|
|
231
|
+
* browsing region drives.
|
|
232
|
+
*/
|
|
233
|
+
export type WorkspaceBrowserInjected = {
|
|
234
|
+
hooks: DirectoryPickingInjected['hooks'] & {
|
|
235
|
+
/**
|
|
236
|
+
* Fixed Host facts, reached through a hook rather than injected as values:
|
|
237
|
+
* the renderer memoizes an entry's inject result for the registration's
|
|
238
|
+
* lifetime, so facts read there would freeze at whatever the first render
|
|
239
|
+
* saw. Select the field the surface needs (`info => info.home`).
|
|
240
|
+
*/
|
|
241
|
+
hostInfo: HostObservable<RemoteHostFacts>;
|
|
242
|
+
workspaceShortcuts: HostObservable<WorkspaceShortcutState>;
|
|
243
|
+
shortcuts: HostObservable<readonly ShortcutCatalogEntry[]>;
|
|
244
|
+
};
|
|
245
|
+
/** Open the browser search and focus its input. */
|
|
246
|
+
requestSearch: () => void;
|
|
247
|
+
/** Request the existing directory picker. */
|
|
248
|
+
requestAddWorkspace: () => void;
|
|
249
|
+
/** Consume the directory-picker opening request. */
|
|
250
|
+
closeAddWorkspace: () => void;
|
|
251
|
+
/** Publish directory interaction occupancy for command availability. */
|
|
252
|
+
setDirectoryBusy: (busy: boolean) => void;
|
|
253
|
+
/** Dismiss the shortcut's fork-failure notification. */
|
|
254
|
+
dismissForkError: () => void;
|
|
255
|
+
/**
|
|
256
|
+
* Create a fresh Session, or preserve a reusable blank with explicit draft options.
|
|
257
|
+
* Without an explicit Workspace, inherit the current Session Workspace,
|
|
258
|
+
* then the recent Workspace, or clear into the New Session view.
|
|
259
|
+
*/
|
|
260
|
+
startSession: (workspaceId?: WorkspaceId, options?: StartSessionOptions) => void;
|
|
261
|
+
/** Open a real Session. */
|
|
262
|
+
open: (sessionId: SessionId) => void;
|
|
263
|
+
/**
|
|
264
|
+
* Search current visible conversation messages. The Host fixes the result
|
|
265
|
+
* bound; `hasMore` means the query needs narrowing.
|
|
266
|
+
*/
|
|
267
|
+
searchSessions: (query: string, signal: AbortSignal) => Promise<{
|
|
268
|
+
items: readonly SessionSearchResultItem[];
|
|
269
|
+
hasMore: boolean;
|
|
270
|
+
}>;
|
|
271
|
+
/** Maximum number of merged rows rendered for one search. */
|
|
272
|
+
searchResultLimit: number;
|
|
273
|
+
/** Open the Session rename dialog (a row title double-click); the rename action entry raises the same request. */
|
|
274
|
+
requestSessionRename: (sessionId: SessionId, currentTitle: string) => void;
|
|
275
|
+
/** Tell the user an archived row cannot be opened (a click on it). */
|
|
276
|
+
notifyArchivedNotOpenable: () => void;
|
|
277
|
+
/** Rename a Host Workspace (rejects on name conflict; resolves on durability). */
|
|
278
|
+
renameWorkspace: (workspaceId: WorkspaceId, title: string) => Promise<void>;
|
|
279
|
+
/** Delete only a Host Workspace registration; directory and Session logs remain. */
|
|
280
|
+
deleteWorkspace: (workspaceId: WorkspaceId) => Promise<void>;
|
|
281
|
+
/**
|
|
282
|
+
* Reorder a Workspace in the durable registry display order.
|
|
283
|
+
* Omitted anchor appends to the end.
|
|
284
|
+
*/
|
|
285
|
+
insertWorkspaceBefore: (workspaceId: WorkspaceId, beforeWorkspaceId?: WorkspaceId) => Promise<void>;
|
|
286
|
+
/** Remove a Session from the registry-global archived set (the search results' restore button). */
|
|
287
|
+
unarchiveSession: (sessionId: SessionId) => Promise<void>;
|
|
288
|
+
/** Adopt a picked host directory as a real Workspace before targeting a Session. */
|
|
289
|
+
createWorkspace: (input: {
|
|
290
|
+
path: string;
|
|
291
|
+
}) => Promise<WorkspaceView>;
|
|
292
|
+
};
|
|
293
|
+
/** The browser's declared viewing store handle, shared with the row actions that write view state. */
|
|
294
|
+
export type WorkspaceViewStoreHandle = ReturnType<typeof createWorkspaceViewStore>;
|
|
295
|
+
/** Props of one shipped row-menu entry: owner share + locale seat + the entry's own injected share. */
|
|
296
|
+
export type SessionMenuItemProps<Injected extends object = object> = PropsRuntime<'sidebar.workspaces.session.menu.item'> & PropsLocale<'workspace'> & InjectFace<Injected>;
|
|
297
|
+
/** Props of one shipped row hover button: owner share + locale seat + the entry's own injected share. */
|
|
298
|
+
export type SessionRowActionProps<Injected extends object = object> = PropsRuntime<'sidebar.workspaces.session.row.action'> & PropsLocale<'workspace'> & InjectFace<Injected>;
|
|
299
|
+
/** One transient Workspace notice rendered by the overlay toast entry. */
|
|
300
|
+
export type RowToast = {
|
|
301
|
+
kind: 'archived';
|
|
302
|
+
sessionId: SessionId;
|
|
303
|
+
} | {
|
|
304
|
+
kind: 'stoppedAndArchived';
|
|
305
|
+
sessionId: SessionId;
|
|
306
|
+
} | {
|
|
307
|
+
kind: 'pinFailed';
|
|
308
|
+
} | {
|
|
309
|
+
kind: 'unpinFailed';
|
|
310
|
+
} | {
|
|
311
|
+
kind: 'archivedNotOpenable';
|
|
312
|
+
} | {
|
|
313
|
+
kind: 'defaultWorkspaceFailed';
|
|
314
|
+
} | {
|
|
315
|
+
kind: 'forkRequiresOpen';
|
|
316
|
+
sessionId: SessionId;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* An explicit New Session request that failed. `message` is untranslated:
|
|
320
|
+
* a Host refusal as `code: message` — the stable code stays in the copy so
|
|
321
|
+
* a report can be searched by it — and any other failure's own message.
|
|
322
|
+
*/
|
|
323
|
+
| {
|
|
324
|
+
kind: 'createFailed';
|
|
325
|
+
message: string;
|
|
326
|
+
};
|
|
327
|
+
/** The notice on display; `seq` keys remounts so a repeated notice restarts its hold. */
|
|
328
|
+
export type RowToastState = RowToast & {
|
|
329
|
+
seq: number;
|
|
330
|
+
};
|
|
331
|
+
/**
|
|
332
|
+
* Pin action share (menu row and hover button). The callbacks carry the whole
|
|
333
|
+
* behavior: the Host call, fronting the Session in its saved orders after a
|
|
334
|
+
* pin, and the failure notice. The hooks are the registry-global sets as
|
|
335
|
+
* Sets, so a row reads its own membership with one lookup.
|
|
336
|
+
*/
|
|
337
|
+
export interface PinSessionInjected {
|
|
338
|
+
hooks: {
|
|
339
|
+
/** Pinned Session ids. */
|
|
340
|
+
pinned: HostObservable<ReadonlySet<SessionId>>;
|
|
341
|
+
/** Archived Session ids (pin does not apply to an archived row). */
|
|
342
|
+
archived: HostObservable<ReadonlySet<SessionId>>;
|
|
343
|
+
};
|
|
344
|
+
/** Pin a Session; on success it leads its accounts' saved orders, on failure the notice says so. */
|
|
345
|
+
pinSession: (sessionId: SessionId) => void;
|
|
346
|
+
/** Unpin a Session; saved positions stay as they are. */
|
|
347
|
+
unpinSession: (sessionId: SessionId) => void;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Archive action share (menu row and hover button). The callbacks carry the
|
|
351
|
+
* whole behavior: the Host call, the notice a success raises, the
|
|
352
|
+
* stop-and-archive confirmation a Host refusal for running work raises, and
|
|
353
|
+
* the diagnostics for any other rejection.
|
|
354
|
+
*/
|
|
355
|
+
export interface ArchiveSessionInjected {
|
|
356
|
+
hooks: {
|
|
357
|
+
/** Archived Session ids. */
|
|
358
|
+
archived: HostObservable<ReadonlySet<SessionId>>;
|
|
359
|
+
};
|
|
360
|
+
/**
|
|
361
|
+
* Archive a Session into the registry-global set: the row keeps its
|
|
362
|
+
* account position and shows per the archived filter; archiving the
|
|
363
|
+
* current session clears the selection into the New Session view state.
|
|
364
|
+
* A Session with running work is not archived by this call: the Host's
|
|
365
|
+
* refusal opens the stop-and-archive confirmation instead.
|
|
366
|
+
*/
|
|
367
|
+
archiveSession: (sessionId: SessionId) => void;
|
|
368
|
+
/** Remove a Session from the registry-global archived set. */
|
|
369
|
+
unarchiveSession: (sessionId: SessionId) => void;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* A stop-and-archive confirmation the archive action asked for: the Host
|
|
373
|
+
* refused the plain archive because this work still runs.
|
|
374
|
+
*/
|
|
375
|
+
export interface SessionArchiveConfirmRequest {
|
|
376
|
+
/** Session to stop and archive. */
|
|
377
|
+
sessionId: SessionId;
|
|
378
|
+
/** The row's display title, named in the dialog. */
|
|
379
|
+
displayTitle: string;
|
|
380
|
+
/** What the Host reported running, in family order. */
|
|
381
|
+
activity: readonly SessionActivity[];
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Stop-and-archive dialog share: the pending confirmation, its settlement,
|
|
385
|
+
* and the archive hop that asks the Host to stop the work first.
|
|
386
|
+
*/
|
|
387
|
+
export interface SessionArchiveConfirmInjected {
|
|
388
|
+
hooks: {
|
|
389
|
+
/** The confirmation asked for, until the dialog consumes or cancels it. */
|
|
390
|
+
archiveRequest: HostObservable<SessionArchiveConfirmRequest | null>;
|
|
391
|
+
};
|
|
392
|
+
/** Consume or cancel the pending confirmation. */
|
|
393
|
+
settleSessionArchive: () => void;
|
|
394
|
+
/**
|
|
395
|
+
* Archive a Session after the Host stops its running work; resolves once
|
|
396
|
+
* the archive set is durable (the stops settle in the background) and
|
|
397
|
+
* raises the stopped-and-archived notice.
|
|
398
|
+
*/
|
|
399
|
+
stopAndArchiveSession: (sessionId: SessionId) => Promise<void>;
|
|
400
|
+
}
|
|
401
|
+
/** Fork action share. */
|
|
402
|
+
export interface ForkSessionInjected {
|
|
403
|
+
/** Fork a Session at its last completed turn; the child arrives through the Host list. */
|
|
404
|
+
forkSession: (sessionId: SessionId) => void;
|
|
405
|
+
}
|
|
406
|
+
/** Rename action share: the row only raises the request; the dialog entry answers it. */
|
|
407
|
+
export interface RenameSessionInjected {
|
|
408
|
+
/** Ask for the rename dialog, seeded with the row's current title. */
|
|
409
|
+
requestSessionRename: (sessionId: SessionId, currentTitle: string) => void;
|
|
410
|
+
}
|
|
411
|
+
/** A Session rename the rename action asked for; the dialog entry opens on it. */
|
|
412
|
+
export interface SessionRenameTarget {
|
|
413
|
+
/** Session to rename. */
|
|
414
|
+
sessionId: SessionId;
|
|
415
|
+
/** Title the dialog seeds its draft from. */
|
|
416
|
+
currentTitle: string;
|
|
417
|
+
}
|
|
418
|
+
/** Rename dialog share: the pending request, its settlement, and the rename hop the dialog confirms with. */
|
|
419
|
+
export interface SessionRenameDialogInjected {
|
|
420
|
+
hooks: {
|
|
421
|
+
/** The rename asked for, until the dialog consumes or cancels it. */
|
|
422
|
+
renameRequest: HostObservable<SessionRenameTarget | null>;
|
|
423
|
+
};
|
|
424
|
+
/** Consume or cancel the pending request. */
|
|
425
|
+
settleSessionRename: () => void;
|
|
426
|
+
/** Rename a Session (explicit user title; resolves on host acceptance). */
|
|
427
|
+
renameSession: (sessionId: SessionId, title: string) => Promise<void>;
|
|
428
|
+
}
|
|
429
|
+
/** Row toast share: the notice, dismissal, archive recovery, and explicit source-history opening. */
|
|
430
|
+
export interface RowToastInjected {
|
|
431
|
+
hooks: {
|
|
432
|
+
/** The notice on display, or none. */
|
|
433
|
+
toast: HostObservable<RowToastState | null>;
|
|
434
|
+
};
|
|
435
|
+
/** Take the notice down. */
|
|
436
|
+
dismissToast: () => void;
|
|
437
|
+
/** Undo an archive from its notice. */
|
|
438
|
+
undoArchive: (sessionId: SessionId) => void;
|
|
439
|
+
/** Switch the archived filter to "show" so the archived row is back in view. */
|
|
440
|
+
showArchived: () => void;
|
|
441
|
+
/** Open the fork source without retrying the fork. */
|
|
442
|
+
openForkSource: (sessionId: SessionId) => void;
|
|
443
|
+
}
|
|
444
|
+
/** Props of the rename dialog entry in `shell.overlay`. */
|
|
445
|
+
export type SessionRenameDialogProps = PropsRuntime<'shell.overlay'> & PropsLocale<'workspace'> & Omit<SessionRenameDialogInjected, 'hooks'> & PropsHooks<SessionRenameDialogInjected['hooks']>;
|
|
446
|
+
/** Props of the stop-and-archive dialog entry in `shell.overlay`. */
|
|
447
|
+
export type SessionArchiveConfirmProps = PropsRuntime<'shell.overlay'> & PropsLocale<'workspace'> & Omit<SessionArchiveConfirmInjected, 'hooks'> & PropsHooks<SessionArchiveConfirmInjected['hooks']>;
|
|
448
|
+
/**
|
|
449
|
+
* Props of the row toast entry in `shell.overlay`. The declared viewing store
|
|
450
|
+
* carries the archived filter; the archived notice omits its filter action
|
|
451
|
+
* when archived rows are already visible.
|
|
452
|
+
*/
|
|
453
|
+
export type RowToastProps = PropsRuntime<'shell.overlay'> & PropsLocale<'workspace'> & PropsStore<WorkspaceViewStoreHandle> & Omit<RowToastInjected, 'hooks'> & PropsHooks<RowToastInjected['hooks']>;
|
|
454
|
+
/** Full browser props: shell owner share + viewing store + injected actions + the locale seat. */
|
|
455
|
+
export type WorkspaceBrowserProps = PropsRuntime<'sidebar.workspaces'> & PropsRenderSlots<'sidebar.workspaces.directoryFlow' | 'sidebar.workspaces.sessionGroups' | 'sidebar.workspaces.session.menu.item' | 'sidebar.workspaces.session.row.action' | 'sidebar.session.row.leading' | 'sidebar.session.row.hover'> & PropsStore<WorkspaceViewStoreHandle> & Omit<WorkspaceBrowserInjected, 'hooks'> & PropsHooks<WorkspaceBrowserInjected['hooks']> & PropsLocale<'workspace'>;
|
|
456
|
+
/**
|
|
457
|
+
* Picker-private injected share. Pick semantics remain in the owner's onPick
|
|
458
|
+
* callback; this callback creates only the real Host Workspace. A type alias
|
|
459
|
+
* supplies the implicit index signature required by the registry.
|
|
460
|
+
*/
|
|
461
|
+
export type WorkspacePickerInjected = DirectoryPickingInjected & {
|
|
462
|
+
/** Adopt a picked host directory as a real Workspace before targeting a Session. */
|
|
463
|
+
createWorkspace: (input: {
|
|
464
|
+
path: string;
|
|
465
|
+
}) => Promise<WorkspaceView>;
|
|
466
|
+
};
|
|
467
|
+
/**
|
|
468
|
+
* Full picker props: the owner share plus the creation callback and the
|
|
469
|
+
* locale seat. The two picker holes (blank-session hero / New-Session view)
|
|
470
|
+
* share one owner currency, so one composed type serves both registrations.
|
|
471
|
+
*/
|
|
472
|
+
export type WorkspacePickerProps = PropsRuntime<'conversation.hero.workspace'> & PropsRenderSlots<'conversation.hero.workspace.directoryFlow'> & Omit<WorkspacePickerInjected, 'hooks'> & PropsHooks<WorkspacePickerInjected['hooks']> & PropsLocale<'workspace'>;
|
|
473
|
+
//# sourceMappingURL=slots.d.ts.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { WorkspaceSnapshot } from '@deepseek-ai/dsh-api-workspace-controller/client';
|
|
3
|
+
import type { SnapshotSelectorHook } from '@deepseek-ai/dsh-client-ui-slots';
|
|
4
|
+
import { type WorkspaceKey } from './locales.ts';
|
|
5
|
+
export type { StartSessionOptions, UiWorkspace } from './navigation.ts';
|
|
6
|
+
export type { DirectoryFlowOwnerProps, DirectoryFlowSlotName, DirectoryPickingHooks, DirectoryPickingInjected, MenuOpenState, RowToast, SessionRenameTarget, SessionRowOwnerProps, UseMenuOpenState, WorkspaceBrowserInjected, SessionRowScheduleOwnerProps, WorkspaceSessionGroupsOwnerProps, WorkspaceBrowserProps, WorkspacePickerInjected, WorkspacePickerProps, } from './contract/slots.ts';
|
|
7
|
+
export type { WorkspaceKey } from './locales.ts';
|
|
8
|
+
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
9
|
+
interface GlobalStandardProps {
|
|
10
|
+
/** Selector hook over the pure Workspace Controller snapshot. */
|
|
11
|
+
useWorkspaces: SnapshotSelectorHook<WorkspaceSnapshot>;
|
|
12
|
+
}
|
|
13
|
+
interface LocaleNamespaceMap {
|
|
14
|
+
/** The workspace browsing region and pick/create flow copy. */
|
|
15
|
+
workspace: WorkspaceKey;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
declare module '@deepseek-ai/dsh-api-session-controller/client' {
|
|
19
|
+
interface SessionReferenceSourceMap {
|
|
20
|
+
workspaceOperation: unknown;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Required services (cordis fiber inject). The target slots are declared by
|
|
25
|
+
* the ui-sidebar / ui-conversation applies, whose activation order relative
|
|
26
|
+
* to this one is NOT constrained: dsh.client.inject edges are informational
|
|
27
|
+
* (loading/prefetch metadata, never apply sequencing) and neither owner
|
|
28
|
+
* provides a waitable service. apply therefore depends on each slot
|
|
29
|
+
* declaration through `slots.inject()` instead of assuming order.
|
|
30
|
+
*/
|
|
31
|
+
export declare const inject: string[];
|
|
32
|
+
/**
|
|
33
|
+
* Register the browser and picker once their slot declarations are on the
|
|
34
|
+
* ledger. Inject factories return plain callbacks; data reads use the
|
|
35
|
+
* framework's global hooks.
|
|
36
|
+
* @param ctx - client root context.
|
|
37
|
+
*/
|
|
38
|
+
export declare function apply(ctx: Context): void;
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|