@lmzhen/dsh-evolution-commands 0.27.0 → 0.27.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/lib/index.js +78 -47
- package/lib/types/doctor.d.ts +17 -2
- package/package.json +5 -5
package/lib/index.js
CHANGED
|
@@ -50,30 +50,48 @@ const FACT_LABELS = {
|
|
|
50
50
|
"platform-line": "平台兼容线",
|
|
51
51
|
"family-version": "家族版本",
|
|
52
52
|
"install-form": "安装形态",
|
|
53
|
-
"preset-ids": "
|
|
54
|
-
"readonly-contract": "
|
|
53
|
+
"preset-ids": "受限预设",
|
|
54
|
+
"readonly-contract": "只读说明",
|
|
55
55
|
"upgrade-order": "升级顺序",
|
|
56
56
|
"fallback-map": "命令兜底"
|
|
57
57
|
};
|
|
58
58
|
const RUNTIME_LABELS = {
|
|
59
59
|
"subagent-channel": "子代理通道",
|
|
60
|
-
"restricted-preset": "
|
|
61
|
-
"host-surface": "
|
|
62
|
-
"session-fold": "
|
|
63
|
-
"platform-services": "
|
|
60
|
+
"restricted-preset": "受限预设",
|
|
61
|
+
"host-surface": "数据面连接",
|
|
62
|
+
"session-fold": "会话事件读取",
|
|
63
|
+
"platform-services": "平台服务",
|
|
64
64
|
runs: "运行登记",
|
|
65
|
-
"platform-pairing": "
|
|
65
|
+
"platform-pairing": "版本兼容",
|
|
66
66
|
"install-form-detected": "实际安装形态"
|
|
67
67
|
};
|
|
68
|
+
/**
|
|
69
|
+
* The install form in reader-facing words. The M1..M4 ids stay internal (the runtime rows and
|
|
70
|
+
* --json keep them); a settings reader sees what the deployment is FOR, not the code name.
|
|
71
|
+
*/
|
|
72
|
+
const FORM_WORDS = Object.freeze({
|
|
73
|
+
M1: "完整功能包",
|
|
74
|
+
M2: "后台自动化包",
|
|
75
|
+
M3: "会话预设包",
|
|
76
|
+
M4: "分层安装"
|
|
77
|
+
});
|
|
78
|
+
/**
|
|
79
|
+
* Build the seven documentation facts. Values are READER-FACING prose: the CLI text, --json and
|
|
80
|
+
* the settings card all print the same strings, so internal codes, raw evidence paths and
|
|
81
|
+
* "declared/inferred" jargon stay out of the value (the runtime rows and the per-fact home carry
|
|
82
|
+
* the technical half).
|
|
83
|
+
* @param inputs - assembled doctor inputs.
|
|
84
|
+
* @returns the ordered fact rows.
|
|
85
|
+
*/
|
|
68
86
|
function factsOf(inputs) {
|
|
69
87
|
const values = {
|
|
70
|
-
"platform-line": inputs.platformLine.version + "
|
|
88
|
+
"platform-line": inputs.platformLine.version + "(最低兼容 " + inputs.platformLine.floor + ")",
|
|
71
89
|
"family-version": inputs.familyVersion,
|
|
72
|
-
"install-form": inputs.form.id + "(" + inputs.form.confidence
|
|
73
|
-
"preset-ids": REVIEWER_PRESET_ID + " / " + MAINTAINER_PRESET_ID + "
|
|
74
|
-
"readonly-contract":
|
|
75
|
-
"upgrade-order": "
|
|
76
|
-
"fallback-map": Object.keys(COMMAND_FALLBACKS).
|
|
90
|
+
"install-form": FORM_WORDS[inputs.form.id] + "(" + (inputs.form.confidence === "declared" ? "安装内容已声明" : "按已安装内容推断") + ")",
|
|
91
|
+
"preset-ids": "审阅 / 维护两个受限只读预设(" + REVIEWER_PRESET_ID + " / " + MAINTAINER_PRESET_ID + ");另可选用 " + String(EVOLUTION_PRESET_IDS.length) + " 个基础预设",
|
|
92
|
+
"readonly-contract": "受限预设只读:可用工具由该预设声明的 allow 集合决定(审阅与维护同构)",
|
|
93
|
+
"upgrade-order": "先升平台,再升家族,最后发布(详见 INSTALL 的升级说明)",
|
|
94
|
+
"fallback-map": String(Object.keys(COMMAND_FALLBACKS).length) + " 个功能面板各有命令兜底(详见 INSTALL 命令兜底表)"
|
|
77
95
|
};
|
|
78
96
|
return DIAGNOSTICS_FACT_KEYS.map((key) => ({
|
|
79
97
|
key,
|
|
@@ -88,7 +106,7 @@ function channelRow(channels) {
|
|
|
88
106
|
key: "subagent-channel",
|
|
89
107
|
label: RUNTIME_LABELS["subagent-channel"] ?? "子代理通道",
|
|
90
108
|
status: "ok",
|
|
91
|
-
detail: "
|
|
109
|
+
detail: "审阅与维护两条子代理通道均可用。"
|
|
92
110
|
};
|
|
93
111
|
const reasons = unavailable.map((state) => state.code + ": " + state.reason);
|
|
94
112
|
return {
|
|
@@ -115,14 +133,14 @@ function presetRow(presets) {
|
|
|
115
133
|
label: RUNTIME_LABELS["restricted-preset"] ?? "受限 preset",
|
|
116
134
|
status: "fail",
|
|
117
135
|
detail: errorText("e-324-restricted-preset-unavailable", { a1: broken.map((entry) => entry.broken ?? "").join(";") }),
|
|
118
|
-
remedy: "
|
|
136
|
+
remedy: "重新加载家族插件;若仍失败,运行 /evolution doctor 查看详情。"
|
|
119
137
|
};
|
|
120
138
|
if (missing.length > 0) return {
|
|
121
139
|
key: "restricted-preset",
|
|
122
140
|
label: RUNTIME_LABELS["restricted-preset"] ?? "受限 preset",
|
|
123
141
|
status: "warn",
|
|
124
|
-
detail: "
|
|
125
|
-
remedy: "
|
|
142
|
+
detail: "受限的只读模式尚未初始化(首次使用审阅或维护时自动创建)。",
|
|
143
|
+
remedy: "运行一次审阅或维护,或稍后重新检查。"
|
|
126
144
|
};
|
|
127
145
|
return {
|
|
128
146
|
key: "restricted-preset",
|
|
@@ -193,13 +211,13 @@ function runtimeOf(inputs) {
|
|
|
193
211
|
key: "session-fold",
|
|
194
212
|
label: RUNTIME_LABELS["session-fold"] ?? "会话事件 fold 单入口",
|
|
195
213
|
status: "ok",
|
|
196
|
-
detail: "
|
|
214
|
+
detail: "事件读取通道正常:对话内容会被读取,其余记录忽略。"
|
|
197
215
|
} : {
|
|
198
216
|
key: "session-fold",
|
|
199
217
|
label: RUNTIME_LABELS["session-fold"] ?? "会话事件 fold 单入口",
|
|
200
218
|
status: "fail",
|
|
201
|
-
detail: "
|
|
202
|
-
remedy: "
|
|
219
|
+
detail: "事件读取组件缺失,无法确认读取通道正常。",
|
|
220
|
+
remedy: "重新安装完整功能包(evolution-all)。"
|
|
203
221
|
},
|
|
204
222
|
missing.length === 0 ? {
|
|
205
223
|
key: "platform-services",
|
|
@@ -230,12 +248,12 @@ function runtimeOf(inputs) {
|
|
|
230
248
|
key: "install-form-detected",
|
|
231
249
|
label: RUNTIME_LABELS["install-form-detected"] ?? "实际安装形态",
|
|
232
250
|
status: "ok",
|
|
233
|
-
detail: inputs.form.id + "
|
|
251
|
+
detail: FORM_WORDS[inputs.form.id] + "(已声明)"
|
|
234
252
|
} : {
|
|
235
253
|
key: "install-form-detected",
|
|
236
254
|
label: RUNTIME_LABELS["install-form-detected"] ?? "实际安装形态",
|
|
237
255
|
status: "warn",
|
|
238
|
-
detail: inputs.form.id + "
|
|
256
|
+
detail: FORM_WORDS[inputs.form.id] + "(按已安装内容推断:" + inputs.form.evidence.join("、") + ")",
|
|
239
257
|
remedy: "在 profile 里显式声明安装行,核对 INSTALL 的形态表。"
|
|
240
258
|
}
|
|
241
259
|
].sort((a, b) => a.key.localeCompare(b.key));
|
|
@@ -1602,40 +1620,53 @@ function legacyLine(row) {
|
|
|
1602
1620
|
const more = row.pending.length > 6 ? ` (+${row.pending.length - 6} more)` : "";
|
|
1603
1621
|
return `legacy settings: ${row.pending.length} family value(s) still on ${row.source ?? "(unknown)"}: ${shown}${more} — /evolution migrate moves them`;
|
|
1604
1622
|
}
|
|
1623
|
+
/**
|
|
1624
|
+
* W8-S7: the doctor's text face, VIEW-FIRST.
|
|
1625
|
+
*
|
|
1626
|
+
* The frozen DiagnosticsView (7 facts + 8 runtime rows) is the single text source for everything
|
|
1627
|
+
* it carries — install form, platform services, runs, channel/preset/host/pairing. The legacy
|
|
1628
|
+
* report now contributes only the facts the view does not represent yet: cross-profile bundles,
|
|
1629
|
+
* the family service inference, capability absence, the scoped-row probe, the legacy settings
|
|
1630
|
+
* document, pending/executing audit records, preset freshness, and the conflict/env/budget/
|
|
1631
|
+
* parameter/session-search findings + next steps. This is the W8-S7 rewrite branch: the text face
|
|
1632
|
+
* has real consumers (the `/evolution doctor` command, README/INSTALL, doctor.spec), so the legacy
|
|
1633
|
+
* rendering was rewritten instead of deleted — but every fact the view owns renders from the view
|
|
1634
|
+
* exactly once (the legacy install-form line is gone).
|
|
1635
|
+
* @param report - the assembled report (view + legacy findings).
|
|
1636
|
+
* @returns the text face.
|
|
1637
|
+
*/
|
|
1605
1638
|
function renderDoctorText(report) {
|
|
1606
|
-
const
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
`executing: ${report.executingCount === null ? "unknown" : report.executingCount}`
|
|
1617
|
-
];
|
|
1639
|
+
const extras = [];
|
|
1640
|
+
extras.push(report.runtimeBundles === null ? "runtime bundles: unknown — the platform bundle surface (pluginManager.listBundles) is not mounted here" : `runtime bundles (this profile): ${report.runtimeBundles.length > 0 ? report.runtimeBundles.join(", ") : "(none)"}`);
|
|
1641
|
+
if (report.dormantBundles.length > 0) extras.push(`installed but not selected: ${report.dormantBundles.join(", ")} — the Plugins page lists them; this runtime mounts neither`);
|
|
1642
|
+
extras.push(`bundles (all profiles): ${report.bundles.length > 0 ? report.bundles.join(", ") : "(none)"}`);
|
|
1643
|
+
extras.push(`services: review=${report.services.review} (${report.serviceSource === "platform" ? "the live row, this runtime" : "inferred from bundles, all profiles"}) curator=${report.services.curator} approval=${report.services.approval} skillUsage=${report.services.skillUsage} io=${report.services.io}`);
|
|
1644
|
+
if (report.capabilityAbsence.length > 0) extras.push(`capability absence (${report.capabilityAbsence.length}): ${report.capabilityAbsence.map((entry) => `${entry.service} — ${entry.feature}`).join("; ")}`);
|
|
1645
|
+
extras.push(scopedProbeLine(report.scopedProbe));
|
|
1646
|
+
extras.push(legacyLine(report.legacy));
|
|
1647
|
+
extras.push(`pending: ${report.pendingCount === null ? "unknown" : report.pendingCount}`);
|
|
1648
|
+
extras.push(`executing: ${report.executingCount === null ? "unknown" : report.executingCount}`);
|
|
1618
1649
|
for (const row of report.presetFreshness) {
|
|
1619
1650
|
if (row.status === "absent") continue;
|
|
1620
1651
|
const verdict = row.status === "fresh" ? "fresh — a fresh generation matches this file byte-for-byte" : row.status === "differs" ? "DIFFERS from a fresh generation — it is an install-time snapshot; re-run the installer (/evolution preset install) to regenerate" : `unknown — a fresh generation could not be recomputed (${row.detail ?? "reason not recorded"})`;
|
|
1621
|
-
|
|
1652
|
+
extras.push(`preset: ${row.base} → ${row.destination} ${verdict}`);
|
|
1622
1653
|
}
|
|
1623
|
-
if (report.presetIssues.length > 0)
|
|
1624
|
-
if (report.foreignProfiles.length > 0)
|
|
1625
|
-
if (report.conflicts.length > 0)
|
|
1626
|
-
if (report.envIssues.length > 0)
|
|
1627
|
-
if (report.budgetIssues.length > 0)
|
|
1628
|
-
if (report.paramIssues.length > 0)
|
|
1629
|
-
if (report.queryIssues.length > 0)
|
|
1630
|
-
if (report.actions.length > 0)
|
|
1631
|
-
return
|
|
1654
|
+
if (report.presetIssues.length > 0) extras.push("agent presets:", ...report.presetIssues.map((line) => ` ! ${line}`));
|
|
1655
|
+
if (report.foreignProfiles.length > 0) extras.push("profiles-foreign: " + report.foreignProfiles.join(", ") + " — not part of this plane: /evolution preset install ignores them, while the bundles (all profiles) line above counts them");
|
|
1656
|
+
if (report.conflicts.length > 0) extras.push("conflicts:", ...report.conflicts.map((line) => ` ! ${line}`));
|
|
1657
|
+
if (report.envIssues.length > 0) extras.push("env:", ...report.envIssues.map((line) => ` ! ${line}`));
|
|
1658
|
+
if (report.budgetIssues.length > 0) extras.push("memory budget:", ...report.budgetIssues.map((line) => ` ! ${line}`));
|
|
1659
|
+
if (report.paramIssues.length > 0) extras.push("parameters:", ...report.paramIssues.map((line) => ` ! ${line}`));
|
|
1660
|
+
if (report.queryIssues.length > 0) extras.push("session search:", ...report.queryIssues.map((line) => ` ! ${line}`));
|
|
1661
|
+
if (report.actions.length > 0) extras.push("next steps:", ...report.actions.map((line) => ` → ${line}`));
|
|
1662
|
+
return renderDiagnosticsText(report.view).trimEnd() + "\n\n补充检查(view 未覆盖的运行时事实):\n" + extras.join("\n");
|
|
1632
1663
|
}
|
|
1633
1664
|
/**
|
|
1634
1665
|
* G6/W8 tail: render the frozen DiagnosticsView as the doctor's diagnostics section.
|
|
1635
1666
|
*
|
|
1636
1667
|
* This is the ONE text face of the 7+8 rows: the same object `--json` and the diagnostics route
|
|
1637
|
-
* answer, so the three readers cannot disagree.
|
|
1638
|
-
*
|
|
1668
|
+
* answer, so the three readers cannot disagree. The legacy report only adds the facts this frozen
|
|
1669
|
+
* view does not carry yet (see renderDoctorText).
|
|
1639
1670
|
* @param view - the assembled view.
|
|
1640
1671
|
* @returns the section text (ends with a newline).
|
|
1641
1672
|
*/
|
|
@@ -3174,7 +3205,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
3174
3205
|
...mounted
|
|
3175
3206
|
});
|
|
3176
3207
|
if (input === "doctor --json") return ok(JSON.stringify(report.view, null, 2));
|
|
3177
|
-
return ok(renderDoctorText(report)
|
|
3208
|
+
return ok(renderDoctorText(report));
|
|
3178
3209
|
}
|
|
3179
3210
|
if (input === "" || input === "help") return ok(`自进化:记忆、技能、会话回顾、技能整理——状态、待批准写入与维护。\n${renderHelpText()}`);
|
|
3180
3211
|
return err(`/evolution ${input} 不是本构建能应答的子命令(已知子命令但缺参数也会落到这里)。\n${renderHint()}`);
|
package/lib/types/doctor.d.ts
CHANGED
|
@@ -159,13 +159,28 @@ export declare function diagnose(ctx: {
|
|
|
159
159
|
home?: string;
|
|
160
160
|
mounted?: MountedProfile;
|
|
161
161
|
}): Promise<DoctorReport>;
|
|
162
|
+
/**
|
|
163
|
+
* W8-S7: the doctor's text face, VIEW-FIRST.
|
|
164
|
+
*
|
|
165
|
+
* The frozen DiagnosticsView (7 facts + 8 runtime rows) is the single text source for everything
|
|
166
|
+
* it carries — install form, platform services, runs, channel/preset/host/pairing. The legacy
|
|
167
|
+
* report now contributes only the facts the view does not represent yet: cross-profile bundles,
|
|
168
|
+
* the family service inference, capability absence, the scoped-row probe, the legacy settings
|
|
169
|
+
* document, pending/executing audit records, preset freshness, and the conflict/env/budget/
|
|
170
|
+
* parameter/session-search findings + next steps. This is the W8-S7 rewrite branch: the text face
|
|
171
|
+
* has real consumers (the `/evolution doctor` command, README/INSTALL, doctor.spec), so the legacy
|
|
172
|
+
* rendering was rewritten instead of deleted — but every fact the view owns renders from the view
|
|
173
|
+
* exactly once (the legacy install-form line is gone).
|
|
174
|
+
* @param report - the assembled report (view + legacy findings).
|
|
175
|
+
* @returns the text face.
|
|
176
|
+
*/
|
|
162
177
|
export declare function renderDoctorText(report: DoctorReport): string;
|
|
163
178
|
/**
|
|
164
179
|
* G6/W8 tail: render the frozen DiagnosticsView as the doctor's diagnostics section.
|
|
165
180
|
*
|
|
166
181
|
* This is the ONE text face of the 7+8 rows: the same object `--json` and the diagnostics route
|
|
167
|
-
* answer, so the three readers cannot disagree.
|
|
168
|
-
*
|
|
182
|
+
* answer, so the three readers cannot disagree. The legacy report only adds the facts this frozen
|
|
183
|
+
* view does not carry yet (see renderDoctorText).
|
|
169
184
|
* @param view - the assembled view.
|
|
170
185
|
* @returns the section text (ends with a newline).
|
|
171
186
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmzhen/dsh-evolution-commands",
|
|
3
3
|
"description": "Human commands for the evolution family (/evolution pending|curator|maintain|doctor) (community build)",
|
|
4
|
-
"version": "0.27.
|
|
4
|
+
"version": "0.27.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -27,12 +27,12 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@deepseek-ai/schemastery": "^3.18.5",
|
|
30
|
-
"@lmzhen/dsh-evolution-approval": "^0.27.
|
|
31
|
-
"@lmzhen/dsh-evolution-core": "^0.27.
|
|
32
|
-
"@lmzhen/dsh-evolution-maintenance": "^0.27.
|
|
30
|
+
"@lmzhen/dsh-evolution-approval": "^0.27.2",
|
|
31
|
+
"@lmzhen/dsh-evolution-core": "^0.27.2",
|
|
32
|
+
"@lmzhen/dsh-evolution-maintenance": "^0.27.2"
|
|
33
33
|
},
|
|
34
34
|
"optionalDependencies": {
|
|
35
|
-
"@lmzhen/dsh-evolution-agent-preset": "^0.27.
|
|
35
|
+
"@lmzhen/dsh-evolution-agent-preset": "^0.27.2"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@deepseek-ai/cordis": "^4.0.5",
|