@dsh-workbench/core 0.2.6 → 0.2.8
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 -9
- package/bin/dsh-workbench +42 -4
- package/client.js +252 -36
- package/dist/client/client.body.js +252 -36
- package/dist/client/index.js +252 -36
- package/dist/host/index.js +1054 -737
- package/dist/types/app/client.d.ts +21 -15
- package/dist/types/app/layouts/rightbar/__tests__/market-order.test.d.ts +1 -0
- package/dist/types/app/layouts/rightbar/__tests__/market-running-display.test.d.ts +1 -0
- package/dist/types/app/layouts/rightbar/__tests__/market-workbench-act.test.d.ts +1 -0
- package/dist/types/app/layouts/rightbar/market-act.d.ts +2 -1
- package/dist/types/app/layouts/rightbar/market-rows.d.ts +3 -0
- package/dist/types/app/layouts/rightbar/market-settle-hold.d.ts +13 -0
- package/dist/types/app/layouts/rightbar/market-settle.d.ts +22 -0
- package/dist/types/app/layouts/rightbar/market-transient-state.d.ts +22 -0
- package/dist/types/app/layouts/rightbar/market-view-text.d.ts +26 -1
- package/dist/types/modules/panels/__tests__/market-tools-harness.d.ts +3 -0
- package/dist/types/modules/panels/model/market-workbench-update.d.ts +19 -0
- package/dist/types/modules/panels/model/market.d.ts +4 -0
- package/dist/types/shared/api/bundle-install.d.ts +1 -0
- package/dist/types/shared/api/config-sync.d.ts +0 -2
- package/dist/types/shared/api/host/__tests__/post-channels.test.d.ts +1 -0
- package/dist/types/shared/api/host/__tests__/self-update.test.d.ts +1 -0
- package/dist/types/shared/api/host/bundle-manager.d.ts +1 -0
- package/dist/types/shared/api/host/bundle-routes.d.ts +1 -1
- package/dist/types/shared/api/host/config-sync.d.ts +2 -2
- package/dist/types/shared/api/host/post-channels.d.ts +18 -0
- package/dist/types/shared/api/host/self-update.d.ts +45 -0
- package/docs/HANDOFF.md +12 -5
- package/docs/OPERATIONS.md +35 -4
- package/package.json +4 -4
- package/scripts/seed-profile.sh +61 -1
|
@@ -22,13 +22,11 @@ export interface ConfigSyncSnapshot {
|
|
|
22
22
|
readonly profiles: readonly ConfigSyncProfile[];
|
|
23
23
|
readonly rows: readonly ConfigSyncRow[];
|
|
24
24
|
readonly emptyProviders: boolean;
|
|
25
|
-
readonly restart: true;
|
|
26
25
|
readonly reason?: string;
|
|
27
26
|
}
|
|
28
27
|
export interface ConfigSyncApplied {
|
|
29
28
|
readonly written: readonly string[];
|
|
30
29
|
readonly skipped: readonly string[];
|
|
31
|
-
readonly restart: true;
|
|
32
30
|
}
|
|
33
31
|
export interface ConfigSyncRequest {
|
|
34
32
|
readonly source: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -5,6 +5,7 @@ export interface BundleManager {
|
|
|
5
5
|
inspect(spec: string, registry?: BundleRegistry): Promise<BundleInspection | null>;
|
|
6
6
|
install(request: BundleInstallRequest): Promise<BundleChange | null>;
|
|
7
7
|
remove(name: string): Promise<BundleChange | null>;
|
|
8
|
+
setEnabled?(name: string, enabled: boolean): Promise<BundleChange | null>;
|
|
8
9
|
cancel(requestId: string): Promise<BundleCancellation | null>;
|
|
9
10
|
}
|
|
10
11
|
export declare function readBundleManager(ctx: DshHostContext): BundleManager | undefined;
|
|
@@ -3,5 +3,5 @@ import { type RouteHandler } from '@dsh-workbench/shared/host';
|
|
|
3
3
|
export declare function bundleRegistriesHandler(ctx: DshHostContext): RouteHandler;
|
|
4
4
|
export declare function resetRefusalLog(): void;
|
|
5
5
|
export declare function resetHoldLog(): void;
|
|
6
|
-
export declare function moduleVersionsHandler(ctx: DshHostContext, shell: DshShell | undefined): RouteHandler;
|
|
6
|
+
export declare function moduleVersionsHandler(ctx: DshHostContext, shell: DshShell | undefined, running?: string | undefined): RouteHandler;
|
|
7
7
|
export declare function bundleInspectHandler(ctx: DshHostContext): RouteHandler;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RouteHandler } from '@dsh-workbench/shared/host';
|
|
1
|
+
import type { PostResource, RouteHandler } from '@dsh-workbench/shared/host';
|
|
2
2
|
import type { ConfigSyncRow, ConfigSyncSnapshot } from '../config-sync.js';
|
|
3
3
|
export interface PatchBlock {
|
|
4
4
|
readonly key: string;
|
|
@@ -39,8 +39,8 @@ export declare function configSyncApply(deps: ConfigSyncDeps, payload: unknown):
|
|
|
39
39
|
ok: true;
|
|
40
40
|
written: string[];
|
|
41
41
|
skipped: string[];
|
|
42
|
-
restart: true;
|
|
43
42
|
} | {
|
|
44
43
|
ok: false;
|
|
45
44
|
text: string;
|
|
46
45
|
};
|
|
46
|
+
export declare function configSyncAction(deps: ConfigSyncDeps): PostResource;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DshHostContext } from '@dsh-workbench/shared';
|
|
2
|
+
import type { PostResource, PostWrite } from '@dsh-workbench/shared/host';
|
|
3
|
+
import { type UnitsPlan } from './mount-units.js';
|
|
4
|
+
export interface PostChannelDeps {
|
|
5
|
+
readonly ctx: DshHostContext;
|
|
6
|
+
readonly mounted: ReadonlyMap<string, {
|
|
7
|
+
readonly plan: UnitsPlan;
|
|
8
|
+
}>;
|
|
9
|
+
readonly facts: {
|
|
10
|
+
bump(names: readonly string[]): unknown;
|
|
11
|
+
};
|
|
12
|
+
readonly shellActions: readonly PostResource[];
|
|
13
|
+
}
|
|
14
|
+
export interface PostChannels {
|
|
15
|
+
rebind(wrote: (resource: string, write: PostWrite) => void): void;
|
|
16
|
+
dispose(): void;
|
|
17
|
+
}
|
|
18
|
+
export declare function createPostChannels(deps: PostChannelDeps): PostChannels;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { type SeedCommand } from './runtime-seed';
|
|
3
|
+
export declare const SELF_UPDATE_STATES: readonly ["running", "ok", "rolled-back", "failed"];
|
|
4
|
+
export type SelfUpdateState = (typeof SELF_UPDATE_STATES)[number];
|
|
5
|
+
export interface SelfUpdatePaths {
|
|
6
|
+
readonly dir: string;
|
|
7
|
+
readonly script: string;
|
|
8
|
+
readonly marker: string;
|
|
9
|
+
readonly log: string;
|
|
10
|
+
}
|
|
11
|
+
export interface SelfUpdateRequest {
|
|
12
|
+
readonly dshHome: string;
|
|
13
|
+
readonly profile: string;
|
|
14
|
+
readonly pkg: string;
|
|
15
|
+
readonly from: string;
|
|
16
|
+
readonly to: string;
|
|
17
|
+
readonly pinned: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface SelfUpdateMarker extends SelfUpdateRequest {
|
|
20
|
+
readonly state: SelfUpdateState;
|
|
21
|
+
readonly version: string;
|
|
22
|
+
readonly at: string;
|
|
23
|
+
}
|
|
24
|
+
export interface SelfUpdatePlan {
|
|
25
|
+
readonly paths: SelfUpdatePaths;
|
|
26
|
+
readonly script: string;
|
|
27
|
+
readonly marker: SelfUpdateMarker;
|
|
28
|
+
readonly command: SeedCommand;
|
|
29
|
+
}
|
|
30
|
+
export interface SelfUpdateStart {
|
|
31
|
+
readonly started: boolean;
|
|
32
|
+
readonly paths: SelfUpdatePaths;
|
|
33
|
+
readonly forward: string;
|
|
34
|
+
}
|
|
35
|
+
export declare function runningVersionOf(moduleUrl: string): string | undefined;
|
|
36
|
+
export declare function selfUpdatePaths(dshHome: string): SelfUpdatePaths;
|
|
37
|
+
export declare function recoveryCommand(input: {
|
|
38
|
+
readonly profile: string;
|
|
39
|
+
readonly pkg: string;
|
|
40
|
+
readonly version: string;
|
|
41
|
+
}): string;
|
|
42
|
+
export declare function selfUpdateMarker(request: SelfUpdateRequest, state: SelfUpdateState, version: string, at: string): SelfUpdateMarker;
|
|
43
|
+
export declare function selfUpdateScript(request: SelfUpdateRequest, paths: SelfUpdatePaths): string;
|
|
44
|
+
export declare function planSelfUpdate(request: SelfUpdateRequest, now?: Date): SelfUpdatePlan;
|
|
45
|
+
export declare function startSelfUpdate(request: SelfUpdateRequest, onError: (message: string) => void, spawnImpl?: typeof spawn): SelfUpdateStart;
|
package/docs/HANDOFF.md
CHANGED
|
@@ -67,7 +67,7 @@ npx @dsh-workbench/core
|
|
|
67
67
|
|
|
68
68
|
- **要配什么就在 `:3081` 配**,落在 `profiles/workbench/cordis.patch.yml` —— 那是它唯一的那份设置文档;
|
|
69
69
|
- **想用 web 那边已经配好的行**(模型供应商 / API key 引用 / 搜索源 / MCP)⇒ `:3081` →
|
|
70
|
-
`Meta+,` → 「配置同步」→ 选来源 `web` → 勾行 →
|
|
70
|
+
`Meta+,` → 「配置同步」→ 选来源 `web` → 勾行 → 同步(即生效,不用重启)。
|
|
71
71
|
它读的是那个 profile 的 `cordis.patch.yml`,按行搬,只搬**显式配过**的行;
|
|
72
72
|
同 id 两边内容不同时**默认不覆盖**,要覆盖得自己勾;行点名的包没装会当场说出来。
|
|
73
73
|
- **web 后来改了不会自动过来** —— 再打开这一页,那几行会重新以「差异」标签出现在这一页,拉一次即可。
|
|
@@ -77,7 +77,9 @@ npx @dsh-workbench/core
|
|
|
77
77
|
Settings → 插件里把 `@dsh-workbench/core` 关掉后,工作台会**退化成原版 dsh web**:
|
|
78
78
|
左栏回到出厂样式、右侧数据面板消失。这是**设计内的降级**(关掉 = 它那份 bundle patch
|
|
79
79
|
整份不再应用,连里面的"禁用出厂左栏"也一并失效),**会话 / 面板配置 / 工作区数据都不丢**。
|
|
80
|
-
恢复:插件页把开关拨回来(或按 `Meta+,`
|
|
80
|
+
恢复:插件页把开关拨回来(或按 `Meta+,` 打开设置);**进程已经退了的**,启动器读到
|
|
81
|
+
"bundle 没被选中"会直接拒绝启动并打印修复命令 —— 跑 `./bin/dsh-workbench setup` 补回来。
|
|
82
|
+
别把它当成故障去重建 profile。
|
|
81
83
|
|
|
82
84
|
顺带一条:即使关掉工作台,profile 里剩下那层差异(会话/存储/附件隔离)**仍然生效**
|
|
83
85
|
—— 那是无害且想要的(数据继续分开)。另外启动器每次都会叠一层 `sandbox-policy`,把执行缝的
|
|
@@ -91,7 +93,12 @@ Settings → 插件里把 `@dsh-workbench/core` 关掉后,工作台会**退化
|
|
|
91
93
|
2. 继承 web 的 **bundle 清单**(装没装东西 —— 安装范畴,走 `dsh plugin` 通路);
|
|
92
94
|
3. 追加**数据隔离层**(会话 / 存储 / 附件各走 `~/.dsh/workbench/**`);
|
|
93
95
|
4. `dsh plugin --profile workbench add @dsh-workbench/core` —— 走 **dsh 自己的**
|
|
94
|
-
安装通路(兼容性预检、profile 写锁、装完自动把 bundle 登记进 profile
|
|
96
|
+
安装通路(兼容性预检、profile 写锁、装完自动把 bundle 登记进 profile 清单);
|
|
97
|
+
5. `./scripts/seed-profile.sh ensure-selected` —— **确保选中**:读 `dsh.profile.bundles`,
|
|
98
|
+
缺 `@dsh-workbench/core` 就补进去(等价于 dsh 的 `selectBundle(name, true)`,已经在里面
|
|
99
|
+
就一个字节不写)。为什么单列这一步:`dsh plugin add` 装完的登记**跳过已存在的依赖**,
|
|
100
|
+
所以重跑 setup(包已在清单里)时它不会补 bundle —— 那一档是静默的(起得来、侧边栏
|
|
101
|
+
没入口),现在启动器拿"选中"当硬门禁,这一步就是它给的修复命令。
|
|
95
102
|
|
|
96
103
|
**设置不在这一步继承**(这里以前快照 web 的 patch、并继承被它点名的依赖):新机器上
|
|
97
104
|
`setup` 完的工作台**没有模型供应商**,第一次打开去 设置 → 「配置同步」拉一次即可 ——
|
|
@@ -188,7 +195,7 @@ manifest;彩排结束、以及「零上传」的失败,都会自动回滚。
|
|
|
188
195
|
`pnpm publish` 的人兜底的(外壳那份 = 整仓门禁);不关掉它们,pnpm 会在**彩排与真发各再跑
|
|
189
196
|
一遍**整门禁 —— 一次发布就是 3 遍门禁 + 3 遍 vitest + 每个包多两轮构建(实测 pnpm 10.32.1:
|
|
190
197
|
`--dry-run` 一样触发)。来历见
|
|
191
|
-
[
|
|
198
|
+
[`../../../.scratch/dsh-ui-alignment/issues/12-s18-pduiv2.md`](../../../.scratch/dsh-ui-alignment/issues/12-s18-pduiv2.md) §18.45。
|
|
192
199
|
|
|
193
200
|
脚本把这几件事变成**硬失败**(都在任何上传之前):
|
|
194
201
|
|
|
@@ -208,7 +215,7 @@ manifest;彩排结束、以及「零上传」的失败,都会自动回滚。
|
|
|
208
215
|
自己拥有的转发脚本。这条由外壳 `selfcheck` 的判据钉着(门禁里跑)。
|
|
209
216
|
这类错**本机复现不出来**,只在别人机器上炸
|
|
210
217
|
(0.1.6 就是这么坏在 `seed-profile.sh: Permission denied` 上的,见
|
|
211
|
-
[`.scratch/dsh-ui-alignment/
|
|
218
|
+
[`.scratch/dsh-ui-alignment/issues/53-18-41-permission-denied-pnpm.md`](../../../.scratch/dsh-ui-alignment/issues/53-18-41-permission-denied-pnpm.md) §18.41)。
|
|
212
219
|
|
|
213
220
|
## 八、版本与兼容(实话)
|
|
214
221
|
|
package/docs/OPERATIONS.md
CHANGED
|
@@ -60,10 +60,10 @@
|
|
|
60
60
|
| 开发(监听改动 + 起工作台) | `pnpm run dev` —— profile 不对会先 `setup`;`:3081` 已在跑就只监听 |
|
|
61
61
|
| 换端口 | `WORKBENCH_PORT=3091 ./bin/dsh-workbench` |
|
|
62
62
|
| 改工作台设置 | 在 `:3081` 的 Settings 页改,落在 `profiles/workbench/cordis.patch.yml`。**这是工作台唯一的那份设置文档**(没有别处叠在它上面),所以模型供应商 / 搜索源 / MCP 每一行都改得动 |
|
|
63
|
-
| 用 web 那边已经配好的行 | `:3081` → `Meta+,` → 「配置同步」→ 选来源(默认 `web`)→ 勾行 →
|
|
63
|
+
| 用 web 那边已经配好的行 | `:3081` → `Meta+,` → 「配置同步」→ 选来源(默认 `web`)→ 勾行 → 同步(`dsh-hmr` 会重组,**不用重启**)。只搬你在那个 profile 里**显式配过**的行;行点名的包没装时页面会说出来(ADR-0044) |
|
|
64
64
|
| 改 web 设置 | 在 `:3080` 改,落在 `profiles/web/cordis.patch.yml`。工作台**不会**再自动跟着变 —— 要就跟上面那条同步一次;不想跟就不动 |
|
|
65
65
|
| 重建 profile | `mv ~/.dsh/profiles/workbench ~/.dsh/profiles/workbench.bak` 后重跑 seed |
|
|
66
|
-
| **别在设置里关掉工作台** | Settings → 插件里 `@dsh-workbench/core` 那个开关**不要关**。关掉=把它从 profile 的 `bundles` 里移除 → 我们那份 bundle patch(含"禁用出厂左栏")**整份不再应用** → 页面退化成**原版 dsh web
|
|
66
|
+
| **别在设置里关掉工作台** | Settings → 插件里 `@dsh-workbench/core` 那个开关**不要关**。关掉=把它从 profile 的 `bundles` 里移除 → 我们那份 bundle patch(含"禁用出厂左栏")**整份不再应用** → 页面退化成**原版 dsh web**(左栏回来、右侧面板消失),**数据一个都不丢**。恢复:进程还在时把开关打开(左栏的「插件」入口也在;进不去设置就按 `Meta+,`);已经重启过的,启动器读到"没选中"会**直接拒绝启动**并给一条修复命令 —— 跑 `./bin/dsh-workbench setup`(幂等,把这一项补回 `dsh.profile.bundles`)即可。实测过这条降级路径,不是推断 |
|
|
67
67
|
|
|
68
68
|
## 开发循环(改完不用重启)
|
|
69
69
|
|
|
@@ -86,7 +86,8 @@ WORKBENCH_PORT=3091 pnpm run dev # 换端口(监听与实例同一个端口
|
|
|
86
86
|
| 浏览器 | Vite 重建 `client.js` → `dsh-client-hmr` 每 500ms stat-poll 到 mtime/大小变化 → `/plugins/events` 发 `rebuilt` → 浏览器作废旧模块、预取新包、换 fiber | 插件内的 React 状态会丢;会话 / 工作区 / 连接状态保留 |
|
|
87
87
|
| 宿主 | Vite 重建 `dist/host/index.js` → `dsh-hmr` 按模块 realpath 匹配并重载插件 | 插件重建,进程与其它插件不受影响 |
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
`cordis.patch.yml`(组合层)与 `package.json` 的 `dsh.profile.bundles` **也在监听里**:`dsh-hmr` 变了就 `recomposeProfile`,
|
|
90
|
+
不用重启(它报 `restartReason` 时才按提示重启)。仍然要重启的是改 `vite.config.ts`。
|
|
90
91
|
|
|
91
92
|
宿主侧监听为什么要环境变量:出厂 `hmr` 的 `root` 默认是 `[]`(不监听),
|
|
92
93
|
而相对路径以 profile 目录为基准 —— 我们的包在 profile 里只是一个指向本仓库的符号链接,
|
|
@@ -128,6 +129,35 @@ WORKBENCH_PORT=3091 pnpm run dev # 换端口(监听与实例同一个端口
|
|
|
128
129
|
| opencli **daemon** | ❌ **整机一个,隔离不了** | 端口 **19825 被扩展写死**(`background.js` 里 `DAEMON_PORT = 19825`;CLI 侧 `OPENCLI_DAEMON_PORT` 设非默认值直接报错)。所以本机的全局 opencli 与工作台的隔离运行时**抢同一个 daemon**:两边版本不一致时,谁的命令后跑谁就把 daemon 重启成自己那版 |
|
|
129
130
|
| profile 的 pnpm 源(私有 scope) | ⚠️ **由工作台写进去** | `<profile>/.npmrc` 里的 `@scope:registry=…`,前面带一行 `# dsh-workbench 写的…` 标记。**为什么在工作台这一侧写**:dsh 的卸载没有源参数(`runPnpm(['remove', name])`),pnpm 只能从 profile 的 `.npmrc` 链知道源;不写它,装私有源的模块能成、卸不了。规则与边界见 [ADR-0030](../../../docs/adr/0030-private-registries-live-in-the-profile-pnpm-config.md):只加不改、只写 scope 行、不碰 `~/.npmrc`。**删了会怎样**:下次从这个源装会再写回来;已经装着的那种,点卸载时撞 404 会自愈补回再重试一次 |
|
|
130
131
|
|
|
132
|
+
## 工作台自己怎么升级、出事怎么救
|
|
133
|
+
|
|
134
|
+
工作台那一行的「更新」**不会把自己摘掉**(见 [ADR-0045](../../docs/adr/0045-workbench-self-update-runs-outside-the-workbench.md)):
|
|
135
|
+
点下去之后工作台把现场写到 `$DSH_HOME/workbench/self-update.sh|json|log`,然后起一个**独立进程**去做
|
|
136
|
+
`dsh plugin --profile <profile> add @dsh-workbench/core@<版本>` —— 就地换版本,一行都不摘,
|
|
137
|
+
所以它换的就是工作台自己也没关系(换的是外头那个进程)。
|
|
138
|
+
|
|
139
|
+
- 成功:`self-update.json` 里 `state: "ok"`,`version` 是新版;**重启一次 dsh** 才用得上(面板会这么说)。
|
|
140
|
+
- 换版没成:脚本自己把旧版本装回去,`state: "rolled-back"` —— 工作台不会因此消失。
|
|
141
|
+
- 回滚也没成:`state: "failed"`,日志最后一行给出救法。终端敲这一条即可:
|
|
142
|
+
`dsh plugin --profile <profile> add @dsh-workbench/core@<版本>`(`<版本>` 取源上最新,或 `latest`)。
|
|
143
|
+
|
|
144
|
+
两种安装形态的差别:
|
|
145
|
+
|
|
146
|
+
| 怎么装的 | profile 里那一条 | 市场自更新 |
|
|
147
|
+
|---|---|---|
|
|
148
|
+
| `npm i -g @dsh-workbench/core` 然后 `dsh-workbench setup` | `@dsh-workbench/core@^x.y.z`(源上) | 能(就是上面那一条) |
|
|
149
|
+
| 仓库副本(`pnpm run dev` / `link:` 本目录) | `link:…` | 拒:不把开发副本换成源上那份 |
|
|
150
|
+
|
|
151
|
+
全局那一份**启动器**不会跟着升级(它只是启动器:真正加载的是 profile 里那份)。换 profile 或重建之前,
|
|
152
|
+
先 `npm i -g @dsh-workbench/core@latest`;已经在跑的 profile 走市场那一颗「更新」。
|
|
153
|
+
|
|
154
|
+
### 起不来:`failed to parse overlay …/cordis.patch.yml`(YAMLException: end of the stream …)
|
|
155
|
+
|
|
156
|
+
早期版本 `seed-profile.sh` 会把隔离层直接接到 dsh 新模板的 patch 后面,而那份模板的内容是「横幅注释 +
|
|
157
|
+
一个空数组 `[]`」—— 空数组本身是一个**完整的 YAML 文档**,后面再接序列就解析不了,profile 一条都组不起来。
|
|
158
|
+
现在的脚本追加前会先把那行单独的 `[]` 让位(`selfcheck` 有判据钉着)。如果你手上那份 profile 是旧脚本建出来的,
|
|
159
|
+
手工把 `cordis.patch.yml` 里**单独一行**的 `[]` 删掉再起即可(其余内容不用动)。
|
|
160
|
+
|
|
131
161
|
## 排障
|
|
132
162
|
|
|
133
163
|
| 症状 | 原因 |
|
|
@@ -136,8 +166,9 @@ WORKBENCH_PORT=3091 pnpm run dev # 换端口(监听与实例同一个端口
|
|
|
136
166
|
| 面板一直空着、`/workbench/api/issues` 返回 `coding-not-logged-in` | opencli 登录态失效:在终端跑 `opencli coding team-current` 完成登录 |
|
|
137
167
|
| 面板显示"这个项目不是 Coding 仓库" | 该工作区的 git `origin` 不指向 `e.coding.net`(或没有 origin) |
|
|
138
168
|
| 打开面板/按刷新要等 5–8 秒 | 正常:opencli 每次调用有**固定约 5 秒**开销(起浏览器会话;接口本身只要 ~260ms)。**没有缓存**——数据一律实时,列表 = 缺陷 + 状态目录两次调用(限并发 2,实测约 7 秒) |
|
|
139
|
-
| 改了源码没变化 | 忘了 `pnpm run build
|
|
169
|
+
| 改了源码没变化 | 忘了 `pnpm run build`,或没刷新页面;改过 `vite.config.ts` 后没重启(正在跑的 watch 用的还是旧配置) |
|
|
140
170
|
| 市场页点「卸载」报 `没成功:… ERR_PNPM_FETCH_404 GET https://registry.npmjs.org/@你的私有 scope/…` 之类 | 这个 profile 里的私有包不在 pnpm 默认源上,而 dsh 的卸载**不带源**。工作台会自己补上 `<profile>/.npmrc` 的 `@scope:registry=` 再重试一次([ADR-0030](../../../docs/adr/0030-private-registries-live-in-the-profile-pnpm-config.md));**还失败**说明那个包没有 scope(一行 scope 行表达不了),这时才需要人/agent 上手:`dsh plugin --profile <p> remove '<包名>' --config.registry=<那个源>`(`pnpm remove` 不认 `--registry=`),或者给 profile 自己配一行默认 `registry=` |
|
|
141
171
|
| 体检那屏「检测浏览器通道 · 没连上」,可面板照样能用 | 本机全局 opencli 与隔离运行时版本不一致 ⇒ daemon 被顶成对方那版(`Stale daemon detected: daemon vX != CLI vY`)。下一条浏览器命令会自动把它重启回来,体检也会复检后改回「已连接」([ADR-0024](../../../docs/adr/0024-warm-the-sites-before-the-panel.md) §3.2.1)。**要彻底不抖**:让两边同版本 —— 把 `OPENCLI_PIN`(`src/shared/config/constants.ts`)对齐到 `opencli --version`,再 `npm i --prefix ~/.dsh/workbench/opencli/toolchain @jackwener/opencli@<那个版本> --cache ~/.dsh/workbench/opencli/npm-cache` |
|
|
142
172
|
| Settings 页报 `overridden by a home patch` | 想在 Settings 里改的行被 `$DSH_HOME/cordis.patch.yml` 或 `--patch` 覆盖了 |
|
|
173
|
+
| `./bin/dsh-workbench` 直接拒绝启动,说 `@dsh-workbench/core 不在 dsh.profile.bundles 里` | 包装着但**没被选中**(在 Settings → 插件里关过;或装到一半:`dsh plugin add` 的 pnpm 那半成功、装完的登记跳过了已存在的依赖)。这一档以前是静默的 —— 起得来、只是侧边栏没有工作台。现在拒绝启动是为了不给你一台"什么都对但没入口"的实例:跑它打印的那条 `./bin/dsh-workbench setup`(幂等,`seed-profile.sh ensure-selected` 会把这一项补回去) |
|
|
143
174
|
| **别人机器上** `npx @dsh-workbench/core setup` 报 `scripts/seed-profile.sh: Permission denied`(或体检永远说"隔离运行时没装好") | 发出去的包里**随包脚本丢了 x 位**:`pnpm publish` 只给 `package.json#bin` 点名那条文件 755,其余一律 644(`npm pack` 会保留,而 `git` 里的 x 位不进 tarball —— 所以**本机永远复现不出来**)。0.1.6 的已知缺陷:应急 `chmod +x <包目录>/{scripts/seed-profile.sh,bin/opencli-isolated}`,正规解是升到 0.1.7(启动器与 `selfcheck` 已改成不吃 x 位) |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-workbench/core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"description": "个人工作台:Agent 工作台外壳(左栏 + 常驻对话 + 自研右侧数据面板)。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"icon": "./icon.svg",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"title": "Workbench",
|
|
43
43
|
"description": "个人工作台"
|
|
44
44
|
},
|
|
45
|
-
"//scripts": "包内不跑 check:docs —— 那份文档管理块住在仓库根的 docs/ARCHITECTURE.md,由根 `pnpm run check` 用 --config 指到本包的 arch.config.mjs 校验。prepublishOnly
|
|
45
|
+
"//scripts": "包内不跑 check:docs —— 那份文档管理块住在仓库根的 docs/ARCHITECTURE.md,由根 `pnpm run check` 用 --config 指到本包的 arch.config.mjs 校验。check 与 prepublishOnly 都走 -w 跑根那一整套:包内自己串一份会漏掉 lint(react-hooks 那几条规则只在这里跑)、check:docs 与模块工具包的十一条判据 —— 2026-10-16 实测踩到(渲染期写 ref,包内全绿、根上一跑就红)。",
|
|
46
46
|
"//dsh.bundle.patch": "一份 preset 就是一个补丁层:它 insert 一行 @deepseek-ai/dsh-agent-preset,config.plugins 是整表插件清单。diy.patch.yml 是**生成的**(scripts/gen-diy-preset.mjs,从 dsh 出厂那份 standard.patch.yml 派生),selfcheck 有一条判据盯着它有没有过期。",
|
|
47
47
|
"dsh": {
|
|
48
48
|
"bundle": {
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"access": "public"
|
|
88
88
|
},
|
|
89
89
|
"dependencies": {
|
|
90
|
-
"@dsh-workbench/shared": "0.2.
|
|
90
|
+
"@dsh-workbench/shared": "0.2.8"
|
|
91
91
|
},
|
|
92
92
|
"scripts": {
|
|
93
93
|
"build": "node scripts/build.mjs && node scripts/build-types.mjs",
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"arch": "arch-guard",
|
|
98
98
|
"selfcheck": "node scripts/selfcheck.mjs",
|
|
99
99
|
"check:runtimes": "node scripts/check-runtimes.mjs",
|
|
100
|
-
"check": "
|
|
100
|
+
"check": "pnpm -w run check",
|
|
101
101
|
"test": "vitest run",
|
|
102
102
|
"coverage": "vitest run --coverage",
|
|
103
103
|
"dev": "node scripts/dev.mjs",
|
package/scripts/seed-profile.sh
CHANGED
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
# 用法:
|
|
16
16
|
# ./scripts/seed-profile.sh
|
|
17
17
|
# WORKBENCH_PROFILE=wb2 ./scripts/seed-profile.sh # 建到别的 profile 名下(试装用)
|
|
18
|
+
# ./scripts/seed-profile.sh ensure-selected # 只做"确保选中"这一步:
|
|
19
|
+
# # 把工作台 bundle 补进 dsh.profile.bundles
|
|
20
|
+
# # (setup 在 `dsh plugin add` **之后**调它)
|
|
18
21
|
|
|
19
22
|
set -euo pipefail
|
|
20
23
|
|
|
@@ -22,6 +25,7 @@ DSH_HOME="${DSH_HOME:-$HOME/.dsh}"
|
|
|
22
25
|
PROFILE="${WORKBENCH_PROFILE:-workbench}"
|
|
23
26
|
SRC_PROFILE="$DSH_HOME/profiles/web"
|
|
24
27
|
DST_PROFILE="$DSH_HOME/profiles/$PROFILE"
|
|
28
|
+
PKG='@dsh-workbench/core'
|
|
25
29
|
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
26
30
|
GIT_TOP="$(git -C "$REPO_DIR" rev-parse --show-toplevel 2>/dev/null || true)"
|
|
27
31
|
ISOLATION="$REPO_DIR/profile/isolation.patch.yml"
|
|
@@ -36,6 +40,53 @@ die() {
|
|
|
36
40
|
exit 1
|
|
37
41
|
}
|
|
38
42
|
|
|
43
|
+
# ── 确保工作台 bundle 被**选中**(`ensure-selected` 子命令,幂等)──────────────
|
|
44
|
+
#
|
|
45
|
+
# 为什么单独一步、还要排在 `dsh plugin add` **之后**:装包与"选中"在 dsh 那侧是两件事。
|
|
46
|
+
# `dsh plugin add` 的 pnpm 那半把包装进 profile;登记 `dsh.profile.bundles` 是它装完后的
|
|
47
|
+
# 对账,而那条对账**跳过已存在的依赖** —— 所以依赖已经在清单里时(重跑 setup、上次装到
|
|
48
|
+
# 一半),bundle 名单永远缺那一项。症状是静默的:profile 照常组起来、服务照常监听,
|
|
49
|
+
# 只是侧边栏什么也不出现。启动器现在拿"选中"当硬门禁(拒绝启动 + 打印修复命令),
|
|
50
|
+
# 这一步就是那条修复命令的落点。
|
|
51
|
+
#
|
|
52
|
+
# 与 dsh 自己的 `selectBundle(name, true)` 等价:已经在清单里就一个字节都不写;
|
|
53
|
+
# 补之前先确认包真的装着(`dsh plugin add` 落了 dependencies)—— 把没装的包塞进
|
|
54
|
+
# bundles 只会让 profile 组不起来,比"面板不出现"更糟。
|
|
55
|
+
ensure_selected() {
|
|
56
|
+
local manifest="$DST_PROFILE/package.json"
|
|
57
|
+
[ -f "$manifest" ] ||
|
|
58
|
+
die "找不到 $manifest —— 先跑一次 '$REPO_DIR/bin/dsh-workbench setup'。"
|
|
59
|
+
|
|
60
|
+
WB_MANIFEST="$manifest" WB_PKG="$PKG" node -e '
|
|
61
|
+
const fs = require("node:fs");
|
|
62
|
+
const manifestPath = process.env.WB_MANIFEST;
|
|
63
|
+
const pkg = process.env.WB_PKG;
|
|
64
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
65
|
+
const dependencies = manifest.dependencies || {};
|
|
66
|
+
if (!Object.hasOwn(dependencies, pkg)) {
|
|
67
|
+
console.error("seed-profile: dependencies 里没有 " + pkg + " —— dsh plugin add 那一步没成,先重装一遍。");
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
const profile = (manifest.dsh || {}).profile || {};
|
|
71
|
+
const bundles = Array.isArray(profile.bundles) ? profile.bundles : [];
|
|
72
|
+
if (bundles.includes(pkg)) {
|
|
73
|
+
console.log("→ 工作台 bundle 已选中: " + pkg);
|
|
74
|
+
process.exit(0);
|
|
75
|
+
}
|
|
76
|
+
manifest.dsh = Object.assign({}, manifest.dsh, {
|
|
77
|
+
profile: Object.assign({}, profile, { bundles: bundles.concat([pkg]) }),
|
|
78
|
+
});
|
|
79
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
80
|
+
console.log("→ 已把工作台 bundle 补进 dsh.profile.bundles: " + pkg);
|
|
81
|
+
' ||
|
|
82
|
+
die "'$PKG' 没被选中,也没能补上(原因见上一行)。"
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if [ "${1:-}" = "ensure-selected" ]; then
|
|
86
|
+
ensure_selected
|
|
87
|
+
exit 0
|
|
88
|
+
fi
|
|
89
|
+
|
|
39
90
|
[ -f "$SRC_PROFILE/package.json" ] ||
|
|
40
91
|
die "找不到 $SRC_PROFILE —— 请先跑一次 'dsh web',让 web profile 落地。"
|
|
41
92
|
[ -f "$ISOLATION" ] || die "找不到 $ISOLATION"
|
|
@@ -87,6 +138,15 @@ console.log("→ 已继承 web 的 bundle 列表: " + merged.join(", "));
|
|
|
87
138
|
if grep -q 'id: session-persistence-jsonl' "$DST_PATCH"; then
|
|
88
139
|
echo "→ 隔离层已存在,跳过"
|
|
89
140
|
else
|
|
141
|
+
# dsh 生成的 profile patch 是「三行横幅注释 + 一个空数组 []」。空数组本身是一个**完整的
|
|
142
|
+
# YAML 文档**,往后直接接一个序列,解析就会在最外层报
|
|
143
|
+
# "end of the stream or a document separator is expected",profile 直接起不来
|
|
144
|
+
# (实测 dsh 0.2.1-alpha.3:setup 出来的 profile 报这条,去掉那行 [] 才起)。
|
|
145
|
+
# 所以追加之前先把那行单独的 [] 拿掉;本来就没有(或已经是序列)时这一步什么都不做。
|
|
146
|
+
if grep -qx '\[\]' "$DST_PATCH"; then
|
|
147
|
+
grep -vx '\[\]' "$DST_PATCH" >"$DST_PATCH.tmp" && mv "$DST_PATCH.tmp" "$DST_PATCH"
|
|
148
|
+
echo "→ 模板 patch 里的空数组 [] 已让位(否则接不上隔离层)"
|
|
149
|
+
fi
|
|
90
150
|
printf '\n' >>"$DST_PATCH"
|
|
91
151
|
cat "$ISOLATION" >>"$DST_PATCH"
|
|
92
152
|
echo "→ 已追加隔离层(sessions / storages / attachments 分家)"
|
|
@@ -105,7 +165,7 @@ bash "$REPO_DIR/scripts/seed-workshop.sh"
|
|
|
105
165
|
if [ -n "$GIT_TOP" ]; then
|
|
106
166
|
BUNDLE_TARGET="$REPO_DIR"
|
|
107
167
|
else
|
|
108
|
-
BUNDLE_TARGET="
|
|
168
|
+
BUNDLE_TARGET="$PKG@^$(node -p "require('$REPO_DIR/package.json').version" 2>/dev/null || echo 0)"
|
|
109
169
|
fi
|
|
110
170
|
|
|
111
171
|
cat <<EOF
|