dsh-paoding 0.3.9 → 0.4.0
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 +6 -1
- package/README_en.md +6 -1
- package/bin/dsh-paoding.mjs +23 -0
- package/docs/architecture.md +4 -3
- package/docs/architecture_en.md +6 -4
- package/docs/configuration.md +85 -12
- package/docs/configuration_en.md +88 -13
- package/docs/installation.md +18 -6
- package/docs/installation_en.md +18 -6
- package/docs/orchestration.md +4 -0
- package/docs/orchestration_en.md +4 -0
- package/package.json +1 -1
- package/plugins/paoding-config-ui/api-core.mjs +107 -4
- package/plugins/paoding-config-ui/index.mjs +93 -28
- package/plugins/paoding-config-ui/lib/client.js +941 -237
- package/plugins/paoding-config-ui/package.json +1 -1
- package/presets/orchestrator/agent.cordis.yml +13 -0
- package/presets/orchestrator/delegation-labels.mjs +80 -0
- package/tools/lib/cli.mjs +91 -13
- package/tools/lib/compose.mjs +103 -16
- package/tools/lib/doctor.mjs +245 -0
- package/tools/lib/glob.mjs +76 -0
- package/tools/lib/health.mjs +298 -0
- package/tools/lib/preset-system.mjs +29 -11
- package/tools/lib/state.mjs +24 -6
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
* directory(安全侧:声明行误落 0.1.6 会炸 profile 启动,目录轨误落
|
|
13
13
|
* 0.1.7 只是预设不显示);
|
|
14
14
|
* 2) 声明行构造 buildPresetRowText:把生成的 agent.cordis.yml 全文内联成
|
|
15
|
-
* 一条声明行的 config.plugins(restrict
|
|
16
|
-
* file: URL——声明轨没有「相对 preset
|
|
15
|
+
* 一条声明行的 config.plugins(restrict 行与 delegation-labels 行的本地
|
|
16
|
+
* name 换成对应 .mjs 的绝对 file: URL——声明轨没有「相对 preset 目录」
|
|
17
|
+
* 语义,必须绝对化);
|
|
17
18
|
* 3) home patch 托管块手术 upsertHomePatchRows / stripHomePatchRows /
|
|
18
19
|
* readHomePatchRows:对 $DSH_HOME/cordis.patch.yml 的 MANAGED 标记块做
|
|
19
20
|
* 行级增删查,块外用户内容一字节不动;托管块损坏(缺结束标记)时拒绝
|
|
@@ -155,11 +156,15 @@ function dshVersionText() {
|
|
|
155
156
|
* 缩进基准:4 空格起排(`- insert:` 列表项层级由 upsertHomePatchRows 拼),
|
|
156
157
|
* plugins: 落 8 空格、插件条目行落 10 空格。name/description 用 JSON.stringify
|
|
157
158
|
* 落值——JSON 字符串即合法 YAML 双引号标量,换行/引号自动转义。agentYmlText
|
|
158
|
-
* 先把 restrict 行的 `name: ./restrict.mjs`
|
|
159
|
-
*
|
|
160
|
-
*
|
|
159
|
+
* 先把 restrict 行的 `name: ./restrict.mjs` 与 delegation-labels 行的
|
|
160
|
+
* `name: ./delegation-labels.mjs` 替换为对应绝对 file: URL(两个本地插件文件
|
|
161
|
+
* 均无「相对 preset 目录」语义),再整体 +10 缩进;空行保持空行(块标量相对
|
|
162
|
+
* 缩进不变),`!!js` 表达式行原样保留(宿主 patch schema 支持,求值仍由
|
|
163
|
+
* cordis 装载时完成)。文本里出现 delegation-labels 行而未提供
|
|
164
|
+
* delegationLabelsFileUrl 时硬错误——漏传会让相对名字静默进 patch,宿主
|
|
165
|
+
* 解析不了、preset 直接挂掉。
|
|
161
166
|
*/
|
|
162
|
-
export function buildPresetRowText({ presetId, name = null, description = null, order = null, agentYmlText, restrictFileUrl }) {
|
|
167
|
+
export function buildPresetRowText({ presetId, name = null, description = null, order = null, agentYmlText, restrictFileUrl, delegationLabelsFileUrl = null }) {
|
|
163
168
|
if (typeof presetId !== 'string' || !/^[a-z0-9][a-z0-9-]*$/.test(presetId)) {
|
|
164
169
|
throw new Error(`buildPresetRowText: 非法 presetId: ${presetId}`)
|
|
165
170
|
}
|
|
@@ -169,6 +174,12 @@ export function buildPresetRowText({ presetId, name = null, description = null,
|
|
|
169
174
|
if (typeof restrictFileUrl !== 'string' || restrictFileUrl === '') {
|
|
170
175
|
throw new Error('buildPresetRowText: restrictFileUrl 不能为空')
|
|
171
176
|
}
|
|
177
|
+
const referencesLabelsRow = String(agentYmlText)
|
|
178
|
+
.split(/\r?\n/)
|
|
179
|
+
.some((line) => line.trim() === 'name: ./delegation-labels.mjs')
|
|
180
|
+
if (referencesLabelsRow && (typeof delegationLabelsFileUrl !== 'string' || delegationLabelsFileUrl === '')) {
|
|
181
|
+
throw new Error('buildPresetRowText: agentYmlText 引用了 ./delegation-labels.mjs,但未提供 delegationLabelsFileUrl')
|
|
182
|
+
}
|
|
172
183
|
const lines = [
|
|
173
184
|
` - id: ${presetRowId(presetId)}`,
|
|
174
185
|
` name: '${PRESET_ROW_NAME}'`,
|
|
@@ -184,10 +195,13 @@ export function buildPresetRowText({ presetId, name = null, description = null,
|
|
|
184
195
|
lines.push('')
|
|
185
196
|
continue
|
|
186
197
|
}
|
|
187
|
-
//
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
:
|
|
198
|
+
// 本地插件行换绝对 file: URL(按行精确内容匹配,缩进原样保留)
|
|
199
|
+
const trimmed = line.trim()
|
|
200
|
+
const fileUrl =
|
|
201
|
+
trimmed === 'name: ./restrict.mjs' ? restrictFileUrl
|
|
202
|
+
: trimmed === 'name: ./delegation-labels.mjs' ? delegationLabelsFileUrl
|
|
203
|
+
: null
|
|
204
|
+
const replaced = fileUrl !== null ? `${line.match(/^[ \t]*/)[0]}name: ${fileUrl}` : line
|
|
191
205
|
lines.push(` ${replaced}`)
|
|
192
206
|
}
|
|
193
207
|
while (lines.length > 0 && lines[lines.length - 1] === '') lines.pop() // 去尾部空行,段拼接才紧凑
|
|
@@ -503,7 +517,8 @@ export function readPresetDirMeta(dir) {
|
|
|
503
517
|
/**
|
|
504
518
|
* 把磁盘上已有的编排类 preset 目录补写进 home patch 托管块(缺行才补,已有行
|
|
505
519
|
* 原样不动);行在、目录没了的撤行——目录与行同生同灭。产物不全(缺
|
|
506
|
-
* agent.cordis.yml / restrict.mjs)的目录跳过并 warn
|
|
520
|
+
* agent.cordis.yml / restrict.mjs / delegation-labels.mjs)的目录跳过并 warn,
|
|
521
|
+
* 不拖垮其余补写(整盘重生成可修复)。
|
|
507
522
|
* 返回实际补写成功的 presetId 列表(既没补也没撤时为空数组)。
|
|
508
523
|
*/
|
|
509
524
|
export function backfillHomePatchRows(dshHome, presetIds) {
|
|
@@ -518,6 +533,8 @@ export function backfillHomePatchRows(dshHome, presetIds) {
|
|
|
518
533
|
const agentYmlText = readFileSync(path.join(dir, 'agent.cordis.yml'), 'utf8')
|
|
519
534
|
const restrictFile = path.join(dir, 'restrict.mjs')
|
|
520
535
|
if (!existsSync(restrictFile)) throw new Error('restrict.mjs 缺失')
|
|
536
|
+
const labelsFile = path.join(dir, 'delegation-labels.mjs')
|
|
537
|
+
if (!existsSync(labelsFile)) throw new Error('delegation-labels.mjs 缺失')
|
|
521
538
|
const meta = readPresetDirMeta(dir)
|
|
522
539
|
rows.push(
|
|
523
540
|
buildPresetRowText({
|
|
@@ -527,6 +544,7 @@ export function backfillHomePatchRows(dshHome, presetIds) {
|
|
|
527
544
|
order: meta.order,
|
|
528
545
|
agentYmlText,
|
|
529
546
|
restrictFileUrl: pathToFileURL(restrictFile).href,
|
|
547
|
+
delegationLabelsFileUrl: pathToFileURL(labelsFile).href,
|
|
530
548
|
}),
|
|
531
549
|
)
|
|
532
550
|
backfilled.push(presetId)
|
package/tools/lib/state.mjs
CHANGED
|
@@ -58,6 +58,25 @@ import {
|
|
|
58
58
|
upsertHomePatchRows,
|
|
59
59
|
} from './preset-system.mjs'
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* 预设源文件清单(generateAndInstall 原样复制件;agent.cordis.yml 走重写,
|
|
63
|
+
* 不在此列)。collectState 的存在性检查与物化复制共用同一份,加源文件只改
|
|
64
|
+
* 这一处。delegation-labels.mjs 与 restrict.mjs 同生命周期:都是本地 cordis
|
|
65
|
+
* 插件,声明行轨内联时按绝对 file: URL 引用。
|
|
66
|
+
*/
|
|
67
|
+
export const PRESET_ASIS_FILES = ['preset.yml', 'restrict.mjs', 'delegation-labels.mjs']
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 预设源文件存在性检查(collectState 第一步):全部源文件缺任一件即硬错误,
|
|
71
|
+
* 报错点名缺的文件——delegation-labels.mjs 与 restrict.mjs 同口径。
|
|
72
|
+
*/
|
|
73
|
+
export function assertPresetSourceFiles(srcDir = SRC_DIR) {
|
|
74
|
+
for (const name of ['agent.cordis.yml', ...PRESET_ASIS_FILES]) {
|
|
75
|
+
const file = path.join(srcDir, name)
|
|
76
|
+
if (!existsSync(file)) throw new Error(`missing preset source file: ${file}`)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
61
80
|
/**
|
|
62
81
|
* Reusable state collection for the CLI and the visual config UI.
|
|
63
82
|
* Runs the whole detection pipeline (patch scan, MCP handshakes, plugin and
|
|
@@ -78,10 +97,7 @@ export async function collectState({ dshHome, configFile, profile = null, patche
|
|
|
78
97
|
const dstAgentFile = path.join(dstDir, 'agent.cordis.yml')
|
|
79
98
|
|
|
80
99
|
// Source preset files must exist before anything else.
|
|
81
|
-
|
|
82
|
-
for (const file of sourceFiles) {
|
|
83
|
-
if (!existsSync(file)) throw new Error(`missing preset source file: ${file}`)
|
|
84
|
-
}
|
|
100
|
+
assertPresetSourceFiles()
|
|
85
101
|
|
|
86
102
|
const yamlMod = loadYaml(dshHome)
|
|
87
103
|
const srcText = readFileSync(path.join(SRC_DIR, 'agent.cordis.yml'), 'utf8')
|
|
@@ -437,7 +453,7 @@ export function generateAndInstall(state, assignments, { dryRun = false, saveCon
|
|
|
437
453
|
mkdirSync(path.join(dshHome, '.agent-presets'), { recursive: true })
|
|
438
454
|
rmSync(dstDir, { recursive: true, force: true })
|
|
439
455
|
mkdirSync(dstDir, { recursive: true })
|
|
440
|
-
for (const name of
|
|
456
|
+
for (const name of PRESET_ASIS_FILES) {
|
|
441
457
|
const src = path.join(SRC_DIR, name)
|
|
442
458
|
const dst = path.join(dstDir, name)
|
|
443
459
|
if (name === 'preset.yml' && displayName !== null) {
|
|
@@ -517,7 +533,8 @@ export function generateAndInstall(state, assignments, { dryRun = false, saveCon
|
|
|
517
533
|
// declarative(0.1.7+):目录扫描机制已删,必须把本 preset 以一条 `- insert:`
|
|
518
534
|
// 声明行写进 home patch 托管块才算安装完成(preset 元信息与写 preset.yml 同
|
|
519
535
|
// 源:显示名取 displayName ?? SRC preset.yml 的 name,description / order 取
|
|
520
|
-
// SRC;restrict.mjs 用绝对 file: URL
|
|
536
|
+
// SRC;restrict.mjs / delegation-labels.mjs 用绝对 file: URL——声明行没有
|
|
537
|
+
// 「相对 preset 目录」语义)。
|
|
521
538
|
// directory(≤0.1.6):上面落盘即完成;home patch 里若有残留托管声明块
|
|
522
539
|
//(宿主刚从 0.1.7 降级等场景)整块撤下自愈——残留声明行会让 profile 启动失败。
|
|
523
540
|
if (wrote) {
|
|
@@ -531,6 +548,7 @@ export function generateAndInstall(state, assignments, { dryRun = false, saveCon
|
|
|
531
548
|
order: meta.order,
|
|
532
549
|
agentYmlText: generatedText,
|
|
533
550
|
restrictFileUrl: pathToFileURL(path.join(dstDir, 'restrict.mjs')).href,
|
|
551
|
+
delegationLabelsFileUrl: pathToFileURL(path.join(dstDir, 'delegation-labels.mjs')).href,
|
|
534
552
|
}),
|
|
535
553
|
])
|
|
536
554
|
} else if (readHomePatchRows(dshHome).length > 0) {
|