@lemoncat7/dsh-knowledge 2.5.1 → 2.6.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.md +15 -3
- package/docs/architecture.md +14 -4
- package/docs/releases/2.6.0.md +20 -0
- package/lib/api.d.ts.map +1 -1
- package/lib/api.js +19 -3
- package/lib/api.js.map +1 -1
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +118 -57
- package/lib/client.js.map +4 -4
- package/lib/config.d.ts +1 -0
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +5 -0
- package/lib/config.js.map +1 -1
- package/lib/extraction.d.ts +25 -1
- package/lib/extraction.d.ts.map +1 -1
- package/lib/extraction.js +70 -47
- package/lib/extraction.js.map +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +55 -64
- package/lib/index.js.map +1 -1
- package/lib/local-provider.d.ts +3 -0
- package/lib/local-provider.d.ts.map +1 -1
- package/lib/local-provider.js +27 -6
- package/lib/local-provider.js.map +1 -1
- package/lib/notes/share-import.d.ts +2 -0
- package/lib/notes/share-import.d.ts.map +1 -1
- package/lib/notes/share-import.js +40 -5
- package/lib/notes/share-import.js.map +1 -1
- package/lib/provider.d.ts +3 -0
- package/lib/provider.d.ts.map +1 -1
- package/lib/remote-provider.d.ts +3 -0
- package/lib/remote-provider.d.ts.map +1 -1
- package/lib/remote-provider.js +10 -0
- package/lib/remote-provider.js.map +1 -1
- package/lib/writeback/queue.d.ts +40 -0
- package/lib/writeback/queue.d.ts.map +1 -0
- package/lib/writeback/queue.js +193 -0
- package/lib/writeback/queue.js.map +1 -0
- package/lib/writeback/status-client.d.ts +22 -0
- package/lib/writeback/status-client.d.ts.map +1 -0
- package/lib/writeback/status-client.js +97 -0
- package/lib/writeback/status-client.js.map +1 -0
- package/package.json +1 -1
- package/web/api-client.js +2 -1
- package/web/app.js +30 -12
- package/web/styles.css +4 -8
- package/web/ui-primitives.js +1 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/** One cancellable request stream per visible turn; stale GETs cannot undo retries. */
|
|
2
|
+
export class WritebackStatusClient {
|
|
3
|
+
url;
|
|
4
|
+
change;
|
|
5
|
+
fetcher;
|
|
6
|
+
request;
|
|
7
|
+
timer;
|
|
8
|
+
disposed = false;
|
|
9
|
+
visible = true;
|
|
10
|
+
retrying = false;
|
|
11
|
+
failures = 0;
|
|
12
|
+
value;
|
|
13
|
+
readError;
|
|
14
|
+
// Browser fetch checks its Window receiver. Never store it as an unbound
|
|
15
|
+
// instance method: this.fetcher() would supply the client as its receiver.
|
|
16
|
+
constructor(url, change, fetcher = (...args) => globalThis.fetch(...args)) {
|
|
17
|
+
this.url = url;
|
|
18
|
+
this.change = change;
|
|
19
|
+
this.fetcher = fetcher;
|
|
20
|
+
}
|
|
21
|
+
setVisible(visible) {
|
|
22
|
+
this.visible = visible;
|
|
23
|
+
if (visible)
|
|
24
|
+
this.refresh();
|
|
25
|
+
else {
|
|
26
|
+
clearTimeout(this.timer);
|
|
27
|
+
if (!this.retrying)
|
|
28
|
+
this.request?.abort();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
refresh() {
|
|
32
|
+
if (this.disposed || !this.visible || this.retrying || this.request && !this.request.signal.aborted)
|
|
33
|
+
return;
|
|
34
|
+
void this.load(false);
|
|
35
|
+
}
|
|
36
|
+
retry() {
|
|
37
|
+
if (this.disposed || this.retrying || !this.value?.retryable)
|
|
38
|
+
return;
|
|
39
|
+
this.retrying = true;
|
|
40
|
+
this.request?.abort();
|
|
41
|
+
this.change(this.value, true);
|
|
42
|
+
void this.load(true);
|
|
43
|
+
}
|
|
44
|
+
async load(retry) {
|
|
45
|
+
clearTimeout(this.timer);
|
|
46
|
+
const controller = new AbortController();
|
|
47
|
+
this.request = controller;
|
|
48
|
+
const timeout = setTimeout(() => controller.abort(new Error('状态请求超时')), 15_000);
|
|
49
|
+
let delay = 15_000;
|
|
50
|
+
try {
|
|
51
|
+
const response = await this.fetcher(this.url, {
|
|
52
|
+
method: retry ? 'POST' : 'GET', signal: controller.signal,
|
|
53
|
+
headers: { accept: 'application/json', 'x-dsh-knowledge-client': 'conversation-web' },
|
|
54
|
+
});
|
|
55
|
+
const body = await response.json();
|
|
56
|
+
if (this.request !== controller || this.disposed)
|
|
57
|
+
return;
|
|
58
|
+
if (!response.ok && (retry || response.status !== 404))
|
|
59
|
+
throw new Error(body.error ?? `状态请求失败(HTTP ${response.status})`);
|
|
60
|
+
this.readError = undefined;
|
|
61
|
+
if (response.ok && body.summary) {
|
|
62
|
+
this.value = body;
|
|
63
|
+
this.failures = 0;
|
|
64
|
+
delay = body.status === 'completed' ? 0 : body.status === 'failed' ? 15_000 : 1_500;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
delay = ++this.failures <= 3 ? 1_500 : 60_000;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
if (this.request !== controller || this.disposed)
|
|
72
|
+
return;
|
|
73
|
+
delay = Math.min(60_000, 2_000 * 2 ** Math.min(5, this.failures++));
|
|
74
|
+
if (retry && this.value)
|
|
75
|
+
this.value = { ...this.value, error: error instanceof Error ? error.message : String(error) };
|
|
76
|
+
else if (this.visible)
|
|
77
|
+
this.readError = '暂时无法读取回写状态,正在自动重试;这不代表回写失败。';
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
clearTimeout(timeout);
|
|
81
|
+
if (this.request === controller && !this.disposed) {
|
|
82
|
+
this.request = undefined;
|
|
83
|
+
if (retry)
|
|
84
|
+
this.retrying = false;
|
|
85
|
+
this.change(this.value, this.retrying, this.readError);
|
|
86
|
+
if (delay && this.visible)
|
|
87
|
+
this.timer = setTimeout(() => this.refresh(), delay);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
dispose() {
|
|
92
|
+
this.disposed = true;
|
|
93
|
+
clearTimeout(this.timer);
|
|
94
|
+
this.request?.abort();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=status-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-client.js","sourceRoot":"","sources":["../../src/writeback/status-client.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lemoncat7/dsh-knowledge",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.1",
|
|
4
4
|
"description": "Local and remote knowledge bases for DeepSeek Harness, with scoped recall, controlled write-back, and a Web management console",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
package/web/api-client.js
CHANGED
|
@@ -30,6 +30,8 @@ export function createApiClient({ apiBase, authMode, getToken }) {
|
|
|
30
30
|
if (!response.ok) {
|
|
31
31
|
const error = new Error(payload?.error || `请求失败(HTTP ${response.status})`)
|
|
32
32
|
error.status = response.status
|
|
33
|
+
error.code = payload?.code
|
|
34
|
+
error.origin = payload?.origin
|
|
33
35
|
throw error
|
|
34
36
|
}
|
|
35
37
|
return payload
|
|
@@ -91,4 +93,3 @@ export function createApiClient({ apiBase, authMode, getToken }) {
|
|
|
91
93
|
|
|
92
94
|
return { api, binaryRequest, binaryUploadRequest }
|
|
93
95
|
}
|
|
94
|
-
|
package/web/app.js
CHANGED
|
@@ -2181,8 +2181,9 @@ function openImportNoteShare() {
|
|
|
2181
2181
|
destination.input.disabled = true
|
|
2182
2182
|
const inspectButton = actionButton('读取分享', () => { void inspect() }, 'small')
|
|
2183
2183
|
const fieldError = element('p', { class: 'share-import-field-error', role: 'alert', hidden: true })
|
|
2184
|
+
const privateConfirmation = element('div', { class: 'share-import-note', hidden: true, role: 'status' })
|
|
2184
2185
|
const preview = element('div', { class: 'share-import-preview', 'data-state': 'empty', 'aria-live': 'polite' },
|
|
2185
|
-
element('span', { class: 'share-import-preview-mark', 'aria-hidden': 'true' }),
|
|
2186
|
+
element('span', { class: 'share-import-preview-mark', 'aria-hidden': 'true' }, interfaceIcon('share-import')),
|
|
2186
2187
|
element('div', {}, element('strong', {}, '等待读取分享'), element('p', {}, '读取后会显示类型、文件数量与大小;导入前不会写入任何内容。')),
|
|
2187
2188
|
)
|
|
2188
2189
|
const destinationHint = element('span', { class: 'field-hint' }, '正在读取你的笔记目录…')
|
|
@@ -2191,11 +2192,13 @@ function openImportNoteShare() {
|
|
|
2191
2192
|
urlField.wrapper.replaceChildren(element('label', {}, '分享链接'), inputRow, fieldError)
|
|
2192
2193
|
const form = element('form', { class: 'share-import-form', onSubmit: event => { event.preventDefault(); void inspect() } },
|
|
2193
2194
|
urlField.wrapper,
|
|
2195
|
+
privateConfirmation,
|
|
2194
2196
|
preview,
|
|
2195
2197
|
destination.wrapper,
|
|
2196
2198
|
element('p', { class: 'share-import-note' }, '导入会创建一份独立副本;之后对方更新或停止分享,都不会改动你已经导入的内容。'),
|
|
2197
2199
|
)
|
|
2198
2200
|
let inspectedUrl = ''
|
|
2201
|
+
let confirmedPrivateUrl = ''
|
|
2199
2202
|
|
|
2200
2203
|
const showFieldError = message => {
|
|
2201
2204
|
fieldError.textContent = message
|
|
@@ -2215,33 +2218,54 @@ function openImportNoteShare() {
|
|
|
2215
2218
|
)
|
|
2216
2219
|
}
|
|
2217
2220
|
const inspect = async () => {
|
|
2221
|
+
if (inspectButton.disabled) return false
|
|
2218
2222
|
if (!urlField.input.reportValidity()) return false
|
|
2223
|
+
const requestedUrl = urlField.input.value.trim()
|
|
2224
|
+
urlField.input.disabled = true
|
|
2225
|
+
privateConfirmation.hidden = true
|
|
2219
2226
|
inspectButton.disabled = true
|
|
2220
2227
|
inspectButton.setAttribute('aria-busy', 'true')
|
|
2221
2228
|
inspectButton.textContent = '正在读取…'
|
|
2222
2229
|
showFieldError('')
|
|
2223
2230
|
preview.dataset.state = 'loading'
|
|
2224
2231
|
try {
|
|
2225
|
-
const result = await api('notes/import-share/inspect', { method: 'POST', body: { url:
|
|
2226
|
-
inspectedUrl =
|
|
2232
|
+
const result = await api('notes/import-share/inspect', { method: 'POST', body: { url: requestedUrl, confirmPrivateShare: confirmedPrivateUrl === requestedUrl } })
|
|
2233
|
+
inspectedUrl = requestedUrl
|
|
2227
2234
|
renderPreview(result.manifest)
|
|
2228
2235
|
return !result.manifest.truncated
|
|
2229
2236
|
} catch (error) {
|
|
2230
2237
|
inspectedUrl = ''
|
|
2231
2238
|
preview.dataset.state = 'error'
|
|
2232
2239
|
preview.replaceChildren(
|
|
2233
|
-
element('span', { class: 'share-import-preview-mark', 'aria-hidden': 'true' }),
|
|
2240
|
+
element('span', { class: 'share-import-preview-mark', 'aria-hidden': 'true' }, interfaceIcon('share-import')),
|
|
2234
2241
|
element('div', {}, element('strong', {}, '无法读取这个分享'), element('p', {}, '请检查链接是否完整、分享是否仍有效。')),
|
|
2235
2242
|
)
|
|
2236
2243
|
showFieldError(friendlyError(error))
|
|
2244
|
+
if (error.code === 'PRIVATE_SHARE_CONFIRMATION_REQUIRED' && error.origin === new URL(requestedUrl).origin) {
|
|
2245
|
+
confirmedPrivateUrl = ''
|
|
2246
|
+
showFieldError('')
|
|
2247
|
+
preview.dataset.state = 'empty'
|
|
2248
|
+
preview.replaceChildren(
|
|
2249
|
+
element('span', { class: 'share-import-preview-mark', 'aria-hidden': 'true' }, interfaceIcon('share-import')),
|
|
2250
|
+
element('div', {}, element('strong', {}, '等待内网访问确认'), element('p', {}, '确认后读取分享清单,不会立即导入。')),
|
|
2251
|
+
)
|
|
2252
|
+
privateConfirmation.replaceChildren(
|
|
2253
|
+
element('p', {}, `目标 ${error.origin} 解析到内网地址。确认后,DSH 服务端将访问此链接的分享接口;请仅允许你信任的来源。授权仅用于本次读取和导入,不会保存到白名单。`),
|
|
2254
|
+
actionButton('允许本次内网分享并读取', () => { confirmedPrivateUrl = requestedUrl; void inspect() }, 'small'),
|
|
2255
|
+
)
|
|
2256
|
+
privateConfirmation.hidden = false
|
|
2257
|
+
}
|
|
2237
2258
|
return false
|
|
2238
2259
|
} finally {
|
|
2239
2260
|
inspectButton.disabled = false
|
|
2261
|
+
urlField.input.disabled = false
|
|
2240
2262
|
inspectButton.removeAttribute('aria-busy')
|
|
2241
2263
|
inspectButton.textContent = '读取分享'
|
|
2242
2264
|
}
|
|
2243
2265
|
}
|
|
2244
2266
|
urlField.input.addEventListener('input', () => {
|
|
2267
|
+
confirmedPrivateUrl = ''
|
|
2268
|
+
privateConfirmation.hidden = true
|
|
2245
2269
|
if (urlField.input.value.trim() !== inspectedUrl) {
|
|
2246
2270
|
inspectedUrl = ''
|
|
2247
2271
|
preview.dataset.state = 'empty'
|
|
@@ -2265,7 +2289,7 @@ function openImportNoteShare() {
|
|
|
2265
2289
|
showFieldError('')
|
|
2266
2290
|
try {
|
|
2267
2291
|
const result = await api('notes/import-share', {
|
|
2268
|
-
method: 'POST', body: { url: requestedUrl, parentId: destination.input.value || null },
|
|
2292
|
+
method: 'POST', body: { url: requestedUrl, parentId: destination.input.value || null, confirmPrivateShare: confirmedPrivateUrl === requestedUrl },
|
|
2269
2293
|
})
|
|
2270
2294
|
state.notes.children.clear()
|
|
2271
2295
|
state.notes.loadedFolders.clear()
|
|
@@ -2747,8 +2771,7 @@ function noteInfoItem(label, value, title = '', key = '') {
|
|
|
2747
2771
|
}
|
|
2748
2772
|
|
|
2749
2773
|
function renderNoteIcon(node, large = false) {
|
|
2750
|
-
|
|
2751
|
-
return element('span', { class: `note-node-icon is-${node.kind}${large ? ' is-large' : ''}`, 'data-media-kind': noteMediaKind(node), 'aria-hidden': 'true' }, label)
|
|
2774
|
+
return element('span', { class: `note-node-icon ${node.kind === 'folder' ? 'tree-folder-icon' : 'tree-document-icon'}${large ? ' is-large' : ''}`, 'data-media-kind': noteMediaKind(node), 'aria-hidden': 'true' })
|
|
2752
2775
|
}
|
|
2753
2776
|
|
|
2754
2777
|
function noteKindLabel(node) {
|
|
@@ -3559,11 +3582,6 @@ function noteMediaKind(node) {
|
|
|
3559
3582
|
return 'file'
|
|
3560
3583
|
}
|
|
3561
3584
|
|
|
3562
|
-
function noteExtension(name) {
|
|
3563
|
-
const extension = name.includes('.') ? name.split('.').pop() : 'FILE'
|
|
3564
|
-
return extension.slice(0, 4).toLocaleUpperCase()
|
|
3565
|
-
}
|
|
3566
|
-
|
|
3567
3585
|
function shortNoteId(id) {
|
|
3568
3586
|
return `${id.slice(0, 11)}…${id.slice(-5)}`
|
|
3569
3587
|
}
|
package/web/styles.css
CHANGED
|
@@ -955,12 +955,8 @@ html,
|
|
|
955
955
|
.notes-search-row strong, .notes-search-row small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
956
956
|
.notes-search-row strong { font-size: 11px; }
|
|
957
957
|
.notes-search-row small { margin-top: 1px; color: var(--text-tertiary); font-size: 10px; }
|
|
958
|
-
.note-node-icon {
|
|
959
|
-
.note-node-icon.is-
|
|
960
|
-
.note-node-icon.is-folder::before { content: ""; position: absolute; top: -4px; left: 1px; width: 9px; height: 4px; border: 1px solid var(--border-strong); border-bottom: 0; border-radius: 3px 3px 0 0; background: inherit; }
|
|
961
|
-
.note-node-icon.is-document, .note-node-icon[data-media-kind="text"] { border-color: color-mix(in srgb, var(--accent) 30%, var(--border-strong)); color: var(--accent); }
|
|
962
|
-
.note-node-icon.is-large { width: 38px; height: 46px; border-radius: 6px; padding-bottom: 5px; font-size: 7px; }
|
|
963
|
-
.note-node-icon.is-folder.is-large { width: 44px; height: 32px; }
|
|
958
|
+
.note-node-icon.is-large { width: 38px; height: 42px; }
|
|
959
|
+
.note-node-icon.tree-folder-icon.is-large { width: 40px; height: 35px; }
|
|
964
960
|
.notes-content { min-width: 0; min-height: 0; overflow: auto; background: transparent; }
|
|
965
961
|
.notes-content-header { position: sticky; top: 0; z-index: 2; border-bottom: 1px solid var(--separator); padding: 11px 22px 13px; background: transparent; -webkit-backdrop-filter: none; backdrop-filter: none; }
|
|
966
962
|
.notes-breadcrumb { min-width: 0; display: flex; align-items: center; gap: 5px; overflow: hidden; color: var(--text-tertiary); font-size: 10px; }
|
|
@@ -1028,8 +1024,8 @@ html,
|
|
|
1028
1024
|
.share-import-preview strong, .share-import-preview p { display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1029
1025
|
.share-import-preview strong { color: var(--text); font-size: 12px; }
|
|
1030
1026
|
.share-import-preview p { margin: 4px 0 0; color: var(--text-tertiary); font-size: 10px; }
|
|
1031
|
-
.share-import-preview-mark {
|
|
1032
|
-
.share-import-preview-mark
|
|
1027
|
+
.share-import-preview-mark { display: grid; place-items: center; width: 42px; height: 42px; border: 1px solid var(--glass-border); border-radius: 12px; background: var(--surface-soft); color: var(--text-secondary); }
|
|
1028
|
+
.share-import-preview-mark > .interface-icon { width: 24px; height: 24px; }
|
|
1033
1029
|
.share-import-note { margin: -4px 0 0; border-left: 2px solid var(--border-strong); padding: 5px 0 5px 10px; color: var(--text-tertiary); font-size: 10px; line-height: 1.6; }
|
|
1034
1030
|
.dialog.share-import-dialog { width: min(560px, calc(100vw - 32px)); }
|
|
1035
1031
|
.notes-content.is-document, .notes-content.is-file { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; overflow: hidden; }
|
package/web/ui-primitives.js
CHANGED
|
@@ -54,6 +54,7 @@ export function interfaceIcon(name, className = 'interface-icon') {
|
|
|
54
54
|
outline: 'M8 6h11M8 12h11M8 18h11M4.5 6h.01M4.5 12h.01M4.5 18h.01',
|
|
55
55
|
history: 'M4 4v5h5M4.8 8.2A8 8 0 1 1 4 13M12 7.5V12l3 2',
|
|
56
56
|
download: 'M12 3v11M8 10l4 4 4-4M5 20h14',
|
|
57
|
+
'share-import': 'M13 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-2M13 3v5h5l-5-5M21 12H10m4-4-4 4 4 4',
|
|
57
58
|
link: 'M9.5 14.5l5-5M8.5 17H6a5 5 0 0 1 0-10h3M15.5 7H18a5 5 0 0 1 0 10h-3',
|
|
58
59
|
rename: 'M4 20l4.2-1 10.4-10.4a2.1 2.1 0 0 0-3-3L5.2 16zM14.5 6.5l3 3',
|
|
59
60
|
move: 'M3 7h6l2 2h10v11H3zM12 4h8m-3-3 3 3-3 3',
|