@dsh-workbench/core 0.1.15 → 0.1.17
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 +5 -1
- package/client.js +660 -128
- package/cordis.patch.yml +22 -0
- package/dist/client/client.body.js +660 -128
- package/dist/client/index.js +660 -128
- package/dist/host/index.js +1733 -324
- package/dist/types/app/client.d.ts +124 -9
- package/dist/types/app/layouts/market/add-module-text.d.ts +2 -0
- package/dist/types/app/layouts/market/use-add-module.d.ts +4 -3
- package/dist/types/app/layouts/market/use-module-versions.d.ts +2 -0
- package/dist/types/app/layouts/rightbar/MarketView.d.ts +3 -1
- package/dist/types/app/layouts/rightbar/__tests__/market-rows-plugins.test.d.ts +1 -0
- package/dist/types/app/layouts/rightbar/market-mock.d.ts +9 -0
- package/dist/types/app/layouts/rightbar/market-plugin-rows.d.ts +8 -0
- package/dist/types/app/layouts/rightbar/market-rows.d.ts +14 -3
- package/dist/types/app/layouts/rightbar/registry.d.ts +0 -1
- package/dist/types/app/units/__tests__/manifests.test.d.ts +1 -0
- package/dist/types/app/units/fixture-unit-mock.d.ts +3 -3
- package/dist/types/app/units/host.d.ts +2 -2
- package/dist/types/app/units/manifests.d.ts +5 -0
- package/dist/types/app/units/registry.d.ts +10 -2
- package/dist/types/modules/panels/__tests__/market-env.test.d.ts +1 -0
- package/dist/types/modules/panels/__tests__/market-plugin.test.d.ts +1 -0
- package/dist/types/modules/panels/__tests__/market-route.test.d.ts +1 -0
- package/dist/types/modules/panels/__tests__/plugin-actions.test.d.ts +1 -0
- package/dist/types/modules/panels/__tests__/plugin-ledger.test.d.ts +1 -0
- package/dist/types/modules/panels/__tests__/plugin-section.test.d.ts +1 -0
- package/dist/types/modules/panels/__tests__/scope.test.d.ts +1 -0
- package/dist/types/modules/panels/__tests__/service-release.test.d.ts +1 -0
- package/dist/types/modules/panels/index.d.ts +2 -2
- package/dist/types/modules/panels/model/config.d.ts +27 -9
- package/dist/types/modules/panels/model/market-dispatch.d.ts +9 -0
- package/dist/types/modules/panels/model/market-env.d.ts +20 -0
- package/dist/types/modules/panels/model/market-route.d.ts +26 -0
- package/dist/types/modules/panels/model/market-types.d.ts +71 -0
- package/dist/types/modules/panels/model/market.d.ts +7 -66
- package/dist/types/modules/panels/model/plugin-actions.d.ts +50 -0
- package/dist/types/modules/panels/model/plugin-ledger.d.ts +22 -0
- package/dist/types/modules/panels/model/plugin-name.d.ts +8 -0
- package/dist/types/modules/panels/model/plugin-name.test.d.ts +1 -0
- package/dist/types/modules/panels/model/plugin-section.d.ts +13 -0
- package/dist/types/modules/panels/model/service.d.ts +8 -6
- package/dist/types/shared/api/bundle-install.d.ts +8 -1
- package/dist/types/shared/api/host/__tests__/registry-declaration.test.d.ts +1 -0
- package/dist/types/shared/api/host/__tests__/unit-roster-facts.test.d.ts +1 -0
- package/dist/types/shared/api/host/bundle-routes.d.ts +1 -0
- package/dist/types/shared/api/host/installed-module.d.ts +7 -0
- package/dist/types/shared/api/host/mount-units.d.ts +5 -3
- package/dist/types/shared/api/host/package-content.d.ts +6 -0
- package/dist/types/shared/api/host/package-content.test.d.ts +1 -0
- package/dist/types/shared/api/host/package-kind.d.ts +21 -0
- package/dist/types/shared/api/host/package-kind.test.d.ts +1 -0
- package/dist/types/shared/api/host/package-route.d.ts +23 -0
- package/dist/types/shared/api/host/package-route.test.d.ts +1 -0
- package/dist/types/shared/api/host/registry-declaration.d.ts +23 -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/dist/types/shared/api/host/unit-registry.d.ts +33 -4
- package/dist/types/shared/api/host/unit-roster-facts.d.ts +5 -0
- package/dist/types/shared/api/installed-plugins.d.ts +12 -0
- package/dist/types/shared/api/unit-manifests.d.ts +5 -0
- package/dist/types/shared/api/unit-manifests.test.d.ts +1 -0
- package/dist/types/shared/hooks/bundle-queries.d.ts +2 -0
- package/dist/types/shared/hooks/use-facts.d.ts +1 -0
- package/docs/HANDOFF.md +82 -44
- package/docs/OPERATIONS.md +22 -1
- package/package.json +5 -4
- package/scripts/seed-workshop.sh +216 -0
- package/skills/workbench-module-diy/BUILD.md +5 -5
- package/skills/workbench-module-diy/DESIGN.md +7 -1
- package/skills/workbench-module-diy/REVIEW.md +3 -2
- package/skills/workbench-module-diy/TOOLING.md +2 -2
- package/skills/workbench-module-diy/TOOLS.md +9 -2
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# DIY 工坊:骨架 + 稳定入口(`dsh-wb-module`)。
|
|
4
|
+
#
|
|
5
|
+
# 由两处共用,所以逻辑只有**一份**:
|
|
6
|
+
# · `seed-profile.sh`(= `dsh-workbench setup`)—— 第一次把工坊建起来、装依赖;
|
|
7
|
+
# · `bin/dsh-workbench`(每次启动)—— 入口每次重写一遍(幂等),骨架不在才自愈。
|
|
8
|
+
#
|
|
9
|
+
# 为什么启动器要自愈而不是只提醒:干净机器上 agent 进工坊第一件事就是 build / check,
|
|
10
|
+
# 而"不在 workspace 里"报出来的话指着别处(实测卡在这一步,它读到的像是"模板写错了")。
|
|
11
|
+
# 提醒是对人的;agent 读不到那句提醒。
|
|
12
|
+
#
|
|
13
|
+
# 用法:
|
|
14
|
+
# bash scripts/seed-workshop.sh # 完整:骨架(缺才建)+ overrides + 依赖(缺才装)+ 入口
|
|
15
|
+
# bash scripts/seed-workshop.sh entry # 只写入口(每次启动用;别的都不碰)
|
|
16
|
+
#
|
|
17
|
+
# 幂等:存在的文件不覆盖、依赖在就跳过安装、重复跑不产生副作用。
|
|
18
|
+
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
|
|
21
|
+
DSH_HOME="${DSH_HOME:-$HOME/.dsh}"
|
|
22
|
+
SELF="${BASH_SOURCE[0]}"
|
|
23
|
+
while [ -L "$SELF" ]; do
|
|
24
|
+
SELF="$(cd "$(dirname "$SELF")" && pwd -P)/$(readlink "$SELF")"
|
|
25
|
+
done
|
|
26
|
+
REPO_DIR="$(cd "$(dirname "$SELF")/.." && pwd -P)"
|
|
27
|
+
GIT_TOP="$(git -C "$REPO_DIR" rev-parse --show-toplevel 2>/dev/null || true)"
|
|
28
|
+
MODE="${1:-skeleton}"
|
|
29
|
+
|
|
30
|
+
# ── 这份副本到底是"仓库副本"还是"装出来的副本" ──────────────────────────────
|
|
31
|
+
#
|
|
32
|
+
# `git rev-parse --show-toplevel` 只是"往上第一个 .git"——**装出来的副本也可能落在别人的
|
|
33
|
+
# 仓库下面**。实测:`DSH_HOME` 恰好在某个 git 仓库里时(开发机上就是本仓),
|
|
34
|
+
# `<profile>/node_modules/@dsh-workbench/core` 一路往上找到了那个仓库,于是这份副本被当成
|
|
35
|
+
# 仓库副本,去 link 一个不存在的 `../module-tools`,脚本当场死在 `cd` 上 —— 而它是**后台**
|
|
36
|
+
# 被拉起来的(宿主自举 / 启动器),症状就是"工坊怎么都没建起来,一声不响"。
|
|
37
|
+
#
|
|
38
|
+
# 所以认仓库要认**本仓的形状**:根上同时有 packages/workbench 与 packages/module-tools。
|
|
39
|
+
if [ -n "$GIT_TOP" ] && [ -f "$GIT_TOP/packages/workbench/package.json" ] &&
|
|
40
|
+
[ -f "$GIT_TOP/packages/module-tools/package.json" ]; then
|
|
41
|
+
IN_REPO=1
|
|
42
|
+
else
|
|
43
|
+
IN_REPO=0
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# ── 稳定入口:$DSH_HOME/workbench/bin/dsh-wb-module ──────────────────────────
|
|
47
|
+
#
|
|
48
|
+
# 为什么要它:指引让 agent 写 `pnpm exec dsh-wb-module …`(到处都对,但它依赖 cwd 在工坊里、
|
|
49
|
+
# 且那句 pnpm 前缀每次都要写对)。这里给一个**与 cwd 无关**的同名入口,启动器把它
|
|
50
|
+
# 挂进 PATH —— 于是"在工坊里"和"在别的目录里"都叫得动同一个工具链。
|
|
51
|
+
#
|
|
52
|
+
# 转发脚本而不是软链:同 `bin/opencli-isolated` 那条坑 —— pnpm publish 之后包里的脚本没有 x 位,
|
|
53
|
+
# 软链过去一执行就是 Permission denied。x 位由 chmod 当场给。
|
|
54
|
+
# ⚠️ 先 rm -f:旧版本留下的软链还在时,`>` 会顺着软链把真脚本覆盖掉。
|
|
55
|
+
ENTRY_DIR="$DSH_HOME/workbench/bin"
|
|
56
|
+
mkdir -p "$ENTRY_DIR"
|
|
57
|
+
rm -f "$ENTRY_DIR/dsh-wb-module"
|
|
58
|
+
cat >"$ENTRY_DIR/dsh-wb-module" <<EOF
|
|
59
|
+
#!/bin/sh
|
|
60
|
+
BIN="$DSH_HOME/workbench/diy/node_modules/.bin/dsh-wb-module"
|
|
61
|
+
if [ -x "\$BIN" ]; then exec "\$BIN" "\$@"; fi
|
|
62
|
+
if command -v pnpm >/dev/null 2>&1; then
|
|
63
|
+
exec pnpm --dir "$DSH_HOME/workbench/diy" exec dsh-wb-module "\$@"
|
|
64
|
+
fi
|
|
65
|
+
echo "dsh-wb-module: 工坊的依赖还没装 —— 先跑 dsh-workbench setup" >&2
|
|
66
|
+
exit 127
|
|
67
|
+
EOF
|
|
68
|
+
chmod +x "$ENTRY_DIR/dsh-wb-module"
|
|
69
|
+
|
|
70
|
+
if [ "$MODE" = "entry" ]; then
|
|
71
|
+
echo "→ DIY 工坊入口:$ENTRY_DIR/dsh-wb-module"
|
|
72
|
+
exit 0
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
# ── 第 6 步:建 DIY 工坊 ────────────────────────────────────────────────
|
|
76
|
+
#
|
|
77
|
+
# 工坊是 DIY 模式的落点:agent 在那里造模块(一个模块一个目录),
|
|
78
|
+
# 而 **DIY 会话的 cwd 就是它** —— dsh 的沙箱把"会话 cwd"当作 workspace-write 的边界,
|
|
79
|
+
# 所以源码写在工坊里天然放行,不需要给用户开 danger-full-access。
|
|
80
|
+
#
|
|
81
|
+
# 为什么它是一个 pnpm workspace 而不是随便一个目录:模块要构建就得有
|
|
82
|
+
# module-tools / core / shared / react / typescript / vitest;把它做成 workspace 根,
|
|
83
|
+
# 依赖只装一次,每个模块只是 packages/ 下多一个目录。而且 module-tools 的发现逻辑
|
|
84
|
+
# 认 `pnpm-workspace.yaml`,于是模块单独跑 check 时能找到同仓的外壳(kit / standalone 两条判据
|
|
85
|
+
# 才不会静默跳过 —— 跳过等于没验)。
|
|
86
|
+
#
|
|
87
|
+
# 两个身份同 bin/dsh-workbench:**仓库副本**把三个 @dsh-workbench/* 用 link 指进本仓
|
|
88
|
+
# (改工具链立刻生效),**安装包副本**从源上按版本装。
|
|
89
|
+
DIY_DIR="$DSH_HOME/workbench/diy"
|
|
90
|
+
mkdir -p "$DIY_DIR/packages"
|
|
91
|
+
|
|
92
|
+
if [ "$IN_REPO" = "1" ]; then
|
|
93
|
+
CORE_SPEC="link:$REPO_DIR"
|
|
94
|
+
TOOLS_SPEC="link:$(cd "$REPO_DIR/../module-tools" && pwd)"
|
|
95
|
+
SHARED_SPEC="link:$(cd "$REPO_DIR/../shared" && pwd)"
|
|
96
|
+
else
|
|
97
|
+
CORE_SPEC="@dsh-workbench/core@^$(node -p "require('$REPO_DIR/package.json').version" 2>/dev/null || echo 0)"
|
|
98
|
+
TOOLS_SPEC="@dsh-workbench/module-tools@^$(node -p "require('$REPO_DIR/package.json').version" 2>/dev/null || echo 0)"
|
|
99
|
+
SHARED_SPEC="@dsh-workbench/shared@^$(node -p "require('$REPO_DIR/package.json').version" 2>/dev/null || echo 0)"
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# 工坊必须**钉住自己那一代 pnpm**(与仓库根钉的同一个)。
|
|
103
|
+
#
|
|
104
|
+
# 不钉的话它用用户机器上那个 pnpm —— 实测这台是 11.21.0,而仓库钉的是 10.32.1,
|
|
105
|
+
# 而**两代的设置住址与键名都不一样**:`store-dir` 在 pnpm 10 从 `.npmrc` 读、
|
|
106
|
+
# 在 pnpm 11 只认 `pnpm-workspace.yaml` 里的 `storeDir`;放行依赖构建的键
|
|
107
|
+
# 在 pnpm 10 是 `onlyBuiltDependencies`、11 是 `allowBuilds`(11 还会往
|
|
108
|
+
# pnpm-workspace.yaml 里写一行 `esbuild: set this to true or false` 占位)。
|
|
109
|
+
# 结果是同一份工坊配置在这台机器上对、在另一台上错,而且错法都是静默或半静默的。
|
|
110
|
+
# 钉了之后两边一致,且这一整轮验证过的就是这一代。
|
|
111
|
+
PNPM_PIN=""
|
|
112
|
+
if [ "$IN_REPO" = "1" ] && [ -f "$GIT_TOP/package.json" ]; then
|
|
113
|
+
PNPM_PIN="$(node -p "require('$GIT_TOP/package.json').packageManager || ''" 2>/dev/null || true)"
|
|
114
|
+
fi
|
|
115
|
+
PNPM_PIN="${PNPM_PIN:-pnpm@10.32.1}"
|
|
116
|
+
|
|
117
|
+
if [ -f "$DIY_DIR/package.json" ]; then
|
|
118
|
+
echo "→ DIY 工坊已存在,跳过建骨架(要重来就先删掉 ${DIY_DIR})"
|
|
119
|
+
else
|
|
120
|
+
echo "→ 建 DIY 工坊 $DIY_DIR"
|
|
121
|
+
cat >"$DIY_DIR/package.json" <<EOF
|
|
122
|
+
{
|
|
123
|
+
"name": "dsh-workbench-diy",
|
|
124
|
+
"version": "0.0.0",
|
|
125
|
+
"private": true,
|
|
126
|
+
"description": "DIY 工坊:工作台模块在这里造。这个目录由 dsh-workbench 的 setup 生成,手改会被覆盖。",
|
|
127
|
+
"packageManager": "$PNPM_PIN",
|
|
128
|
+
"devDependencies": {
|
|
129
|
+
"@dsh-workbench/core": "$CORE_SPEC",
|
|
130
|
+
"@dsh-workbench/module-tools": "$TOOLS_SPEC",
|
|
131
|
+
"@dsh-workbench/shared": "$SHARED_SPEC",
|
|
132
|
+
"@types/node": "^24.19.0",
|
|
133
|
+
"@types/react": "^19.3.0",
|
|
134
|
+
"esbuild": "^0.28.2",
|
|
135
|
+
"react": "^19.3.0",
|
|
136
|
+
"typescript": "5.9",
|
|
137
|
+
"vitest": "^5.0.2"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
EOF
|
|
141
|
+
cat >"$DIY_DIR/pnpm-workspace.yaml" <<'EOF'
|
|
142
|
+
packages:
|
|
143
|
+
- "packages/*"
|
|
144
|
+
|
|
145
|
+
# esbuild 的构建脚本要放行:pnpm 默认不跑依赖的 postinstall,而模块的构建就是 esbuild。
|
|
146
|
+
# 不放行的话每次 install 都会打一行
|
|
147
|
+
# `[ERR_PNPM_IGNORED_BUILDS] Ignored build scripts: esbuild@0.28.2` —— 看着像失败,
|
|
148
|
+
# 其实退出码是 0(实测踩过)。
|
|
149
|
+
# 钉在 10.32.1 之后这个键名是对的(同一代 pnpm 也从 package.json 的 `pnpm` 段读它,
|
|
150
|
+
# 仓库根就是这么放的);换 pnpm 11 会变成 `allowBuilds`,所以上面那句「钉住 pnpm」是前提。
|
|
151
|
+
onlyBuiltDependencies:
|
|
152
|
+
- esbuild
|
|
153
|
+
EOF
|
|
154
|
+
cat >"$DIY_DIR/.npmrc" <<EOF
|
|
155
|
+
# 工坊自己的 store 与 cache。
|
|
156
|
+
#
|
|
157
|
+
# 为什么必须指进来:agent 的 shell 跑在**会话沙箱**里,可写根就是会话 cwd(= 这个目录)。
|
|
158
|
+
# 而 pnpm 默认的 store(例如 ~/Library/pnpm/store/v10)与 npm 默认的 cache(~/.npm)
|
|
159
|
+
# 都在可写根**之外** —— 不指进来的话,agent 在会话里跑一次 pnpm install 会被沙箱拒(EPERM),
|
|
160
|
+
# 而"给模块加一个依赖"只有这一条路。setup 时的安装由人跑,不受沙箱限制,但用的也是这份配置,
|
|
161
|
+
# 于是装一次之后 agent 那边也能继续装。
|
|
162
|
+
store-dir=$DIY_DIR/.pnpm-store
|
|
163
|
+
cache-dir=$DIY_DIR/.npm-cache
|
|
164
|
+
EOF
|
|
165
|
+
cat >"$DIY_DIR/README.md" <<'EOF'
|
|
166
|
+
# DIY 工坊
|
|
167
|
+
|
|
168
|
+
工作台模块在这里造。**一个模块一个目录**,都住在 `packages/` 下。
|
|
169
|
+
|
|
170
|
+
- 这个目录是「DIY 会话」的工作目录 —— 在对话里让 agent 造模块,它就写在这里。
|
|
171
|
+
- 依赖已经装好(`@dsh-workbench/core` / `module-tools` / `shared` / react / typescript / vitest)。
|
|
172
|
+
- 造一个新模块:`dsh-wb-module init <名字> --dir packages/module-<名字>`
|
|
173
|
+
(`dsh-wb-module` 挂在 PATH 上、与 cwd 无关;写成 `pnpm exec dsh-wb-module …` 也对)
|
|
174
|
+
- 每个模块自己的四件事:`pnpm build` / `pnpm typecheck` / `pnpm test` / `pnpm selfcheck`,
|
|
175
|
+
外加 `dsh-wb-module check` 的十条判据。
|
|
176
|
+
|
|
177
|
+
不要手改这个目录下的 `package.json` / `pnpm-workspace.yaml` / `.npmrc`:
|
|
178
|
+
它们是 `dsh-workbench setup` 生成的,模块要加依赖就加在**模块自己**的 `package.json` 里。
|
|
179
|
+
EOF
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
# 工坊里只该有**一份** `@dsh-workbench/*` —— 模块自己声明的 `^0.1.x` 也算。
|
|
183
|
+
#
|
|
184
|
+
# 不钉的话 pnpm 会给每个模块**另装一份来源上的包**,于是同一个工坊里两代工具链并存:
|
|
185
|
+
# 模块自己的 `pnpm build` / `pnpm exec dsh-wb-module` 用的是源上那份(模板、判据、报错都是旧的,
|
|
186
|
+
# `init --template diy` 还会直接报"模板不存在"),而工坊根 `.bin/dsh-wb-module` 是 link 到本仓那份;
|
|
187
|
+
# `check --only kit` 比的也会是那份旧外壳(实测:0.1.13 与 0.1.14 两台工具并存,全程一声不响)。
|
|
188
|
+
#
|
|
189
|
+
# 用 pnpm 的 overrides 而不是改模块模板:模板里写死 link 路径会把"装到别人机器上"这条弄坏,
|
|
190
|
+
# overrides 活在**这个工坊**里,模块的 package.json 仍旧是干净的 `^0.1.x`。
|
|
191
|
+
# 放在第一次 `pnpm install` **之前**,这样一次装就是对的;已存在的工坊再跑一次 setup 也会被修好。
|
|
192
|
+
if [ "$IN_REPO" = "1" ] && [ -f "$DIY_DIR/package.json" ]; then
|
|
193
|
+
node - "$DIY_DIR/package.json" "$CORE_SPEC" "$TOOLS_SPEC" "$SHARED_SPEC" <<'NODE'
|
|
194
|
+
const [file, core, tools, shared] = process.argv.slice(2);
|
|
195
|
+
const fs = require('node:fs');
|
|
196
|
+
const manifest = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
197
|
+
manifest.pnpm = {
|
|
198
|
+
overrides: {
|
|
199
|
+
'@dsh-workbench/core': core,
|
|
200
|
+
'@dsh-workbench/module-tools': tools,
|
|
201
|
+
'@dsh-workbench/shared': shared,
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
fs.writeFileSync(file, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
205
|
+
NODE
|
|
206
|
+
fi
|
|
207
|
+
|
|
208
|
+
if [ -d "$DIY_DIR/node_modules" ]; then
|
|
209
|
+
echo "→ 工坊依赖已装,跳过"
|
|
210
|
+
elif ! command -v pnpm >/dev/null 2>&1; then
|
|
211
|
+
echo "→ ⚠️ PATH 上没有 pnpm,工坊依赖没装。装好 pnpm 后跑一次:" >&2
|
|
212
|
+
echo " cd $DIY_DIR && pnpm install" >&2
|
|
213
|
+
else
|
|
214
|
+
echo "→ 装工坊依赖(第一次会下载 react / typescript / vitest,几百 MB,之后不再下)"
|
|
215
|
+
(cd "$DIY_DIR" && pnpm install 2>&1 | tail -6)
|
|
216
|
+
fi
|
|
@@ -46,7 +46,7 @@ pnpm exec dsh-wb-module init <unit> --dir <工坊>/packages/module-<unit> --temp
|
|
|
46
46
|
`<unit>` 是小写短横线标识(如 `my-thing`),它同时是单元 id、包名后缀、卡片样式前缀。
|
|
47
47
|
**它必须全局唯一** —— 和工作台里其它模块、和外壳里已有的单元都不能撞;撞了装上去当场抛。
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
生成的骨架是**能直接跑的**(十一条判据 + 三个脚本开箱全绿;门禁还在,模板改坏了当场报)。
|
|
50
50
|
|
|
51
51
|
**两个模板,按需要挑**(加 `--template <名字>`):
|
|
52
52
|
|
|
@@ -61,7 +61,7 @@ pnpm exec dsh-wb-module init <unit> --dir <工坊>/packages/module-<unit> --temp
|
|
|
61
61
|
|
|
62
62
|
| 文件 | 职责 |
|
|
63
63
|
|---|---|
|
|
64
|
-
| `package.json` | 自述清单:包名、`dsh.bundle.patch`、`dsh.client`、`dsh.workbench.unit
|
|
64
|
+
| `package.json` | 自述清单:包名、`dsh.bundle.patch`、`dsh.client`、`dsh.workbench.unit`、`dsh.workbenchFaces{host,client}`(工具链字段,**不在协议里**,但门禁必填)、四个脚本、peer 依赖 |
|
|
65
65
|
| `cordis.patch.yml` | 把自己插进 profile 的那一行 |
|
|
66
66
|
| `src/host.ts` | 宿主面:`manifest` + `mount()`(路由 / 工具) |
|
|
67
67
|
| `src/client.tsx` | 浏览器面:`manifest` + `card` |
|
|
@@ -85,7 +85,7 @@ README 里 `<!-- dsh-wb:design:start/end -->` 之间那一段**由它生成**(
|
|
|
85
85
|
|
|
86
86
|
```bash
|
|
87
87
|
dsh-wb-module build # 出 client.js 与 dist/host.js
|
|
88
|
-
dsh-wb-module check #
|
|
88
|
+
dsh-wb-module check # 十一条判据,全跑
|
|
89
89
|
dsh-wb-module check --only cards # 单跑一条(contracts / bundles / source / primitives /
|
|
90
90
|
# kit / cards / standalone / markers / alias / style)
|
|
91
91
|
```
|
|
@@ -104,13 +104,13 @@ pnpm test # vitest
|
|
|
104
104
|
pnpm selfcheck # 构建 + 把 client.js 当加载器跑一遍(`diy` 骨架里还多一条 `design check`)
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
-
**自己的门禁自己过,红了别抛给用户。**
|
|
107
|
+
**自己的门禁自己过,红了别抛给用户。** 十一条判据在 [REVIEW.md](REVIEW.md) 里逐条翻了人话。
|
|
108
108
|
⚠️ **`check` 不替你跑 `pnpm test`**(它只看形状与产物):状态级的渲染、换算、边界都在你自己的
|
|
109
109
|
`test` 里 —— 骨架开箱就带一份,改了数据源与渲染就顺手把它跑一遍,别让红线留在包里。
|
|
110
110
|
⚠️ **工坊里恒有两条是「不适用」,那不是「通过」**:`独立构建` 扫的是 `packages/*` 里的外壳源码
|
|
111
111
|
(工坊里没有),`公开包无内部标识` 只扫要发出去的包(DIY 模块一律 `private`)。汇总行下面会把
|
|
112
112
|
这次没查的那几条逐条列出来;**要验它们,回工作台仓库根跑一次 `dsh-wb-module check`**。
|
|
113
|
-
所以「8 通过 · 2
|
|
113
|
+
所以「8 通过 · 2 不适用」不等于十一条全绿 —— 别把这句话念给用户听。
|
|
114
114
|
|
|
115
115
|
装上板那一步不是命令,是一把 agent 工具:`workbench_diy`(`action=list` 看工坊里有什么、`action=status, unit=<单元 id>`
|
|
116
116
|
看它现在走到哪一步、`action=install` 装上并上板、`action=open` 只上板)—— 见 §7。
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
- 门禁是绿的 —— 那是 agent 自己的门槛,不用他关心。
|
|
84
84
|
- 下次他再说一句"改一下",不用从头问:设计留下的记录还在。
|
|
85
85
|
|
|
86
|
-
## 5 落点:`design.json
|
|
86
|
+
## 5 落点:`design.json`(设计底稿:人话一处,机器字段在清单)
|
|
87
87
|
|
|
88
88
|
三张表 + 状态矩阵 + 数据源记录 + 验收清单住在模块根目录的 `design.json`,README 里那一段**由它生成**
|
|
89
89
|
(夹在 `<!-- dsh-wb:design:start/end -->` 之间,别手改 —— 下一次 `check` 会判红):
|
|
@@ -100,6 +100,12 @@ key 固定 `idle|loading|ready|empty|unreadable`)+ `config[]` + `capabilities[
|
|
|
100
100
|
`config` / `capabilities` **允许空数组**("这份模块故意没有能力"是一种决定);其余空着就是没定的事。
|
|
101
101
|
`link` 这类**可选格**留空渲染成 `—`,不算空格。
|
|
102
102
|
|
|
103
|
+
`design.json` 是**设计底稿**:只装人话。"这条能力在哪些工作区出现"**哪里都别写** ——
|
|
104
|
+
它既不在底稿、也不在清单:那是**用户**的事(他在 `workbench_panels` 里决定,见 [TOOLS.md](TOOLS.md) §12)。
|
|
105
|
+
协议里那个 `scope`(`tools[].scope` / `card.scope`)**已经删掉**:用户口径是「模块开发者不能定义 scope,
|
|
106
|
+
scope 永远是用户来决定的」(见 [ADR-0038 §2.4 / §6.16](../../../../docs/adr/0038-module-declaration-protocol.md))。
|
|
107
|
+
`contracts` 只拿名字把底稿与清单对起来(键集合对账)。
|
|
108
|
+
|
|
103
109
|
五态那五行是矩阵的行,**不能省**;但某一态对这份模块确实不适用时,写一句为什么就行 ——
|
|
104
110
|
`{ "key": "idle", "na": "读的是账号,不随项目变:没选项目时这张卡压根不渲染" }`,
|
|
105
111
|
那一行不填 `sees` / `canDo` / `agentCan`,表里渲染成「(这份模块不适用)…」。
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 门禁红了怎么办:十一条判据的人话对照表
|
|
2
2
|
|
|
3
3
|
跑 `dsh-wb-module check`(或单跑一条 `--only <名字>`)。
|
|
4
4
|
**每一条红的都在讲一件真出过事的事**,不是形式主义。红了就照下面修,别抛给用户。
|
|
5
5
|
|
|
6
6
|
| 判据 | 它防的事故 | 红了的典型说法 | 怎么修 |
|
|
7
7
|
|---|---|---|---|
|
|
8
|
-
| `contracts` | dsh 组合阶段**不校验**你 `package.json` 里的声明 —— 错的 `external` 要到浏览器 `require`
|
|
8
|
+
| `contracts` | dsh 组合阶段**不校验**你 `package.json` 里的声明 —— 错的 `external` 要到浏览器 `require` 那一刻才炸;清单与代码、底稿与清单之间漂了也没人拦 | `单元 id "x" 与 … 撞了` / `dsh.workbenchFaces.client 指的文件不存在` / `dsh.workbenchFaces.host 没声明` / `没有对 @dsh-workbench/core 的 peer 依赖` / `没有 typecheck 脚本` / `它不是 private,却既没声明 publishConfig.access=public…` / `dsh.workbench 声明的能力与代码真正注册的对不上` / `design.json 的能力行里有「x」,清单的 tools[] 里却没有它` | 按报的那一条改 `package.json`;`unit` 换个不撞的名字;`dsh.workbenchFaces` 补上两个**源码**入口;四个脚本补全;私有不发就保持 `private: true`。**工具只声明在清单里**(`dsh.workbench.tools`)且必须与 `mount()` 里 `registerTools()` 真正注册的**不重不漏**;写了 `design.json` 的话,它的 `capabilities[].name` 与清单的 `tools[].name` 也要不重不漏(U1c 的**键集合对账**,只对名字 —— 内容各写一处);`gate.deniedTools` 是可选的运行期收窄,门禁不再对它做声明对账(协议里的 `scope` 已删 —— 哪些工作区出现由用户的板决定) |
|
|
9
|
+
| `protocol` | `dsh.workbench` 是外壳读你得懂的那份声明:缺版本、形状不对、**多一个键**、枚举值不认都要在装机前拦下来。多出来的键最阴 —— 外壳会**静默忽略**它(拼错一个键 = 那句话白写) | `没有 apiVersion` / `apiVersion 是 99,这份只认 1` / `声明了 apiVersion 就要把静态半写全 —— 缺 dsh.workbench.tools` / `dsh.workbench 里有协议 v1 不认识的键 "faces"` / `card 里有不认的键 "enabledByDefault"`(这个键连外壳里都没有了 —— A-3 删的,见 [ADR-0038](../../../../docs/adr/0038-module-declaration-protocol.md) §6.7) / `tools[0] 里有协议不认的键 "scopes"` / `tools[0] 里有不认的键 "scope"`(`scope` 自本轮更正起**不在协议里**:能力在哪些工作区出现由用户的板决定,见 [ADR-0038 §2.4 / §6.16](../../../../docs/adr/0038-module-declaration-protocol.md)) | 补 `"apiVersion": 1`;把 `unit` / `card` / `tools` / `host` 四个键写全(没卡片写 `"card": null`、没工具写 `"tools": []`、一个服务都不要写 `"host": { "inject": [] }`);删掉协议外的键(`faces` 自 A-2 起搬到 `dsh.workbenchFaces`,写回 `dsh.workbench` 里就是生字段);`scope` **不要写**(协议不认它,写了就是生字段)。字段清单见 `dsh-wb-module` 的 README「协议」那一节 |
|
|
9
10
|
| `bundles` | 两个运行时互串:浏览器产物里带 node 内置、宿主产物里带 DOM / react | `浏览器产物里出现了 node 内置 …` / `宿主产物里出现了 react` | 宿主面别 import 浏览器侧的东西;浏览器面别 import `node:*`。两侧只通过服务名相接 |
|
|
10
11
|
| `source` | 非种子词的 `@deepseek-ai/*`、宿主侧碰 dsh 的浏览器包、`@/` 指到工作台源码 | `…在宿主侧可达` / `不是平台种子词` | 宿主侧只用 Node 侧的东西;dsh 原语一律走 `kit`;`@/` 只指自己的 `src/` |
|
|
11
12
|
| `primitives` | 声明了 `external` 却没有产物物证 ⇒ dsh 原语被**内联**成第二份实例 | `…用了却没声明 external` / `宿主产物里出现了` | 在 `dsh.client.external` 里显式声明它;确认产物里是 `require(...)` 而不是被打包进来 |
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
| 纪律(出处) | 固化形态 |
|
|
14
14
|
|---|---|
|
|
15
|
-
|
|
|
15
|
+
| 十一条判据([REVIEW.md](REVIEW.md)) | `dsh-wb-module check`(`--only <判据>` 单跑;`--only kit` 列这份外壳的 kit 成员) |
|
|
16
16
|
| 落点、文件形状、四个脚本([BUILD.md](BUILD.md) §1–§2) | `dsh-wb-module init --template diy`(骨架带一条真读盘的数据源)+ `scripts/smoke.mjs` |
|
|
17
17
|
| 装、上板、不重装([WIRING.md](WIRING.md) §3) | `workbench_diy`(`install` / `open` / `status`)+ `workbench_panels` |
|
|
18
18
|
| 空着的格就是还没定的事([DESIGN.md](DESIGN.md) §5) | `design.json` + `design check`(点名叫出空格)/ `render` / `accept` |
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
| DOM 读怎么读([DATASOURCE.md](DATASOURCE.md) 第 2 步) | `probe`(探)+ `browserFind`(固化)—— 切格 / 按列取值是两个纯函数 |
|
|
28
28
|
| 链接只有一副样子([PANEL.md](PANEL.md) §6) | kit 的 `Link` 是唯一一份(**没有 `icon` 口子**),`check --only style` 拦裸 `<a>` |
|
|
29
29
|
| 输入框不用自己配样式([PANEL.md](PANEL.md) §5.1) | `TextField` 的默认内边距 + kit 的 `Field`(标签 + 提示的排布) |
|
|
30
|
-
|
|
|
30
|
+
| 这个单元在哪些工作区出现([TOOLS.md](TOOLS.md) §12) | **不是模块能声明的事** —— 用户用 `workbench_panels` 的板决定(卡片与全部工具同判);协议里的 `scope` 已删。`gate.deniedTools` 是可选的运行期收窄,门禁不再对它做声明对账 |
|
|
31
31
|
|
|
32
32
|
## 留给 agent 的(判断,不该固化)
|
|
33
33
|
|
|
@@ -250,5 +250,12 @@ return {
|
|
|
250
250
|
`packages/workbench/src/modules/panels/index.ts`):某张卡在这个项目上没开 → 那张卡的工具全不出现;
|
|
251
251
|
工坊那把窄门工具 `workbench_diy` **只在工坊会话里**出现,别处一律不出现。
|
|
252
252
|
|
|
253
|
-
|
|
254
|
-
|
|
253
|
+
**"这条能力在哪些工作区出现"不用你声明 —— 那是用户的事。** 用户口径:「模块开发者不能定义 scope,
|
|
254
|
+
scope 永远是用户来决定的」。他在 `workbench_panels`(agent 工具)里把它们放上/收起;一个单元在不在,
|
|
255
|
+
它的卡片与**全部**工具同判(外壳的 `resolveScope` 只看两份板:本工作区那份,否则机器级那份)。
|
|
256
|
+
协议里那个 `scope`(`dsh.workbench.tools[].scope` / `card.scope`)**已经删掉**,写它就是写了一个
|
|
257
|
+
不认识的键、`check --only protocol` 当场红(见 [ADR-0038 §2.4 / §6.16](../../../../docs/adr/0038-module-declaration-protocol.md))。
|
|
258
|
+
`design.json` 的能力行也没有这一格。
|
|
259
|
+
|
|
260
|
+
`gate.deniedTools` 仍然可以接,但它是**可选**的运行期收窄("这个能力还没配好,先按我自己的开关藏起来"),
|
|
261
|
+
**不是**一条声明出来的承诺:门禁不再拿任何声明去对账它(那条判据已删 —— 没有作者侧声明就没有可比的东西)。
|