dsh-paoding 0.4.0 → 0.4.2
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
|
@@ -22,7 +22,7 @@ dsh-paoding(中文品牌「庖丁」,典出《庄子》——庖丁顺纹理
|
|
|
22
22
|
- **保存前先体检**:预览/应用时自动过一遍检查——配置了但未挂载的工具、零工具角色、查无此名的模型、预设落后于配置,分级提示一目了然;CLI 侧 `dsh-paoding doctor` 六项只读自检(配置可解析、安装轨道、声明行托管块、孤儿目录、版本标记、预设漂移),一条命令查全身。
|
|
23
23
|
- **场景模板一键换班底**:轻量(只留实现)、调研(只留检索)、全开(全员到齐、主 agent 带满检测库存)三档点一下就切,只动「谁在场 + 主 agent 额外带什么」,精调过的角色配置分毫不动。
|
|
24
24
|
- **配置可导出可导入**:面板「更多」菜单一键下载 `dsh-paoding.config.yml`,换机迁移、备份整份拷走;导入先验格式,覆盖整体配置(含工作区段)需二次确认。
|
|
25
|
-
- **面板中英双语**:界面文案 zh/en
|
|
25
|
+
- **面板中英双语**:界面文案 zh/en 全覆盖,语言自动识别(显式选择 → 中文信号优先:浏览器语言、宿主页面语言、中文时区),「更多」菜单一键切换并记住。
|
|
26
26
|
- **版本更新有提醒,面板一键升级**:面板会对比 npm registry(npmmirror 镜像、GitHub release 依次兜底)上的最新版本,发现新版就地提示并附上发布页链接;点「升级」就地换上新版(profile 自动探测:普通 profile 走 `dsh plugin update dsh-paoding`;desktop profile 被 dsh CLI 的 Electron 专属守卫挡住,改在 profile 目录直跑 `pnpm add dsh-paoding@<版本>`),重启 DSH 后生效,编排预设会在重启时按新版自动重生成。开发检出的 link 形态无法就地升级,面板会提示切回 registry 版的办法;检测失败时页头留一行「版本检测失败 · 重试」(完整原因与代理排查提示在悬浮提示里),不弹窗打扰。
|
|
27
27
|
- **来去自由**:不改 DSH 一行源码;装完新会话即用,卸载即删目录。
|
|
28
28
|
- **两代宿主都兼容**:DSH 0.1.5 – 0.2.0-rc.2 全支持(0.1.5 / 0.1.6 / 0.1.7-rc.1 / 0.1.7-rc.2 / 0.2.0-rc.1 / 0.2.0-rc.2)——两代宿主发现预设的机制不同(目录扫描 vs patch 声明行),安装器自动检测宿主版本选对落点;编排组合里的 workflow worker 行也按宿主版本自动适配(0.1.5 用 workflow-worker-thread,0.1.6+ 换 workflow-ptc——旧包 0.1.6 起已删除,残留行正是 0.2.0 面板上「加载失败」的元凶),宿主升级、降级后的首次保存/自愈自动迁移,全程无感。
|
package/README_en.md
CHANGED
|
@@ -22,7 +22,7 @@ dsh-paoding (Chinese brand 「庖丁」/ Pao Ding, from the Zhuangzi parable of
|
|
|
22
22
|
- **A health check before every save**: preview/apply runs a built-in check — tools configured but not mounted, zero-tool roles, unknown model names, a preset lagging behind the config — each flagged by severity; on the CLI side, `dsh-paoding doctor` runs six read-only checks (config parses, install track, managed declaration block, orphan directories, version marker, preset drift) in one command.
|
|
23
23
|
- **Scenario templates swap the roster in one click**: Lite (implement only), Research (search roles only), and Full (everyone on deck, main agent carrying the whole detected inventory) — templates only touch who is present and what the main agent carries; hand-tuned role settings are never touched.
|
|
24
24
|
- **Config export & import**: download `dsh-paoding.config.yml` from the panel's More menu for migration or backup; imports are validated first, and overwriting the whole config (workspaces included) asks for confirmation.
|
|
25
|
-
- **Panel in English and Chinese**: every UI string ships in both languages, auto-detected
|
|
25
|
+
- **Panel in English and Chinese**: every UI string ships in both languages, auto-detected (explicit choice first, then Chinese signals — browser language, host page language, Chinese time zones — outrank English ones, since the Electron shell pins navigator to en-US regardless of the OS), switchable from the More menu and remembered.
|
|
26
26
|
- **Notified of new releases, one-click upgrade in the panel**: the panel compares your local version against the latest npm registry publish (npmmirror and GitHub release as successive fallbacks) and points to the release page when a newer one is out. The Upgrade button swaps in the new version in place (profile auto-detected): regular profiles go through `dsh plugin update dsh-paoding`, while the Electron-owned desktop profile — which the dsh CLI guards against — gets a direct `pnpm add dsh-paoding@<version>` run in the profile directory; a DSH restart applies it, and the orchestrator preset regenerates itself against the new version on startup. A dev checkout in link: form cannot be upgraded in place — the panel tells you how to switch back to the registry version. If the check fails (offline, rate-limited), a subdued "version check failed · retry" row stays in the header (full causes and proxy hints in its tooltip) without popping anything up.
|
|
27
27
|
- **Installs and uninstalls cleanly**: no DSH source changes; active in a new session right after install, gone when you delete one directory.
|
|
28
28
|
- **Works on both host generations**: DSH 0.1.5 through 0.2.0-rc.2 are all supported (0.1.5 / 0.1.6 / 0.1.7-rc.1 / 0.1.7-rc.2 / 0.2.0-rc.1 / 0.2.0-rc.2) — the two generations discover presets differently (directory scan vs patch declaration rows), and the installer picks the right landing automatically; from 0.2.0 the workflow worker row in the orchestration composition also adapts to the host version at generation time (0.1.5 uses workflow-worker-thread, 0.1.6+ swaps to workflow-ptc). Migration happens on the first save/self-heal after a host upgrade or downgrade, all without user action.
|
package/docs/installation.md
CHANGED
|
@@ -234,6 +234,12 @@ doctor 不改任何文件,逐项检查并给出 `✔ 正常 / ⚠ 警告 / ✘
|
|
|
234
234
|
|
|
235
235
|
`dsh plugin add` 报 pnpm 相关错误:`dsh plugin` 依赖 pnpm 装包。`npm i -g pnpm`(或 `corepack enable`)装好后重试。
|
|
236
236
|
|
|
237
|
+
面板「升级」报 `spawn pnpm ENOENT` 是同一件事的 desktop 形态:desktop profile 的升级不走 dsh 转发器,而是直跑 `pnpm add`,PATH 里没有裸 `pnpm`(pnpm 由 corepack 托管、又没跑过 `corepack enable` 的机器就是这样)即报此错。0.4.1 起升级自动按「裸 pnpm → `corepack pnpm` → PNPM_HOME 常见落位」回落,一般无需处理;更早版本手动升一把即可:
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
cd "${DSH_HOME:-$HOME/.dsh}/profiles/desktop" && corepack pnpm add dsh-paoding@latest
|
|
241
|
+
```
|
|
242
|
+
|
|
237
243
|
**装了插件,预设列表里却没有「编排模式 (Orchestrator)」**
|
|
238
244
|
|
|
239
245
|
预设由插件启动时自动生成:先确认装完后**重启过 DSH**;预设在新会话创建时装载,重启后还要新建一个会话才会出现在选择器里。仍没有就查 DSH 日志里 `paoding-config-ui` 的告警(自动生成失败会记日志,可到面板手动「保存并应用」补上),再检查 `ls "${DSH_HOME:-$HOME/.dsh}/.agent-presets/orchestrator"`——目录为空多半是插件运行时的 `$DSH_HOME` 与你以为的家目录不一致(启动 DSH 前显式 `export DSH_HOME=…`)。目录在、宿主又是 0.1.7+ 而选择器里仍没有时,再查 `$DSH_HOME/cordis.patch.yml` 里有无 dsh-paoding 托管块——0.1.7 靠块内声明行发现预设,缺块就到面板点一次「保存并应用」补写(见第 2 节「版本支持与预设落点双轨」)。
|
package/docs/installation_en.md
CHANGED
|
@@ -234,6 +234,12 @@ The panel runs the same checks on every save: each Preview / Save & Apply respon
|
|
|
234
234
|
|
|
235
235
|
`dsh plugin add` fails with a pnpm error: `dsh plugin` relies on pnpm to install packages. Install it (`npm i -g pnpm` or `corepack enable`) and retry.
|
|
236
236
|
|
|
237
|
+
The panel's Upgrade button reporting `spawn pnpm ENOENT` is the same problem in its desktop form: desktop-profile upgrades bypass the dsh forwarder and run `pnpm add` directly, which fails the same way when no bare `pnpm` is on PATH (typical for corepack-managed setups that never ran `corepack enable`). Since 0.4.1 the upgrade falls back automatically — bare `pnpm` → `corepack pnpm` → common PNPM_HOME locations — so no action is normally needed; on earlier versions, upgrade manually:
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
cd "${DSH_HOME:-$HOME/.dsh}/profiles/desktop" && corepack pnpm add dsh-paoding@latest
|
|
241
|
+
```
|
|
242
|
+
|
|
237
243
|
**The plugin is installed but "编排模式 (Orchestrator)" is not in the preset list**
|
|
238
244
|
|
|
239
245
|
The preset is generated automatically when the plugin starts: first make sure you **restarted DSH** after installing; presets load when a session is created, so after the restart you also need a new session for it to appear in the selector. Still nothing? Check the DSH log for `paoding-config-ui` warnings (a failed auto-generation is logged; apply manually from the panel), then check `ls "${DSH_HOME:-$HOME/.dsh}/.agent-presets/orchestrator"` — an empty directory usually means the plugin's runtime `$DSH_HOME` differs from the home directory you assumed (export `DSH_HOME=…` explicitly before launching DSH). If the directory is there, the host is 0.1.7+, and the selector still shows nothing, check `$DSH_HOME/cordis.patch.yml` for the dsh-paoding managed block — 0.1.7 discovers presets through the declaration rows inside it; if the block is missing, hit Save & Apply once in the panel to write it (see §2 "Version support and the dual preset landing").
|
package/package.json
CHANGED
|
@@ -97,9 +97,12 @@ window.__ModuleLoader__.load({
|
|
|
97
97
|
// - t(key, params):按当前语言取文案,params 做 {name} 插值(split/join
|
|
98
98
|
// 而非 replace,避免替换串里的 $ 模式被二次解释)。缺 key 原样返回 key
|
|
99
99
|
// 本身——线上宁可露出 key 也不静默吞掉,测试侧保证不会发生。
|
|
100
|
-
// -
|
|
101
|
-
// navigator.language
|
|
102
|
-
//
|
|
100
|
+
// - 语言解析(zh 信号优先):localStorage "paoding-lang" 显式优先 →
|
|
101
|
+
// navigator.language/languages 与宿主页面 <html lang> 任一带 zh 前缀
|
|
102
|
+
// → zh → 时区属中文地区 → zh → en 前缀命中 → en → 兜底 zh。Electron
|
|
103
|
+
// 外壳会把 navigator 语言钉成应用 locale(常 en-US,不跟操作系统),
|
|
104
|
+
// en 信号不可信而时区可信,故 zh 信号整体压过 en;服务端消息仅中文,
|
|
105
|
+
// 误判 zh(真英文用户点一次 English 即记住)代价远小于误判 en 混排。
|
|
103
106
|
// - 切语言:setLang(lang) 写 localStorage + 同步广播 onLangChange;
|
|
104
107
|
// 监听方各自刷新(86 PageShell 整页重渲染、82 委派行重建标题),面板
|
|
105
108
|
// 数据重拉复用既有 registerReload 通道,不另造机制。
|
|
@@ -113,15 +116,48 @@ window.__ModuleLoader__.load({
|
|
|
113
116
|
// 语言探测:localStorage 显式值优先;其余按 navigator.language 首缀猜 zh,
|
|
114
117
|
// 兜底 en。全程 try/catch——非浏览器/受限环境(vm 测试、老内核)不炸,逐层回落。
|
|
115
118
|
function paodingDetectLang() {
|
|
119
|
+
// zh 信号优先于 en 信号(不是平级链):Electron 外壳会把 navigator
|
|
120
|
+
// 语言钉成应用 locale(常为 en-US,跟打包不跟操作系统),en 命中在
|
|
121
|
+
// 本环境不可信;而本插件服务端消息仅中文,误判 zh 的代价(真英文
|
|
122
|
+
// 用户点一次 English,localStorage 记住)远小于误判 en(中文用户看
|
|
123
|
+
// 中英混排面板)。故顺序:显式选择 → 任一 zh 信号 → en 信号 → zh。
|
|
124
|
+
// ① 手动选择(localStorage)显式最优先
|
|
116
125
|
try {
|
|
117
126
|
var saved = window.localStorage.getItem(PAODING_LANG_KEY);
|
|
118
127
|
if (saved === "zh" || saved === "en") return saved;
|
|
119
128
|
} catch (err) { /* localStorage 不可用:继续探测 */ }
|
|
129
|
+
var navLangs = [];
|
|
120
130
|
try {
|
|
121
|
-
if (typeof navigator !== "undefined"
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
131
|
+
if (typeof navigator !== "undefined") {
|
|
132
|
+
if (navigator.language) navLangs.push(String(navigator.language));
|
|
133
|
+
if (navigator.languages && navigator.languages.length) {
|
|
134
|
+
for (var i = 0; i < navigator.languages.length; i++) navLangs.push(String(navigator.languages[i]));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
} catch (err) { /* navigator 不可用:navLangs 留空 */ }
|
|
138
|
+
var docLang = "";
|
|
139
|
+
try {
|
|
140
|
+
docLang = String((document.documentElement && document.documentElement.lang) || "");
|
|
141
|
+
} catch (err) { /* 无 document:留空 */ }
|
|
142
|
+
// ② navigator / 宿主页面 <html lang> 任一带 zh 前缀 → zh
|
|
143
|
+
for (var j = 0; j < navLangs.length; j++) {
|
|
144
|
+
if (navLangs[j].toLowerCase().indexOf("zh") === 0) return "zh";
|
|
145
|
+
}
|
|
146
|
+
if (docLang.toLowerCase().indexOf("zh") === 0) return "zh";
|
|
147
|
+
// ③ 时区属中文地区 → zh:Electron webview 里 navigator 常整体被钉成
|
|
148
|
+
// en-US,时区是跟着操作系统走的最后真身(Asia/Shanghai 等)。
|
|
149
|
+
try {
|
|
150
|
+
var tz = Intl.DateTimeFormat().resolvedOptions().timeZone || "";
|
|
151
|
+
if (/Asia\/(Shanghai|Hong_Kong|Macau|Taipei|Urumqi|Chongqing)$/.test(tz)) return "zh";
|
|
152
|
+
} catch (err) { /* 无 Intl:继续 */ }
|
|
153
|
+
// ④ en 信号(浏览器环境常规英文用户在此命中;Electron 假 en-US 已被
|
|
154
|
+
// ③ 时区先一步接走——中文时区的 Electron 用户不会再走到这里)
|
|
155
|
+
for (var k = 0; k < navLangs.length; k++) {
|
|
156
|
+
if (navLangs[k].toLowerCase().indexOf("en") === 0) return "en";
|
|
157
|
+
}
|
|
158
|
+
if (docLang.toLowerCase().indexOf("en") === 0) return "en";
|
|
159
|
+
// ⑤ 无任何信号 → zh(服务端消息仅中文,en 面板必混排)
|
|
160
|
+
return "zh";
|
|
125
161
|
}
|
|
126
162
|
|
|
127
163
|
var paodingLang = paodingDetectLang();
|
package/tools/lib/upgrade.mjs
CHANGED
|
@@ -13,7 +13,10 @@
|
|
|
13
13
|
* profile 目录里直跑 `pnpm add dsh-paoding@<目标版本>`:本包已在 profile
|
|
14
14
|
* package.json 的 dsh.profile.bundles 清单里,无需 bundle reconcile;用
|
|
15
15
|
* 精确版本而非 update,避开 pnpm 新鲜度防护 / 镜像 packument 滞后造成的
|
|
16
|
-
* 静默空转。
|
|
16
|
+
* 静默空转。pnpm 本身按候选链解析(裸 pnpm → corepack pnpm → PNPM_HOME
|
|
17
|
+
* 常见落位,仅 ENOENT 换下一路)——corepack 管的机器没跑过 corepack
|
|
18
|
+
* enable 时 PATH 里没有裸 pnpm,0.3.8~0.4.0 直 spawn 裸名即报
|
|
19
|
+
* `spawn pnpm ENOENT`(0.4.1 修)。
|
|
17
20
|
*
|
|
18
21
|
* 本模块只负责「拿目标版本 → 探测自身 profile → 跑子进程」这一段编排;
|
|
19
22
|
* profile 名从本文件运行时真实路径反推(registry 安装形态必然位于
|
|
@@ -77,7 +80,7 @@ function defaultSpawn(command, args, options, timeoutMs, timeoutLabel) {
|
|
|
77
80
|
}, timeoutMs)
|
|
78
81
|
child.on('error', (err) => {
|
|
79
82
|
clearTimeout(timer)
|
|
80
|
-
resolve({ code: null, output: tailOutput(output), error: String(err?.message ?? err) })
|
|
83
|
+
resolve({ code: null, output: tailOutput(output), error: String(err?.message ?? err), errorCode: err?.code ?? null })
|
|
81
84
|
})
|
|
82
85
|
child.on('close', (code) => {
|
|
83
86
|
clearTimeout(timer)
|
|
@@ -128,8 +131,10 @@ function desktopProfileDir() {
|
|
|
128
131
|
* node:child_process 的 spawn、Date.now()。
|
|
129
132
|
* - timeoutMs:升级子进程超时(含 pnpm 下载安装),默认 120s。
|
|
130
133
|
* - spawnImpl 契约:(command, args, options, timeoutMs, timeoutLabel) →
|
|
131
|
-
* Promise resolving { code, output, error? }(同 defaultSpawn
|
|
132
|
-
*
|
|
134
|
+
* Promise resolving { code, output, error?, errorCode? }(同 defaultSpawn
|
|
135
|
+
* 的收敛形状;errorCode 为子进程 spawn 失败的 err.code,如 'ENOENT',
|
|
136
|
+
* desktop 分支据此走 pnpm 候选链回落;timeoutLabel 仅缺省实现用于超时
|
|
137
|
+
* 文案,注入桩可忽略)。
|
|
133
138
|
* @returns {Promise<object>} 恒不抛错,收敛为:
|
|
134
139
|
* - { ok: true, upToDate: true, current } 本地已不落后 registry
|
|
135
140
|
* - { ok: true, version, profile, output, elapsedMs } 升级成功(退出码 0)
|
|
@@ -193,19 +198,62 @@ async function doRunUpgrade({ profile, fetchImpl, spawnImpl, timeoutMs, now }) {
|
|
|
193
198
|
return { ok: false, error: `desktop profile 目录不存在或未初始化: ${desktopDir}` }
|
|
194
199
|
}
|
|
195
200
|
const useShell = process.platform === 'win32'
|
|
196
|
-
const command = isDesktop ? (useShell ? 'pnpm.cmd' : 'pnpm') : useShell ? 'dsh.cmd' : 'dsh'
|
|
197
201
|
const args = isDesktop
|
|
198
202
|
? ['add', `dsh-paoding@${targetVersion}`]
|
|
199
203
|
: ['plugin', '--profile', resolved, 'update', 'dsh-paoding']
|
|
200
204
|
const run = typeof spawnImpl === 'function' ? spawnImpl : defaultSpawn
|
|
201
|
-
const
|
|
205
|
+
const spawnOptions = {
|
|
202
206
|
cwd: isDesktop ? desktopDir : os.tmpdir(),
|
|
203
207
|
env: process.env,
|
|
204
208
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
205
209
|
shell: useShell,
|
|
206
|
-
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// pnpm/dsh 候选链:spawn ENOENT(命令在 PATH 里不存在)才换下一路,
|
|
213
|
+
// EACCES / 超时 / 退出码非 0 都是真实运行结果,如实返回不换通道。
|
|
214
|
+
// - 裸 pnpm:npm i -g pnpm / homebrew 等常规安装直接命中;
|
|
215
|
+
// - corepack pnpm:corepack 随 node 发行,node 在 PATH 就兜得住,
|
|
216
|
+
// 未 enable 也能即装即用(corepack pnpm add ...);
|
|
217
|
+
// - PNPM_HOME 常见落位(darwin ~/Library/pnpm、linux ~/.local/share/pnpm)
|
|
218
|
+
// 的绝对路径:pnpm 独立安装脚本形态,spawn 绝对路径不依赖 PATH;
|
|
219
|
+
// existsSync 预筛,不存在不浪费一次 spawn。
|
|
220
|
+
// 常规 profile 的 dsh 单候选同走这套循环,ENOENT 也收敛成可读文案。
|
|
221
|
+
const suffix = useShell ? '.cmd' : ''
|
|
222
|
+
const candidates = isDesktop
|
|
223
|
+
? [
|
|
224
|
+
{ command: `pnpm${suffix}`, argsPrefix: [], label: 'pnpm' },
|
|
225
|
+
{ command: `corepack${suffix}`, argsPrefix: ['pnpm'], label: 'corepack pnpm' },
|
|
226
|
+
]
|
|
227
|
+
: [{ command: `dsh${suffix}`, argsPrefix: [], label: 'dsh' }]
|
|
228
|
+
if (isDesktop) {
|
|
229
|
+
const homes = [path.join(os.homedir(), 'Library', 'pnpm'), path.join(os.homedir(), '.local', 'share', 'pnpm')]
|
|
230
|
+
for (const home of homes) {
|
|
231
|
+
const bin = path.join(home, `pnpm${suffix}`)
|
|
232
|
+
if (existsSync(bin)) candidates.push({ command: bin, argsPrefix: [], label: bin })
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
let proc = null
|
|
237
|
+
for (const cand of candidates) {
|
|
238
|
+
proc = await run(cand.command, [...cand.argsPrefix, ...args], spawnOptions, timeoutMs,
|
|
239
|
+
isDesktop ? 'pnpm add' : 'dsh plugin update')
|
|
240
|
+
if (proc?.errorCode !== 'ENOENT') break
|
|
241
|
+
}
|
|
207
242
|
const output = tailOutput(proc?.output)
|
|
208
243
|
|
|
244
|
+
// 全候选 ENOENT:给可操作的出路,不裸抛 spawn xxx ENOENT。
|
|
245
|
+
if (proc?.errorCode === 'ENOENT') {
|
|
246
|
+
const tried = candidates.map((c) => c.label).join(' / ')
|
|
247
|
+
return {
|
|
248
|
+
ok: false,
|
|
249
|
+
error: isDesktop
|
|
250
|
+
? `未找到可用的 pnpm(已试 ${tried})。可先在终端执行 corepack enable 并重启 DSH 后重试;或手动升级:cd ${desktopDir} && corepack pnpm add dsh-paoding@${targetVersion}`
|
|
251
|
+
: `未找到 dsh 命令(PATH 异常?已试 ${tried}),请检查 dsh 安装后重试`,
|
|
252
|
+
output,
|
|
253
|
+
elapsedMs: elapsedMs(),
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
209
257
|
// ④ 无磁盘后验(旧 npx 时代读 $DSH_HOME/dsh-paoding 对账的方案已随该目录
|
|
210
258
|
// 一并废弃):本进程代码不随升级变化,无从对账;成功与否以退出码为准,
|
|
211
259
|
// 新版本重启 DSH 后生效(preset 由新版启动钩子自动重生成)。
|