@qilin-agent/client-ui-workspace 0.0.0-stage → 3.1.4
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 +67 -0
- package/README.md +134 -2
- package/README.zh.md +135 -0
- package/lib/client.js +3334 -0
- package/lib/index.js +11 -0
- package/lib/types/client/WorkspacePicker.d.ts +57 -0
- package/lib/types/client/contract/slots.d.ts +213 -0
- package/lib/types/client/index.d.ts +49 -0
- package/lib/types/client/locales.d.ts +160 -0
- package/lib/types/client/navigation.d.ts +148 -0
- package/lib/types/client/pin-order.d.ts +26 -0
- package/lib/types/client/rows/Rows.d.ts +116 -0
- package/lib/types/client/rows/WorkspaceBrowser.d.ts +8 -0
- package/lib/types/client/shortcuts.d.ts +39 -0
- package/lib/types/client/stores.d.ts +54 -0
- package/lib/types/client/subagent-lineage.d.ts +21 -0
- package/lib/types/client/tree.d.ts +187 -0
- package/lib/types/index.d.ts +9 -0
- package/package.json +85 -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 qilin.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,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, WorkspaceSnapshot, WorkspaceView } from '@qilin-agent/api-workspace-controller/client';
|
|
13
|
+
import type { SnapshotSelectorHook } from '@qilin-agent/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
|
+
/** 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,213 @@
|
|
|
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, PropsHooks, PropsLocale, PropsRenderSlots, PropsRuntime, PropsStore } from '@qilin-agent/client-ui-slots';
|
|
26
|
+
import type { SessionSearchResultItem } from '@qilin-agent/api-session-controller/client';
|
|
27
|
+
import type { RemoteHostFacts } from '@qilin-agent/api-remotes/client';
|
|
28
|
+
import type { WorkspaceId, WorkspaceView } from '@qilin-agent/api-workspace-controller/client';
|
|
29
|
+
import type { SessionId } from '@qilin-agent/session/types';
|
|
30
|
+
import type { createWorkspaceViewStore } from '../stores.ts';
|
|
31
|
+
import type { ShortcutCatalogEntry } from '@qilin-agent/client-shortcuts/client';
|
|
32
|
+
import type { WorkspaceShortcutState } from '../shortcuts.ts';
|
|
33
|
+
/**
|
|
34
|
+
* Owner share of the directory-flow holes: the complete conversation between
|
|
35
|
+
* the trigger surface and the picking interaction. The occupant reads `open`
|
|
36
|
+
* to run/render its interaction and reports exactly one outcome per open.
|
|
37
|
+
*/
|
|
38
|
+
export interface DirectoryFlowOwnerProps {
|
|
39
|
+
/** True while a picking interaction is requested; flipping back to false withdraws the request. */
|
|
40
|
+
open: boolean;
|
|
41
|
+
/** True while the owner adopts a picked path (`createWorkspace` in flight); occupants disable their commit affordances. */
|
|
42
|
+
busy: boolean;
|
|
43
|
+
/** The operator picked a directory (absolute host path); the owner adopts it. */
|
|
44
|
+
onPicked: (path: string) => void;
|
|
45
|
+
/** The operator dismissed the interaction; the owner just closes the flow. */
|
|
46
|
+
onCancel: () => void;
|
|
47
|
+
/** The interaction itself failed (chooser missing, listing denied); the owner shows its error surface. */
|
|
48
|
+
onError: (message: string) => void;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Owner share of the two Session-row schedule seats. Both receive only the
|
|
52
|
+
* row's Session identity: the occupant reads that Session's own scheduled
|
|
53
|
+
* tasks, and reading them activates nothing.
|
|
54
|
+
*/
|
|
55
|
+
export interface SessionRowScheduleOwnerProps {
|
|
56
|
+
/** Session this row shows; the occupant addresses its own data by this id. */
|
|
57
|
+
readonly sessionId: SessionId;
|
|
58
|
+
}
|
|
59
|
+
declare module '@qilin-agent/client-ui-slots' {
|
|
60
|
+
interface SlotMap {
|
|
61
|
+
/** Directory-flow hole under the conversation empty-state picker (declared by the WorkspacePicker entry). */
|
|
62
|
+
'conversation.hero.workspace.directoryFlow': {
|
|
63
|
+
kind: 'single';
|
|
64
|
+
scope: 'root';
|
|
65
|
+
owner: DirectoryFlowOwnerProps;
|
|
66
|
+
};
|
|
67
|
+
/** Directory-flow hole under the sidebar browsing region (declared by the WorkspaceBrowser entry). */
|
|
68
|
+
'sidebar.workspaces.directoryFlow': {
|
|
69
|
+
kind: 'single';
|
|
70
|
+
scope: 'root';
|
|
71
|
+
owner: DirectoryFlowOwnerProps;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Leading decoration of one Session row, in the 16px cell before the title
|
|
75
|
+
* that the row's own state dot otherwise occupies. A higher-priority state
|
|
76
|
+
* (a pending interaction, a new message, live activity) replaces the seat
|
|
77
|
+
* with that dot for the same row, so an occupant here never renders beside
|
|
78
|
+
* a status dot and is mounted only by a row whose primary state is idle.
|
|
79
|
+
* An archived row keeps that cell blank — neither its status dot nor this
|
|
80
|
+
* seat renders there, and its live status appears on the hover card only.
|
|
81
|
+
*/
|
|
82
|
+
'sidebar.session.row.leading': {
|
|
83
|
+
kind: 'list';
|
|
84
|
+
scope: 'root';
|
|
85
|
+
owner: SessionRowScheduleOwnerProps;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Section of the Session row's hover card between its relative time and
|
|
89
|
+
* its trailing status line. Mounted only while that card is open.
|
|
90
|
+
*/
|
|
91
|
+
'sidebar.session.row.hover': {
|
|
92
|
+
kind: 'list';
|
|
93
|
+
scope: 'root';
|
|
94
|
+
owner: SessionRowScheduleOwnerProps;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/** The two directory-flow holes; a flow package's client half registers its one component into both. */
|
|
99
|
+
export type DirectoryFlowSlotName = 'conversation.hero.workspace.directoryFlow' | 'sidebar.workspaces.directoryFlow';
|
|
100
|
+
/**
|
|
101
|
+
* Directory-picking share both trigger surfaces consume. Occupancy rides the
|
|
102
|
+
* inject face's reserved `hooks` compartment: the renderer binds the source
|
|
103
|
+
* into the `useDirectoryFlow` selector hook, so an empty hole hides the
|
|
104
|
+
* "Add workspace…" entry reactively and the surface withdraws an open
|
|
105
|
+
* flow whose occupant unloaded mid-interaction (nobody is left to cancel).
|
|
106
|
+
*/
|
|
107
|
+
export type DirectoryPickingInjected = {
|
|
108
|
+
hooks: {
|
|
109
|
+
/** True while this surface's directory-flow hole is occupied. */
|
|
110
|
+
directoryFlow: HostObservable<boolean>;
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
/** Component-side view of the picking share: the bound occupancy selector hook. */
|
|
114
|
+
export type DirectoryPickingHooks = PropsHooks<DirectoryPickingInjected['hooks']>;
|
|
115
|
+
/**
|
|
116
|
+
* Browser-private injected share (arrives via the register inject factory).
|
|
117
|
+
* Data reads use the global framework hooks; these are the Host actions the
|
|
118
|
+
* browsing region drives.
|
|
119
|
+
*/
|
|
120
|
+
export type WorkspaceBrowserInjected = {
|
|
121
|
+
hooks: DirectoryPickingInjected['hooks'] & {
|
|
122
|
+
/**
|
|
123
|
+
* Fixed Host facts, reached through a hook rather than injected as values:
|
|
124
|
+
* the renderer memoizes an entry's inject result for the registration's
|
|
125
|
+
* lifetime, so facts read there would freeze at whatever the first render
|
|
126
|
+
* saw. Select the field the surface needs (`info => info.home`).
|
|
127
|
+
*/
|
|
128
|
+
hostInfo: HostObservable<RemoteHostFacts>;
|
|
129
|
+
/** Keyboard-command opening requests the browser consumes. */
|
|
130
|
+
workspaceShortcuts: HostObservable<WorkspaceShortcutState>;
|
|
131
|
+
/** Effective command catalog for row shortcut hints. */
|
|
132
|
+
shortcuts: HostObservable<readonly ShortcutCatalogEntry[]>;
|
|
133
|
+
};
|
|
134
|
+
/** Open the browser search and focus its input. */
|
|
135
|
+
requestSearch: () => void;
|
|
136
|
+
/** Request the existing directory picker. */
|
|
137
|
+
requestAddWorkspace: () => void;
|
|
138
|
+
/** Consume the directory-picker opening request. */
|
|
139
|
+
closeAddWorkspace: () => void;
|
|
140
|
+
/** Consume the rename-dialog opening request. */
|
|
141
|
+
closeRenameRequest: () => void;
|
|
142
|
+
/** Publish directory interaction occupancy for command availability. */
|
|
143
|
+
setDirectoryBusy: (busy: boolean) => void;
|
|
144
|
+
/**
|
|
145
|
+
* Start a New Session in a Workspace: reuse-or-create its blank session and
|
|
146
|
+
* open it; without an explicit workspace, inherit the current Session
|
|
147
|
+
* Workspace, then the recent Workspace, or clear into the New Session view.
|
|
148
|
+
*/
|
|
149
|
+
startSession: (workspaceId?: WorkspaceId) => void;
|
|
150
|
+
/** Open a real Session. */
|
|
151
|
+
open: (sessionId: SessionId) => void;
|
|
152
|
+
/**
|
|
153
|
+
* Search current visible conversation messages. The Host fixes the result
|
|
154
|
+
* bound; `hasMore` means the query needs narrowing.
|
|
155
|
+
*/
|
|
156
|
+
searchSessions: (query: string, signal: AbortSignal) => Promise<{
|
|
157
|
+
items: readonly SessionSearchResultItem[];
|
|
158
|
+
hasMore: boolean;
|
|
159
|
+
}>;
|
|
160
|
+
/** Maximum number of merged rows rendered for one search. */
|
|
161
|
+
searchResultLimit: number;
|
|
162
|
+
/** Rename a Session (explicit user title; resolves on host acceptance). */
|
|
163
|
+
renameSession: (sessionId: SessionId, title: string) => Promise<void>;
|
|
164
|
+
/** Fork a Session at its last completed turn and open the child. */
|
|
165
|
+
forkSession: (sessionId: SessionId) => void;
|
|
166
|
+
/** Rename a Host Workspace (rejects on name conflict; resolves on durability). */
|
|
167
|
+
renameWorkspace: (workspaceId: WorkspaceId, title: string) => Promise<void>;
|
|
168
|
+
/** Delete only a Host Workspace registration; directory and Session logs remain. */
|
|
169
|
+
deleteWorkspace: (workspaceId: WorkspaceId) => Promise<void>;
|
|
170
|
+
/**
|
|
171
|
+
* Reorder a Workspace in the durable registry display order.
|
|
172
|
+
* Omitted anchor appends to the end.
|
|
173
|
+
*/
|
|
174
|
+
insertWorkspaceBefore: (workspaceId: WorkspaceId, beforeWorkspaceId?: WorkspaceId) => Promise<void>;
|
|
175
|
+
/**
|
|
176
|
+
* Archive a Session into the registry-global set: hidden from grouping
|
|
177
|
+
* surfaces, log and accounting slot retained. Archiving the current
|
|
178
|
+
* session clears the selection into the New Session view state.
|
|
179
|
+
*/
|
|
180
|
+
archiveSession: (sessionId: SessionId) => Promise<void>;
|
|
181
|
+
/**
|
|
182
|
+
* Pin a Session ahead of unpinned ones in its group and the flat list, and
|
|
183
|
+
* front its saved manual position. Rejects on Host failure so the caller
|
|
184
|
+
* can report it.
|
|
185
|
+
*/
|
|
186
|
+
pinSession: (sessionId: SessionId) => Promise<void>;
|
|
187
|
+
/** Drop one Session's pin; saved positions stay as they are. */
|
|
188
|
+
unpinSession: (sessionId: SessionId) => Promise<void>;
|
|
189
|
+
/** Adopt a picked host directory as a real Workspace before targeting a Session. */
|
|
190
|
+
createWorkspace: (input: {
|
|
191
|
+
path: string;
|
|
192
|
+
}) => Promise<WorkspaceView>;
|
|
193
|
+
};
|
|
194
|
+
/** Full browser props: shell owner share + viewing store + injected actions + the locale seat. */
|
|
195
|
+
export type WorkspaceBrowserProps = PropsRuntime<'sidebar.workspaces'> & PropsRenderSlots<'sidebar.workspaces.directoryFlow' | 'sidebar.session.row.leading' | 'sidebar.session.row.hover'> & PropsStore<ReturnType<typeof createWorkspaceViewStore>> & Omit<WorkspaceBrowserInjected, 'hooks'> & PropsHooks<WorkspaceBrowserInjected['hooks']> & PropsLocale<'workspace'>;
|
|
196
|
+
/**
|
|
197
|
+
* Picker-private injected share. Pick semantics remain in the owner's onPick
|
|
198
|
+
* callback; this callback creates only the real Host Workspace. A type alias
|
|
199
|
+
* supplies the implicit index signature required by the registry.
|
|
200
|
+
*/
|
|
201
|
+
export type WorkspacePickerInjected = DirectoryPickingInjected & {
|
|
202
|
+
/** Adopt a picked host directory as a real Workspace before targeting a Session. */
|
|
203
|
+
createWorkspace: (input: {
|
|
204
|
+
path: string;
|
|
205
|
+
}) => Promise<WorkspaceView>;
|
|
206
|
+
};
|
|
207
|
+
/**
|
|
208
|
+
* Full picker props: the owner share plus the creation callback and the
|
|
209
|
+
* locale seat. The two picker holes (blank-session hero / New-Session view)
|
|
210
|
+
* share one owner currency, so one composed type serves both registrations.
|
|
211
|
+
*/
|
|
212
|
+
export type WorkspacePickerProps = PropsRuntime<'conversation.hero.workspace'> & PropsRenderSlots<'conversation.hero.workspace.directoryFlow'> & Omit<WorkspacePickerInjected, 'hooks'> & DirectoryPickingHooks & PropsLocale<'workspace'>;
|
|
213
|
+
//# sourceMappingURL=slots.d.ts.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace plugin, browser half. Two registrations: WorkspaceBrowser fills
|
|
3
|
+
* the sidebar shell's `sidebar.workspaces` hole (the whole browsing region),
|
|
4
|
+
* and WorkspacePicker fills the conversation hero's picker hole
|
|
5
|
+
* (`conversation.hero.workspace` — both hero forms). Both read real Host
|
|
6
|
+
* Workspaces through the global useWorkspaces hook, and each declares its
|
|
7
|
+
* own `single` directory-flow child hole for the composed picker package's
|
|
8
|
+
* client half (see the contract module doc). Export discipline:
|
|
9
|
+
* packages/client/AGENTS.md.
|
|
10
|
+
*/
|
|
11
|
+
import type { Context } from '@qilin-agent/kylin';
|
|
12
|
+
import type { WorkspaceSnapshot } from '@qilin-agent/api-workspace-controller/client';
|
|
13
|
+
import type { SnapshotSelectorHook } from '@qilin-agent/client-ui-slots';
|
|
14
|
+
import { type WorkspaceKey } from './locales.ts';
|
|
15
|
+
export type { MainSelection, UiWorkspace } from './navigation.ts';
|
|
16
|
+
export type { DirectoryFlowOwnerProps, DirectoryFlowSlotName, DirectoryPickingHooks, DirectoryPickingInjected, SessionRowScheduleOwnerProps, WorkspaceBrowserInjected, WorkspaceBrowserProps, WorkspacePickerInjected, WorkspacePickerProps, } from './contract/slots.ts';
|
|
17
|
+
export type { WorkspaceKey } from './locales.ts';
|
|
18
|
+
declare module '@qilin-agent/client-ui-slots' {
|
|
19
|
+
interface GlobalStandardProps {
|
|
20
|
+
/** Selector hook over the pure Workspace Controller snapshot. */
|
|
21
|
+
useWorkspaces: SnapshotSelectorHook<WorkspaceSnapshot>;
|
|
22
|
+
}
|
|
23
|
+
interface LocaleNamespaceMap {
|
|
24
|
+
/** The workspace browsing region and pick/create flow copy. */
|
|
25
|
+
workspace: WorkspaceKey;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
declare module '@qilin-agent/api-session-controller/client' {
|
|
29
|
+
interface SessionReferenceSourceMap {
|
|
30
|
+
workspaceOperation: unknown;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Required services (cordis fiber inject). The target slots are declared by
|
|
35
|
+
* the ui-sidebar / ui-conversation applies, whose activation order relative
|
|
36
|
+
* to this one is NOT constrained: qilin.client.inject edges are informational
|
|
37
|
+
* (loading/prefetch metadata, never apply sequencing) and neither owner
|
|
38
|
+
* provides a waitable service. apply therefore depends on each slot
|
|
39
|
+
* declaration through `slots.inject()` instead of assuming order.
|
|
40
|
+
*/
|
|
41
|
+
export declare const inject: string[];
|
|
42
|
+
/**
|
|
43
|
+
* Register the browser and picker once their slot declarations are on the
|
|
44
|
+
* ledger. Inject factories return plain callbacks; data reads use the
|
|
45
|
+
* framework's global hooks.
|
|
46
|
+
* @param ctx - client root context.
|
|
47
|
+
*/
|
|
48
|
+
export declare function apply(ctx: Context): void;
|
|
49
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,160 @@
|
|
|
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
|
+
'session.untitled': string;
|
|
11
|
+
'shortcut.noSession': string;
|
|
12
|
+
'shortcut.noPicker': string;
|
|
13
|
+
'shortcut.directoryBusy': string;
|
|
14
|
+
'shortcut.noCompletedTurn': string;
|
|
15
|
+
'section.workspaces': string;
|
|
16
|
+
'section.sessions': string;
|
|
17
|
+
'viewOptions.label': string;
|
|
18
|
+
'groupBy.label': string;
|
|
19
|
+
'groupBy.workspace': string;
|
|
20
|
+
'groupBy.workspaceTree': string;
|
|
21
|
+
'groupBy.flat': string;
|
|
22
|
+
'orderBy.label': string;
|
|
23
|
+
'orderBy.manual': string;
|
|
24
|
+
'orderBy.updated': string;
|
|
25
|
+
'sessions.expand': string;
|
|
26
|
+
'sessions.collapse': string;
|
|
27
|
+
'empty.none': string;
|
|
28
|
+
'empty.noMatches': string;
|
|
29
|
+
'workspace.add': string;
|
|
30
|
+
'search.sessions.aria': string;
|
|
31
|
+
'search.placeholder': string;
|
|
32
|
+
'search.clear': string;
|
|
33
|
+
'search.results.aria': string;
|
|
34
|
+
'search.pending': string;
|
|
35
|
+
'search.unavailable': string;
|
|
36
|
+
'search.noMatches': string;
|
|
37
|
+
'search.hasMore': string;
|
|
38
|
+
'menu.addWorkspace': string;
|
|
39
|
+
'picker.loading': string;
|
|
40
|
+
'conflict.named': string;
|
|
41
|
+
'folderError.title': string;
|
|
42
|
+
'folderError.retry': string;
|
|
43
|
+
rename: string;
|
|
44
|
+
'rename.workspace.title': string;
|
|
45
|
+
'rename.session.title': string;
|
|
46
|
+
'field.workspaceName': string;
|
|
47
|
+
'field.sessionName': string;
|
|
48
|
+
'delete.workspace': string;
|
|
49
|
+
'delete.desc': string;
|
|
50
|
+
'delete.pending': string;
|
|
51
|
+
'menu.pinSession': string;
|
|
52
|
+
'menu.unpinSession': string;
|
|
53
|
+
'menu.fork': string;
|
|
54
|
+
'menu.archiveSession': string;
|
|
55
|
+
'row.pinned': string;
|
|
56
|
+
'sessions.count.one': string;
|
|
57
|
+
'sessions.count.other': string;
|
|
58
|
+
'actions.workspace.aria': string;
|
|
59
|
+
'actions.session.aria': string;
|
|
60
|
+
'actions.newSession.aria': string;
|
|
61
|
+
'actions.pin': string;
|
|
62
|
+
'actions.unpin': string;
|
|
63
|
+
'status.running': string;
|
|
64
|
+
'status.subagentsRunning.one': string;
|
|
65
|
+
'status.subagentsRunning.other': string;
|
|
66
|
+
'status.idle': string;
|
|
67
|
+
'status.waitingApproval': string;
|
|
68
|
+
'status.planReview': string;
|
|
69
|
+
'status.waitingAnswer': string;
|
|
70
|
+
'status.completed': string;
|
|
71
|
+
'hover.created': string;
|
|
72
|
+
'hover.copied': string;
|
|
73
|
+
'date.ymd': string;
|
|
74
|
+
'time.now': string;
|
|
75
|
+
'time.minutes': string;
|
|
76
|
+
'time.hours': string;
|
|
77
|
+
'time.days': string;
|
|
78
|
+
'time.months': string;
|
|
79
|
+
'time.years': string;
|
|
80
|
+
'time.ago': string;
|
|
81
|
+
};
|
|
82
|
+
/** The workspace namespace key union. */
|
|
83
|
+
export type WorkspaceKey = keyof typeof zh;
|
|
84
|
+
/** English dictionary, checked complete against the zh key set. */
|
|
85
|
+
export declare const en: {
|
|
86
|
+
'group.ungrouped': string;
|
|
87
|
+
'session.new': string;
|
|
88
|
+
'session.untitled': string;
|
|
89
|
+
'shortcut.noSession': string;
|
|
90
|
+
'shortcut.noPicker': string;
|
|
91
|
+
'shortcut.directoryBusy': string;
|
|
92
|
+
'shortcut.noCompletedTurn': string;
|
|
93
|
+
'section.workspaces': string;
|
|
94
|
+
'section.sessions': string;
|
|
95
|
+
'viewOptions.label': string;
|
|
96
|
+
'groupBy.label': string;
|
|
97
|
+
'groupBy.workspace': string;
|
|
98
|
+
'groupBy.workspaceTree': string;
|
|
99
|
+
'groupBy.flat': string;
|
|
100
|
+
'orderBy.label': string;
|
|
101
|
+
'orderBy.manual': string;
|
|
102
|
+
'orderBy.updated': string;
|
|
103
|
+
'sessions.expand': string;
|
|
104
|
+
'sessions.collapse': string;
|
|
105
|
+
'empty.none': string;
|
|
106
|
+
'empty.noMatches': string;
|
|
107
|
+
'workspace.add': string;
|
|
108
|
+
'search.sessions.aria': string;
|
|
109
|
+
'search.placeholder': string;
|
|
110
|
+
'search.clear': string;
|
|
111
|
+
'search.results.aria': string;
|
|
112
|
+
'search.pending': string;
|
|
113
|
+
'search.unavailable': string;
|
|
114
|
+
'search.noMatches': string;
|
|
115
|
+
'search.hasMore': string;
|
|
116
|
+
'menu.addWorkspace': string;
|
|
117
|
+
'picker.loading': string;
|
|
118
|
+
'conflict.named': string;
|
|
119
|
+
'folderError.title': string;
|
|
120
|
+
'folderError.retry': string;
|
|
121
|
+
rename: string;
|
|
122
|
+
'rename.workspace.title': string;
|
|
123
|
+
'rename.session.title': string;
|
|
124
|
+
'field.workspaceName': string;
|
|
125
|
+
'field.sessionName': string;
|
|
126
|
+
'delete.workspace': string;
|
|
127
|
+
'delete.desc': string;
|
|
128
|
+
'delete.pending': string;
|
|
129
|
+
'menu.pinSession': string;
|
|
130
|
+
'menu.unpinSession': string;
|
|
131
|
+
'menu.fork': string;
|
|
132
|
+
'menu.archiveSession': string;
|
|
133
|
+
'row.pinned': string;
|
|
134
|
+
'sessions.count.one': string;
|
|
135
|
+
'sessions.count.other': string;
|
|
136
|
+
'actions.workspace.aria': string;
|
|
137
|
+
'actions.session.aria': string;
|
|
138
|
+
'actions.newSession.aria': string;
|
|
139
|
+
'actions.pin': string;
|
|
140
|
+
'actions.unpin': string;
|
|
141
|
+
'status.running': string;
|
|
142
|
+
'status.subagentsRunning.one': string;
|
|
143
|
+
'status.subagentsRunning.other': string;
|
|
144
|
+
'status.idle': string;
|
|
145
|
+
'status.waitingApproval': string;
|
|
146
|
+
'status.planReview': string;
|
|
147
|
+
'status.waitingAnswer': string;
|
|
148
|
+
'status.completed': string;
|
|
149
|
+
'hover.created': string;
|
|
150
|
+
'hover.copied': string;
|
|
151
|
+
'date.ymd': string;
|
|
152
|
+
'time.now': string;
|
|
153
|
+
'time.minutes': string;
|
|
154
|
+
'time.hours': string;
|
|
155
|
+
'time.days': string;
|
|
156
|
+
'time.months': string;
|
|
157
|
+
'time.years': string;
|
|
158
|
+
'time.ago': string;
|
|
159
|
+
};
|
|
160
|
+
//# sourceMappingURL=locales.d.ts.map
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/** Workspace archive and directory UI capability. */
|
|
2
|
+
import { Service, type Context } from '@qilin-agent/kylin';
|
|
3
|
+
import type { ClientRemote, DirectoryListing, RemoteFailure } from '@qilin-agent/api-remotes/client';
|
|
4
|
+
import type { ISessions, SessionTarget } from '@qilin-agent/api-session-controller/client';
|
|
5
|
+
import { type ObservableSnapshot } from '@qilin-agent/client-store';
|
|
6
|
+
import type { SubagentAddress } from '@qilin-agent/subagent/client';
|
|
7
|
+
import type { IWorkspaces, WorkspaceId } from '@qilin-agent/api-workspace-controller/client';
|
|
8
|
+
import type { SessionId } from '@qilin-agent/session/types';
|
|
9
|
+
import type { WorkspaceViewStoreActions } from './stores.ts';
|
|
10
|
+
/** The main-pane selection a navigation action publishes: one Session, or one direct-parent subagent address. */
|
|
11
|
+
export interface MainSelection {
|
|
12
|
+
readonly sessionId?: SessionId;
|
|
13
|
+
readonly subagentAddress?: SubagentAddress;
|
|
14
|
+
}
|
|
15
|
+
/** Workspace archive and directory operations consumed by Client UI domains. */
|
|
16
|
+
export interface UiWorkspace {
|
|
17
|
+
/**
|
|
18
|
+
* The persisted main-pane selection. The Session Controller owns the catalog and
|
|
19
|
+
* leaves view selection to navigation, so surfaces that need "the Session the
|
|
20
|
+
* shell is showing" read it here.
|
|
21
|
+
*/
|
|
22
|
+
readonly selection: ObservableSnapshot<MainSelection>;
|
|
23
|
+
/**
|
|
24
|
+
* Select a Session and show its Conversation as one UI navigation action.
|
|
25
|
+
* @param target - known Session identity or durable direct-parent subagent address to display.
|
|
26
|
+
*/
|
|
27
|
+
openSession(target: SessionTarget): void;
|
|
28
|
+
/**
|
|
29
|
+
* Connect a Workspace and open its Session unless a later navigation supersedes it.
|
|
30
|
+
* @param workspaceId - target Workspace.
|
|
31
|
+
* @param beforeOpen - optional synchronous preparation for the selected Session,
|
|
32
|
+
* skipped after supersession; a throw aborts the open and releases the retained reference.
|
|
33
|
+
* @returns completion; a superseded request may create a Session but does not open it.
|
|
34
|
+
*/
|
|
35
|
+
openWorkspace(workspaceId: WorkspaceId, beforeOpen?: (sessionId: SessionId) => void): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Fork a Session and open the child unless a later navigation supersedes it.
|
|
38
|
+
* @param sessionId - source Session.
|
|
39
|
+
* @returns completion; a superseded request leaves its child available without selecting it.
|
|
40
|
+
*/
|
|
41
|
+
forkSession(sessionId: SessionId): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Resolve the reusable or newly created blank Session for a Workspace.
|
|
44
|
+
* @param workspaceId - target Workspace.
|
|
45
|
+
* @returns a Session already addressable through the Session Controller.
|
|
46
|
+
*/
|
|
47
|
+
connectWorkspace(workspaceId: WorkspaceId): Promise<SessionId>;
|
|
48
|
+
/**
|
|
49
|
+
* Start a New Session flow and navigate to its Session.
|
|
50
|
+
* @param workspaceId - explicit target; absent inherits the current or most recent Workspace.
|
|
51
|
+
*/
|
|
52
|
+
startSession(workspaceId?: WorkspaceId): void;
|
|
53
|
+
/**
|
|
54
|
+
* Archive a Session and clear it when it is the current selection.
|
|
55
|
+
* @param sessionId - Session to archive.
|
|
56
|
+
*/
|
|
57
|
+
archiveSession(sessionId: SessionId): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Unarchive a Session, restoring it to its recorded Workspace position.
|
|
60
|
+
* @param sessionId - Session to unarchive.
|
|
61
|
+
*/
|
|
62
|
+
unarchiveSession(sessionId: SessionId): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Pin a Session on the Host and front its saved position in every account that owns it.
|
|
65
|
+
* @param sessionId - Session to pin.
|
|
66
|
+
*/
|
|
67
|
+
pinSession(sessionId: SessionId): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Unpin a Session on the Host; saved positions stay as they are.
|
|
70
|
+
* @param sessionId - Session to unpin.
|
|
71
|
+
*/
|
|
72
|
+
unpinSession(sessionId: SessionId): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Open the Host-native directory picker.
|
|
75
|
+
* @returns the selected directory, or null when cancelled.
|
|
76
|
+
*/
|
|
77
|
+
pickDirectory(): Promise<string | null>;
|
|
78
|
+
/**
|
|
79
|
+
* List one Host directory level.
|
|
80
|
+
* @param path - directory path; absent selects the Host home.
|
|
81
|
+
* @param signal - cancellation for a superseded scan.
|
|
82
|
+
* @returns directory entries and breadcrumb ancestry.
|
|
83
|
+
*/
|
|
84
|
+
listDirectory(path?: string, signal?: AbortSignal): Promise<DirectoryListing>;
|
|
85
|
+
/**
|
|
86
|
+
* Create a child directory.
|
|
87
|
+
* @param path - existing parent directory.
|
|
88
|
+
* @param name - child directory name.
|
|
89
|
+
* @returns created absolute path.
|
|
90
|
+
*/
|
|
91
|
+
createDirectory(path: string, name: string): Promise<string>;
|
|
92
|
+
}
|
|
93
|
+
declare module '@qilin-agent/kylin' {
|
|
94
|
+
interface Context {
|
|
95
|
+
/** Cross-Controller Workspace navigation and directory UI capability. */
|
|
96
|
+
uiWorkspace: UiWorkspace;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** Structured directory failure exposed to directory UI consumers. */
|
|
100
|
+
export declare class DirectoryBrowseError extends Error {
|
|
101
|
+
readonly rpcError: RemoteFailure;
|
|
102
|
+
readonly name = "DirectoryBrowseError";
|
|
103
|
+
/** @param rpcError - Host directory business failure. */
|
|
104
|
+
constructor(rpcError: RemoteFailure);
|
|
105
|
+
}
|
|
106
|
+
/** Implements Workspace archive and directory UI operations. */
|
|
107
|
+
declare class UiWorkspaceService extends Service implements UiWorkspace {
|
|
108
|
+
private readonly directoryPicker;
|
|
109
|
+
private readonly workspaces;
|
|
110
|
+
private readonly sessions;
|
|
111
|
+
private readonly view;
|
|
112
|
+
private readonly connecting;
|
|
113
|
+
private readonly lifetime;
|
|
114
|
+
/**
|
|
115
|
+
* The persisted main-pane selection. Published as the `mainSelection` root
|
|
116
|
+
* standard source, because the Session Controller owns the catalog and leaves
|
|
117
|
+
* view selection to navigation.
|
|
118
|
+
*/
|
|
119
|
+
readonly selection: import("@qilin-agent/client-store").SnapshotStore<MainSelection>;
|
|
120
|
+
private mainReference;
|
|
121
|
+
/**
|
|
122
|
+
* @param ctx - Client root Context.
|
|
123
|
+
* @param directoryPicker - the directory-picking Remote namespace.
|
|
124
|
+
* @param workspaces - pure Workspace Controller.
|
|
125
|
+
* @param sessions - pure Session Controller.
|
|
126
|
+
* @param view - the browser's viewing-store write set, which owns saved Session order.
|
|
127
|
+
*/
|
|
128
|
+
constructor(ctx: Context, directoryPicker: ClientRemote['directoryPicker'], workspaces: IWorkspaces, sessions: ISessions, view: Pick<WorkspaceViewStoreActions, 'pinSessionOrder'>);
|
|
129
|
+
connectWorkspace(workspaceId: WorkspaceId): Promise<SessionId>;
|
|
130
|
+
openSession(target: SessionTarget): void;
|
|
131
|
+
openWorkspace(workspaceId: WorkspaceId, beforeOpen?: (sessionId: SessionId) => void): Promise<void>;
|
|
132
|
+
forkSession(sessionId: SessionId): Promise<void>;
|
|
133
|
+
startSession(workspaceId?: WorkspaceId): void;
|
|
134
|
+
archiveSession(sessionId: SessionId): Promise<void>;
|
|
135
|
+
unarchiveSession(sessionId: SessionId): Promise<void>;
|
|
136
|
+
pinSession(sessionId: SessionId): Promise<void>;
|
|
137
|
+
unpinSession(sessionId: SessionId): Promise<void>;
|
|
138
|
+
pickDirectory(): Promise<string | null>;
|
|
139
|
+
listDirectory(path?: string, signal?: AbortSignal): Promise<DirectoryListing>;
|
|
140
|
+
createDirectory(path: string, name: string): Promise<string>;
|
|
141
|
+
private watchNavigation;
|
|
142
|
+
/** @returns true when an archived current selection was cleared. */
|
|
143
|
+
private clearArchivedCurrent;
|
|
144
|
+
private clearMain;
|
|
145
|
+
private replaceMain;
|
|
146
|
+
}
|
|
147
|
+
export { UiWorkspaceService };
|
|
148
|
+
//# sourceMappingURL=navigation.d.ts.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The account memberships a pin order write reconciles against, derived from
|
|
3
|
+
* the same Host snapshots the browser orders by, so the UiWorkspace service
|
|
4
|
+
* completes the write without the browser in the loop.
|
|
5
|
+
*/
|
|
6
|
+
import type { SessionListState } from '@qilin-agent/api-session-controller/client';
|
|
7
|
+
import type { WorkspaceView } from '@qilin-agent/api-workspace-controller/client';
|
|
8
|
+
import type { SessionId } from '@qilin-agent/session/types';
|
|
9
|
+
/**
|
|
10
|
+
* Every account's complete membership: each Workspace, Ungrouped, and the flat list.
|
|
11
|
+
* @param workspaces - current Host Workspaces.
|
|
12
|
+
* @param list - current Session list snapshot.
|
|
13
|
+
* @returns membership per account key plus the summaries a reconciliation orders by.
|
|
14
|
+
*/
|
|
15
|
+
export declare function pinOrderSource(workspaces: readonly WorkspaceView[], list: SessionListState): {
|
|
16
|
+
members: Readonly<Record<string, readonly SessionId[]>>;
|
|
17
|
+
summaries: SessionListState['byId'];
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* The accounts a pinned Session leads: its group (or Ungrouped) and the flat list.
|
|
21
|
+
* @param workspaces - current Host Workspaces.
|
|
22
|
+
* @param sessionId - the Session being pinned.
|
|
23
|
+
* @returns the account keys a pin write fronts.
|
|
24
|
+
*/
|
|
25
|
+
export declare function pinOrderAccounts(workspaces: readonly WorkspaceView[], sessionId: SessionId): readonly string[];
|
|
26
|
+
//# sourceMappingURL=pin-order.d.ts.map
|