@deepseek-ai/dsh-client-ui-reference 0.1.5-rc.2 → 0.1.6-alpha.2
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 +2 -2
- package/README.md +3 -1
- package/README.zh.md +3 -1
- package/lib/client.js +80 -6
- package/lib/types/client/locales.d.ts +2 -0
- package/package.json +17 -15
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/client/ui-reference/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 6b5046f1c6300f5ec02d3737617019874762d47a
|
|
6
|
+
README.zh.md: 99ba6fda18a73f5686f5e02403e48d5e556f9c3c
|
package/README.md
CHANGED
|
@@ -37,6 +37,8 @@ A session pick inserts an atomic inline reference whose hidden `ref` and clipboa
|
|
|
37
37
|
|
|
38
38
|
One unavailable or failed candidate domain yields no rows for that domain while the other still lists. A session-reference preparation failure occurs after prompt acceptance and terminates that agent turn.
|
|
39
39
|
|
|
40
|
+
Click a file reference in the composer to preview its current contents in the right Sidebar. Quoted paths retain their spaces, and paths resolve in the composer Session. Folder and Session references retain their editing behavior.
|
|
41
|
+
|
|
40
42
|
-----
|
|
41
43
|
|
|
42
44
|
<a id="understand-the-implementation"></a>
|
|
@@ -49,7 +51,7 @@ The source keeps candidate encoding internal to the registration effect: the `/c
|
|
|
49
51
|
|
|
50
52
|
### Candidate flow
|
|
51
53
|
|
|
52
|
-
For an unquoted token, the browser starts the `fileReferences/list` and `sessionReferenceResolver/candidates` Remote calls together, then deterministically orders files
|
|
54
|
+
For an unquoted token, the browser starts the `fileReferences/list` and `sessionReferenceResolver/candidates` Remote calls together, then deterministically orders files, direct subagents of the current Session, and other Sessions. Rows use the resolver's display title, which prefers a subagent's creation label while ordinary Sessions retain their projected title, and render under locale-owned group headings without a redundant raw `reference` source title. A session row is dated from the Host session list's `updatedAt` through the same relative-time bucket that list uses, so one session reads the same age on both surfaces; a session the list does not carry falls back to the candidate's creation time. A drilled query publishes a breadcrumb from the workspace root to the current directory; each crumb carries the drill payload a folder row would, so returning to a step and descending into one are one outcome.
|
|
53
55
|
|
|
54
56
|
### Serialization
|
|
55
57
|
|
package/README.zh.md
CHANGED
|
@@ -37,6 +37,8 @@ Web 用户需要从同一个 `@` 补全菜单提及文件、文件夹或会话
|
|
|
37
37
|
|
|
38
38
|
某个候选领域不可用或失败时,该领域不产生任何行,另一领域仍正常列出。会话引用准备失败发生在提示词接受后,并会终止该 agent 轮次。
|
|
39
39
|
|
|
40
|
+
点击输入框中的文件引用,可在右侧栏预览文件当前的内容。带引号路径中的空格会保留,路径按输入框所属 Session 解析。文件夹和 Session 引用保留原有的编辑行为。
|
|
41
|
+
|
|
40
42
|
-----
|
|
41
43
|
|
|
42
44
|
<a id="understand-the-implementation"></a>
|
|
@@ -49,7 +51,7 @@ Web 用户需要从同一个 `@` 补全菜单提及文件、文件夹或会话
|
|
|
49
51
|
|
|
50
52
|
### 候选流程
|
|
51
53
|
|
|
52
|
-
对于未加引号的 token,浏览器会同时启动 `fileReferences/list` 与 `sessionReferenceResolver/candidates` Remote
|
|
54
|
+
对于未加引号的 token,浏览器会同时启动 `fileReferences/list` 与 `sessionReferenceResolver/candidates` Remote 调用,再按文件、当前 Session 的直接 subagent、其他 Session 的确定性顺序排列。各行使用 resolver 的显示标题;subagent 优先使用创建标签,普通 Session 保持投影标题,并渲染在 locale 管理的分组标题下,不显示重复的原始 `reference` source 标题。会话行用宿主会话列表的 `updatedAt` 经该列表相同的相对时间分档标注时间,因此同一个会话在两处读到的时长一致;列表中没有的会话回落到候选自带的创建时间。下钻后的查询会发布一条从工作区根目录到当前目录的面包屑;每一节携带的下钻载荷与文件夹行相同,因此「回到某一步」与「进入某一层」是同一个结果。
|
|
53
55
|
|
|
54
56
|
### 序列化
|
|
55
57
|
|
package/lib/client.js
CHANGED
|
@@ -22,12 +22,46 @@ window.__ModuleLoader__.load({
|
|
|
22
22
|
return `@"${path}"`;
|
|
23
23
|
}
|
|
24
24
|
//#endregion
|
|
25
|
+
//#region ../../util/workspace-path/src/file-address.ts
|
|
26
|
+
/** The scheme and type every file address opens with. */
|
|
27
|
+
const FILE_ADDRESS_PREFIX = "dsh-resource://file/";
|
|
28
|
+
/** Component-encode one id or path segment, keeping `:` literal for drive letters. */
|
|
29
|
+
function encodeSegment(segment) {
|
|
30
|
+
return encodeURIComponent(segment).replace(/%3A/gi, ":");
|
|
31
|
+
}
|
|
32
|
+
/** Encode a `/`-separated path segment by segment. */
|
|
33
|
+
function encodePath(path) {
|
|
34
|
+
return path.split("/").map(encodeSegment).join("/");
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build the address of a file read through one Session.
|
|
38
|
+
* @param sessionId - the Session whose Host workspace resolves the path.
|
|
39
|
+
* @param path - absolute or workspace-relative path; backslashes are normalized to `/`, and leading `./` prefixes are dropped.
|
|
40
|
+
* @returns the `dsh-resource://file/session/<sessionId>/<path>` address.
|
|
41
|
+
*/
|
|
42
|
+
function sessionFileAddress(sessionId, path) {
|
|
43
|
+
const normalized = path.replace(/\\/g, "/").replace(/^(?:\.\/)+/, "");
|
|
44
|
+
return `${FILE_ADDRESS_PREFIX}session/${encodeSegment(sessionId)}/${encodePath(normalized)}`;
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
25
47
|
//#region ../../util/workspace-path/src/index.ts
|
|
48
|
+
/**
|
|
49
|
+
* Browser-safe Workspace path and display helpers.
|
|
50
|
+
* @module @deepseek-ai/dsh-util-workspace-path
|
|
51
|
+
*/
|
|
26
52
|
/** Whether a path uses a Windows drive or UNC prefix. */
|
|
27
53
|
function isWindowsStylePath(value) {
|
|
28
54
|
return /^[A-Za-z]:[/\\]/.test(value) || value.startsWith("\\\\");
|
|
29
55
|
}
|
|
30
56
|
/**
|
|
57
|
+
* Whether a path is absolute in either spelling the Host accepts: POSIX (`/a/b`) or Windows drive or UNC.
|
|
58
|
+
* @param path - the path to classify.
|
|
59
|
+
* @returns `true` for an absolute path; `false` for a Workspace-relative one.
|
|
60
|
+
*/
|
|
61
|
+
function isAbsoluteWorkspacePath(path) {
|
|
62
|
+
return path.startsWith("/") || isWindowsStylePath(path);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
31
65
|
* Abbreviate a POSIX home directory for display.
|
|
32
66
|
* @param path - Absolute or already-short display path.
|
|
33
67
|
* @param home - Host account home; absent skips abbreviation.
|
|
@@ -42,6 +76,24 @@ window.__ModuleLoader__.load({
|
|
|
42
76
|
if (path.startsWith(`${root}/`)) return `~${path.slice(root.length)}`;
|
|
43
77
|
return path;
|
|
44
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* The address for a path as a caller holds it: a relative path, or an absolute
|
|
81
|
+
* path inside the Session's workspace, becomes a `session`-scoped address; an
|
|
82
|
+
* absolute path outside it, or one whose workspace root is unknown, keeps its
|
|
83
|
+
* absolute path in that Session's address.
|
|
84
|
+
* @param sessionId - the Session the path is read in.
|
|
85
|
+
* @param cwd - that Session's workspace root, when known.
|
|
86
|
+
* @param path - absolute or workspace-relative path, in either separator spelling.
|
|
87
|
+
* @returns the `dsh-resource://file/…` address.
|
|
88
|
+
*/
|
|
89
|
+
function fileAddressFor(sessionId, cwd, path) {
|
|
90
|
+
const normalized = path.replace(/\\/g, "/");
|
|
91
|
+
if (!isAbsoluteWorkspacePath(normalized)) return sessionFileAddress(sessionId, normalized);
|
|
92
|
+
const root = cwd === void 0 ? "" : cwd.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
93
|
+
if (root !== "" && normalized === root) return sessionFileAddress(sessionId, "");
|
|
94
|
+
if (root !== "" && normalized.startsWith(`${root}/`)) return sessionFileAddress(sessionId, normalized.slice(root.length + 1));
|
|
95
|
+
return sessionFileAddress(sessionId, normalized);
|
|
96
|
+
}
|
|
45
97
|
//#endregion
|
|
46
98
|
//#region lib/types/client/locales.js
|
|
47
99
|
/** `reference` namespace dictionaries for the unified `@` source. */
|
|
@@ -56,6 +108,7 @@ window.__ModuleLoader__.load({
|
|
|
56
108
|
*/
|
|
57
109
|
const zh = {
|
|
58
110
|
"section.files": "文件与文件夹",
|
|
111
|
+
"section.subagents": "子智能体",
|
|
59
112
|
"section.sessions": "对话",
|
|
60
113
|
"candidate.noCwd": "(无工作目录)",
|
|
61
114
|
"crumb.root": "工作区",
|
|
@@ -69,6 +122,7 @@ window.__ModuleLoader__.load({
|
|
|
69
122
|
/** English dictionary, checked complete against the zh key set. */
|
|
70
123
|
const en = {
|
|
71
124
|
"section.files": "Files & folders",
|
|
125
|
+
"section.subagents": "Subagents",
|
|
72
126
|
"section.sessions": "Sessions",
|
|
73
127
|
"candidate.noCwd": "(no cwd)",
|
|
74
128
|
"crumb.root": "Workspace",
|
|
@@ -88,7 +142,8 @@ window.__ModuleLoader__.load({
|
|
|
88
142
|
"sessions",
|
|
89
143
|
"remote",
|
|
90
144
|
"remote.fileReferences",
|
|
91
|
-
"remote.sessionReferenceResolver"
|
|
145
|
+
"remote.sessionReferenceResolver",
|
|
146
|
+
"sidebarRight"
|
|
92
147
|
];
|
|
93
148
|
/**
|
|
94
149
|
* Register the combined `@file` / `@session` source.
|
|
@@ -114,7 +169,19 @@ window.__ModuleLoader__.load({
|
|
|
114
169
|
const now = Date.now();
|
|
115
170
|
const home = ctx.remote.$host.home;
|
|
116
171
|
const listed = sessions.list.getSnapshot().byId;
|
|
117
|
-
|
|
172
|
+
const sessionRows = sessionItems.map((candidate) => {
|
|
173
|
+
const summary = listed[candidate.sessionId];
|
|
174
|
+
const child = summary?.origin === "subagent" && summary.parentId === session.sessionId;
|
|
175
|
+
return {
|
|
176
|
+
child,
|
|
177
|
+
row: sessionCandidate(candidate, candidate.displayTitle ?? candidate.label, summary?.updatedAt ?? candidate.createdAt, now, home, t(child ? "section.subagents" : "section.sessions"), t)
|
|
178
|
+
};
|
|
179
|
+
});
|
|
180
|
+
return [
|
|
181
|
+
...fileItems.flatMap((candidate) => fileCandidate(candidate, quoted === true, withLocation, t)),
|
|
182
|
+
...sessionRows.filter((item) => item.child).map((item) => item.row),
|
|
183
|
+
...sessionRows.filter((item) => !item.child).map((item) => item.row)
|
|
184
|
+
];
|
|
118
185
|
},
|
|
119
186
|
header(_session, req) {
|
|
120
187
|
return crumbsFor(req.query, req.quoted === true, req.drilled, t);
|
|
@@ -142,6 +209,13 @@ window.__ModuleLoader__.load({
|
|
|
142
209
|
clipboardText: value.mention
|
|
143
210
|
} };
|
|
144
211
|
},
|
|
212
|
+
openReference(session, { ref, appearance }) {
|
|
213
|
+
if (appearance !== "file") return false;
|
|
214
|
+
const path = ref.startsWith("@\"") ? ref.slice(2, -1) : ref.slice(1);
|
|
215
|
+
const cwd = sessions.list.getSnapshot().byId[session.sessionId]?.cwd;
|
|
216
|
+
ctx.sidebarRight.openResource(fileAddressFor(session.sessionId, cwd, path));
|
|
217
|
+
return true;
|
|
218
|
+
},
|
|
145
219
|
codec: {
|
|
146
220
|
clipboardText: (ref) => ref,
|
|
147
221
|
serialize: (ref) => Promise.resolve(ref)
|
|
@@ -217,20 +291,20 @@ window.__ModuleLoader__.load({
|
|
|
217
291
|
...directory ? { drill: true } : {}
|
|
218
292
|
}];
|
|
219
293
|
}
|
|
220
|
-
function sessionCandidate(candidate, updatedAt, now, home, t) {
|
|
294
|
+
function sessionCandidate(candidate, label, updatedAt, now, home, section, t) {
|
|
221
295
|
const { unit, n } = (0, _deepseek_ai_dsh_client_ui_primitives.relativeTime)(updatedAt, now);
|
|
222
296
|
const age = unit === "now" ? t("time.now") : t(`time.${unit}`, { n });
|
|
223
297
|
const location = candidate.sameWorkspace ? void 0 : candidate.cwd === void 0 ? t("candidate.noCwd") : abbreviateHomePath(candidate.cwd, home);
|
|
224
298
|
const value = {
|
|
225
299
|
kind: "session",
|
|
226
|
-
label
|
|
300
|
+
label,
|
|
227
301
|
mention: candidate.mention
|
|
228
302
|
};
|
|
229
303
|
return {
|
|
230
|
-
name:
|
|
304
|
+
name: label,
|
|
231
305
|
description: location === void 0 ? age : `${location} · ${age}`,
|
|
232
306
|
icon: "session",
|
|
233
|
-
section
|
|
307
|
+
section,
|
|
234
308
|
value: JSON.stringify(value)
|
|
235
309
|
};
|
|
236
310
|
}
|
|
@@ -10,6 +10,7 @@ export declare const NS = "reference";
|
|
|
10
10
|
*/
|
|
11
11
|
export declare const zh: {
|
|
12
12
|
'section.files': string;
|
|
13
|
+
'section.subagents': string;
|
|
13
14
|
'section.sessions': string;
|
|
14
15
|
'candidate.noCwd': string;
|
|
15
16
|
'crumb.root': string;
|
|
@@ -31,6 +32,7 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
|
31
32
|
/** English dictionary, checked complete against the zh key set. */
|
|
32
33
|
export declare const en: {
|
|
33
34
|
'section.files': string;
|
|
35
|
+
'section.subagents': string;
|
|
34
36
|
'section.sessions': string;
|
|
35
37
|
'candidate.noCwd': string;
|
|
36
38
|
'crumb.root': string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-client-ui-reference",
|
|
3
3
|
"description": "Unified Web @file and @session reference source",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.6-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"@deepseek-ai/dsh-api-session-controller",
|
|
33
33
|
"@deepseek-ai/dsh-client-connection",
|
|
34
34
|
"@deepseek-ai/dsh-client-locale",
|
|
35
|
-
"@deepseek-ai/dsh-client-ui-input-trigger"
|
|
35
|
+
"@deepseek-ai/dsh-client-ui-input-trigger",
|
|
36
|
+
"@deepseek-ai/dsh-client-ui-sidebar-right"
|
|
36
37
|
],
|
|
37
38
|
"platform": "web"
|
|
38
39
|
}
|
|
@@ -42,19 +43,20 @@
|
|
|
42
43
|
"@deepseek-ai/cordis": "^4.0.2"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
|
-
"@deepseek-ai/dsh-api-remotes": "^0.1.
|
|
46
|
-
"@deepseek-ai/dsh-api-session-controller": "^0.1.
|
|
47
|
-
"@deepseek-ai/dsh-client-
|
|
48
|
-
"@deepseek-ai/dsh-client-
|
|
49
|
-
"@deepseek-ai/dsh-client-
|
|
50
|
-
"@deepseek-ai/dsh-client-
|
|
51
|
-
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.
|
|
52
|
-
"@deepseek-ai/dsh-client-ui-slots": "^0.1.
|
|
53
|
-
"@deepseek-ai/dsh-file-reference": "^0.1.
|
|
54
|
-
"@deepseek-ai/dsh-session-reference": "^0.1.
|
|
55
|
-
"@deepseek-ai/dsh-typert-protocol": "^0.1.
|
|
56
|
-
"@deepseek-ai/dsh-util-workspace-path": "^0.1.
|
|
57
|
-
"@deepseek-ai/cordis": "^4.0.2"
|
|
46
|
+
"@deepseek-ai/dsh-api-remotes": "^0.1.6-alpha.2",
|
|
47
|
+
"@deepseek-ai/dsh-api-session-controller": "^0.1.6-alpha.2",
|
|
48
|
+
"@deepseek-ai/dsh-client-connection": "^0.1.6-alpha.2",
|
|
49
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.6-alpha.2",
|
|
50
|
+
"@deepseek-ai/dsh-client-test-runtime": "^0.1.6-alpha.2",
|
|
51
|
+
"@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.6-alpha.2",
|
|
52
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.6-alpha.2",
|
|
53
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.6-alpha.2",
|
|
54
|
+
"@deepseek-ai/dsh-file-reference": "^0.1.6-alpha.2",
|
|
55
|
+
"@deepseek-ai/dsh-session-reference": "^0.1.6-alpha.2",
|
|
56
|
+
"@deepseek-ai/dsh-typert-protocol": "^0.1.6-alpha.2",
|
|
57
|
+
"@deepseek-ai/dsh-util-workspace-path": "^0.1.6-alpha.2",
|
|
58
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
59
|
+
"@deepseek-ai/dsh-client-ui-sidebar-right": "^0.1.6-alpha.2"
|
|
58
60
|
},
|
|
59
61
|
"files": [
|
|
60
62
|
"lib/index.js",
|