@deepseek-ai/dsh-client-ui-workspace 0.1.7-rc.2 → 0.2.0-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/README.i18n.yaml CHANGED
@@ -6,8 +6,8 @@
6
6
  en: 7c0f613105d4008a
7
7
  zh: c36c0cdff7e77576
8
8
  /deepseek-ai-dsh-client-ui-workspace:
9
- en: c611184cd49f130f
10
- zh: caddcda48dc30f11
9
+ en: b286adf3aca51710
10
+ zh: 6122f6e7c8015197
11
11
  /deepseek-ai-dsh-client-ui-workspace/summary:
12
12
  en: 1a76ace6a18e3ab5
13
13
  zh: b274d1e98e133851
@@ -15,8 +15,8 @@
15
15
  en: d152484eb41ac6b4
16
16
  zh: 09388d293f9be9cb
17
17
  /deepseek-ai-dsh-client-ui-workspace/use-this-package:
18
- en: c8d579e1e65bc8c5
19
- zh: 56f8e45351445ec7
18
+ en: b164014ee565be16
19
+ zh: 6a741647932b93e6
20
20
  /deepseek-ai-dsh-client-ui-workspace/use-this-package/reordering-and-view-options:
21
21
  en: 1fe0693758e0536b
22
22
  zh: ef30198bc767fc04
package/README.md CHANGED
@@ -7,6 +7,8 @@ kind: "package-reference"
7
7
 
8
8
  English | [中文](README.zh.md)
9
9
 
10
+ Desktop product events use the optional [product analytics service](../product-analytics/README.md); ordinary Web interactions are excluded.
11
+
10
12
  ## Summary
11
13
 
12
14
  This package lets users browse grouped or flat Session lists, choose a Workspace for a new Session, and manage Workspaces and Sessions through add, rename, reorder, search, fork, archive, and Workspace deletion; the Session row menu and its hover buttons are slot lists that client plugins extend. Pending interactions appear as warning dots, and subagent-origin Sessions remain hidden. An idle, unarchived Session row with active scheduled tasks shows a clock mark, and its hover card lists those tasks. Canonically distinct folder paths remain separate Workspaces. Adding a Workspace requires a composed directory picker; without one, adding is unavailable.
@@ -27,6 +29,8 @@ This package lets users browse grouped or flat Session lists, choose a Workspace
27
29
 
28
30
  Use the sidebar to browse Workspaces and their Sessions, reorder them, and start new ones; use the picker in the Session Intent hero to choose a Workspace for a new session. An open Workspace shows five idle, non-blank Sessions by default. Running Sessions, including parents with running children, remain visible in their ordered positions without using that quota; the selected blank **New Session** is also an extra row until its first prompt. Each **Show more** click reveals up to five more idle Sessions; after the final batch, **Show less** restores the initial rows while keeping running Sessions visible. Closing and reopening the Workspace also restores this folded projection.
29
31
 
32
+ History rows without a stored title use the localized unnamed label (未命名 / Untitled), rather than a directory name. The current blank row remains New Session; other blank rows remain hidden. Rename drafts use the stored title, or start empty when unnamed; unnamed rows do not offer title copying.
33
+
30
34
  ### Reordering and view options
31
35
 
32
36
  Pinned Sessions lead ordinary Sessions in both grouped and flat views. **Last updated** sorts each partition strictly by the latest user prompt or steer time, newest first; pin time does not affect it. **Manual** uses the relative positions in one complete Session sequence, including hidden archives. Returning to Last updated discards the manual layout, and entering Manual again freezes the then-current chronological order. The browser defaults to Last updated and remembers the selected mode across reloads.
package/README.zh.md CHANGED
@@ -7,6 +7,8 @@ kind: "package-reference"
7
7
 
8
8
  [English](README.md) | 中文
9
9
 
10
+ 桌面端产品事件使用可选的[产品埋点服务](../product-analytics/README.zh.md),不包含普通 Web 交互。
11
+
10
12
  ## 概述
11
13
 
