@hydraharness/harness-client-ui-workspace 0.0.0-stage → 0.1.1-rc.6
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.md +42 -2
- package/lib/client.js +3415 -0
- package/lib/index.js +11 -0
- package/lib/invariant.js +25 -0
- package/lib/types/client/ArchivedSessionsSection.d.ts +14 -0
- package/lib/types/client/DeleteSessionDialog.d.ts +13 -0
- package/lib/types/client/SessionMenu.d.ts +41 -0
- package/lib/types/client/WorkspaceBrowser.d.ts +8 -0
- package/lib/types/client/WorkspacePicker.d.ts +57 -0
- package/lib/types/client/contract/slots.d.ts +160 -0
- package/lib/types/client/index.d.ts +27 -0
- package/lib/types/client/locales.d.ts +125 -0
- package/lib/types/client/organization.d.ts +28 -0
- package/lib/types/client/rows/Rows.d.ts +115 -0
- package/lib/types/client/session-markdown.d.ts +12 -0
- package/lib/types/client/stores.d.ts +57 -0
- package/lib/types/client/tree.d.ts +134 -0
- package/lib/types/index.d.ts +9 -0
- package/lib/types/invariant.d.ts +16 -0
- package/package.json +84 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,43 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @hydraharness/harness-client-ui-workspace
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Shared Workspace browser, picker, and archive-restoration plugin. `WorkspaceBrowser` fills the sidebar's `sidebar.workspaces` slot, `WorkspacePicker` fills the page-local Session Intent hero's `conversation.hero.workspace` slot, and the Archived sessions page fills `settings.section`; the browser and picker use the same Workspace menu and add flow.
|
|
4
|
+
|
|
5
|
+
The browser renders grouped or flat Session rows from the global runtime hooks and owns Workspace add/rename/reorder plus Session reorder. A Workspace remembers whether it is closed or showing Sessions; an open Workspace shows five Sessions by default, offers a transient **Show more** control for the remainder, and returns to five after the whole Workspace is closed and reopened. Creating a Session from a Workspace row first opens that group so the new row remains visible when the Session state arrives. Once the Workspace list baseline is ready, browser-persisted expansion and Session-order records retain only current Workspace ids plus Ungrouped and the flat-list account. View options combine grouping with one browser-persisted Session order per account: real Workspaces initialize from `WorkspaceView.sessionIds`, while Ungrouped and the cross-Workspace flat list initialize from recency. **Manual** and **Last updated** apply in either presentation. Entering Last updated performs a complete recency sort and later user prompts or steers promote their Session once, while entering Manual preserves every current position and disables later promotion. Dragging edits the current order in either mode; Manual-mode drags for real Workspaces also update the Host Session account, while Ungrouped and flat-list orders remain browser-local because neither has one Workspace account. Flat rows omit the empty leading status slot because they have no parent hierarchy, but retain it when a Session status is visible. Workspace drag order is Host-durable in either Session order mode.
|
|
6
|
+
|
|
7
|
+
Collapsed search is one header action beside the view and add actions. In the rail, add and search render as 36px controls on the shell's shared horizontal entry path. Activating search expands the field across the header; an outside click collapses only a query that is empty after trimming — except while the rail search gesture is still in flight (until focus lands in the input after the column slide), so the expanding click cannot dismiss the search it opened — while the clear control always resets and collapses it. A non-blank search query replaces either browsing mode with one flat result list: case-insensitive title and Workspace substring matches appear immediately, while a 250 ms debounced Host request adds ranked current-conversation content matches and snippets. The English search input and its defensive request path remove NUL, cap the query at the wire schema's 500 UTF-16 code units without splitting a surrogate pair, and preserve the existing debounce and cancellation behavior. Each new query aborts the preceding request; a failed content search leaves metadata matches visible with a warning. The list is capped at 20, asks the user to narrow broader queries, and opens the selected Session without clearing the query or jumping to a specific event.
|
|
8
|
+
|
|
9
|
+
The picker lists real Host Workspace entities through the global `useWorkspaces` hook. Selecting a Workspace invokes the slot owner's `onPick` callback to retarget the frontend Session object. Distinct canonical paths remain separate id-keyed Workspaces when their basenames and display titles match; the sidebar hover detail shows a POSIX home or descendant as `~` / `~/…` and leaves a Windows path verbatim. Each registration declares a **directory-flow child hole** (`single` kind: `conversation.hero.workspace.directoryFlow` / `sidebar.workspaces.directoryFlow`) that the composed picker package's client half fills with its picking interaction — the [`-native`](../../host/directory-picker-native/README.md) backend's renderless OS-chooser driver today, an in-app browsing dialog under a `-browse` composition. The flat **Add workspace...** action renders only while the surface's hole is occupied (occupancy read per menu render; an empty hole means the composition has no picking affordance — the seam's documented no-flow default, under which the sidebar header drops its add button rather than offering a dead one). This package owns the trigger and the adoption: the occupant reports one picked path per open through the hole's owner conversation (`open`/`busy`/`onPicked`/`onCancel`/`onError`), and the owner adopts it through the object layer, selecting the committed Workspace only after its list projection has refreshed; cancellation is silent, and errors land in the retryable folder dialog whose **Choose again** reopens the flow. Adding has exactly one route: the occupant's own create-folder affordance already covers a brand-new directory, so no separate create-by-name dialog exists. A menu only appears where there is something to choose between — with no Workspace listed, the anchor gesture raises the flow directly instead of a one-row popover, and it waits for the list baseline before treating an empty list as final. The runtime Session and Workspace services own materialization. The Workspace row's Delete action opens a confirmation that states the retention boundary, blocks duplicate submission, and keeps failures open; success removes the group while its Sessions remain under Ungrouped. The Ungrouped row has the same ellipsis affordance but only offers **Delete orphan chats**, which reuses the bulk Session deletion confirmation and excludes the blank New Session placeholder; it has no Rename action. The Session row's Rename action opens the same browser-owned dialog pattern prefilled with the row's display title: no client-side conflict rule exists (the host normalizes and may reject with `title-invalid`, rendered in the dialog alert), and confirming an unchanged title is deliberately allowed — it pins the current automatic title against regeneration. The Session row's Archive action commits without a confirmation dialog (non-destructive: the log and the workspace accounting slot remain) through `ctx.workspaces.archiveSession`; the row disappears from every grouping surface — workspace groups, Ungrouped, content search, and the flat list — when the archive-set echo lands, and failures are console diagnostics that leave the tree unchanged. The Session row's Delete action opens a permanent-deletion confirmation that blocks duplicate submission and keeps failures open; success removes the conversation's affected rows, including descendant subagents and Workspace/archive references. A blank New Session row is a pure placeholder: it renders no row menu and no time label (nothing has happened in it yet), so rename, fork, archive, and delete first apply once the first prompt lands.
|
|
10
|
+
|
|
11
|
+
The Settings → Archived sessions section lists the registry-global archive set in Host order, shows each Session's title and retained Workspace path, and supports checkbox multi-selection with bulk **Restore selected** and **Delete selected** actions. Restore calls `ctx.workspaces.unarchiveSession` for each selected id in archive order; the archive set keeps each Workspace `sessionIds` slot, so each response removes only the archive marker and the Session returns to its original Workspace automatically. An unavailable metadata row remains restorable by id. Bulk deletion uses the same permanent-deletion confirmation as the sidebar, runs selected ids in order, and retains failed ids in the dialog for retry; success removes the conversation revisions and subagent descendants selected by the Host cascade.
|
|
12
|
+
|
|
13
|
+
Workspace and Session hover cards copy the value their row clips: activating a Workspace card writes its full directory path, while activating a non-blank Session card writes its full display title. A provisional blank New Session card remains read-only because its localized label is a placeholder rather than session content. The card reports the dictionary-driven copied state only after the browser accepts the clipboard write.
|
|
14
|
+
|
|
15
|
+
The Session row's Fork action forks at the source's last completed turn, increments the inherited persisted title on the client, and then opens the child; a trailing ASCII or fullwidth parenthesized number is incremented in the same style, while an unnumbered title gets ` (1)` appended. Ordinary fork source and child appear as peer rows within a workspace group. Prompt revisions share one row in grouped, flat, and search views: the viewed version represents the conversation, otherwise the newest version does. Archiving a version hides the conversation from these views. A fork or rename failure leaves the current selection unchanged; after a rename failure, the created child remains in the list.
|
|
16
|
+
|
|
17
|
+
Session rows render the runtime's live `pendingInteraction` classification: approvals report **Waiting for approval**, plan reviews report **Plan awaiting review**, and ordinary questions report **Waiting for answer**. Every pending interaction uses an amber warning dot that takes precedence over the running indicator; ordinary rows repeat the localized status in their hover card, and both ordinary and search-result rows carry the same text as a visually hidden label for assistive technology. Running uses the blue indicator and its hidden label; an idle row leaves the reserved status slot empty.
|
|
18
|
+
|
|
19
|
+
Both target slots are declared by other plugins, so `apply` uses `slots.inject()` to register for each declaration lifetime and re-register after a declaring slot is restored.
|
|
20
|
+
|
|
21
|
+
The shared sidebar projection hides rows whose durable Session summary has `origin: 'subagent'`; users enter those conversations through the selected parent's subagent header catalog. Each visible ordinary row inherits the blue activity indicator while any descendant reached through uninterrupted subagent-origin lineage is running, and its hover and assistive text report the exact running-descendant count without describing an idle parent as running. Ordinary forks remain visible and terminate this aggregation because lineage alone does not set their origin. Pending user interaction outranks the session's own running state, and either remains the primary row status while descendant activity stays available as a separate hover and assistive status. With neither present, descendant activity outranks the green unviewed-completion reminder; the reminder returns once no descendant is running. The runtime keeps hidden rows available for conversation, title, and addressed transport state.
|
|
22
|
+
|
|
23
|
+
Session rows share a context menu opened by right-click, Shift+F10 or the overflow button. Pin, explicit unread markers, custom Section assignments and display Project assignments persist in the browser's viewing store. Pinned rows precede sections; a row appears once in grouped and flat views. Opening a row clears its explicit unread marker. Project moves organize the sidebar and retain the session's execution directory and Host Workspace account; a deleted display project falls back to that account. Copy working directory always reports the original session directory. Organization is local to one browser profile.
|
|
24
|
+
|
|
25
|
+
Copy deeplink opens the session after the list baseline loads. Copy as Markdown reads all history pages without selecting or resuming the session and includes committed user/assistant text; reasoning, tools, injected context and replacements are excluded. A failed page or clipboard write reports an error. Open in new window uses a browser popup or the Desktop window bridge. Share is disabled with Coming soon text; Git worktree forking is disabled because the Host provides no creation capability. Focused session rows accept the shortcuts displayed in their menu.
|
|
26
|
+
|
|
27
|
+
## Model Experience
|
|
28
|
+
|
|
29
|
+
None, as the picker is browser chrome; nothing here reaches a model request.
|
|
30
|
+
|
|
31
|
+
#### KV Cache effect
|
|
32
|
+
|
|
33
|
+
None; this package neither assembles nor sends a provider request.
|
|
34
|
+
|
|
35
|
+
## Known Limitations and Deferred Work
|
|
36
|
+
|
|
37
|
+
- **Organization is browser-local** — pins, unread markers, sections and display-project moves do not synchronize across devices or change the execution directory. Empty custom sections have no row until assigned a visible session.
|
|
38
|
+
- **Share and worktree fork are unavailable** — Share displays Coming soon; creating a Git worktree requires a Host capability.
|
|
39
|
+
|
|
40
|
+
- **No fuzzy content search or event deep links** — the content backend uses literal token/phrase matching, and selecting a result opens the Session rather than the matching event.
|
|
41
|
+
- **Permanent deletion has no undo** — Session deletion removes the selected conversation's retained logs and derived sidecar data; there is no recycle bin or restoration path.
|
|
42
|
+
- **Pending user interaction is not aggregated into collapsed groups** — a waiting row inside a collapsed group lights no group-header indicator and becomes visible only after that group is expanded.
|
|
43
|
+
- **Native folder selection depends on the local Host carrier** — under the `-native` composition, in-process or remote browser deployments cannot open a local operating-system dialog; platform failures are shown in a retryable modal. Remote-capable picking is the `-browse` composition's in-app flow.
|