@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 CHANGED
@@ -1,6 +1,12 @@
1
1
  # dsh-ecolink-adapter
2
2
 
3
- v0.3.0 起提供指定全文读取、记忆侧栏与通用/非通用分类、网页完整成果保存。仅对 DSH `0.2.1-rc.2` 的公开宿主接口做过验证,`dsh.compatibility` 也只声明该版本。发布包需由仓库根目录的 `scripts/build-npm-pkgs.mjs` 生成镜像布局,不能直接把 adapter 子目录当作完整包。
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
- v0.3.0 起提供指定全文读取、记忆侧栏与通用/非通用分类、网页完整成果保存。仅对 DSH `0.2.1-rc.2` 的公开宿主接口做过验证,`dsh.compatibility` 也只声明该版本。发布包需由仓库根目录的 `scripts/build-npm-pkgs.mjs` 生成镜像布局,不能直接把 adapter 子目录当作完整包。
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、临时目录和虚构池下运行,不能用真实记忆测试:
@@ -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':'打开记忆池',style:control},'记忆池')
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
- const entries=()=>flattenPool(JSON.parse(readFile(expandHome(config.poolPath))))
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.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.1-rc.2",
39
+ "dsh": "0.2.2-rc.1",
39
40
  "dshReleases": {
40
- "0.2.1-rc.2": "compatible"
41
+ "0.2.2-rc.1": "compatible"
41
42
  }
42
43
  },
43
44
  "client": {
package/service/README.md CHANGED
@@ -1,4 +1,4 @@
1
- > **v0.3.0(2026-10-29)**:新增 `/memory/artifact` 完整成果存储(独立于短记忆,保留历史修订)、池条目的类型与时间排序、跨池分页读取。规则与限制见 [adapter/README.md](../adapter/README.md)。
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
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zoria-lind/dsh-ecolink-service",
3
- "version": "0.3.0",
3
+ "version": "1.0.0",
4
4
  "description": "dsh-ecolink 本地记忆服务:网页扩展与 DSH 共享记忆池的唯一写者(零依赖、127.0.0.1、token 鉴权)",
5
5
  "license": "MIT",
6
6
  "type": "module",