12
14
  本包让用户浏览分组或扁平的 Session 列表、为新 Session 选择 Workspace,并通过添加、重命名、重排序、搜索、fork、归档和删除 Workspace 来管理 Workspace 与 Session;Session 行菜单及其悬停按钮是可由客户端插件扩展的 slot 列表。待处理交互显示为警告点,subagent 来源的 Session 则保持隐藏。处于空闲状态且未归档、其 Session 有活动定时任务的 Session 行会显示时钟标记,其悬浮卡片会列出这些任务。规范化后仍有差异的文件夹路径会保留为独立 Workspace。添加 Workspace 需要组合目录选择器;没有目录选择器时,添加操作不可用。
@@ -27,6 +29,8 @@ kind: "package-reference"
27
29
 
28
30
  用侧边栏浏览 Workspace 及其 Session、重排它们并新建会话;在 Session Intent 主视觉区用选择器为新会话选择 Workspace。打开的 Workspace 默认显示五条空闲的非空白 Session。正在运行的 Session(包括有子会话正在运行的父会话)始终按原顺序显示,不占用这五条配额;当前选中的空白**新会话**在首条提示词落地前也作为额外行。每次点击**展开其余**最多再显示五条空闲 Session;全部显示后,**收起**恢复初始行数,但仍显示正在运行的 Session。关闭再打开 Workspace 也会恢复该折叠投影。
29
31
 
32
+ 未保存标题的历史会话显示本地化名称「未命名 / Untitled」,不使用目录名兜底。当前空会话仍显示「新会话」,其他空会话仍隐藏。重命名草稿使用已保存标题,无标题时留空;无标题行不提供标题复制。
33
+
30
34
  ### 重排序与视图选项
31
35
 
32
36
  分组和平铺视图都先显示置顶 Session,再显示普通 Session。**最近更新**在各分区内严格按最近一次用户提示词或 steering(中途引导)时间降序排列,置顶时间不影响它。**手动排序**使用同一条完整 Session 序列中的相对位置,包括隐藏的归档项。返回最近更新会丢弃手动布局,再次进入手动排序时冻结当时的时间顺序。浏览器默认采用最近更新,并在重新加载后记住所选模式。
package/lib/client.js CHANGED
@@ -164,7 +164,7 @@ window.__ModuleLoader__.load({
164
164
  } : {
165
165
  status: "handled",
166
166
  run: () => {
167
- controls.rename(target.id, target.displayTitle);
167
+ controls.rename(target.id, target.title?.trim() ?? "");
168
168
  }
169
169
  };
170
170
  });
