@dsh-workbench/core 0.1.14 → 0.1.16
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 +19 -0
- package/bin/dsh-workbench +21 -1
- package/client.js +163 -89
- package/cordis.patch.yml +40 -0
- package/dist/client/client.body.js +163 -89
- package/dist/client/index.js +163 -89
- package/dist/host/index.js +1474 -93
- package/dist/types/app/__tests__/workbench-styles.test.d.ts +1 -0
- package/dist/types/app/client.d.ts +39 -15
- package/dist/types/app/layouts/rightbar/board-columns.d.ts +8 -0
- package/dist/types/app/layouts/rightbar/board-columns.test.d.ts +1 -0
- package/dist/types/app/layouts/rightbar/market-rows.d.ts +2 -0
- package/dist/types/app/layouts/workbench-styles.d.ts +2 -0
- package/dist/types/modules/panels/__tests__/diy-harness.d.ts +51 -0
- package/dist/types/modules/panels/__tests__/diy-tools-status.test.d.ts +1 -0
- package/dist/types/modules/panels/__tests__/diy-tools.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-tools.d.ts +4 -0
- package/dist/types/modules/panels/unit.d.ts +1 -0
- package/dist/types/shared/api/bundle-install.d.ts +1 -0
- package/dist/types/shared/api/host/diy-facts.d.ts +9 -0
- package/dist/types/shared/api/host/diy-facts.test.d.ts +1 -0
- package/dist/types/shared/api/host/diy-recon-fs.d.ts +3 -0
- package/dist/types/shared/api/host/diy-recon-fs.test.d.ts +1 -0
- package/dist/types/shared/api/host/diy-recon.d.ts +39 -0
- package/dist/types/shared/api/host/diy-recon.test.d.ts +1 -0
- package/dist/types/shared/api/host/diy-workshop.d.ts +12 -0
- package/dist/types/shared/api/host/diy-workshop.test.d.ts +1 -0
- package/dist/types/shared/api/host/installed-module.d.ts +2 -0
- package/dist/types/shared/api/host/opencli-command.d.ts +10 -0
- package/dist/types/shared/api/host/opencli-command.test.d.ts +1 -0
- package/dist/types/shared/api/host/runtime-seed.d.ts +40 -0
- package/dist/types/shared/api/host/runtime-seed.test.d.ts +1 -0
- package/docs/HANDOFF.md +82 -44
- package/docs/OPERATIONS.md +22 -1
- package/package.json +5 -5
- package/scripts/seed-profile.sh +4 -113
- package/scripts/seed-workshop.sh +216 -0
- package/skills/workbench-module-diy/BUILD.md +36 -66
- package/skills/workbench-module-diy/DATASOURCE.md +80 -12
- package/skills/workbench-module-diy/DESIGN.md +27 -2
- package/skills/workbench-module-diy/LINKAGE.md +49 -19
- package/skills/workbench-module-diy/PANEL.md +78 -4
- package/skills/workbench-module-diy/REVIEW.md +6 -5
- package/skills/workbench-module-diy/SKILL.md +32 -12
- package/skills/workbench-module-diy/STEPS.md +4 -0
- package/skills/workbench-module-diy/TOOLING.md +47 -0
- package/skills/workbench-module-diy/TOOLS.md +147 -5
- package/skills/workbench-module-diy/WIRING.md +88 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import type { DshHostContext } from '@dsh-workbench/shared';
|
|
3
|
+
export declare const WORKSHOP_SKILLS_DIR = "workbench-module-diy";
|
|
4
|
+
export type SeedLog = (message: string) => void;
|
|
5
|
+
export interface RuntimeSeedPaths {
|
|
6
|
+
readonly root: string;
|
|
7
|
+
readonly entryDir: string;
|
|
8
|
+
readonly opencliRoot: string;
|
|
9
|
+
readonly opencliBinDir: string;
|
|
10
|
+
readonly opencliBin: string;
|
|
11
|
+
readonly opencliHome: string;
|
|
12
|
+
readonly workshop: string;
|
|
13
|
+
readonly workshopPackages: string;
|
|
14
|
+
readonly workshopManifest: string;
|
|
15
|
+
readonly skillsLink: string;
|
|
16
|
+
}
|
|
17
|
+
export interface RuntimeSeedOptions {
|
|
18
|
+
readonly root: string;
|
|
19
|
+
readonly home: string;
|
|
20
|
+
readonly packageRoot: string;
|
|
21
|
+
readonly log?: SeedLog;
|
|
22
|
+
}
|
|
23
|
+
export declare function runtimeSeedPaths(root: string): RuntimeSeedPaths;
|
|
24
|
+
export declare function runtimeSeedRootOf(ctx: DshHostContext): string | null;
|
|
25
|
+
export declare function packageRootOf(moduleUrl: string): string;
|
|
26
|
+
export declare function isInstalledCopy(packageRoot: string): boolean;
|
|
27
|
+
export declare function opencliWrapperScript(packageRoot: string, home: string): string;
|
|
28
|
+
export interface SeedCommand {
|
|
29
|
+
readonly file: string;
|
|
30
|
+
readonly args: readonly string[];
|
|
31
|
+
readonly env: Readonly<Record<string, string>>;
|
|
32
|
+
readonly log: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function workshopSeedPlan(packageRoot: string, home: string, root: string): {
|
|
35
|
+
readonly entry: SeedCommand;
|
|
36
|
+
readonly full: SeedCommand;
|
|
37
|
+
};
|
|
38
|
+
export declare function runDetached(command: SeedCommand, onError: SeedLog, spawnImpl?: typeof spawn): void;
|
|
39
|
+
export declare function prependPath(entryDir: string, env?: NodeJS.ProcessEnv): boolean;
|
|
40
|
+
export declare function seedRuntimeFiles(options: RuntimeSeedOptions): readonly string[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/docs/HANDOFF.md
CHANGED
|
@@ -1,37 +1,55 @@
|
|
|
1
1
|
# 把工作台给别人用
|
|
2
2
|
|
|
3
|
-
工作台是一个 **dsh
|
|
4
|
-
`
|
|
5
|
-
|
|
3
|
+
工作台是一个 **dsh 插件包**,现在发在**公网 npm** 上:`@dsh-workbench/core`
|
|
4
|
+
(实测 `npm view @dsh-workbench/core version` 出号,`npm pack` 的产物里
|
|
5
|
+
`dsh.bundle.patch` / `cordis.patch.yml` / `client.js` / `dist/host/index.js` 都在)。
|
|
6
|
+
所以**对方不需要配任何私有源**就能装。
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
两种给法,先挑一种:
|
|
9
|
+
|
|
10
|
+
| 给法 | 对方要做的事 | 换来的 |
|
|
11
|
+
| --- | --- | --- |
|
|
12
|
+
| **A. 装进他自己的 `dsh web`**(最短) | Plugins → Add plugin → `@dsh-workbench/core` → Enable now → **刷新页面** | 就在那份 web 里换成工作台;**同一个 profile、同一份会话**、同一个端口 |
|
|
13
|
+
| **B. 独立实例**(要数据分家就选它) | `npx --yes @dsh-workbench/core@latest setup` → `npx @dsh-workbench/core` | 另一个 profile、另一个端口(:3081),他自己那份 `dsh web` **一行不改** |
|
|
14
|
+
|
|
15
|
+
一条路径一句话:**A = 点一下装(单 profile);B = `setup` 然后起(双 profile)**。
|
|
16
|
+
取舍与代价见 [`docs/adr/0037`](../../../docs/adr/0037-workbench-installs-into-any-profile.md)。
|
|
8
17
|
|
|
9
18
|
## 一、对方机器上要有的
|
|
10
19
|
|
|
11
20
|
| # | 东西 | 为什么 | 怎么有 |
|
|
12
21
|
| --- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------- |
|
|
13
22
|
| 1 | `dsh` | 本体。本仓库在 `0.1.7-rc.2` 上验过 | `npm i -g @deepseek-ai/dsh`(公网 npm 上有) |
|
|
14
|
-
| 2 | `node` + **`pnpm`** | dsh 的 `plugin`
|
|
15
|
-
| 3 | 跑过一次 `dsh web` | `setup` 拿 `~/.dsh/profiles/web`
|
|
16
|
-
| 4 |
|
|
17
|
-
| 5 | Coding 账号 + opencli 登录态 | 面板的数据来自 opencli 的 coding 插件 |
|
|
23
|
+
| 2 | `node` + **`pnpm`** | dsh 的 `plugin` 子命令(以及 web 的 Plugins 页)都是**转发给 pnpm** 的;没有 pnpm 会直接报 `dsh: pnpm was not found` | 各自装 |
|
|
24
|
+
| 3 | 跑过一次 `dsh web` | 走 A 需要它给出那个 profile;走 B 时 `setup` 拿 `~/.dsh/profiles/web` 当模板。没有它会**明确报错**,不会静默建出半个 profile | `dsh web` |
|
|
25
|
+
| 4 | 一个能解析这个包的源 | 包在**公网 npm** 上,默认源即可。只有将来改发内网源时,才要 `npm config set @<scope>:registry …` + `npm login`(带 scope 的包只去 `.npmrc` 里给这个 scope 指的源找) | `npm view @dsh-workbench/core version` 出号即可 |
|
|
26
|
+
| 5 | Coding 账号 + opencli 登录态 | 面板的数据来自 opencli 的 coding 插件 | 见第五节 |
|
|
18
27
|
|
|
19
|
-
##
|
|
28
|
+
## 二、A:装进他自己的 `dsh web`(插件页,一条龙)
|
|
20
29
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
在 `dsh web`(:3080)里:
|
|
31
|
+
|
|
32
|
+
1. 侧栏 **Plugins → Add plugin**,填 `@dsh-workbench/core`;
|
|
33
|
+
2. **Install → Enable now**;
|
|
34
|
+
3. **刷新一次页面**(客户端 bundle 是页面加载时装进去的)。
|
|
35
|
+
|
|
36
|
+
装完左栏就是工作台、右侧多出面板列。缺的那几件(隔离 opencli 的入口、`dsh-wb-module`、
|
|
37
|
+
DIY 工坊骨架、可写根)由**外壳自己**补齐 —— 不用跑 `setup`,也不用起第二个实例。
|
|
38
|
+
|
|
39
|
+
差别(先跟对方说清):**会话 / 存储不分家**(接着用他原来那份)、**没有独立端口与进程**、
|
|
40
|
+
**改外壳源码不热重载**、DIY 工坊依赖是首次启动在后台装的。
|
|
25
41
|
|
|
26
|
-
|
|
42
|
+
## 三、B:两步装(独立 profile,占 :3081)
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# ① 建 profile + 把工作台装进去,然后起(占 :3081,dsh web 继续用 :3080)
|
|
27
46
|
npx --yes @dsh-workbench/core@latest setup
|
|
28
47
|
npx @dsh-workbench/core
|
|
29
48
|
```
|
|
30
49
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
不设这一行,症状是 `404 Not Found - GET https://registry.npmjs.org/@pagoda%2fdsh-workbench`。
|
|
50
|
+
> 若团队后来把包改发到内网源,这两条命令之前要各加一次:
|
|
51
|
+
> `npm config set @<scope>:registry "$NPM_REGISTRY"` 与 `npm login --registry=$NPM_REGISTRY`。
|
|
52
|
+
> 不设的话症状是 `404 Not Found - GET https://registry.npmjs.org/@<scope>%2F…`。
|
|
35
53
|
|
|
36
54
|
> ⚠️ **0.1.6 的已知缺陷**:`setup` 可能死在
|
|
37
55
|
> `…/@dsh-workbench/core/scripts/seed-profile.sh: Permission denied`(发出去的包里随包脚本丢了
|
|
@@ -76,7 +94,7 @@ Settings → 插件里把 `@dsh-workbench/core` 关掉后,工作台会**退化
|
|
|
76
94
|
要重新同步得重跑 `setup`。有意共享的只有两样:**API 凭据**(`~/.dsh/.credentials.yaml`,
|
|
77
95
|
一机一把 key)和 `$DSH_HOME/cordis.patch.yml`(机器公共层,对所有 profile 实时生效)。
|
|
78
96
|
|
|
79
|
-
##
|
|
97
|
+
## 四、不想用 npx?仓库副本也可以
|
|
80
98
|
|
|
81
99
|
`bin/dsh-workbench` 认得出自己是不是仓库副本(看有没有 `.git`):
|
|
82
100
|
|
|
@@ -88,7 +106,7 @@ git clone <仓库> && cd dsh-workbench && pnpm install
|
|
|
88
106
|
|
|
89
107
|
两种身份装出来的东西**同一个包名**,所以对方以后换成正装也不会打架。
|
|
90
108
|
|
|
91
|
-
##
|
|
109
|
+
## 五、数据通路(面板要有数据)
|
|
92
110
|
|
|
93
111
|
1. **opencli 隔离运行时**。第一次打开工作台,启动体检会**自己装**它(`@jackwener/opencli`,
|
|
94
112
|
公网包),落在 `$DSH_HOME/workbench/opencli/toolchain/`,**与对方本机的 `opencli` 完全隔离**
|
|
@@ -142,35 +160,52 @@ git clone <仓库> && cd dsh-workbench && pnpm install
|
|
|
142
160
|
装的时候 `bin/opencli-isolated` 会把 `~/.npmrc` 指回去,就为了拿到源的 token;
|
|
143
161
|
npm 缓存则一律落在那台机器自己的隔离运行时里(**不碰** `~/.npm`)。
|
|
144
162
|
|
|
145
|
-
##
|
|
163
|
+
## 六、不用管的
|
|
146
164
|
|
|
147
165
|
- **`dsh web` 一行不改**:`./scripts/verify.sh` 是外部证据 —— 比对 web 的 profile 哈希、
|
|
148
166
|
两个 profile 的组合树差异、数据是否分家,而不是自证。
|
|
149
167
|
- 会话 / 存储 / 附件各自独立;工作台是**另一个端口、另一个进程**,可与 `dsh web` 同开。
|
|
150
168
|
- 改工作台设置只落在 `profiles/workbench/cordis.patch.yml`。
|
|
151
169
|
|
|
152
|
-
##
|
|
170
|
+
## 七、发版(发起人)
|
|
153
171
|
|
|
154
172
|
```bash
|
|
155
173
|
cd <仓库根>
|
|
156
|
-
pnpm release:dry #
|
|
157
|
-
pnpm release
|
|
174
|
+
pnpm release:dry # 彩排:门禁 → 选版本号 → 构建 → publish --dry-run;不上传,结束回滚版本号
|
|
175
|
+
pnpm release # 真发:上面那一串 + 逐包上传 + git 收尾(提交 / tag / 推送)
|
|
158
176
|
```
|
|
159
177
|
|
|
160
|
-
|
|
178
|
+
不用先 `npm version`:版本号由脚本选(交互,或 `--target 0.2.0`),同步到根与所有包的
|
|
179
|
+
manifest;彩排结束、以及「零上传」的失败,都会自动回滚。
|
|
180
|
+
|
|
181
|
+
**门禁整次发布只跑一遍**(preflight 那次 `pnpm run check`;`--resume` 也跑)。发布走
|
|
182
|
+
`pnpm -r publish --ignore-scripts`:各包的 `prepublishOnly` / `prepack` 是留给**手敲**
|
|
183
|
+
`pnpm publish` 的人兜底的(外壳那份 = 整仓门禁);不关掉它们,pnpm 会在**彩排与真发各再跑
|
|
184
|
+
一遍**整门禁 —— 一次发布就是 3 遍门禁 + 3 遍 vitest + 每个包多两轮构建(实测 pnpm 10.32.1:
|
|
185
|
+
`--dry-run` 一样触发)。来历见
|
|
186
|
+
[`.scratch/dsh-ui-alignment/spec.md`](../../../.scratch/dsh-ui-alignment/spec.md) §18.45。
|
|
187
|
+
|
|
188
|
+
脚本把这几件事变成**硬失败**(都在任何上传之前):
|
|
189
|
+
|
|
190
|
+
- **工作区不干净** → 默认拒(发布会把它们 `git add -A` 一起提交),`--allow-dirty` 才放行;
|
|
191
|
+
- **目标版本必须高于当前版本**;目标版本若在源上**已完整存在**,直接拒(要补发用 `--resume`);
|
|
192
|
+
- **npm 没登录** → 就地拉起 `npm login`;
|
|
193
|
+
- **彩排不过**(`publish --dry-run` 打不出包)→ 零上传退出。
|
|
194
|
+
|
|
195
|
+
只能自己盯、脚本不查的两条:
|
|
161
196
|
|
|
162
197
|
- **`dist/` 在 `.gitignore` 里**:npm 打包的兜底就是 `.gitignore`,不在 `files` 里显式列出
|
|
163
|
-
就会漏掉构建产物 —— 症状不是报错,而是"别人装上后宿主侧起不来"
|
|
164
|
-
|
|
165
|
-
- `private: true` 没摘;
|
|
198
|
+
就会漏掉构建产物 —— 症状不是报错,而是"别人装上后宿主侧起不来"(外壳与 `module-hello` 的
|
|
199
|
+
`files` 都显式列了 `dist` / `client.js`,但发布脚本不核这件事);
|
|
166
200
|
- **随包脚本的可执行位**:`pnpm publish` 只给 `package.json#bin` 点名的那**一个**文件 755,
|
|
167
201
|
其余在 tarball 里一律 644(`npm pack` 会保留,而 git 里的 x 位不进 tarball)——
|
|
168
202
|
所以随包脚本一律不吃 x 位:启动器里 `bash` 呼 `seed-profile.sh`、opencli 那条稳定路径写成
|
|
169
|
-
|
|
203
|
+
自己拥有的转发脚本。这条由外壳 `selfcheck` 的判据钉着(门禁里跑)。
|
|
204
|
+
这类错**本机复现不出来**,只在别人机器上炸
|
|
170
205
|
(0.1.6 就是这么坏在 `seed-profile.sh: Permission denied` 上的,见
|
|
171
206
|
[`.scratch/dsh-ui-alignment/spec.md`](../../../.scratch/dsh-ui-alignment/spec.md) §18.41)。
|
|
172
207
|
|
|
173
|
-
##
|
|
208
|
+
## 八、版本与兼容(实话)
|
|
174
209
|
|
|
175
210
|
`package.json` 的 `peerDependencies` 里**没有** `@deepseek-ai/dsh`,这是有意的:
|
|
176
211
|
dsh 目前是 `0.1.7-rc.2`(预发布),声明范围会让版本不一致的人**装不上**;不声明则是
|
|
@@ -195,29 +230,31 @@ dsh 会用这条做**安装预检**(`evaluatePluginCompatibility`),不满
|
|
|
195
230
|
## 发布(一个脚本,一条命令)
|
|
196
231
|
|
|
197
232
|
```bash
|
|
198
|
-
pnpm release # 门禁 →
|
|
199
|
-
pnpm release:dry #
|
|
233
|
+
pnpm release # 门禁 → 选版本号 → 构建 → 彩排 → 逐包上传 → git 收尾
|
|
234
|
+
pnpm release:dry # 同上,但 publish 只 dry-run:零上传,结束回滚版本号
|
|
200
235
|
```
|
|
201
236
|
|
|
202
|
-
`scripts/release.mjs`
|
|
203
|
-
谁要发、发到哪、要发什么,全部从各包自述清单读,不写死名单:
|
|
237
|
+
`scripts/release.mjs` 是**唯一**的发布入口。发什么、发到哪、谁先谁后,都从各包自述清单读:
|
|
204
238
|
|
|
205
|
-
- **发不发** =
|
|
206
|
-
|
|
207
|
-
-
|
|
208
|
-
|
|
239
|
+
- **发不发** = `packages/*` 一级目录里,非 `private` 且自述了 `publishConfig`(`access` 或 `registry`);
|
|
240
|
+
私有模块必须显式写发布目标这条,由门禁的 `contracts` 判据守着(不许默认落到公网);
|
|
241
|
+
- **发到哪** = 包自己的 `publishConfig.registry`(pnpm 在 recursive publish 里逐包取它),没写的
|
|
242
|
+
落到脚本顶部的 `REGISTRY`(npmjs);本仓现在这 4 个包都发公网,命令一律带 `--access public`。
|
|
243
|
+
注意 `inspectTarget` **只查 npmjs** —— "这个版本发出去没有"对发内网源的包看不准;
|
|
244
|
+
- **什么顺序** = pnpm 自己拓扑排序(`shared` → `core` → 用到它们的模块);
|
|
245
|
+
- **发什么** = pnpm 按各包 `files` / `.gitignore` 打包;**打包清单没人替你核**(见上一章
|
|
246
|
+
「只能自己盯」)。要看清单用 `dsh-wb-module publish`:它只 dry-run、打印清单,不发布。
|
|
209
247
|
|
|
210
|
-
|
|
211
|
-
发布用 `pnpm publish`(不是 `npm publish`):只有 pnpm 会把 `workspace:*` 改写成真实版本,
|
|
248
|
+
发布必须走 `pnpm publish`(不是 `npm publish`):只有 pnpm 会把 `workspace:*` 改写成真实版本,
|
|
212
249
|
`npm pack` / `npm publish` 不会 —— 直接发别人装不上。
|
|
213
250
|
|
|
214
|
-
###
|
|
251
|
+
### 版本同步规则(约定 —— 门禁只守其中一条)
|
|
215
252
|
|
|
216
253
|
| 关系 | 规则 |
|
|
217
254
|
| --- | --- |
|
|
218
|
-
| 模块 ↔ 外壳 | 模块 `peerDependencies['@dsh-workbench/core'] = ^0.1.0`。**`^0.x` 锁次版本**:外壳升到 `0.2.0` 时 `^0.1.0`
|
|
255
|
+
| 模块 ↔ 外壳 | 模块 `peerDependencies['@dsh-workbench/core'] = ^0.1.0`。**`^0.x` 锁次版本**:外壳升到 `0.2.0` 时 `^0.1.0` 不再满足 —— 要把每个模块的范围一起改(或一起升)。门禁只守"peer 依赖存在"(`contracts` 判据),**范围合不合体没人替你算**,靠自觉 |
|
|
219
256
|
| `shared` ↔ 外壳/模块 | 依赖写的是 `workspace:*`,发布时会被改写成**当时那个版本号** → `shared` 必须先发;`shared` 升版后,用到它的包要重新发一次才会带上新范围 |
|
|
220
|
-
| `module-tools` ↔ `init` 模板 | 模板里 `@dsh-workbench/core` / `module-tools` 的范围要跟着本仓版本走,否则 `init`
|
|
257
|
+
| `module-tools` ↔ `init` 模板 | 模板里 `@dsh-workbench/core` / `module-tools` 的范围要跟着本仓版本走,否则 `init` 生成的是过期范围 —— **现在没有任何判据检查它**(上一版 release 脚本查过,换成现在这份之后这条没了),升外壳次版本时记得一起改 |
|
|
221
258
|
|
|
222
259
|
### 中断了怎么续跑(发布是可中断的)
|
|
223
260
|
|
|
@@ -228,7 +265,8 @@ pnpm release:resume # 从现场恢复;**已在源上的包自动跳过**
|
|
|
228
265
|
```
|
|
229
266
|
|
|
230
267
|
- **不带 `--resume` 重跑会被拒**:目标版本必须高于当前版本;源上若已有同名同版本,脚本会说"先提版本号"。这正是为续跑设计的语义(不是 bug)。
|
|
268
|
+
- **`--resume` 照样跑一遍门禁**:断了之后很可能改过包,而门禁整次发布只有 preflight 那一处。真要跳过用 `--skip-gate`(发布不会再补跑一遍)。
|
|
231
269
|
- `pnpm release:dry` 是**彩排**:改版本号 → 构建 → `publish --dry-run` → **回滚本地版本号**,不上传。
|
|
232
270
|
- 发布**成功之后**才做 git 收尾:`git add -A` → `commit -m "chore: 发布版本 v<ver>"` → `tag v<ver>` → `push` → `push origin v<ver>`。git 收尾失败时包已经发出去了,脚本会把该手打的命令打出来,并提示可以 `pnpm release:resume`。
|
|
233
|
-
- 常用旗标:`--target <ver>` 跳出版本选择 · `-y/--yes` 跳过确认 · `--allow-dirty` · `--skip-gate
|
|
271
|
+
- 常用旗标:`--target <ver>` 跳出版本选择 · `-y/--yes` 跳过确认 · `--allow-dirty` · `--skip-gate` / `--skip-rehearsal`(都不推荐) · `--skip-build`(用磁盘上现有产物 —— `prepack` 已关,不再兜底重建)。
|
|
234
272
|
- 依赖:`enquirer`(交互选择版本)与 `semver`(版本比较)是根上的 devDependencies。
|
package/docs/OPERATIONS.md
CHANGED
|
@@ -28,7 +28,28 @@
|
|
|
28
28
|
前提:`dsh` 和 `pnpm` 在 PATH 上(`dsh plugin` 是转发给 pnpm 的),
|
|
29
29
|
且 `~/.dsh/profiles/web` 已存在(跑过一次 `dsh web` 即可)。
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
**给别人用**(两条路:插件页装进他自己的 web / 独立实例 `setup`;包在公网 npm 上)见 [`HANDOFF.md`](HANDOFF.md)。
|
|
32
|
+
|
|
33
|
+
### 变体:装进**当前** profile(在 `dsh web` 里装,不起第二个实例)
|
|
34
|
+
|
|
35
|
+
`dsh web` 侧栏 **Plugins → Add plugin** → 填 `@dsh-workbench/core`(公网 npm 上有,默认源即可)
|
|
36
|
+
→ **Install → Enable now** → **刷新页面**。装的就是 `dsh web` 自己那个 profile。
|
|
37
|
+
|
|
38
|
+
**完成判据**:刷新后左栏是工作台的、右侧出现面板列;`$DSH_HOME/workbench/opencli/bin/opencli`
|
|
39
|
+
存在且指向本包 `bin/opencli-isolated`;`$DSH_HOME/workbench/bin/dsh-wb-module` 可执行
|
|
40
|
+
(这三条不再依赖启动器 —— 宿主自举写的)。
|
|
41
|
+
|
|
42
|
+
这条路上没有启动器,缺的几件由**宿主自举**补齐(建目录、写隔离 opencli 入口、前插 `PATH`、
|
|
43
|
+
后台建 DIY 工坊骨架),可写根由 bundle 层那一行 `sandbox-policy` 放行 —— 见
|
|
44
|
+
[ADR-0037](../../../docs/adr/0037-workbench-installs-into-any-profile.md)。
|
|
45
|
+
|
|
46
|
+
自举是**静默**的:它写了什么只在宿主日志里,后台脚本(工坊骨架 / 依赖)的输出在
|
|
47
|
+
`$DSH_HOME/workbench/seed.log`。DIY 那个工坊“怎么都没建起来”时先看这两个地方。
|
|
48
|
+
|
|
49
|
+
差别:**会话 / 存储不隔离**(接着用你原来那份)、**没有独立端口与进程**、
|
|
50
|
+
**改外壳源码不热重载**、DIY 工坊依赖是首次启动在后台装的(几百 MB,失败只落日志)。
|
|
51
|
+
|
|
52
|
+
撤销:Plugins 页卸载 `@dsh-workbench/core`(配置与数据不清);`~/.dsh/workbench/**` 想清就手删。
|
|
32
53
|
|
|
33
54
|
## 日常
|
|
34
55
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-workbench/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "个人工作台:Agent 工作台外壳(左栏 + 常驻对话 + 自研右侧数据面板)。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"icon": "./icon.svg",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"bin": {
|
|
23
23
|
"dsh-workbench": "./bin/dsh-workbench"
|
|
24
24
|
},
|
|
25
|
-
"//files": "npm 的兜底是 .gitignore —— 而 dist/ 在 .gitignore 里,不显式列出就会**漏掉宿主入口**(exports['.'] 指向它)。发出去之前用 npm pack --dry-run 数一遍 dist/ 有几条。skills/ 是 DIY 模式挂给 agent 的指引(经 skill-filesystem 的 customSkillDirs 挂载),漏了不报错、只是 DIY 的 agent 什么都不知道 —— selfcheck 有一条判据盯着它。",
|
|
25
|
+
"//files": "npm 的兜底是 .gitignore —— 而 dist/ 在 .gitignore 里,不显式列出就会**漏掉宿主入口**(exports['.'] 指向它)。发出去之前用 npm pack --dry-run 数一遍 dist/ 有几条。skills/ 是 DIY 模式挂给 agent 的指引(经 skill-filesystem 的 customSkillDirs 挂载),漏了不报错、只是 DIY 的 agent 什么都不知道 —— selfcheck 有一条判据盯着它。scripts/ 下是**随包出货的脚本**:启动器与宿主自举都要跑它们(seed-profile.sh / seed-workshop.sh),漏一个的症状是「仓库里怎么都对、装出去那台静默什么也没做」。",
|
|
26
26
|
"files": [
|
|
27
27
|
"dist",
|
|
28
28
|
"client.js",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"skills",
|
|
34
34
|
"preset",
|
|
35
35
|
"scripts/seed-profile.sh",
|
|
36
|
+
"scripts/seed-workshop.sh",
|
|
36
37
|
"README.md",
|
|
37
38
|
"docs/HANDOFF.md",
|
|
38
39
|
"docs/OPERATIONS.md"
|
|
@@ -81,12 +82,12 @@
|
|
|
81
82
|
"vite": "^8.3.1",
|
|
82
83
|
"vitest": "^5.0.2"
|
|
83
84
|
},
|
|
84
|
-
"//publishConfig": "
|
|
85
|
+
"//publishConfig": "只影响**发布这个包**,不影响别人解析依赖。现在发**公网 npm**(scripts/release.mjs 走 registry.npmjs.org),所以这里只有 access;哪天真要改发内网源,地址写在这一段的 registry 里(release.mjs 会优先读它)。",
|
|
85
86
|
"publishConfig": {
|
|
86
87
|
"access": "public"
|
|
87
88
|
},
|
|
88
89
|
"dependencies": {
|
|
89
|
-
"@dsh-workbench/shared": "0.1.
|
|
90
|
+
"@dsh-workbench/shared": "0.1.16"
|
|
90
91
|
},
|
|
91
92
|
"scripts": {
|
|
92
93
|
"build": "node scripts/build.mjs && node scripts/build-types.mjs",
|
|
@@ -95,7 +96,6 @@
|
|
|
95
96
|
"typecheck": "tsc --noEmit",
|
|
96
97
|
"arch": "arch-guard",
|
|
97
98
|
"selfcheck": "node scripts/selfcheck.mjs",
|
|
98
|
-
"check:host": "node scripts/check-host.mjs",
|
|
99
99
|
"check:runtimes": "node scripts/check-runtimes.mjs",
|
|
100
100
|
"check": "npm run typecheck && npm run coverage && npm run arch && npm run check:runtimes && npm run selfcheck",
|
|
101
101
|
"test": "vitest run",
|
package/scripts/seed-profile.sh
CHANGED
|
@@ -170,119 +170,10 @@ fi
|
|
|
170
170
|
|
|
171
171
|
# ── 第 6 步:建 DIY 工坊 ────────────────────────────────────────────────
|
|
172
172
|
#
|
|
173
|
-
# 工坊是 DIY 模式的落点:agent
|
|
174
|
-
#
|
|
175
|
-
#
|
|
176
|
-
|
|
177
|
-
# 为什么它是一个 pnpm workspace 而不是随便一个目录:模块要构建就得有
|
|
178
|
-
# module-tools / core / shared / react / typescript / vitest;把它做成 workspace 根,
|
|
179
|
-
# 依赖只装一次,每个模块只是 packages/ 下多一个目录。而且 module-tools 的发现逻辑
|
|
180
|
-
# 认 `pnpm-workspace.yaml`,于是模块单独跑 check 时能找到同仓的外壳(kit / standalone 两条判据
|
|
181
|
-
# 才不会静默跳过 —— 跳过等于没验)。
|
|
182
|
-
#
|
|
183
|
-
# 两个身份同 bin/dsh-workbench:**仓库副本**把三个 @dsh-workbench/* 用 link 指进本仓
|
|
184
|
-
# (改工具链立刻生效),**安装包副本**从源上按版本装。
|
|
185
|
-
DIY_DIR="$DSH_HOME/workbench/diy"
|
|
186
|
-
mkdir -p "$DIY_DIR/packages"
|
|
187
|
-
|
|
188
|
-
if [ -n "$GIT_TOP" ]; then
|
|
189
|
-
CORE_SPEC="link:$REPO_DIR"
|
|
190
|
-
TOOLS_SPEC="link:$(cd "$REPO_DIR/../module-tools" && pwd)"
|
|
191
|
-
SHARED_SPEC="link:$(cd "$REPO_DIR/../shared" && pwd)"
|
|
192
|
-
else
|
|
193
|
-
CORE_SPEC="@dsh-workbench/core@^$(node -p "require('$REPO_DIR/package.json').version" 2>/dev/null || echo 0)"
|
|
194
|
-
TOOLS_SPEC="@dsh-workbench/module-tools@^$(node -p "require('$REPO_DIR/package.json').version" 2>/dev/null || echo 0)"
|
|
195
|
-
SHARED_SPEC="@dsh-workbench/shared@^$(node -p "require('$REPO_DIR/package.json').version" 2>/dev/null || echo 0)"
|
|
196
|
-
fi
|
|
197
|
-
|
|
198
|
-
# 工坊必须**钉住自己那一代 pnpm**(与仓库根钉的同一个)。
|
|
199
|
-
#
|
|
200
|
-
# 不钉的话它用用户机器上那个 pnpm —— 实测这台是 11.21.0,而仓库钉的是 10.32.1,
|
|
201
|
-
# 而**两代的设置住址与键名都不一样**:`store-dir` 在 pnpm 10 从 `.npmrc` 读、
|
|
202
|
-
# 在 pnpm 11 只认 `pnpm-workspace.yaml` 里的 `storeDir`;放行依赖构建的键
|
|
203
|
-
# 在 pnpm 10 是 `onlyBuiltDependencies`、11 是 `allowBuilds`(11 还会往
|
|
204
|
-
# pnpm-workspace.yaml 里写一行 `esbuild: set this to true or false` 占位)。
|
|
205
|
-
# 结果是同一份工坊配置在这台机器上对、在另一台上错,而且错法都是静默或半静默的。
|
|
206
|
-
# 钉了之后两边一致,且这一整轮验证过的就是这一代。
|
|
207
|
-
PNPM_PIN=""
|
|
208
|
-
if [ -n "$GIT_TOP" ] && [ -f "$GIT_TOP/package.json" ]; then
|
|
209
|
-
PNPM_PIN="$(node -p "require('$GIT_TOP/package.json').packageManager || ''" 2>/dev/null || true)"
|
|
210
|
-
fi
|
|
211
|
-
PNPM_PIN="${PNPM_PIN:-pnpm@10.32.1}"
|
|
212
|
-
|
|
213
|
-
if [ -f "$DIY_DIR/package.json" ]; then
|
|
214
|
-
echo "→ DIY 工坊已存在,跳过建骨架(要重来就先删掉 $DIY_DIR)"
|
|
215
|
-
else
|
|
216
|
-
echo "→ 建 DIY 工坊 $DIY_DIR"
|
|
217
|
-
cat >"$DIY_DIR/package.json" <<EOF
|
|
218
|
-
{
|
|
219
|
-
"name": "dsh-workbench-diy",
|
|
220
|
-
"version": "0.0.0",
|
|
221
|
-
"private": true,
|
|
222
|
-
"description": "DIY 工坊:工作台模块在这里造。这个目录由 dsh-workbench 的 setup 生成,手改会被覆盖。",
|
|
223
|
-
"packageManager": "$PNPM_PIN",
|
|
224
|
-
"devDependencies": {
|
|
225
|
-
"@dsh-workbench/core": "$CORE_SPEC",
|
|
226
|
-
"@dsh-workbench/module-tools": "$TOOLS_SPEC",
|
|
227
|
-
"@dsh-workbench/shared": "$SHARED_SPEC",
|
|
228
|
-
"@types/node": "^24.19.0",
|
|
229
|
-
"@types/react": "^19.3.0",
|
|
230
|
-
"esbuild": "^0.28.2",
|
|
231
|
-
"react": "^19.3.0",
|
|
232
|
-
"typescript": "5.9",
|
|
233
|
-
"vitest": "^5.0.2"
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
EOF
|
|
237
|
-
cat >"$DIY_DIR/pnpm-workspace.yaml" <<'EOF'
|
|
238
|
-
packages:
|
|
239
|
-
- "packages/*"
|
|
240
|
-
|
|
241
|
-
# esbuild 的构建脚本要放行:pnpm 默认不跑依赖的 postinstall,而模块的构建就是 esbuild。
|
|
242
|
-
# 不放行的话每次 install 都会打一行
|
|
243
|
-
# `[ERR_PNPM_IGNORED_BUILDS] Ignored build scripts: esbuild@0.28.2` —— 看着像失败,
|
|
244
|
-
# 其实退出码是 0(实测踩过)。
|
|
245
|
-
# 钉在 10.32.1 之后这个键名是对的(同一代 pnpm 也从 package.json 的 `pnpm` 段读它,
|
|
246
|
-
# 仓库根就是这么放的);换 pnpm 11 会变成 `allowBuilds`,所以上面那句「钉住 pnpm」是前提。
|
|
247
|
-
onlyBuiltDependencies:
|
|
248
|
-
- esbuild
|
|
249
|
-
EOF
|
|
250
|
-
cat >"$DIY_DIR/.npmrc" <<EOF
|
|
251
|
-
# 工坊自己的 store 与 cache。
|
|
252
|
-
#
|
|
253
|
-
# 为什么必须指进来:agent 的 shell 跑在**会话沙箱**里,可写根就是会话 cwd(= 这个目录)。
|
|
254
|
-
# 而 pnpm 默认的 store(例如 ~/Library/pnpm/store/v10)与 npm 默认的 cache(~/.npm)
|
|
255
|
-
# 都在可写根**之外** —— 不指进来的话,agent 在会话里跑一次 pnpm install 会被沙箱拒(EPERM),
|
|
256
|
-
# 而"给模块加一个依赖"只有这一条路。setup 时的安装由人跑,不受沙箱限制,但用的也是这份配置,
|
|
257
|
-
# 于是装一次之后 agent 那边也能继续装。
|
|
258
|
-
store-dir=$DIY_DIR/.pnpm-store
|
|
259
|
-
cache-dir=$DIY_DIR/.npm-cache
|
|
260
|
-
EOF
|
|
261
|
-
cat >"$DIY_DIR/README.md" <<'EOF'
|
|
262
|
-
# DIY 工坊
|
|
263
|
-
|
|
264
|
-
工作台模块在这里造。**一个模块一个目录**,都住在 `packages/` 下。
|
|
265
|
-
|
|
266
|
-
- 这个目录是「DIY 会话」的工作目录 —— 在对话里让 agent 造模块,它就写在这里。
|
|
267
|
-
- 依赖已经装好(`@dsh-workbench/core` / `module-tools` / `shared` / react / typescript / vitest)。
|
|
268
|
-
- 造一个新模块:`dsh-wb-module init <名字> --dir packages/module-<名字>`
|
|
269
|
-
- 每个模块自己的四件事:`pnpm build` / `pnpm typecheck` / `pnpm test` / `pnpm selfcheck`,
|
|
270
|
-
外加 `dsh-wb-module check` 的十条判据。
|
|
271
|
-
|
|
272
|
-
不要手改这个目录下的 `package.json` / `pnpm-workspace.yaml` / `.npmrc`:
|
|
273
|
-
它们是 `dsh-workbench setup` 生成的,模块要加依赖就加在**模块自己**的 `package.json` 里。
|
|
274
|
-
EOF
|
|
275
|
-
fi
|
|
276
|
-
|
|
277
|
-
if [ -d "$DIY_DIR/node_modules" ]; then
|
|
278
|
-
echo "→ 工坊依赖已装,跳过"
|
|
279
|
-
elif ! command -v pnpm >/dev/null 2>&1; then
|
|
280
|
-
echo "→ ⚠️ PATH 上没有 pnpm,工坊依赖没装。装好 pnpm 后跑一次:" >&2
|
|
281
|
-
echo " cd $DIY_DIR && pnpm install" >&2
|
|
282
|
-
else
|
|
283
|
-
echo "→ 装工坊依赖(第一次会下载 react / typescript / vitest,几百 MB,之后不再下)"
|
|
284
|
-
(cd "$DIY_DIR" && pnpm install 2>&1 | tail -6)
|
|
285
|
-
fi
|
|
173
|
+
# 工坊是 DIY 模式的落点:agent 在那里造模块(一个模块一个目录),而 **DIY 会话的 cwd 就是它**。
|
|
174
|
+
# 骨架 + 依赖 + 稳定入口都交给 `scripts/seed-workshop.sh` —— 启动器(bin/dsh-workbench)
|
|
175
|
+
# 每次启动也调它(幂等),所以"干净机器上工坊是空的"这件事不再需要人来处理。
|
|
176
|
+
bash "$REPO_DIR/scripts/seed-workshop.sh"
|
|
286
177
|
|
|
287
178
|
# 装 bundle 的目标:开发态是这个仓库(link),安装包态是源上那个包。
|
|
288
179
|
# 判据是「git 顶层在不在」—— npm pack 的产物里不含 .git(见 package.json 的 files)。
|