@zoria-lind/dsh-ecolink-adapter 0.3.0 → 1.0.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.
- package/README.md +11 -1
- package/adapter/README.md +11 -1
- package/adapter/src/client.js +111 -2
- package/adapter/src/modules/memoryReader.js +7 -1
- package/package.json +5 -4
- package/service/README.md +1 -1
- package/service/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# dsh-ecolink-adapter
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
v1.0.0 起提供指定全文读取、记忆侧栏与通用/非通用分类、网页完整成果保存,并配套可选的桌面宿主补丁(同窗 DeepSeek 网页、划选入池、缩放、带入草稿)。核心接口自 1.0.0 起冻结:新增功能走 1.x,破坏性改动走 2.0.0;桌面宿主补丁是实验性本地补丁,不属于 npm 契约。仅在 DSH `0.2.2-rc.1` 实测,`engines.dsh` 与 `dsh.compatibility` 都只声明该版本。发布包需由仓库根目录的 `scripts/build-npm-pkgs.mjs` 生成镜像布局,不能直接把 adapter 子目录当作完整包。
|
|
4
|
+
|
|
5
|
+
## 安装与包关系
|
|
6
|
+
|
|
7
|
+
- DSH 用户只装 `@zoria-lind/dsh-ecolink-adapter` 即可;npm 包里自带 `service/`,适配层会自动拉起本地服务,不需要再装 `@zoria-lind/dsh-ecolink-service`。
|
|
8
|
+
- `@zoria-lind/dsh-ecolink-service` 是可选独立形态:不装 DSH、只用浏览器扩展,或需要登录自启时单独安装。
|
|
9
|
+
- 浏览器扩展不是 DSH 内置网页的前置条件;只有普通浏览器、网页端自动注入或 popup 功能才需要它。
|
|
4
10
|
|
|
5
11
|
## 指定读取
|
|
6
12
|
|
|
@@ -30,6 +36,10 @@ v0.3.0 起提供指定全文读取、记忆侧栏与通用/非通用分类、网
|
|
|
30
36
|
|
|
31
37
|
保存保留空白、Markdown、代码和标签字面量,正文上限1.5MB;目录摘要和自动短记忆独立。完整成果默认非通用且不参与自动短记忆筛选或压缩。同名保存须确认并校验旧版本;服务保留历史全文,当前面板读取最新版本,暂未提供旧版本浏览界面。断网/失败不会报成功或清空编辑框;同一内容重试采用相同请求 ID 防重复。关闭页面前未保存的编辑内容需要自行保留。
|
|
32
38
|
|
|
39
|
+
## 桌面宿主补丁
|
|
40
|
+
|
|
41
|
+
同窗 DeepSeek 网页、页内划选入池、缩放与“带入草稿”由仓库 `desktop/` 提供:需要管理员替换桌面安装的 `app.asar`,基线 DSH `0.2.2-rc.1`,实验性,DSH 升级后需重建。它不属于 npm 包和 1.0.0 稳定契约,详见 [desktop/README.md](../desktop/README.md)。
|
|
42
|
+
|
|
33
43
|
## 验收
|
|
34
44
|
|
|
35
45
|
所有命令必须在隔离 HOME、临时目录和虚构池下运行,不能用真实记忆测试:
|
package/adapter/README.md
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# dsh-ecolink-adapter
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
v1.0.0 起提供指定全文读取、记忆侧栏与通用/非通用分类、网页完整成果保存,并配套可选的桌面宿主补丁(同窗 DeepSeek 网页、划选入池、缩放、带入草稿)。核心接口自 1.0.0 起冻结:新增功能走 1.x,破坏性改动走 2.0.0;桌面宿主补丁是实验性本地补丁,不属于 npm 契约。仅在 DSH `0.2.2-rc.1` 实测,`engines.dsh` 与 `dsh.compatibility` 都只声明该版本。发布包需由仓库根目录的 `scripts/build-npm-pkgs.mjs` 生成镜像布局,不能直接把 adapter 子目录当作完整包。
|
|
4
|
+
|
|
5
|
+
## 安装与包关系
|
|
6
|
+
|
|
7
|
+
- DSH 用户只装 `@zoria-lind/dsh-ecolink-adapter` 即可;npm 包里自带 `service/`,适配层会自动拉起本地服务,不需要再装 `@zoria-lind/dsh-ecolink-service`。
|
|
8
|
+
- `@zoria-lind/dsh-ecolink-service` 是可选独立形态:不装 DSH、只用浏览器扩展,或需要登录自启时单独安装。
|
|
9
|
+
- 浏览器扩展不是 DSH 内置网页的前置条件;只有普通浏览器、网页端自动注入或 popup 功能才需要它。
|
|
4
10
|
|
|
5
11
|
## 指定读取
|
|
6
12
|
|
|
@@ -30,6 +36,10 @@ v0.3.0 起提供指定全文读取、记忆侧栏与通用/非通用分类、网
|
|
|
30
36
|
|
|
31
37
|
保存保留空白、Markdown、代码和标签字面量,正文上限1.5MB;目录摘要和自动短记忆独立。完整成果默认非通用且不参与自动短记忆筛选或压缩。同名保存须确认并校验旧版本;服务保留历史全文,当前面板读取最新版本,暂未提供旧版本浏览界面。断网/失败不会报成功或清空编辑框;同一内容重试采用相同请求 ID 防重复。关闭页面前未保存的编辑内容需要自行保留。
|
|
32
38
|
|
|
39
|
+
## 桌面宿主补丁
|
|
40
|
+
|
|
41
|
+
同窗 DeepSeek 网页、页内划选入池、缩放与“带入草稿”由仓库 `desktop/` 提供:需要管理员替换桌面安装的 `app.asar`,基线 DSH `0.2.2-rc.1`,实验性,DSH 升级后需重建。它不属于 npm 包和 1.0.0 稳定契约,详见 [desktop/README.md](../desktop/README.md)。
|
|
42
|
+
|
|
33
43
|
## 验收
|
|
34
44
|
|
|
35
45
|
所有命令必须在隔离 HOME、临时目录和虚构池下运行,不能用真实记忆测试:
|
package/adapter/src/client.js
CHANGED
|
@@ -2,6 +2,49 @@ window.__ModuleLoader__.load({id:'@zoria-lind/dsh-ecolink-adapter',factory:requi
|
|
|
2
2
|
const React=require('react'), h=React.createElement
|
|
3
3
|
const KIND='ecolink-memory', PAGE=1500
|
|
4
4
|
const control={color:'inherit',background:'var(--dsw-alias-bg-layer-2, transparent)',border:'1px solid var(--dsw-alias-border-l2, #8886)',borderRadius:6,padding:'5px 8px'}
|
|
5
|
+
const HEADER_BUTTON_CSS = `
|
|
6
|
+
.ecolink-header-button {
|
|
7
|
+
display: inline-flex;
|
|
8
|
+
flex: none;
|
|
9
|
+
align-items: center;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
height: 28px;
|
|
12
|
+
padding: 0 8px;
|
|
13
|
+
border: 0;
|
|
14
|
+
border-radius: 6px;
|
|
15
|
+
background: transparent;
|
|
16
|
+
color: var(--dsw-alias-label-secondary, inherit);
|
|
17
|
+
font: inherit;
|
|
18
|
+
font-size: 12px;
|
|
19
|
+
white-space: nowrap;
|
|
20
|
+
cursor: pointer;
|
|
21
|
+
}
|
|
22
|
+
.ecolink-header-button:hover,
|
|
23
|
+
.ecolink-header-button:focus-visible {
|
|
24
|
+
background: var(--dsw-alias-interactive-bg-hover, #8882);
|
|
25
|
+
color: var(--dsw-alias-label-primary, inherit);
|
|
26
|
+
}
|
|
27
|
+
.ecolink-header-button:focus-visible {
|
|
28
|
+
outline: 2px solid var(--dsw-alias-brand-primary, currentColor);
|
|
29
|
+
outline-offset: 2px;
|
|
30
|
+
}
|
|
31
|
+
.ecolink-switch {
|
|
32
|
+
position: fixed;
|
|
33
|
+
inset: 6px auto auto 152px;
|
|
34
|
+
z-index: 1800;
|
|
35
|
+
-webkit-app-region: no-drag;
|
|
36
|
+
app-region: no-drag;
|
|
37
|
+
}
|
|
38
|
+
.ecolink-web-surface {
|
|
39
|
+
position: fixed;
|
|
40
|
+
inset: 40px 0 0;
|
|
41
|
+
z-index: 1799;
|
|
42
|
+
background: var(--dsw-alias-bg-layer-1, Canvas);
|
|
43
|
+
}
|
|
44
|
+
.ecolink-web-surface[hidden] { display: none; }
|
|
45
|
+
.ecolink-web-guest, .ecolink-web-guest webview { width: 100%; height: 100%; }
|
|
46
|
+
.ecolink-web-error { position: absolute; top: 8px; left: 20px; }
|
|
47
|
+
`
|
|
5
48
|
async function api(args,method='GET',signal) {
|
|
6
49
|
const path='api/ecolink'
|
|
7
50
|
const response=await fetch(method==='GET'?`${path}?${new URLSearchParams(args)}`:path,
|
|
@@ -12,7 +55,7 @@ window.__ModuleLoader__.load({id:'@zoria-lind/dsh-ecolink-adapter',factory:requi
|
|
|
12
55
|
const date=new Date(value)
|
|
13
56
|
return value && Number.isFinite(date.getTime())?date.toLocaleString('zh-CN',{hour12:false}):'时间未知'
|
|
14
57
|
}
|
|
15
|
-
function Panel({sessionId}) {
|
|
58
|
+
function Panel({sessionId,inputActions}) {
|
|
16
59
|
const [q,setQ]=React.useState(''),[page,setPage]=React.useState(null),[selected,setSelected]=React.useState(null),
|
|
17
60
|
[read,setRead]=React.useState(null),[state,setState]=React.useState(null),[message,setMessage]=React.useState(''),[busy,setBusy]=React.useState(false),
|
|
18
61
|
[loading,setLoading]=React.useState(false),[offset,setOffset]=React.useState(0),[policy,setPolicy]=React.useState('all')
|
|
@@ -66,6 +109,11 @@ window.__ModuleLoader__.load({id:'@zoria-lind/dsh-ecolink-adapter',factory:requi
|
|
|
66
109
|
}catch(e){if(active.current===target)setMessage(e.message)}finally{if(active.current===target)setBusy(false)}
|
|
67
110
|
}
|
|
68
111
|
const button=(text,onClick,disabled=false)=>h('button',{type:'button',onClick,disabled:busy||disabled,style:{...control,margin:'3px'}},text)
|
|
112
|
+
const insertDraft=()=>{
|
|
113
|
+
if(!read?.complete||active.current!==selected?.sessionId||!inputActions?.captureInsertion)return
|
|
114
|
+
const ok=inputActions.insertText(read.content,inputActions.captureInsertion())
|
|
115
|
+
setMessage(ok?'已带入当前对话草稿。':'当前草稿暂时无法编辑,请稍后重试。')
|
|
116
|
+
}
|
|
69
117
|
const refresh=()=>{clearPreview();setMessage('');list()}
|
|
70
118
|
const filter=value=>{setPolicy(value);clearPreview();setMessage('');setPage(null);list(0,undefined,value)}
|
|
71
119
|
const detail=()=>h('section',{'aria-label':'记忆完整正文','aria-busy':busy,style:{padding:'8px 0'}},
|
|
@@ -76,6 +124,7 @@ window.__ModuleLoader__.load({id:'@zoria-lind/dsh-ecolink-adapter',factory:requi
|
|
|
76
124
|
...(state?.items??[]).filter(i=>i.ref===selected?.ref&&i.version===selected?.version).map(i=>h('p',{key:i.token,role:'status'},i.status==='admitted'?'这条记忆已进入当前对话上下文':`这条记忆已排队${i.partial?'(所选分段)':''},下次发送时注入当前对话`)),
|
|
77
125
|
read?.complete&&h('div',null,
|
|
78
126
|
button('注入全文',()=>mutate('inject'),!sessionId),
|
|
127
|
+
window.dshDesktop?.browser?.acquireEcolink&&inputActions?.insertText&&button('带入草稿',insertDraft,!sessionId),
|
|
79
128
|
button(selected.injectionPolicy==='universal'?'改为非通用':'改为通用',()=>mutate('policy')),
|
|
80
129
|
read.totalChars>PAGE&&h('details',null,h('summary',null,'长文分段注入'),
|
|
81
130
|
h('p',null,`当前段 ${offset+1}–${Math.min(offset+PAGE,read.totalChars)} / ${read.totalChars} 字`),
|
|
@@ -102,10 +151,70 @@ window.__ModuleLoader__.load({id:'@zoria-lind/dsh-ecolink-adapter',factory:requi
|
|
|
102
151
|
state&&h('div',null,state.notice,state.omitted>0&&h('p',null,`开局超预算未注入 ${state.omitted} 条`),
|
|
103
152
|
...state.items.map(i=>h('div',{key:i.token},`${i.status==='admitted'?'已进入上下文':'待注入'}${i.partial?'(部分正文)':''} · ${i.ref}`))))
|
|
104
153
|
}
|
|
154
|
+
function DeepSeekSwitch() {
|
|
155
|
+
const bridge=window.dshDesktop?.browser
|
|
156
|
+
const [shown,setShown]=React.useState(false),[started,setStarted]=React.useState(false)
|
|
157
|
+
const [error,setError]=React.useState('')
|
|
158
|
+
const host=React.useRef(null)
|
|
159
|
+
React.useEffect(()=>{
|
|
160
|
+
if(!started||!bridge?.acquireEcolink)return
|
|
161
|
+
let disposed=false,lease,guest
|
|
162
|
+
const target=host.current
|
|
163
|
+
const failure=()=>{if(!disposed)setError('DeepSeek 网页加载失败。可切回 Harness 后重新打开应用再试。')}
|
|
164
|
+
async function mount(){
|
|
165
|
+
const reservation=await bridge.acquireEcolink()
|
|
166
|
+
lease=reservation.lease
|
|
167
|
+
if(disposed){await bridge.release(lease);return}
|
|
168
|
+
guest=document.createElement('webview')
|
|
169
|
+
guest.dataset.sidebarBrowserFrame='webview'
|
|
170
|
+
guest.setAttribute('aria-label','DeepSeek 网页')
|
|
171
|
+
guest.setAttribute('name',lease)
|
|
172
|
+
guest.setAttribute('partition',reservation.partition)
|
|
173
|
+
guest.setAttribute('src','about:blank#'+lease)
|
|
174
|
+
guest.addEventListener('dom-ready',()=>{
|
|
175
|
+
if(!disposed)guest.loadURL('https://chat.deepseek.com/').catch(failure)
|
|
176
|
+
},{once:true})
|
|
177
|
+
guest.addEventListener('did-fail-load',event=>{
|
|
178
|
+
if(event.isMainFrame&&event.errorCode!==-3)failure()
|
|
179
|
+
})
|
|
180
|
+
guest.addEventListener('did-finish-load',()=>{
|
|
181
|
+
if(!disposed)setError('')
|
|
182
|
+
})
|
|
183
|
+
target.append(guest)
|
|
184
|
+
}
|
|
185
|
+
mount().catch(failure)
|
|
186
|
+
return ()=>{
|
|
187
|
+
disposed=true
|
|
188
|
+
guest?.remove()
|
|
189
|
+
if(lease)bridge.release(lease).catch(()=>{})
|
|
190
|
+
}
|
|
191
|
+
},[started,bridge])
|
|
192
|
+
if(!bridge?.acquireEcolink)return null
|
|
193
|
+
const toggle=()=>{
|
|
194
|
+
if(!started)setStarted(true)
|
|
195
|
+
setShown(!shown)
|
|
196
|
+
}
|
|
197
|
+
return h(React.Fragment,null,
|
|
198
|
+
h('button',{type:'button',className:'ecolink-header-button ecolink-switch','aria-pressed':shown,
|
|
199
|
+
title:shown?'返回当前 Harness 对话':'在当前窗口打开 DeepSeek 网页',onClick:toggle},
|
|
200
|
+
shown?'返回 Harness':'DeepSeek 网页'),
|
|
201
|
+
started&&h('section',{className:'ecolink-web-surface',hidden:!shown,'aria-label':'内嵌 DeepSeek 网页'},
|
|
202
|
+
h('div',{ref:host,className:'ecolink-web-guest'}),
|
|
203
|
+
error&&h('p',{className:'ecolink-web-error',role:'alert'},error)))
|
|
204
|
+
}
|
|
105
205
|
function OpenMemory({openMemory}) {
|
|
106
|
-
return h('button',{type:'button',onClick:openMemory,title:'浏览完整记忆并注入当前对话','aria-label':'打开记忆池',
|
|
206
|
+
return h('button',{type:'button',onClick:openMemory,title:'浏览完整记忆并注入当前对话','aria-label':'打开记忆池',className:'ecolink-header-button'},'记忆池')
|
|
107
207
|
}
|
|
108
208
|
return {inject:['slots','sidebarRightTabs','sidebarRight'],apply(ctx){
|
|
209
|
+
ctx.effect(()=>{
|
|
210
|
+
const style=document.createElement('style')
|
|
211
|
+
style.textContent=HEADER_BUTTON_CSS
|
|
212
|
+
document.head.appendChild(style)
|
|
213
|
+
return ()=>style.remove()
|
|
214
|
+
})
|
|
215
|
+
if(window.dshDesktop?.browser?.acquireEcolink)ctx.effect(()=>ctx.slots.inject('shell.overlay',()=>ctx.slots.register({
|
|
216
|
+
name:'shell.overlay',id:'ecolink-deepseek-switch'
|
|
217
|
+
},DeepSeekSwitch)))
|
|
109
218
|
ctx.effect(()=>ctx.sidebarRightTabs.register({id:KIND,kind:KIND,title:()=> '记忆池',
|
|
110
219
|
guide:[{id:'ecolink',order:50,title:()=> '记忆池',description:()=> '浏览完整正文并注入当前对话'}]}))
|
|
111
220
|
ctx.effect(()=>ctx.slots.inject('sidebar.right.pane.tab',()=>ctx.slots.register({name:'sidebar.right.pane.tab',key:KIND},Panel)))
|
|
@@ -37,7 +37,13 @@ function integer(value, fallback, max) {
|
|
|
37
37
|
}
|
|
38
38
|
export function createMemoryReader(config, deps={}) {
|
|
39
39
|
const readFile=deps.readFile ?? (p=>readFileSync(p,'utf8'))
|
|
40
|
-
|
|
40
|
+
function entries() {
|
|
41
|
+
try { return flattenPool(JSON.parse(readFile(expandHome(config.poolPath)))) }
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (error?.code === 'ENOENT') return []
|
|
44
|
+
throw error
|
|
45
|
+
}
|
|
46
|
+
}
|
|
41
47
|
function select(args={}) {
|
|
42
48
|
let all=entries()
|
|
43
49
|
if (args.pool) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zoria-lind/dsh-ecolink-adapter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "DSH 跨端记忆:指定全文读取、侧栏浏览与注入、通用/非通用分类",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
"!service/fix-pool.mjs"
|
|
25
25
|
],
|
|
26
26
|
"engines": {
|
|
27
|
-
"node": ">=18.0.0"
|
|
27
|
+
"node": ">=18.0.0",
|
|
28
|
+
"dsh": "0.2.2-rc.1"
|
|
28
29
|
},
|
|
29
30
|
"repository": {
|
|
30
31
|
"type": "git",
|
|
@@ -35,9 +36,9 @@
|
|
|
35
36
|
"patch": "./adapter/cordis.patch.yml"
|
|
36
37
|
},
|
|
37
38
|
"compatibility": {
|
|
38
|
-
"dsh": "0.2.
|
|
39
|
+
"dsh": "0.2.2-rc.1",
|
|
39
40
|
"dshReleases": {
|
|
40
|
-
"0.2.
|
|
41
|
+
"0.2.2-rc.1": "compatible"
|
|
41
42
|
}
|
|
42
43
|
},
|
|
43
44
|
"client": {
|
package/service/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
> **
|
|
1
|
+
> **v1.0.0(2026-11-06)**:本版 service 无功能变化;1.0.0 的核心是把 adapter、扩展与桌面补丁的接口冻结。`/memory/artifact`(完整成果、历史修订)、池条目类型/时间排序、跨池分页读取沿用 0.3.0。规则与限制见 [adapter/README.md](../adapter/README.md)。
|
|
2
2
|
|
|
3
3
|
# dsh-ecolink-service
|
|
4
4
|
|