@@ -384,10 +384,11 @@ window.__ModuleLoader__.load({
384
384
  /**
385
385
  * A blank session is the selected Workspace's provisional New Session row;
386
386
  * its canonical title never enters search (blank rows are query-excluded)
387
- * and the renderer localizes its display label.
387
+ * and the renderer localizes its display label. Unnamed history also yields an
388
+ * empty title for localization and does not match a directory-name title search.
388
389
  */
389
390
  function sessionTitle(session) {
390
- return session.blank ? "" : session.displayTitle;
391
+ return session.blank ? "" : session.title?.trim() ?? "";
391
392
  }
392
393
  /** Build one group without projecting session lineage into presentation. */
393
394
  function buildGroup(key, workspaceId, cwd, createdAt, label, members) {
@@ -834,10 +835,11 @@ window.__ModuleLoader__.load({
834
835
  if (navigation.aborted) return;
835
836
  this.replaceMain(sessionId, navigation, "reveal", beforeOpen);
836
837
  }
837
- async forkSession(sessionId) {
838
- await this.sessions.fork({
838
+ async forkSession(sessionId, onCreated) {
839
+ return this.sessions.fork({
839
840
  sessionId,
840
- increaseTitle: true
841
+ increaseTitle: true,
842
+ ...onCreated === void 0 ? {} : { onCreated }
841
843
  });
842
844
  }
843
845
  startSession(workspaceId) {
@@ -1117,7 +1119,7 @@ window.__ModuleLoader__.load({
1117
1119
  */
1118
1120
  /** Row display title: blank rows show the localized New Session label. */
1119
1121
  function displayTitle(node, t) {
1120
- return node.blank ? t("session.new") : node.title;
1122
+ return node.blank ? t("session.new") : node.title || t("session.untitled");
1121
1123
  }
1122
1124
  const MIN_TITLE_REVEAL_PX = 8;
1123
1125
  const TITLE_MARQUEE_PX_PER_MS = .03;
@@ -1511,7 +1513,7 @@ window.__ModuleLoader__.load({
1511
1513
  }),
1512
1514
  (0, react_jsx_runtime.jsx)("span", {
1513
1515
  className: Rows_module_css_default.searchResultTitle,
1514
- children: result.title
1516
+ children: result.title || t("session.untitled")
1515
1517
  }),
1516
1518
  result.archived && (0, react_jsx_runtime.jsx)("span", {
1517
1519
  className: Rows_module_css_default.rowActions,
@@ -1674,7 +1676,7 @@ window.__ModuleLoader__.load({
1674
1676
  }),
1675
1677
  openDelayMs: 800,
1676
1678
  disabled: menuOpen || drag?.active === true,
1677
- copyText: row.blank ? void 0 : row.title,
1679
+ copyText: row.blank || row.title === "" ? void 0 : row.title,
1678
1680
  copyLabel: t("copy"),
1679
1681
  copiedLabel: t("hover.copied")
1680
1682
  });
@@ -3696,7 +3698,7 @@ window.__ModuleLoader__.load({
3696
3698
  * one dialog per request (keyed by the Session, so a new request starts a
3697
3699
  * fresh draft). Sessions have no client-side name-conflict rule (the host
3698
3700
  * normalizes), and unlike Workspace rename an unchanged title is NOT
3699
- * blocked: confirming the current automatic title is the gesture that pins it.
3701
+ * blocked. An unnamed Session starts with an empty draft and requires a name.
3700
3702
  * @param props - the request hook, its settlement, the rename hop, and the locale seat.
3701
3703
  * @returns the open dialog, or null.
3702
3704
  */
@@ -3865,6 +3867,7 @@ window.__ModuleLoader__.load({
3865
3867
  "defaultWorkspace.failed": "无法创建默认工作区,请通过“选择工作区”选择文件夹",
3866
3868
  "group.ungrouped": "未分组",
3867
3869
  "session.new": "新会话",
3870
+ "session.untitled": "未命名",
3868
3871
  "shortcut.noSession": "请先选择一个会话",
3869
3872
  "shortcut.noPicker": "目录选择器不可用",
3870
3873
  "shortcut.directoryBusy": "正在选择或添加工作区",
@@ -3979,6 +3982,7 @@ window.__ModuleLoader__.load({
3979
3982
  "defaultWorkspace.failed": "Unable to create default workspace. Use Choose workspace to select a folder.",
3980
3983
  "group.ungrouped": "Ungrouped",
3981
3984
  "session.new": "New Session",
3985
+ "session.untitled": "Untitled",
3982
3986
  "shortcut.noSession": "Select a session first",
3983
3987
  "shortcut.noPicker": "Directory picker unavailable",
3984
3988
  "shortcut.directoryBusy": "Selecting or adding a workspace",
@@ -4227,7 +4231,13 @@ window.__ModuleLoader__.load({
4227
4231
  }
4228
4232
  });
4229
4233
  const forkInjected = () => ({ forkSession: (sessionId) => {
4230
- uiWorkspace.forkSession(sessionId).catch(() => {});
4234
+ uiWorkspace.forkSession(sessionId, (childId) => {
4235
+ ctx.get("productAnalytics")?.track("branch_session_click", {
4236
+ session_id: childId,
4237
+ parent_session_id: sessionId,
4238
+ click_position: "sidebar"
4239
+ });
4240
+ }).catch(() => {});
4231
4241
  } });
4232
4242
  const renameInjected = () => ({ requestSessionRename });
4233
4243
  const renameDialogInjected = () => ({
@@ -67,7 +67,7 @@ export interface DirectoryFlowOwnerProps {
67
67
  export interface SessionRowOwnerProps {
68
68
  /** Session the row shows. */
69
69
  sessionId: SessionId;
70
- /** Row display title: persisted title, project basename, or Session id. */
70
+ /** Row display title: persisted title, or empty when the Session has none. */
71
71
  displayTitle: string;
72
72
  }
73
73
  /** The row menu's open state as its owner holds it: the `useState` pair. */
@@ -1,20 +1,3 @@
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. WorkspaceBrowser additionally declares the two Session row
9
- * action lists, and this apply registers the shipped actions — pin, rename,
10
- * fork, archive — into them the way any client plugin would, each with its
11
- * own behavior, plus the rename dialog and the row-action notice into
12
- * `shell.overlay` (see the contract module doc). It also declares two
13
- * Session-row seats: the leading decoration a row renders only while its own
14
- * primary state is idle, and the section the row's hover card renders between
15
- * its relative time and its trailing status line. Export discipline:
16
- * packages/client/AGENTS.md.
17
- */
18
1
  import type { Context } from '@deepseek-ai/cordis';
19
2
  import type { WorkspaceSnapshot } from '@deepseek-ai/dsh-api-workspace-controller/client';
20
3
  import type { SnapshotSelectorHook } from '@deepseek-ai/dsh-client-ui-slots';
@@ -8,6 +8,7 @@ export declare const zh: {
8
8
  'defaultWorkspace.failed': string;
9
9
  'group.ungrouped': string;
10
10
  'session.new': string;
11
+ 'session.untitled': string;
11
12
  'shortcut.noSession': string;
12
13
  'shortcut.noPicker': string;
13
14
  'shortcut.directoryBusy': string;
@@ -124,6 +125,7 @@ export declare const en: {
124
125
  'defaultWorkspace.failed': string;
125
126
  'group.ungrouped': string;
126
127
  'session.new': string;
128
+ 'session.untitled': string;
127
129
  'shortcut.noSession': string;
128
130
  'shortcut.noPicker': string;
129
131
  'shortcut.directoryBusy': string;
@@ -26,9 +26,10 @@ export interface UiWorkspace {
26
26
  /**
27
27
  * Fork a Session without changing the current selection.
28
28
  * @param sessionId - source Session.
29
- * @returns completion after child creation and inherited-title increment.
29
+ * @param onCreated - observer before the optional child-title update.
30
+ * @returns the child SessionId after creation and inherited-title increment.
30
31
  */
31
- forkSession(sessionId: SessionId): Promise<void>;
32
+ forkSession(sessionId: SessionId, onCreated?: (childId: SessionId) => void): Promise<SessionId>;
32
33
  /**
33
34
  * Resolve the reusable or newly created blank Session for a Workspace.
34
35
  * @param workspaceId - target Workspace.
@@ -125,7 +126,7 @@ declare class UiWorkspaceService extends Service implements UiWorkspace {
125
126
  private reuseBlank;
126
127
  openSession(target: SessionTarget): void;
127
128
  openWorkspace(workspaceId: WorkspaceId, beforeOpen?: (sessionId: SessionId) => void): Promise<void>;
128
- forkSession(sessionId: SessionId): Promise<void>;
129
+ forkSession(sessionId: SessionId, onCreated?: (childId: SessionId) => void): Promise<SessionId>;
129
130
  startSession(workspaceId?: WorkspaceId): void;
130
131
  archiveSession(sessionId: SessionId, options?: {
131
132
  readonly stopActivity?: boolean;
@@ -10,7 +10,7 @@ export declare function RenameSessionMenuItem({ sessionId, displayTitle, useMenu
10
10
  * one dialog per request (keyed by the Session, so a new request starts a
11
11
  * fresh draft). Sessions have no client-side name-conflict rule (the host
12
12
  * normalizes), and unlike Workspace rename an unchanged title is NOT
13
- * blocked: confirming the current automatic title is the gesture that pins it.
13
+ * blocked. An unnamed Session starts with an empty draft and requires a name.
14
14
  * @param props - the request hook, its settlement, the rename hop, and the locale seat.
15
15
  * @returns the open dialog, or null.
16
16
  */
@@ -22,7 +22,7 @@ type SessionStatuses = SessionStatusSnapshot;
22
22
  /** One top-level session row in a group or the flat list. */
23
23
  export interface SessionNode {
24
24
  id: SessionId;
25
- /** Stored display title; the renderer substitutes the localized New Session label for blank rows. */
25
+ /** Stored title, or empty; the renderer localizes blank and unnamed row labels. */
26
26
  title: string;
27
27
  /** The provisional blank session (renderer shows the localized New Session title). */
28
28
  blank: boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-ui-workspace",
3
3
  "description": "Workspace picker plugin: one WorkspacePicker registered into the sidebar and empty-state workspace slots",
4
- "version": "0.1.7-rc.2",
4
+ "version": "0.2.0-rc.1",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -51,30 +51,31 @@
51
51
  "@types/react": "~18.3.1",
52
52
  "clsx": "^2.0.0",
53
53
  "react": "^18.2.0",
54
+ "@deepseek-ai/dsh-api-remotes": "0.2.0-rc.1",
55
+ "@deepseek-ai/dsh-agent": "0.2.0-rc.1",
56
+ "@deepseek-ai/dsh-api-session-controller": "0.2.0-rc.1",
57
+ "@deepseek-ai/dsh-api-workspace-controller": "0.2.0-rc.1",
54
58
  "@deepseek-ai/cordis": "~4.0.4",
55
- "@deepseek-ai/dsh-api-remotes": "0.1.7-rc.2",
56
- "@deepseek-ai/dsh-agent": "0.1.7-rc.2",
57
- "@deepseek-ai/dsh-api-session-controller": "0.1.7-rc.2",
58
- "@deepseek-ai/dsh-api-workspace-controller": "0.1.7-rc.2",
59
- "@deepseek-ai/dsh-client-connection": "0.1.7-rc.2",
60
- "@deepseek-ai/dsh-client-store": "0.1.7-rc.2",
61
- "@deepseek-ai/dsh-client-locale": "0.1.7-rc.2",
62
- "@deepseek-ai/dsh-client-test-runtime": "0.1.7-rc.2",
63
- "@deepseek-ai/dsh-client-ui-conversation": "0.1.7-rc.2",
64
- "@deepseek-ai/dsh-client-ui-layout": "0.1.7-rc.2",
65
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-rc.2",
66
- "@deepseek-ai/dsh-client-ui-session": "0.1.7-rc.2",
67
- "@deepseek-ai/dsh-client-ui-renderer": "0.1.7-rc.2",
68
- "@deepseek-ai/dsh-client-ui-sidebar": "0.1.7-rc.2",
69
- "@deepseek-ai/dsh-jobs": "0.1.7-rc.2",
70
- "@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.2",
71
- "@deepseek-ai/dsh-session": "0.1.7-rc.2",
72
- "@deepseek-ai/dsh-schedule": "0.1.7-rc.2",
73
- "@deepseek-ai/dsh-subagent": "0.1.7-rc.2",
74
- "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2",
75
- "@deepseek-ai/dsh-util-workspace-path": "0.1.7-rc.2",
76
- "@deepseek-ai/dsh-client-shortcuts": "0.1.7-rc.2",
77
- "@deepseek-ai/dsh-util-values": "0.1.7-rc.2"
59
+ "@deepseek-ai/dsh-client-connection": "0.2.0-rc.1",
60
+ "@deepseek-ai/dsh-client-locale": "0.2.0-rc.1",
61
+ "@deepseek-ai/dsh-client-test-runtime": "0.2.0-rc.1",
62
+ "@deepseek-ai/dsh-client-ui-conversation": "0.2.0-rc.1",
63
+ "@deepseek-ai/dsh-client-store": "0.2.0-rc.1",
64
+ "@deepseek-ai/dsh-client-ui-layout": "0.2.0-rc.1",
65
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.0-rc.1",
66
+ "@deepseek-ai/dsh-client-ui-renderer": "0.2.0-rc.1",
67
+ "@deepseek-ai/dsh-client-ui-session": "0.2.0-rc.1",
68
+ "@deepseek-ai/dsh-client-ui-sidebar": "0.2.0-rc.1",
69
+ "@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.1",
70
+ "@deepseek-ai/dsh-jobs": "0.2.0-rc.1",
71
+ "@deepseek-ai/dsh-schedule": "0.2.0-rc.1",
72
+ "@deepseek-ai/dsh-session": "0.2.0-rc.1",
73
+ "@deepseek-ai/dsh-subagent": "0.2.0-rc.1",
74
+ "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.1",
75
+ "@deepseek-ai/dsh-util-values": "0.2.0-rc.1",
76
+ "@deepseek-ai/dsh-util-workspace-path": "0.2.0-rc.1",
77
+ "@deepseek-ai/dsh-client-shortcuts": "0.2.0-rc.1",
78
+ "@deepseek-ai/dsh-client-product-analytics": "0.2.0-rc.1"
78
79
  },
79
80
  "files": [
80
81
  "lib/index.js",