dsh-as-aistudio 0.2.5 → 0.2.6
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 +8 -6
- package/cordis.patch.yml +53 -15
- package/docs/INTEROP.md +34 -19
- package/package.json +7 -3
- package/src/client.js +366 -14
- package/src/components.js +35 -1
- package/src/index.js +116 -94
- package/src/shell.js +126 -0
- package/src/studio.js +115 -31
- package/src/vendor/dsh-edit-turn.js +269 -2
- package/src/vendor/dsh-rerun-turn.js +2 -2
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ AI Studio 的好用之处不在模型,在于一轮对话中的每一步都能
|
|
|
20
20
|
|
|
21
21
|
### 特性
|
|
22
22
|
|
|
23
|
-
- **一行搞定** —— 插件列表里只有 AI Studio 一行。四个组件是本包的 dependencies
|
|
23
|
+
- **一行搞定** —— 插件列表里只有 AI Studio 一行。四个组件是本包的 dependencies,由本包的四个补丁行 `dsh-as-aistudio/edit` 等挂载(详情页因此能列出这 4 个组件),不再各自占一行(和 @linxin666/dsh-web-all 同一个模式)。
|
|
24
24
|
- **组件仍是独立包** —— 每个都有自己的仓库与 cordis.patch.yml,单独安装照样工作;本包不复制任何组件逻辑:宿主半侧(路由、回滚、重放)就是组件自己,浏览器 factory 由 tools/vendor.mjs 从组件源码逐字剥离生成。
|
|
25
25
|
- **副本不会漂移** —— npm run vendor 重新生成内联包,npm run build 重新生成大 bundle,verify:vendor / verify:build 是只读校验;测试里 vendor-sync / build-sync 会在副本过期时失败。
|
|
26
26
|
- **一个挂了不影响其余** —— 四个 vendored factory 各自带 guard 挂载,一个抛错不会带走另外三个。
|
|
@@ -45,10 +45,11 @@ dsh plugin --profile web add dsh-as-aistudio
|
|
|
45
45
|
|
|
46
46
|
### 工作原理
|
|
47
47
|
|
|
48
|
-
-
|
|
48
|
+
- **四个组件行**(cordis.patch.yml + src/shell.js):每个组件一条 `dsh-as-aistudio/<后缀>` 行,行名经本包 `exports` 全部指向同一个壳文件,壳读行配置里的 `config.plugin` 并 `import` + `ctx.plugin` 挂真正的组件包 —— 组件的 loopback 路由与回滚/重放服务因此就位。缺哪个报哪个,绝不致命;宿主半侧自己一个组件都不挂(再挂一次就是挂两遍,路由必冲突)。
|
|
49
49
|
- **浏览器半侧**(src/client.js,由 tools/build.mjs 生成):单一大 bundle —— studio 自己的浏览器半侧 + 四个组件的 factory(各自 var module / var exports / const react,靠 var 提升共处一个 scope)。bundle 是按 Loader 行下发的,所以这是它们到达页面的唯一方式。
|
|
50
50
|
- **为什么宿主半侧不内联**:宿主代码对插件列表不可见,复制它只会凭空多出一份要维护的东西。
|
|
51
|
-
- **状态面板**:读 GET /api/dsh-as-aistudio/status,对每个组件报告 installed / hostMounted / version / ownRows(ownRows 大于 0 表示它还被独立安装着)。
|
|
51
|
+
- **状态面板**:读 GET /api/dsh-as-aistudio/status,对每个组件报告 installed / hostMounted / version / ownRows(ownRows 大于 0 表示它还被独立安装着)。hostMounted 不是自报,是从 Loader 读那一条行的 fiber 状态(只有 state === 2 才算活着),所以关掉的行、没装好的包、起失败的组件都会如实显示成因。
|
|
52
|
+
- **挂载门**:浏览器半侧挂载前先读一次这道状态,只画 hostMounted 为真的组件 —— 宿主没挂起来就没有路由,按钮画出来也点不动。宿主答不上来时按「未知」处理,四个都挂(保持旧行为)。
|
|
52
53
|
|
|
53
54
|
### 已知限制
|
|
54
55
|
|
|
@@ -76,7 +77,7 @@ What makes AI Studio pleasant is not the model: it is that every step of a turn
|
|
|
76
77
|
|
|
77
78
|
### Features
|
|
78
79
|
|
|
79
|
-
- **One row** — the plugin list shows only AI Studio. The four components are dependencies mounted by this package and no longer occupy rows of their own (the @linxin666/dsh-web-all pattern).
|
|
80
|
+
- **One row** — the plugin list shows only AI Studio. The four components are dependencies mounted by this package's four patch rows (`dsh-as-aistudio/edit` and friends, which is why the detail page can list all four) and no longer occupy rows of their own (the @linxin666/dsh-web-all pattern).
|
|
80
81
|
- **Components stay independent packages** — each keeps its own repo and its own cordis.patch.yml and works alone. This package copies no component logic: the host halves ARE the components, and the browser factories are lifted verbatim from their sources by tools/vendor.mjs.
|
|
81
82
|
- **The vendored copy cannot drift** — npm run vendor regenerates it, npm run build regenerates the bundle, and verify:vendor / verify:build are read-only gates; the test suite fails on a stale copy.
|
|
82
83
|
- **One failure does not take the rest** — each vendored factory mounts behind its own guard.
|
|
@@ -99,10 +100,11 @@ Use --profile desktop on the desktop app. The four components arrive as dependen
|
|
|
99
100
|
|
|
100
101
|
### How it works
|
|
101
102
|
|
|
102
|
-
- **
|
|
103
|
+
- **The four component rows** (cordis.patch.yml + src/shell.js): one row per component, named `dsh-as-aistudio/<suffix>`; every one of those names maps through this package's exports to the same shell, which reads `config.plugin` from the row and imports + applies the real component package — that is what puts its loopback routes and its rollback / replay services in place. A missing one is reported, never fatal. The host half itself mounts nothing: mounting here too would run every component twice and collide on its routes.
|
|
103
104
|
- **Browser half** (src/client.js, generated by tools/build.mjs): one bundle — the studio's own browser half plus the four component factories, each with its own var module / var exports / const react in one scope via hoisting. A bundle is served per Loader row, so this is the only way they can reach the page.
|
|
104
105
|
- **Why the host halves are not vendored**: host code is invisible to the plugin list, so copying it would only create a second thing to fix.
|
|
105
|
-
- **The panel** reads GET /api/dsh-as-aistudio/status and reports installed / hostMounted / version / ownRows per component (ownRows greater than 0 means it is also installed standalone).
|
|
106
|
+
- **The panel** reads GET /api/dsh-as-aistudio/status and reports installed / hostMounted / version / ownRows per component (ownRows greater than 0 means it is also installed standalone). hostMounted is not self-reported: it is read from the Loader row's fiber state (only state === 2 counts as live), so a disabled row, a missing package and a failed start each show their own reason.
|
|
107
|
+
- **The mount gate**: before mounting anything, the browser half reads that status once and draws only the components it calls mounted — a component whose host half is not up has no routes, so its buttons would do nothing. A host that cannot answer is treated as unknown and all four mount, which is the pre-gate behaviour.
|
|
106
108
|
|
|
107
109
|
### Known limitations
|
|
108
110
|
|
package/cordis.patch.yml
CHANGED
|
@@ -1,23 +1,61 @@
|
|
|
1
|
-
# dsh-as-aistudio bundle patch: the AI Studio composition, ONE row.
|
|
1
|
+
# dsh-as-aistudio bundle patch: the AI Studio composition, ONE row in the plugin list.
|
|
2
2
|
#
|
|
3
|
-
# Self-contained: the plugin list shows exactly this
|
|
4
|
-
# ordinary npm dependencies of this package (see package.json), not profile
|
|
3
|
+
# Self-contained: the plugin list shows exactly this package. The four components
|
|
4
|
+
# are ordinary npm dependencies of this package (see package.json), not profile
|
|
5
5
|
# bundles, so they have no rows of their own and never appear in that list.
|
|
6
6
|
#
|
|
7
|
-
#
|
|
8
|
-
# rollback / replay services) by importing the installed package, so host logic
|
|
9
|
-
# stays in the components and there is only one copy of it. The browser bundles
|
|
10
|
-
# travel inside this package (src/client.js) because a browser bundle is served
|
|
11
|
-
# per Loader row and the components have none.
|
|
7
|
+
# Five rows are inserted here, and they are what "包含的组件" lists:
|
|
12
8
|
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
9
|
+
# 1. this package's own row. Its name is the BARE package name on purpose: the
|
|
10
|
+
# client-module scanner treats an exact package specifier as a package and
|
|
11
|
+
# resolves <name>/package.json for the dsh.client declaration. That is the
|
|
12
|
+
# row the single browser bundle (src/client.js, which carries the studio's
|
|
13
|
+
# own half and all four vendored component factories) is served for.
|
|
16
14
|
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
15
|
+
# 2-5. one row per component, named <this package>/<suffix>. Every one of those
|
|
16
|
+
# names resolves through package.json exports to src/shell.js, and the shell
|
|
17
|
+
# mounts the component named in config.plugin. Two properties ride on that
|
|
18
|
+
# name, both load-bearing:
|
|
19
|
+
#
|
|
20
|
+
# * the plugin list is a deduplicated set of package identities, and a
|
|
21
|
+
# subpath of this package resolves to this package's identity - so the
|
|
22
|
+
# four extra rows cost exactly zero extra rows in that list;
|
|
23
|
+
# * the client-module scanner accepts only an exact package specifier, so a
|
|
24
|
+
# subpath row never becomes a second browser source. The components'
|
|
25
|
+
# browser halves keep travelling inside this package's bundle, and the
|
|
26
|
+
# scanner's negative verdict for these specifiers is what keeps the boot
|
|
27
|
+
# graph from growing a second entry per component.
|
|
28
|
+
#
|
|
29
|
+
# The component host halves (loopback routes, rollback / replay services) are not
|
|
30
|
+
# copied anywhere: each row imports the real package, so host logic stays in the
|
|
31
|
+
# components and there is exactly one copy of it. Each component also keeps its
|
|
32
|
+
# own cordis.patch.yml, so installing one standalone mounts it through its own
|
|
33
|
+
# row.
|
|
34
|
+
#
|
|
35
|
+
# A component that is not installed is not fatal: every row fails in isolation
|
|
36
|
+
# (the Loader reports the missing module and the other entries still start), and
|
|
37
|
+
# /api/dsh-as-aistudio/status reports hostMounted: false with the reason - which
|
|
38
|
+
# is also what keeps its buttons off the page.
|
|
21
39
|
- insert:
|
|
22
40
|
- id: dsh-as-aistudio
|
|
23
41
|
name: 'dsh-as-aistudio'
|
|
42
|
+
- insert:
|
|
43
|
+
- id: dsh-as-aistudio-edit
|
|
44
|
+
name: 'dsh-as-aistudio/edit'
|
|
45
|
+
config:
|
|
46
|
+
plugin: 'dsh-edit-turn'
|
|
47
|
+
- insert:
|
|
48
|
+
- id: dsh-as-aistudio-rerun
|
|
49
|
+
name: 'dsh-as-aistudio/rerun'
|
|
50
|
+
config:
|
|
51
|
+
plugin: 'dsh-rerun-turn'
|
|
52
|
+
- insert:
|
|
53
|
+
- id: dsh-as-aistudio-delete
|
|
54
|
+
name: 'dsh-as-aistudio/delete'
|
|
55
|
+
config:
|
|
56
|
+
plugin: 'dsh-delete-turn'
|
|
57
|
+
- insert:
|
|
58
|
+
- id: dsh-as-aistudio-markdown
|
|
59
|
+
name: 'dsh-as-aistudio/markdown'
|
|
60
|
+
config:
|
|
61
|
+
plugin: 'dsh-markdown-bubble'
|
package/docs/INTEROP.md
CHANGED
|
@@ -181,35 +181,50 @@ function foreignHideOn(row, own) {
|
|
|
181
181
|
`node --test test/contract.test.js`;把探测状态的 400 改成 404 会让 2 例转红,给 `/apply` 加一个必填
|
|
182
182
|
`confirmToken` 会让 5 例转红 —— 破坏契约会在本地就暴露,而不是等用户发现按钮点不动。
|
|
183
183
|
|
|
184
|
-
## 11. 自包含架构(2026-10-02
|
|
184
|
+
## 11. 自包含架构(2026-10-02 重写,2026-10-04 改为四条目行)
|
|
185
185
|
|
|
186
|
-
用户要求「插件列表里只有 AI Studio
|
|
187
|
-
!entry.options.group && !entry.disabled && entry.fiber
|
|
188
|
-
(@deepseek-ai/dsh-plugin-package-inventory-deepseek/lib/index.js:100
|
|
189
|
-
|
|
186
|
+
用户要求「插件列表里只有 AI Studio 一行」。平台的清单服务(同一份 dsh_plugin_packages 也喂给模型)
|
|
187
|
+
收的是**包身份集合**:先按 !entry.options.group && !entry.disabled && entry.fiber?.state === 2 取活跃行
|
|
188
|
+
(@deepseek-ai/dsh-plugin-package-inventory-deepseek/lib/index.js:100),每条行经 barePackageName() 解析
|
|
189
|
+
回它所属的包,再按 name + version 去重。于是有两条硬约束:
|
|
190
190
|
|
|
191
|
-
|
|
191
|
+
1. **行名不能是组件自己的包名**,否则那个包成为新的身份,列表立刻多一行;
|
|
192
|
+
2. **行名必须是本包的子路径**:barePackageName('dsh-as-aistudio/edit') === 'dsh-as-aistudio',
|
|
193
|
+
解析回本包、与自己的行去重 —— 四条组件行因此不占列表行(@linxin666/dsh-web-all 同款:
|
|
194
|
+
它 19 条声明只占 1 行)。
|
|
195
|
+
|
|
196
|
+
而详情页的「包含的组件」读的是另一件事:bundle 的 patch 里 insert 的每一行
|
|
197
|
+
(@deepseek-ai/dsh-plugin-manager/lib/index.js:1864 declaredRows)。要让四个组件在那里出现,
|
|
198
|
+
它们就必须真的是本包 patch 里的行 —— 这正是 2026-10-04 的改动:宿主半侧的运行时 ctx.plugin
|
|
199
|
+
换成四条补丁行,行名是子路径、真正的包名写在 config.plugin 里,由 src/shell.js 挂载。
|
|
192
200
|
|
|
193
201
|
| 部件 | 位置 | 说明 |
|
|
194
202
|
| --- | --- | --- |
|
|
195
|
-
| patch | cordis.patch.yml |
|
|
203
|
+
| patch | cordis.patch.yml | 插 5 行:本包自己(裸包名,带 ./client)加四条 dsh-as-aistudio/<后缀> |
|
|
196
204
|
| 组件身份 | package.json dependencies | 普通依赖,不是 profile bundle |
|
|
197
|
-
| 宿主半侧 | src/
|
|
198
|
-
| 浏览器半侧 | src/client.js | 单一大 bundle
|
|
205
|
+
| 宿主半侧 | src/shell.js | 组件行读 config.plugin,await import 后 ctx.plugin(等价于组件自己的行) |
|
|
206
|
+
| 浏览器半侧 | src/client.js | 单一大 bundle(生成物),只由本包那一行下发 |
|
|
199
207
|
| 内联来源 | src/vendor/*.js | tools/vendor.mjs 从组件源码逐字剥离 factory |
|
|
200
208
|
| 缝合器 | tools/build.mjs | studio 加四个 factory 合成一个 bundle |
|
|
209
|
+
| 状态 | src/index.js | /api/dsh-as-aistudio/status:hostMounted 从 Loader 行 fiber 状态读 |
|
|
210
|
+
|
|
211
|
+
三条设计红线:
|
|
201
212
|
|
|
202
|
-
|
|
213
|
+
1. 宿主半侧不内联。宿主代码对列表不可见,复制它只会多出一份要维护的东西;组件行导入真正的包,
|
|
214
|
+
组件的路由、回滚、重放逻辑仍是唯一正本。
|
|
215
|
+
2. 宿主半侧也不许自己挂。四个组件已由四条行挂载,host 再 ctx.plugin 一次就是同进程挂两遍,
|
|
216
|
+
路由必冲突;host 只回答状态。
|
|
217
|
+
3. 浏览器半侧必须内联。bundle 是按 Loader 行下发的(/plugins/<行id>/client.js),且只有精确包说明符
|
|
218
|
+
会被客户端模块扫描器收进 boot graph —— 四条子路径行被跳过,组件也不会各自多出一份浏览器源。
|
|
203
219
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
2. 浏览器半侧必须内联。bundle 是按 Loader 行下发的(/plugins/<行id>/client.js),
|
|
207
|
-
组件没有行就没有 bundle。
|
|
220
|
+
状态与界面:hostMounted 只在行 fiber 的 state === 2 时为真(关掉的行、缺包、起失败各有自己的 reason);
|
|
221
|
+
浏览器半侧挂载前先读一次这道状态,只画 hostMounted 为真的组件,宿主答不上来时按「未知」全挂。
|
|
208
222
|
|
|
209
|
-
防漂移:副本由工具生成、带 sha256 戳,
|
|
210
|
-
|
|
223
|
+
防漂移:副本由工具生成、带 sha256 戳,node tools/vendor.mjs --check / node tools/build.mjs --check
|
|
224
|
+
只读校验,测试在副本与组件源不一致时失败。手工编辑 src/vendor/* 或 src/client.js 是禁止的。
|
|
211
225
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
226
|
+
实测(2026-10-02 旧行结构,隔离实例只装本包 tarball):composed 184 行里组件行 0;
|
|
227
|
+
GET /dsh-rerun-turn/state 返回 400(edit-turn 的挂载探测契约未破);boot graph 66 条里组件条目 0;
|
|
228
|
+
served bundle 200 且含四个 factory。换成四条行之后,同一套门禁要补一条:四条行 fiber 必须 active,
|
|
229
|
+
/api/dsh-as-aistudio/status 才会给出 hostMounted 4/4。
|
|
215
230
|
|
package/package.json
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-as-aistudio",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "Google-AI-Studio-style turn controls for DeepSeek Harness, in one install: edit a prompt and re-run it, re-run a reply in place, delete a turn from the model context, and render sent prompts as Markdown. Self-contained: the plugin list shows this one row; the four components are dependencies mounted by it. Each still installs alone and works alone.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": "./src/index.js",
|
|
9
9
|
"./client": "./src/client.js",
|
|
10
|
+
"./edit": "./src/shell.js",
|
|
11
|
+
"./rerun": "./src/shell.js",
|
|
12
|
+
"./delete": "./src/shell.js",
|
|
13
|
+
"./markdown": "./src/shell.js",
|
|
10
14
|
"./package.json": "./package.json"
|
|
11
15
|
},
|
|
12
16
|
"files": [
|
|
@@ -49,9 +53,9 @@
|
|
|
49
53
|
},
|
|
50
54
|
"dependencies": {
|
|
51
55
|
"dsh-delete-turn": "^0.1.8",
|
|
52
|
-
"dsh-edit-turn": "^0.2.
|
|
56
|
+
"dsh-edit-turn": "^0.2.17",
|
|
53
57
|
"dsh-markdown-bubble": "^0.1.4",
|
|
54
|
-
"dsh-rerun-turn": "^0.1.
|
|
58
|
+
"dsh-rerun-turn": "^0.1.25"
|
|
55
59
|
},
|
|
56
60
|
"dsh": {
|
|
57
61
|
"bundle": {
|