dsh-edge 0.10.0 → 0.11.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.
@@ -0,0 +1,140 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@deepseek-ai/dsh-client-ui-plan",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let react_jsx_runtime = require("react/jsx-runtime");
8
+ let react = require("react");
9
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
10
+ //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-plan/src/client/PlanModeControl.module.css.mjs
11
+ const css = ".rS3zOq_wrap{align-items:center;gap:6px;display:inline-flex}.rS3zOq_chip{corner-shape:round;background:var(--dsw-alias-state-warn-tertiary);min-width:34px;color:var(--dsw-alias-state-warn-label);cursor:pointer;border:none;border-radius:999px;align-items:center;gap:4px;padding:2px 8px;font-size:13px;font-weight:500;line-height:20px;display:inline-flex}.rS3zOq_chip:hover:not(:disabled){color:var(--dsw-alias-state-warn-primary)}.rS3zOq_chip:focus-visible{outline:2px solid var(--dsw-alias-state-warn-label);outline-offset:2px}.rS3zOq_chip:disabled{opacity:.6;cursor:default}.rS3zOq_close{color:currentColor;align-items:center;display:inline-flex}.rS3zOq_error{color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}";
12
+ const tagId = "@deepseek-ai/dsh-client-ui-plan/PlanModeControl.module.css";
13
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
14
+ const tag = document.createElement("style");
15
+ tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-plan";
16
+ tag.dataset.pluginCss = tagId;
17
+ tag.textContent = css;
18
+ document.head.appendChild(tag);
19
+ }
20
+ var PlanModeControl_module_css_default = {
21
+ "chip": "rS3zOq_chip",
22
+ "close": "rS3zOq_close",
23
+ "error": "rS3zOq_error",
24
+ "wrap": "rS3zOq_wrap"
25
+ };
26
+ //#endregion
27
+ //#region lib/types/client/PlanModeControl.js
28
+ /**
29
+ * Plan-mode status over the host-computed `plan` projection. The chip renders
30
+ * only while the effective target is plan mode (`pending ? !active : active`
31
+ * — a folded host value, not client optimism) and executes /plan off.
32
+ */
33
+ function PlanChip({ useProjection, locked, exitPlanMode, t }) {
34
+ const plan = useProjection("plan");
35
+ const [leaving, setLeaving] = (0, react.useState)(false);
36
+ const [error, setError] = (0, react.useState)(null);
37
+ const aliveRef = (0, react.useRef)(true);
38
+ (0, react.useEffect)(() => {
39
+ aliveRef.current = true;
40
+ return () => {
41
+ aliveRef.current = false;
42
+ };
43
+ }, []);
44
+ if (plan === void 0) return null;
45
+ if (!(plan.pending ? !plan.active : plan.active)) return null;
46
+ const off = () => {
47
+ setLeaving(true);
48
+ setError(null);
49
+ exitPlanMode().then((failure) => {
50
+ if (!aliveRef.current) return;
51
+ setLeaving(false);
52
+ setError(failure);
53
+ }, (reason) => {
54
+ if (!aliveRef.current) return;
55
+ setLeaving(false);
56
+ setError(reason instanceof Error ? reason.message : String(reason));
57
+ });
58
+ };
59
+ return (0, react_jsx_runtime.jsxs)("span", {
60
+ className: PlanModeControl_module_css_default.wrap,
61
+ children: [(0, react_jsx_runtime.jsxs)("button", {
62
+ type: "button",
63
+ className: PlanModeControl_module_css_default.chip,
64
+ "aria-label": t("chip.on.aria"),
65
+ title: t("chip.on.title"),
66
+ disabled: locked || leaving,
67
+ onClick: off,
68
+ children: [t("chip.label"), (0, react_jsx_runtime.jsx)("span", {
69
+ className: PlanModeControl_module_css_default.close,
70
+ "aria-hidden": true,
71
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseFill14, { size: 12 })
72
+ })]
73
+ }), error !== null && (0, react_jsx_runtime.jsx)("span", {
74
+ className: PlanModeControl_module_css_default.error,
75
+ role: "status",
76
+ title: error,
77
+ children: t("chip.exitFailed")
78
+ })]
79
+ });
80
+ }
81
+ //#endregion
82
+ //#region lib/types/client/locales.js
83
+ /** `plan` namespace dictionaries (the composer plan chip's copy). */
84
+ /** Simplified Chinese dictionary (the key-set source of truth). */
85
+ const zh = {
86
+ "chip.label": "Plan",
87
+ "chip.on.aria": "plan mode 已开启,按下关闭",
88
+ "chip.on.title": "plan mode 已开启 — 点击关闭(/plan off)",
89
+ "chip.off.aria": "plan mode 已关闭,按下开启",
90
+ "chip.off.title": "plan mode 已关闭 — 点击开启(/plan)",
91
+ "chip.exitFailed": "退出 plan mode 失败"
92
+ };
93
+ /** English dictionary, checked complete against the zh key set. */
94
+ const en = {
95
+ "chip.label": "Plan",
96
+ "chip.on.aria": "Plan mode on, press to turn off",
97
+ "chip.on.title": "Plan mode on — click to turn off (/plan off)",
98
+ "chip.off.aria": "Plan mode off, press to turn on",
99
+ "chip.off.title": "Plan mode off — click to turn on (/plan)",
100
+ "chip.exitFailed": "Failed to exit plan mode"
101
+ };
102
+ //#endregion
103
+ //#region lib/types/client/index.js
104
+ /** Dictionary namespace owned by this plugin. */
105
+ const NS = "plan";
106
+ /** Required services: the seat's slot registry, commands Remote, and locale registry. */
107
+ const inject = [
108
+ "slots",
109
+ "remote",
110
+ "remote.commands",
111
+ "locale"
112
+ ];
113
+ /**
114
+ * Client plugin body: register the plan chip over the command channel.
115
+ * @param ctx - client root context.
116
+ */
117
+ function apply(ctx) {
118
+ ctx.effect(() => ctx.locale.register(NS, {
119
+ zh,
120
+ en
121
+ }), "ui-plan: dictionaries");
122
+ ctx.slots.inject("conversation.input.plan", () => ctx.slots.register({
123
+ name: "conversation.input.plan",
124
+ locale: NS,
125
+ inject: (sessionId) => ({ exitPlanMode: async () => {
126
+ const result = await ctx.remote.commands.execute(sessionId, "/plan off", []);
127
+ if (!result.ok) return `${result.error.message} (${result.error.code})`;
128
+ if (result.value === void 0) return "unknown command: /plan off";
129
+ return null;
130
+ } })
131
+ }, PlanChip));
132
+ }
133
+ //#endregion
134
+ exports.apply = apply;
135
+ exports.inject = inject;
136
+ return module.exports;
137
+ }
138
+ });
139
+
140
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1,252 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@deepseek-ai/dsh-client-ui-reference",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
8
+ //#region ../../context/file-reference/src/grammar.ts
9
+ /**
10
+ * Format a selected path as prompt text. Whitespace uses the quoted
11
+ * `@"path"` grammar; a quoted directory keeps that quote open after its
12
+ * trailing slash so completion can descend another level.
13
+ * @param candidate - selected file or directory.
14
+ * @param preserveQuote - retain an explicitly opened quote even when unnecessary.
15
+ * @returns the insertion value, or `undefined` for a path the editor grammar cannot represent safely.
16
+ */
17
+ function formatFileMention(candidate, preserveQuote) {
18
+ const path = candidate.kind === "directory" ? `${candidate.path}/` : candidate.path;
19
+ if (/[\u0000-\u001f\u007f-\u009f"]/u.test(path)) return void 0;
20
+ if (!(preserveQuote || /\s/u.test(path))) return `@${path}`;
21
+ if (candidate.kind === "directory") return `@"${path}`;
22
+ return `@"${path}"`;
23
+ }
24
+ //#endregion
25
+ //#region ../../util/workspace-path/src/index.ts
26
+ /**
27
+ * Browser-safe Workspace path and display helpers.
28
+ * @module @deepseek-ai/dsh-util-workspace-path
29
+ */
30
+ /** Whether a path uses a Windows drive or UNC prefix. */
31
+ function isWindowsStylePath(value) {
32
+ return /^[A-Za-z]:[/\\]/.test(value) || value.startsWith("\\\\");
33
+ }
34
+ /**
35
+ * Abbreviate a POSIX home directory for display.
36
+ * @param path - Absolute or already-short display path.
37
+ * @param home - Host account home; absent skips abbreviation.
38
+ * @returns `~` or `~/…` for the POSIX home and its descendants, otherwise `path`.
39
+ */
40
+ function abbreviateHomePath(path, home) {
41
+ if (home === void 0 || home === "") return path;
42
+ if (isWindowsStylePath(path) || isWindowsStylePath(home)) return path;
43
+ const root = home.replace(/\/+$/, "");
44
+ if (root === "" || root === "/") return path;
45
+ if (path.replace(/\/+$/, "") === root) return "~";
46
+ if (path.startsWith(`${root}/`)) return `~${path.slice(root.length)}`;
47
+ return path;
48
+ }
49
+ //#endregion
50
+ //#region lib/types/client/locales.js
51
+ /** `reference` namespace dictionaries for the unified `@` source. */
52
+ /** Dictionary namespace owned by this plugin. */
53
+ const NS = "reference";
54
+ /**
55
+ * Simplified Chinese dictionary (the key-set source of truth).
56
+ *
57
+ * The `time.*` bucket words are this namespace's own copy of the session-row
58
+ * vocabulary: locale-owned copy keeps the words per plugin, while the
59
+ * bucketing they name is the one shared {@link relativeTime} in ui-primitives.
60
+ */
61
+ const zh = {
62
+ "section.files": "文件与文件夹",
63
+ "section.sessions": "对话",
64
+ "candidate.noCwd": "(无工作目录)",
65
+ "crumb.root": "工作区",
66
+ "time.now": "刚刚",
67
+ "time.minutes": "{n}分钟",
68
+ "time.hours": "{n}小时",
69
+ "time.days": "{n}天",
70
+ "time.months": "{n}个月",
71
+ "time.years": "{n}年"
72
+ };
73
+ /** English dictionary, checked complete against the zh key set. */
74
+ const en = {
75
+ "section.files": "Files & folders",
76
+ "section.sessions": "Sessions",
77
+ "candidate.noCwd": "(no cwd)",
78
+ "crumb.root": "Workspace",
79
+ "time.now": "now",
80
+ "time.minutes": "{n}min",
81
+ "time.hours": "{n}h",
82
+ "time.days": "{n}d",
83
+ "time.months": "{n}mo",
84
+ "time.years": "{n}y"
85
+ };
86
+ //#endregion
87
+ //#region lib/types/client/index.js
88
+ /** Required services: the trigger registry, the Remote namespaces, and the copy. */
89
+ const inject = [
90
+ "inputTriggers",
91
+ "locale",
92
+ "sessions",
93
+ "remote",
94
+ "remote.fileReferences",
95
+ "remote.sessionReferenceResolver"
96
+ ];
97
+ /**
98
+ * Register the combined `@file` / `@session` source.
99
+ * @param ctx - client root context.
100
+ */
101
+ function apply(ctx) {
102
+ ctx.effect(() => ctx.locale.register(NS, {
103
+ zh,
104
+ en
105
+ }), "ui-reference: dictionaries");
106
+ const t = ctx.locale.bind(NS);
107
+ const sessions = ctx.get("sessions");
108
+ const source = {
109
+ trigger: "@",
110
+ name: "reference",
111
+ showGroupTitle: false,
112
+ async candidates(session, { query, quoted, drilled, signal }) {
113
+ const fileLookup = ctx.remote.fileReferences.list(session.sessionId, query, signal).then((result) => result.ok ? result.value : []);
114
+ const sessionLookup = quoted === true ? Promise.resolve([]) : ctx.remote.sessionReferenceResolver.candidates(session.sessionId, query, signal).then((result) => result.ok ? result.value : []);
115
+ const [fileItems, sessionItems] = await Promise.all([fileLookup, sessionLookup]);
116
+ if (signal.aborted) return [];
117
+ const withLocation = crumbsFor(query, quoted === true, drilled, t) === void 0;
118
+ const now = Date.now();
119
+ const home = ctx.remote.$host.home;
120
+ const listed = sessions.list.getSnapshot().byId;
121
+ return [...fileItems.flatMap((candidate) => fileCandidate(candidate, quoted === true, withLocation, t)), ...sessionItems.map((candidate) => sessionCandidate(candidate, listed[candidate.sessionId]?.updatedAt ?? candidate.createdAt, now, home, t))];
122
+ },
123
+ header(_session, req) {
124
+ return crumbsFor(req.query, req.quoted === true, req.drilled, t);
125
+ },
126
+ onPick({ candidate, action }) {
127
+ const value = parseCandidate(candidate.value);
128
+ if (value?.kind === "file") {
129
+ if (value.fileKind === "directory" && action === "drill") return {
130
+ text: value.mention,
131
+ continue: true
132
+ };
133
+ return { insert: {
134
+ source: "reference",
135
+ ref: value.mention,
136
+ label: value.fileKind === "directory" ? `${value.label}/` : value.label,
137
+ appearance: value.fileKind === "directory" ? "folder" : "file",
138
+ clipboardText: value.mention
139
+ } };
140
+ }
141
+ if (value?.kind === "session") return { insert: {
142
+ source: "reference",
143
+ ref: value.mention,
144
+ label: value.label,
145
+ appearance: "session",
146
+ clipboardText: value.mention
147
+ } };
148
+ },
149
+ codec: {
150
+ clipboardText: (ref) => ref,
151
+ serialize: (ref) => Promise.resolve(ref)
152
+ }
153
+ };
154
+ const inputTriggers = ctx.get("inputTriggers");
155
+ ctx.effect(() => inputTriggers.registerSource(source), "ui-reference: @ source");
156
+ }
157
+ /**
158
+ * The breadcrumb of a drilled directory listing, from the workspace root down
159
+ * to the directory being listed.
160
+ *
161
+ * Only a drill produces one: a path the user typed carries its own context in
162
+ * the draft, while a drill replaced the text they were reading with a deeper
163
+ * one and owes them the way back.
164
+ * @param query - the live query, path text following `@` or `@"`.
165
+ * @param quoted - whether the active token is an open quoted path.
166
+ * @param drilled - whether a drill pick, rather than typing, produced the query.
167
+ * @param t - the reference dictionary.
168
+ * @returns the crumbs, or undefined when this listing needs no header.
169
+ */
170
+ function crumbsFor(query, quoted, drilled, t) {
171
+ if (!drilled) return void 0;
172
+ const slash = query.lastIndexOf("/");
173
+ if (slash < 0) return void 0;
174
+ const segments = query.slice(0, slash).split("/").filter((segment) => segment !== "");
175
+ const crumbs = [{
176
+ label: t("crumb.root"),
177
+ value: directoryValue(t("crumb.root"), quoted ? "@\"" : "@")
178
+ }];
179
+ for (const [index, segment] of segments.entries()) {
180
+ const mention = formatFileMention({
181
+ path: segments.slice(0, index + 1).join("/"),
182
+ kind: "directory"
183
+ }, quoted);
184
+ if (mention === void 0) return void 0;
185
+ crumbs.push({
186
+ label: segment,
187
+ value: directoryValue(segment, mention),
188
+ ...index === segments.length - 1 ? { current: true } : {}
189
+ });
190
+ }
191
+ return crumbs;
192
+ }
193
+ /** Project one directory destination as the drill payload `onPick` already understands. */
194
+ function directoryValue(label, mention) {
195
+ return JSON.stringify({
196
+ kind: "file",
197
+ fileKind: "directory",
198
+ label,
199
+ mention
200
+ });
201
+ }
202
+ function fileCandidate(candidate, preserveQuote, withLocation, t) {
203
+ const mention = formatFileMention(candidate, preserveQuote);
204
+ if (mention === void 0) return [];
205
+ const slash = candidate.path.lastIndexOf("/");
206
+ const name = candidate.path.slice(slash + 1);
207
+ const parent = slash < 0 ? "" : candidate.path.slice(0, slash);
208
+ const directory = candidate.kind === "directory";
209
+ const value = {
210
+ kind: "file",
211
+ fileKind: candidate.kind,
212
+ label: name,
213
+ mention
214
+ };
215
+ return [{
216
+ name: `${name}${directory ? "/" : ""}`,
217
+ ...withLocation && parent !== "" ? { description: parent } : {},
218
+ icon: directory ? "folder" : "file",
219
+ section: t("section.files"),
220
+ value: JSON.stringify(value),
221
+ ...directory ? { drill: true } : {}
222
+ }];
223
+ }
224
+ function sessionCandidate(candidate, updatedAt, now, home, t) {
225
+ const { unit, n } = (0, _deepseek_ai_dsh_client_ui_primitives.relativeTime)(updatedAt, now);
226
+ const age = unit === "now" ? t("time.now") : t(`time.${unit}`, { n });
227
+ const location = candidate.sameWorkspace ? void 0 : candidate.cwd === void 0 ? t("candidate.noCwd") : abbreviateHomePath(candidate.cwd, home);
228
+ const value = {
229
+ kind: "session",
230
+ label: candidate.label,
231
+ mention: candidate.mention
232
+ };
233
+ return {
234
+ name: candidate.label,
235
+ description: location === void 0 ? age : `${location} · ${age}`,
236
+ icon: "session",
237
+ section: t("section.sessions"),
238
+ value: JSON.stringify(value)
239
+ };
240
+ }
241
+ function parseCandidate(value) {
242
+ if (value === void 0) return void 0;
243
+ return JSON.parse(value);
244
+ }
245
+ //#endregion
246
+ exports.apply = apply;
247
+ exports.inject = inject;
248
+ return module.exports;
249
+ }
250
+ });
251
+
252
+ //# sourceMappingURL=client.js.map