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.
- package/README.i18n.yaml +2 -2
- package/README.md +6 -6
- package/README.zh.md +6 -6
- package/dist/index.html +1 -1
- package/dist/plugins/@deepseek-ai/dsh-session-log-export/client.js +317 -0
- package/package.json +2 -1
- package/worker/direct/index.js +2556 -1379
- package/worker/isolated/index.js +2107 -930
|
@@ -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.
|
|
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",
|