dsh-edge 0.27.0 → 0.28.0-alpha.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.
@@ -0,0 +1,317 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@deepseek-ai/dsh-session-log-export",
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_store = require("@deepseek-ai/dsh-client-store");
8
+ let react_jsx_runtime = require("react/jsx-runtime");
9
+ let react = require("react");
10
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
11
+ /** Browser-relative form of {@link SESSION_LOG_EXPORT_PATH}. */
12
+ const SESSION_LOG_EXPORT_ROUTE = "/api/session.export".slice(1);
13
+ //#endregion
14
+ //#region lib/types/client/controller.js
15
+ /** Browser download state shared by the Session Header button and `/export`. */
16
+ const INITIAL = { bySession: {} };
17
+ /**
18
+ * Collapse an untrusted Session id into the filename convention owned by the host endpoint.
19
+ * @param sessionId - Session whose archive is downloaded.
20
+ * @returns one safe browser download filename.
21
+ */
22
+ function sessionLogZipFilename(sessionId) {
23
+ return `dsh-session-${String(sessionId).replace(/[^A-Za-z0-9_-]/g, "_")}.zip`;
24
+ }
25
+ /**
26
+ * Hand a Host download route to the browser download manager, which resolves it
27
+ * against the document's own base.
28
+ * @param url - document-relative Host download route.
29
+ * @param filename - browser download filename.
30
+ */
31
+ function downloadUrl(url, filename) {
32
+ const anchor = document.createElement("a");
33
+ anchor.href = url;
34
+ anchor.download = filename;
35
+ anchor.click();
36
+ }
37
+ function messageOf(error) {
38
+ return error instanceof Error ? error.message : String(error);
39
+ }
40
+ /** Owns one in-flight browser download per Session and publishes modal state. */
41
+ var SessionLogDownloadController = class {
42
+ fetcher;
43
+ save;
44
+ /** uSES-safe state source shared by every Session-scoped modal contribution. */
45
+ store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(INITIAL);
46
+ active = /* @__PURE__ */ new Map();
47
+ disposed = false;
48
+ /**
49
+ * @param fetcher - HTTP carrier used to read the host-streamed ZIP.
50
+ * @param save - browser save operation.
51
+ */
52
+ constructor(fetcher = (input, init) => fetch(input, init), save = downloadUrl) {
53
+ this.fetcher = fetcher;
54
+ this.save = save;
55
+ }
56
+ /**
57
+ * Download one Session tree; concurrent gestures for the same Session share one operation.
58
+ * @param sessionId - root Session whose ZIP includes descendants and attachments.
59
+ * @returns after the browser save starts, an error state is published, or a late post-disposal request is ignored.
60
+ */
61
+ download(sessionId) {
62
+ const existing = this.active.get(sessionId);
63
+ if (existing !== void 0) return existing.done;
64
+ if (this.disposed) return Promise.resolve();
65
+ const abort = new AbortController();
66
+ const done = this.run(sessionId, abort.signal).finally(() => {
67
+ this.active.delete(sessionId);
68
+ });
69
+ this.active.set(sessionId, {
70
+ abort,
71
+ done
72
+ });
73
+ return done;
74
+ }
75
+ /**
76
+ * Close one Session's dialog without cancelling an in-flight browser download.
77
+ * @param sessionId - Session whose modal closes.
78
+ */
79
+ dismiss(sessionId) {
80
+ const current = this.store.getSnapshot().bySession[String(sessionId)];
81
+ if (current === void 0 || !current.open) return;
82
+ this.publish(sessionId, {
83
+ ...current,
84
+ open: false
85
+ });
86
+ }
87
+ /**
88
+ * Abort active fetches and reach quiescence.
89
+ * @returns after every active operation settles.
90
+ */
91
+ async dispose() {
92
+ this.disposed = true;
93
+ const active = [...this.active.values()];
94
+ for (const operation of active) operation.abort.abort();
95
+ await Promise.allSettled(active.map((operation) => operation.done));
96
+ }
97
+ async run(sessionId, signal) {
98
+ this.publish(sessionId, {
99
+ open: true,
100
+ status: "downloading",
101
+ error: null
102
+ });
103
+ try {
104
+ const route = `${SESSION_LOG_EXPORT_ROUTE}?${new URLSearchParams({
105
+ sessionId,
106
+ includeDescendants: "true"
107
+ }).toString()}`;
108
+ const response = await this.fetcher(route, {
109
+ method: "HEAD",
110
+ signal
111
+ });
112
+ if (!response.ok) {
113
+ const detail = await response.text().catch(() => "");
114
+ throw new Error(`Export failed: HTTP ${response.status}${detail === "" ? "" : ` ${detail}`}`);
115
+ }
116
+ this.save(route, sessionLogZipFilename(sessionId));
117
+ const open = this.store.getSnapshot().bySession[String(sessionId)]?.open ?? true;
118
+ this.publish(sessionId, {
119
+ open,
120
+ status: "success",
121
+ error: null
122
+ });
123
+ } catch (error) {
124
+ if (signal.aborted) return;
125
+ const open = this.store.getSnapshot().bySession[String(sessionId)]?.open ?? true;
126
+ this.publish(sessionId, {
127
+ open,
128
+ status: "error",
129
+ error: messageOf(error)
130
+ });
131
+ }
132
+ }
133
+ publish(sessionId, entry) {
134
+ this.store.update((state) => {
135
+ state.bySession = {
136
+ ...state.bySession,
137
+ [String(sessionId)]: entry
138
+ };
139
+ });
140
+ }
141
+ };
142
+ //#endregion
143
+ //#region lib/types/client/Dialog.js
144
+ /**
145
+ * Modal shared by the Session Header download menu item and this browser's `/export` command.
146
+ * @param props - Session runtime, bound controller state, actions, and localized copy.
147
+ * @returns the modal portal contribution.
148
+ */
149
+ function SessionLogDownloadDialog({ sessionId, useSessionLogDownload, dismiss, t }) {
150
+ const entry = useSessionLogDownload((state) => state.bySession[String(sessionId)]);
151
+ const status = entry?.status;
152
+ const open = entry?.open === true;
153
+ const error = status === "error" ? entry?.error || t("dialog.commandFailed") : null;
154
+ return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
155
+ open,
156
+ onClose: () => {
157
+ dismiss(sessionId);
158
+ },
159
+ title: status === "downloading" ? t("dialog.preparingTitle") : status === "success" ? t("dialog.successTitle") : t("dialog.errorTitle"),
160
+ description: status === "downloading" ? t("dialog.preparingDescription") : status === "success" ? t("dialog.successDescription") : error ?? t("dialog.commandFailed"),
161
+ closeLabel: t("dialog.close"),
162
+ footer: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
163
+ variant: "primary",
164
+ onClick: () => {
165
+ dismiss(sessionId);
166
+ },
167
+ children: t("dialog.close")
168
+ })
169
+ });
170
+ }
171
+ //#endregion
172
+ //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/session-query/session-log-export/src/client/HeaderAction.module.css.mjs
173
+ const css = ".nL4_yW_moreButton{width:28px;color:var(--dsw-alias-label-secondary);flex:none;padding:0}.nL4_yW_moreButton svg{width:15px;height:15px}";
174
+ const tagId = "@deepseek-ai/dsh-session-log-export/HeaderAction.module.css";
175
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
176
+ const tag = document.createElement("style");
177
+ tag.dataset.plugin = "@deepseek-ai/dsh-session-log-export";
178
+ tag.dataset.pluginCss = tagId;
179
+ tag.textContent = css;
180
+ document.head.appendChild(tag);
181
+ }
182
+ var HeaderAction_module_css_default = { "moreButton": "nL4_yW_moreButton" };
183
+ //#endregion
184
+ //#region lib/types/client/HeaderAction.js
185
+ /**
186
+ * Render the Session Header menu with download and optional feedback actions.
187
+ * @param props - Session runtime, download controller, and localized copy.
188
+ * @returns the persistent Header action and Session-scoped dialog.
189
+ */
190
+ function SessionLogDownloadHeaderAction(props) {
191
+ const { sessionId, useSessionLogDownload, useFeedbackAvailable, request, openFeedback, t } = props;
192
+ const feedbackAvailable = useFeedbackAvailable((value) => value);
193
+ const busy = useSessionLogDownload((state) => state.bySession[String(sessionId)])?.status === "downloading";
194
+ const [open, setOpen] = (0, react.useState)(false);
195
+ return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
196
+ open,
197
+ align: "end",
198
+ dense: true,
199
+ onClose: () => {
200
+ setOpen(false);
201
+ },
202
+ items: [{
203
+ id: "download",
204
+ label: t("menu.download"),
205
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDownloadOutlineRegular, {}),
206
+ disabled: busy
207
+ }, ...feedbackAvailable ? [{
208
+ id: "feedback",
209
+ label: t("menu.feedback"),
210
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPaperPlaneOutlineRegular, {})
211
+ }] : []],
212
+ onSelect: (id) => {
213
+ setOpen(false);
214
+ if (id === "feedback") openFeedback(sessionId);
215
+ else request(sessionId);
216
+ },
217
+ anchor: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
218
+ size: "sm",
219
+ className: HeaderAction_module_css_default.moreButton,
220
+ "aria-label": t("header.more"),
221
+ "aria-haspopup": "menu",
222
+ "aria-expanded": open,
223
+ "aria-busy": busy,
224
+ onClick: () => {
225
+ setOpen((value) => !value);
226
+ },
227
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutlineRegular, {})
228
+ })
229
+ }), (0, react_jsx_runtime.jsx)(SessionLogDownloadDialog, { ...props })] });
230
+ }
231
+ //#endregion
232
+ //#region lib/types/client/locales.js
233
+ /** Locale namespace owned by Session export browser feedback. */
234
+ const NS = "session-log-download";
235
+ /** Simplified-Chinese Session export strings. */
236
+ const zh = {
237
+ "header.more": "更多操作",
238
+ "menu.download": "下载 Session 日志",
239
+ "menu.feedback": "反馈",
240
+ "dialog.preparingTitle": "正在导出 Session",
241
+ "dialog.preparingDescription": "正在准备包含当前 Session、子 Session 和附件的 ZIP 文件。",
242
+ "dialog.successTitle": "Session 导出已开始下载",
243
+ "dialog.successDescription": "浏览器正在下载 Session ZIP 文件。",
244
+ "dialog.errorTitle": "Session 导出失败",
245
+ "dialog.close": "关闭",
246
+ "dialog.commandFailed": "无法启动 Session 导出。"
247
+ };
248
+ /** English Session export strings. */
249
+ const en = {
250
+ "header.more": "More actions",
251
+ "menu.download": "Download session log",
252
+ "menu.feedback": "Feedback",
253
+ "dialog.preparingTitle": "Exporting Session",
254
+ "dialog.preparingDescription": "Preparing a ZIP containing this Session, its sub-Sessions, and attachments.",
255
+ "dialog.successTitle": "Session download started",
256
+ "dialog.successDescription": "The browser is downloading the Session ZIP.",
257
+ "dialog.errorTitle": "Session export failed",
258
+ "dialog.close": "Close",
259
+ "dialog.commandFailed": "Could not start the Session export."
260
+ };
261
+ //#endregion
262
+ //#region lib/types/client/index.js
263
+ /** Browser plugin owning Session export download state and its shared modal. */
264
+ const inject = ["slots", "locale"];
265
+ /**
266
+ * Provide the download controller and mount its modal into the Session Header.
267
+ * @param ctx - browser context carrying slots and locale services.
268
+ */
269
+ function apply(ctx) {
270
+ const controller = new SessionLogDownloadController();
271
+ ctx.provide("sessionLogDownload", controller);
272
+ ctx.effect(() => async () => {
273
+ await controller.dispose();
274
+ }, "session-log-download: browser download lifecycle");
275
+ ctx.effect(() => ctx.locale.register(NS, {
276
+ zh,
277
+ en
278
+ }), "session-log-download: browser dictionaries");
279
+ const feedbackAvailable = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(false);
280
+ ctx.inject(["feedbackUi"], (scope) => {
281
+ scope.effect(() => {
282
+ feedbackAvailable.set(true);
283
+ return () => {
284
+ feedbackAvailable.set(false);
285
+ };
286
+ }, "session-log-download: feedback availability");
287
+ });
288
+ ctx.on("command/executed", (sessionId, commandName, result) => {
289
+ if (commandName === "export" && result.kind === "success") controller.download(sessionId);
290
+ });
291
+ ctx.slots.inject("conversation.session.header.utilities", () => ctx.slots.register({
292
+ name: "conversation.session.header.utilities",
293
+ id: "session-log-download",
294
+ locale: NS,
295
+ inject: () => ({
296
+ hooks: {
297
+ sessionLogDownload: controller.store,
298
+ feedbackAvailable
299
+ },
300
+ request: (sessionId) => controller.download(sessionId),
301
+ dismiss: (sessionId) => {
302
+ controller.dismiss(sessionId);
303
+ },
304
+ openFeedback: (sessionId) => {
305
+ ctx.get("feedbackUi")?.openSession(sessionId);
306
+ }
307
+ })
308
+ }, SessionLogDownloadHeaderAction));
309
+ }
310
+ //#endregion
311
+ exports.apply = apply;
312
+ exports.inject = inject;
313
+ return module.exports;
314
+ }
315
+ });
316
+
317
+ //# sourceMappingURL=client.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-edge",
3
- "version": "0.27.0",
3
+ "version": "0.28.0-alpha.1",
4
4
  "description": "Your DeepSeek Harness, anywhere — deploy a persistent personal coding agent to Cloudflare Workers in one command",
5
5
  "author": "pawaca",
6
6
  "license": "MIT",
@@ -75,6 +75,7 @@
75
75
  "@deepseek-ai/dsh-attachment": "0.2.1-rc.2",
76
76
  "@deepseek-ai/dsh-brand": "0.2.1-rc.2",
77
77
  "@deepseek-ai/dsh-client-connection": "0.2.1-rc.2",
78
+ "@deepseek-ai/dsh-client-file-upload": "0.2.1-rc.2",
78
79
  "@deepseek-ai/dsh-client-locale": "0.2.1-rc.2",
79
80
  "@deepseek-ai/dsh-client-store": "0.2.1-rc.2",
80
81
  "@deepseek-ai/dsh-client-ui-chat": "0.2.1-rc.2",