@zmice/zc 0.2.1 → 0.2.4

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.
Files changed (253) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +242 -55
  3. package/dist/cli/__tests__/platform.test.js +573 -34
  4. package/dist/cli/__tests__/platform.test.js.map +1 -1
  5. package/dist/cli/__tests__/toolkit.test.js +35 -0
  6. package/dist/cli/__tests__/toolkit.test.js.map +1 -1
  7. package/dist/cli/platform.d.ts +15 -1
  8. package/dist/cli/platform.d.ts.map +1 -1
  9. package/dist/cli/platform.js +1195 -87
  10. package/dist/cli/platform.js.map +1 -1
  11. package/dist/cli/toolkit.d.ts.map +1 -1
  12. package/dist/cli/toolkit.js +26 -1
  13. package/dist/cli/toolkit.js.map +1 -1
  14. package/dist/node_modules/@zmice/platform-core/dist/index.d.ts +54 -1
  15. package/dist/node_modules/@zmice/platform-core/dist/index.d.ts.map +1 -1
  16. package/dist/node_modules/@zmice/platform-core/dist/index.js +53 -0
  17. package/dist/node_modules/@zmice/platform-core/dist/index.js.map +1 -1
  18. package/dist/node_modules/@zmice/platform-core/dist/index.test.js +1 -1
  19. package/dist/node_modules/@zmice/platform-core/dist/index.test.js.map +1 -1
  20. package/dist/node_modules/@zmice/platform-core/package.json +1 -1
  21. package/dist/platform-state/doctor.d.ts +3 -0
  22. package/dist/platform-state/doctor.d.ts.map +1 -0
  23. package/dist/platform-state/doctor.js +96 -0
  24. package/dist/platform-state/doctor.js.map +1 -0
  25. package/dist/platform-state/index.d.ts +2 -1
  26. package/dist/platform-state/index.d.ts.map +1 -1
  27. package/dist/platform-state/index.js +1 -0
  28. package/dist/platform-state/index.js.map +1 -1
  29. package/dist/platform-state/receipt.d.ts +5 -0
  30. package/dist/platform-state/receipt.d.ts.map +1 -1
  31. package/dist/platform-state/receipt.js +5 -0
  32. package/dist/platform-state/receipt.js.map +1 -1
  33. package/dist/platform-state/types.d.ts +16 -0
  34. package/dist/platform-state/types.d.ts.map +1 -1
  35. package/dist/utils/install-target.d.ts +1 -1
  36. package/dist/utils/install-target.d.ts.map +1 -1
  37. package/dist/utils/install-target.js +16 -6
  38. package/dist/utils/install-target.js.map +1 -1
  39. package/dist/utils/install-target.test.js +19 -10
  40. package/dist/utils/install-target.test.js.map +1 -1
  41. package/dist/utils/platform-install-cleanup.d.ts +7 -0
  42. package/dist/utils/platform-install-cleanup.d.ts.map +1 -0
  43. package/dist/utils/platform-install-cleanup.js +34 -0
  44. package/dist/utils/platform-install-cleanup.js.map +1 -0
  45. package/dist/utils/platform-install-cleanup.test.d.ts +2 -0
  46. package/dist/utils/platform-install-cleanup.test.d.ts.map +1 -0
  47. package/dist/utils/platform-install-cleanup.test.js +30 -0
  48. package/dist/utils/platform-install-cleanup.test.js.map +1 -0
  49. package/dist/utils/platform-install-receipt.d.ts +1 -0
  50. package/dist/utils/platform-install-receipt.d.ts.map +1 -1
  51. package/dist/utils/platform-install-receipt.js +10 -2
  52. package/dist/utils/platform-install-receipt.js.map +1 -1
  53. package/dist/utils/platform-install-receipt.test.js +30 -2
  54. package/dist/utils/platform-install-receipt.test.js.map +1 -1
  55. package/dist/utils/qwen-extension-cli.d.ts +52 -0
  56. package/dist/utils/qwen-extension-cli.d.ts.map +1 -0
  57. package/dist/utils/qwen-extension-cli.js +169 -0
  58. package/dist/utils/qwen-extension-cli.js.map +1 -0
  59. package/dist/utils/qwen-extension-cli.test.d.ts +2 -0
  60. package/dist/utils/qwen-extension-cli.test.d.ts.map +1 -0
  61. package/dist/utils/qwen-extension-cli.test.js +100 -0
  62. package/dist/utils/qwen-extension-cli.test.js.map +1 -0
  63. package/package.json +22 -8
  64. package/vendor/node_modules/@zmice/platform-core/dist/index.d.ts +54 -1
  65. package/vendor/node_modules/@zmice/platform-core/dist/index.d.ts.map +1 -1
  66. package/vendor/node_modules/@zmice/platform-core/dist/index.js +53 -0
  67. package/vendor/node_modules/@zmice/platform-core/dist/index.js.map +1 -1
  68. package/vendor/node_modules/@zmice/platform-core/dist/index.test.js +1 -1
  69. package/vendor/node_modules/@zmice/platform-core/dist/index.test.js.map +1 -1
  70. package/vendor/node_modules/@zmice/platform-core/package.json +1 -1
  71. package/vendor/packages/platform-claude/dist/generate.d.ts +2 -0
  72. package/vendor/packages/platform-claude/dist/generate.d.ts.map +1 -0
  73. package/vendor/packages/platform-claude/dist/generate.js +2 -0
  74. package/vendor/packages/platform-claude/dist/generate.js.map +1 -0
  75. package/vendor/packages/platform-claude/dist/index.d.ts +50 -0
  76. package/vendor/packages/platform-claude/dist/index.d.ts.map +1 -0
  77. package/vendor/packages/platform-claude/dist/index.js +250 -0
  78. package/vendor/packages/platform-claude/dist/index.js.map +1 -0
  79. package/vendor/packages/platform-claude/dist/index.test.js +81 -0
  80. package/vendor/packages/platform-claude/dist/index.test.js.map +1 -0
  81. package/vendor/packages/platform-claude/dist/install.d.ts +2 -0
  82. package/vendor/packages/platform-claude/dist/install.d.ts.map +1 -0
  83. package/vendor/packages/platform-claude/dist/install.js +2 -0
  84. package/vendor/packages/platform-claude/dist/install.js.map +1 -0
  85. package/vendor/packages/platform-claude/package.json +46 -0
  86. package/vendor/packages/platform-claude/templates/.gitkeep +1 -0
  87. package/vendor/packages/platform-claude/templates/CLAUDE.md +1 -0
  88. package/vendor/packages/platform-codex/dist/index.d.ts +36 -2
  89. package/vendor/packages/platform-codex/dist/index.d.ts.map +1 -1
  90. package/vendor/packages/platform-codex/dist/index.js +231 -6
  91. package/vendor/packages/platform-codex/dist/index.js.map +1 -1
  92. package/vendor/packages/platform-codex/dist/index.test.js +40 -10
  93. package/vendor/packages/platform-codex/dist/index.test.js.map +1 -1
  94. package/vendor/packages/platform-opencode/dist/generate.d.ts +2 -0
  95. package/vendor/packages/platform-opencode/dist/generate.d.ts.map +1 -0
  96. package/vendor/packages/platform-opencode/dist/generate.js +2 -0
  97. package/vendor/packages/platform-opencode/dist/generate.js.map +1 -0
  98. package/vendor/packages/platform-opencode/dist/index.d.ts +46 -0
  99. package/vendor/packages/platform-opencode/dist/index.d.ts.map +1 -0
  100. package/vendor/packages/platform-opencode/dist/index.js +308 -0
  101. package/vendor/packages/platform-opencode/dist/index.js.map +1 -0
  102. package/vendor/packages/platform-opencode/dist/index.test.d.ts +2 -0
  103. package/vendor/packages/platform-opencode/dist/index.test.d.ts.map +1 -0
  104. package/vendor/packages/platform-opencode/dist/index.test.js +106 -0
  105. package/vendor/packages/platform-opencode/dist/index.test.js.map +1 -0
  106. package/vendor/packages/platform-opencode/dist/install.d.ts +2 -0
  107. package/vendor/packages/platform-opencode/dist/install.d.ts.map +1 -0
  108. package/vendor/packages/platform-opencode/dist/install.js +2 -0
  109. package/vendor/packages/platform-opencode/dist/install.js.map +1 -0
  110. package/vendor/packages/{platform-qoder → platform-opencode}/package.json +2 -2
  111. package/vendor/packages/platform-opencode/templates/AGENTS.md +1 -0
  112. package/vendor/packages/platform-qwen/dist/index.d.ts +55 -2
  113. package/vendor/packages/platform-qwen/dist/index.d.ts.map +1 -1
  114. package/vendor/packages/platform-qwen/dist/index.js +229 -11
  115. package/vendor/packages/platform-qwen/dist/index.js.map +1 -1
  116. package/vendor/packages/platform-qwen/dist/index.test.js +54 -16
  117. package/vendor/packages/platform-qwen/dist/index.test.js.map +1 -1
  118. package/vendor/packages/toolkit/dist/loaders.test.js +1 -1
  119. package/vendor/packages/toolkit/dist/loaders.test.js.map +1 -1
  120. package/vendor/packages/toolkit/dist/manifests.test.js +29 -2
  121. package/vendor/packages/toolkit/dist/manifests.test.js.map +1 -1
  122. package/vendor/packages/toolkit/dist/query/toolkit-query.d.ts +4 -6
  123. package/vendor/packages/toolkit/dist/query/toolkit-query.d.ts.map +1 -1
  124. package/vendor/packages/toolkit/dist/query/toolkit-query.js +99 -1
  125. package/vendor/packages/toolkit/dist/query/toolkit-query.js.map +1 -1
  126. package/vendor/packages/toolkit/dist/query.test.js +209 -0
  127. package/vendor/packages/toolkit/dist/query.test.js.map +1 -1
  128. package/vendor/packages/toolkit/dist/schema/asset-meta.d.ts.map +1 -1
  129. package/vendor/packages/toolkit/dist/schema/asset-meta.js +105 -1
  130. package/vendor/packages/toolkit/dist/schema/asset-meta.js.map +1 -1
  131. package/vendor/packages/toolkit/dist/types.d.ts +41 -1
  132. package/vendor/packages/toolkit/dist/types.d.ts.map +1 -1
  133. package/vendor/packages/toolkit/dist/types.js +26 -1
  134. package/vendor/packages/toolkit/dist/types.js.map +1 -1
  135. package/vendor/packages/toolkit/package.json +1 -1
  136. package/vendor/packages/toolkit/src/content/agents/architect/meta.yaml +2 -1
  137. package/vendor/packages/toolkit/src/content/agents/backend-specialist/meta.yaml +2 -1
  138. package/vendor/packages/toolkit/src/content/agents/code-reviewer/meta.yaml +2 -1
  139. package/vendor/packages/toolkit/src/content/agents/frontend-specialist/meta.yaml +2 -1
  140. package/vendor/packages/toolkit/src/content/agents/performance-engineer/meta.yaml +2 -1
  141. package/vendor/packages/toolkit/src/content/agents/product-owner/meta.yaml +2 -1
  142. package/vendor/packages/toolkit/src/content/agents/security-auditor/meta.yaml +2 -1
  143. package/vendor/packages/toolkit/src/content/agents/test-engineer/meta.yaml +2 -1
  144. package/vendor/packages/toolkit/src/content/commands/api/meta.yaml +2 -1
  145. package/vendor/packages/toolkit/src/content/commands/build/body.md +15 -20
  146. package/vendor/packages/toolkit/src/content/commands/build/meta.yaml +12 -1
  147. package/vendor/packages/toolkit/src/content/commands/careful/body.md +21 -11
  148. package/vendor/packages/toolkit/src/content/commands/careful/meta.yaml +16 -1
  149. package/vendor/packages/toolkit/src/content/commands/ci/meta.yaml +2 -1
  150. package/vendor/packages/toolkit/src/content/commands/commit/meta.yaml +2 -1
  151. package/vendor/packages/toolkit/src/content/commands/ctx-health/body.md +16 -16
  152. package/vendor/packages/toolkit/src/content/commands/ctx-health/meta.yaml +11 -1
  153. package/vendor/packages/toolkit/src/content/commands/debug/body.md +16 -17
  154. package/vendor/packages/toolkit/src/content/commands/debug/meta.yaml +12 -1
  155. package/vendor/packages/toolkit/src/content/commands/doc/body.md +15 -16
  156. package/vendor/packages/toolkit/src/content/commands/doc/meta.yaml +11 -1
  157. package/vendor/packages/toolkit/src/content/commands/freeze/body.md +20 -9
  158. package/vendor/packages/toolkit/src/content/commands/freeze/meta.yaml +16 -1
  159. package/vendor/packages/toolkit/src/content/commands/guard/body.md +21 -10
  160. package/vendor/packages/toolkit/src/content/commands/guard/meta.yaml +16 -1
  161. package/vendor/packages/toolkit/src/content/commands/idea/body.md +15 -16
  162. package/vendor/packages/toolkit/src/content/commands/idea/meta.yaml +12 -1
  163. package/vendor/packages/toolkit/src/content/commands/learn/meta.yaml +2 -1
  164. package/vendor/packages/toolkit/src/content/commands/migrate/meta.yaml +2 -1
  165. package/vendor/packages/toolkit/src/content/commands/onboard/body.md +15 -17
  166. package/vendor/packages/toolkit/src/content/commands/onboard/meta.yaml +11 -1
  167. package/vendor/packages/toolkit/src/content/commands/perf/meta.yaml +2 -1
  168. package/vendor/packages/toolkit/src/content/commands/plan-review/body.md +21 -20
  169. package/vendor/packages/toolkit/src/content/commands/plan-review/meta.yaml +12 -1
  170. package/vendor/packages/toolkit/src/content/commands/product-analysis/body.md +52 -0
  171. package/vendor/packages/toolkit/src/content/commands/product-analysis/meta.yaml +35 -0
  172. package/vendor/packages/toolkit/src/content/commands/qa/meta.yaml +2 -1
  173. package/vendor/packages/toolkit/src/content/commands/quality-review/body.md +13 -18
  174. package/vendor/packages/toolkit/src/content/commands/quality-review/meta.yaml +13 -1
  175. package/vendor/packages/toolkit/src/content/commands/retro/meta.yaml +2 -1
  176. package/vendor/packages/toolkit/src/content/commands/sdd-tdd/body.md +29 -29
  177. package/vendor/packages/toolkit/src/content/commands/sdd-tdd/meta.yaml +11 -1
  178. package/vendor/packages/toolkit/src/content/commands/secure/meta.yaml +2 -1
  179. package/vendor/packages/toolkit/src/content/commands/ship/body.md +16 -11
  180. package/vendor/packages/toolkit/src/content/commands/ship/meta.yaml +11 -1
  181. package/vendor/packages/toolkit/src/content/commands/simplify/meta.yaml +2 -1
  182. package/vendor/packages/toolkit/src/content/commands/spec/body.md +16 -21
  183. package/vendor/packages/toolkit/src/content/commands/spec/meta.yaml +12 -1
  184. package/vendor/packages/toolkit/src/content/commands/start/body.md +148 -0
  185. package/vendor/packages/toolkit/src/content/commands/start/meta.yaml +55 -0
  186. package/vendor/packages/toolkit/src/content/commands/task-plan/body.md +13 -18
  187. package/vendor/packages/toolkit/src/content/commands/task-plan/meta.yaml +12 -1
  188. package/vendor/packages/toolkit/src/content/commands/ui/meta.yaml +2 -1
  189. package/vendor/packages/toolkit/src/content/commands/verify/body.md +12 -17
  190. package/vendor/packages/toolkit/src/content/commands/verify/meta.yaml +15 -1
  191. package/vendor/packages/toolkit/src/content/skills/api-and-interface-design/meta.yaml +2 -1
  192. package/vendor/packages/toolkit/src/content/skills/brainstorming-and-design/meta.yaml +2 -1
  193. package/vendor/packages/toolkit/src/content/skills/branch-finish-and-cleanup/meta.yaml +2 -1
  194. package/vendor/packages/toolkit/src/content/skills/browser-qa-testing/meta.yaml +2 -1
  195. package/vendor/packages/toolkit/src/content/skills/ci-cd-and-automation/meta.yaml +2 -1
  196. package/vendor/packages/toolkit/src/content/skills/code-review-and-quality/meta.yaml +2 -1
  197. package/vendor/packages/toolkit/src/content/skills/code-simplification/meta.yaml +2 -1
  198. package/vendor/packages/toolkit/src/content/skills/codebase-onboarding/body.md +6 -3
  199. package/vendor/packages/toolkit/src/content/skills/codebase-onboarding/meta.yaml +2 -1
  200. package/vendor/packages/toolkit/src/content/skills/context-budget-audit/meta.yaml +2 -1
  201. package/vendor/packages/toolkit/src/content/skills/context-engineering/body.md +7 -5
  202. package/vendor/packages/toolkit/src/content/skills/context-engineering/meta.yaml +2 -1
  203. package/vendor/packages/toolkit/src/content/skills/continuous-learning/body.md +15 -15
  204. package/vendor/packages/toolkit/src/content/skills/continuous-learning/meta.yaml +2 -1
  205. package/vendor/packages/toolkit/src/content/skills/debugging-and-error-recovery/body.md +9 -6
  206. package/vendor/packages/toolkit/src/content/skills/debugging-and-error-recovery/meta.yaml +2 -1
  207. package/vendor/packages/toolkit/src/content/skills/deprecation-and-migration/meta.yaml +2 -1
  208. package/vendor/packages/toolkit/src/content/skills/developer-experience-audit/meta.yaml +2 -1
  209. package/vendor/packages/toolkit/src/content/skills/documentation-and-adrs/body.md +7 -11
  210. package/vendor/packages/toolkit/src/content/skills/documentation-and-adrs/meta.yaml +2 -1
  211. package/vendor/packages/toolkit/src/content/skills/engineering-principles/meta.yaml +2 -1
  212. package/vendor/packages/toolkit/src/content/skills/frontend-ui-engineering/meta.yaml +2 -1
  213. package/vendor/packages/toolkit/src/content/skills/git-workflow-and-versioning/meta.yaml +2 -1
  214. package/vendor/packages/toolkit/src/content/skills/idea-refine/body.md +31 -160
  215. package/vendor/packages/toolkit/src/content/skills/idea-refine/meta.yaml +2 -1
  216. package/vendor/packages/toolkit/src/content/skills/incremental-implementation/meta.yaml +2 -1
  217. package/vendor/packages/toolkit/src/content/skills/multi-perspective-review/meta.yaml +2 -1
  218. package/vendor/packages/toolkit/src/content/skills/parallel-agent-dispatch/meta.yaml +2 -1
  219. package/vendor/packages/toolkit/src/content/skills/performance-optimization/meta.yaml +2 -1
  220. package/vendor/packages/toolkit/src/content/skills/planning-and-task-breakdown/meta.yaml +2 -1
  221. package/vendor/packages/toolkit/src/content/skills/release-documentation-sync/meta.yaml +2 -1
  222. package/vendor/packages/toolkit/src/content/skills/review-response-and-resolution/meta.yaml +2 -1
  223. package/vendor/packages/toolkit/src/content/skills/safety-guardrails/body.md +6 -2
  224. package/vendor/packages/toolkit/src/content/skills/safety-guardrails/meta.yaml +2 -1
  225. package/vendor/packages/toolkit/src/content/skills/sdd-tdd-workflow/meta.yaml +2 -1
  226. package/vendor/packages/toolkit/src/content/skills/security-and-hardening/meta.yaml +2 -1
  227. package/vendor/packages/toolkit/src/content/skills/shipping-and-launch/body.md +7 -11
  228. package/vendor/packages/toolkit/src/content/skills/shipping-and-launch/meta.yaml +2 -1
  229. package/vendor/packages/toolkit/src/content/skills/source-driven-development/meta.yaml +2 -1
  230. package/vendor/packages/toolkit/src/content/skills/spec-driven-development/meta.yaml +2 -1
  231. package/vendor/packages/toolkit/src/content/skills/sprint-retrospective/meta.yaml +2 -1
  232. package/vendor/packages/toolkit/src/content/skills/subagent-driven-development/meta.yaml +2 -1
  233. package/vendor/packages/toolkit/src/content/skills/team-orchestration/meta.yaml +2 -1
  234. package/vendor/packages/toolkit/src/content/skills/test-driven-development/meta.yaml +2 -1
  235. package/vendor/packages/toolkit/src/content/skills/using-agent-skills/meta.yaml +2 -1
  236. package/vendor/packages/toolkit/src/content/skills/verification-before-completion/meta.yaml +2 -1
  237. package/vendor/packages/platform-qoder/dist/generate.d.ts +0 -2
  238. package/vendor/packages/platform-qoder/dist/generate.d.ts.map +0 -1
  239. package/vendor/packages/platform-qoder/dist/generate.js +0 -2
  240. package/vendor/packages/platform-qoder/dist/generate.js.map +0 -1
  241. package/vendor/packages/platform-qoder/dist/index.d.ts +0 -15
  242. package/vendor/packages/platform-qoder/dist/index.d.ts.map +0 -1
  243. package/vendor/packages/platform-qoder/dist/index.js +0 -46
  244. package/vendor/packages/platform-qoder/dist/index.js.map +0 -1
  245. package/vendor/packages/platform-qoder/dist/index.test.js +0 -38
  246. package/vendor/packages/platform-qoder/dist/index.test.js.map +0 -1
  247. package/vendor/packages/platform-qoder/dist/install.d.ts +0 -2
  248. package/vendor/packages/platform-qoder/dist/install.d.ts.map +0 -1
  249. package/vendor/packages/platform-qoder/dist/install.js +0 -2
  250. package/vendor/packages/platform-qoder/dist/install.js.map +0 -1
  251. package/vendor/packages/platform-qoder/templates/instructions.md +0 -7
  252. /package/vendor/packages/{platform-qoder → platform-claude}/dist/index.test.d.ts +0 -0
  253. /package/vendor/packages/{platform-qoder → platform-claude}/dist/index.test.d.ts.map +0 -0
@@ -2,12 +2,110 @@ import { InvalidArgumentError } from "commander";
2
2
  import { readFileSync } from "node:fs";
3
3
  import { join, resolve } from "node:path";
4
4
  import { attachPlanMetadata } from "@zmice/platform-core";
5
+ import { resolvePlatformInstallDoctor } from "../platform-state/doctor.js";
5
6
  import { resolvePlatformInstallStatus } from "../platform-state/status.js";
6
7
  import { normalizeInstallSelector, resolveInstallTarget } from "../utils/install-target.js";
7
- import { resolvePlatformInstallReceiptPath, writePlatformInstallReceiptForPlan, } from "../utils/platform-install-receipt.js";
8
+ import { deletePlatformInstallReceipt, resolvePlatformInstallReceiptPath, writePlatformInstallReceiptForPlan, } from "../utils/platform-install-receipt.js";
9
+ import { pathExists, removeManagedPaths } from "../utils/platform-install-cleanup.js";
8
10
  import { ArtifactConflictError, importWorkspaceDistModule, resolveWorkspacePath, writeArtifacts, } from "../utils/workspace.js";
9
- const platformNames = ["qwen", "codex", "qoder"];
10
- const defaultPlatforms = ["qwen", "codex", "qoder"];
11
+ import { QwenOfficialCliUnavailableError, installQwenExtensionFromOfficialRepoWithCli, installQwenExtensionWithOfficialCli, qwenOfficialExtensionRepoUrl, relinkQwenExtensionWithOfficialCli, resolveQwenOfficialCliReleaseBundleDir, syncQwenOfficialCliReleaseBundle, toQwenOfficialCliReleaseArtifacts, uninstallQwenExtensionWithOfficialCli, updateQwenExtensionWithOfficialCli, } from "../utils/qwen-extension-cli.js";
12
+ const platformNames = ["qwen", "codex", "claude", "opencode"];
13
+ function getPlanCapabilitySummary(plan) {
14
+ const capability = plan.capability;
15
+ if (!capability) {
16
+ return null;
17
+ }
18
+ const exposure = (() => {
19
+ switch (plan.platform) {
20
+ case "codex":
21
+ return {
22
+ style: "skill-alias",
23
+ entryPattern: "$zc-*",
24
+ examples: [
25
+ "zc:start -> $zc-start",
26
+ "zc:product-analysis -> $zc-product-analysis",
27
+ "zc:sdd-tdd -> $zc-sdd-tdd",
28
+ ],
29
+ };
30
+ case "claude":
31
+ return {
32
+ style: "slash-command",
33
+ entryPattern: "/zc-*",
34
+ examples: [
35
+ "zc:start -> /zc-start",
36
+ "zc:product-analysis -> /zc-product-analysis",
37
+ "zc:sdd-tdd -> /zc-sdd-tdd",
38
+ ],
39
+ };
40
+ case "opencode":
41
+ return {
42
+ style: "slash-command",
43
+ entryPattern: "/zc-*",
44
+ examples: [
45
+ "zc:start -> /zc-start",
46
+ "zc:product-analysis -> /zc-product-analysis",
47
+ "zc:sdd-tdd -> /zc-sdd-tdd",
48
+ ],
49
+ };
50
+ case "qwen":
51
+ return {
52
+ style: "namespaced-command",
53
+ entryPattern: "zc:*",
54
+ examples: [
55
+ "zc:start -> zc:start",
56
+ "zc:product-analysis -> zc:product-analysis",
57
+ "zc:sdd-tdd -> zc:sdd-tdd",
58
+ ],
59
+ };
60
+ }
61
+ })();
62
+ return {
63
+ namespace: capability.namespace,
64
+ surfaces: capability.surfaces,
65
+ entryFile: capability.entryFile?.fileName ?? null,
66
+ commandsDir: capability.commands?.relativeDir ?? null,
67
+ skillsDir: capability.skills?.relativeDir ?? null,
68
+ agentsDir: capability.agents?.relativeDir ?? null,
69
+ extensionDir: capability.extension
70
+ ? `${capability.extension.relativeDir}/${capability.extension.name}`
71
+ : null,
72
+ exposure,
73
+ };
74
+ }
75
+ function formatSurfaceLabel(surface) {
76
+ switch (surface) {
77
+ case "entry-file":
78
+ return "入口文件";
79
+ case "skills-dir":
80
+ return "skills 目录";
81
+ case "commands-dir":
82
+ return "commands 目录";
83
+ case "agents-dir":
84
+ return "agents 目录";
85
+ case "extension-dir":
86
+ return "extension 目录";
87
+ default:
88
+ return surface;
89
+ }
90
+ }
91
+ function summarizeCapability(plan) {
92
+ const capability = getPlanCapabilitySummary(plan);
93
+ if (!capability) {
94
+ return [];
95
+ }
96
+ return [
97
+ `命名空间:${capability.namespace}`,
98
+ `入口形式:${capability.exposure.entryPattern}`,
99
+ `安装面:${capability.surfaces.map((surface) => formatSurfaceLabel(surface)).join("、")}`,
100
+ ...(capability.entryFile ? [`入口文件:${capability.entryFile}`] : []),
101
+ ...(capability.commandsDir ? [`commands 目录:${capability.commandsDir}`] : []),
102
+ ...(capability.skillsDir ? [`skills 目录:${capability.skillsDir}`] : []),
103
+ ...(capability.agentsDir ? [`agents 目录:${capability.agentsDir}`] : []),
104
+ ...(capability.extensionDir ? [`extension 目录:${capability.extensionDir}`] : []),
105
+ `示例映射:${capability.exposure.examples.join(";")}`,
106
+ ];
107
+ }
108
+ const defaultPlatforms = ["qwen", "codex", "claude", "opencode"];
11
109
  function getCliVersion() {
12
110
  const packageJsonPath = new URL("../../package.json", import.meta.url);
13
111
  const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
@@ -19,10 +117,13 @@ function normalizeManifest(manifest) {
19
117
  assets: manifest.assets.map((asset) => ({
20
118
  id: asset.id,
21
119
  kind: asset.meta.kind,
120
+ name: asset.meta.name,
22
121
  platforms: asset.meta.platforms ?? defaultPlatforms,
23
122
  title: asset.meta.title,
24
123
  summary: asset.meta.description,
25
- body: asset.body
124
+ body: asset.body,
125
+ tools: asset.meta.tools,
126
+ requires: asset.meta.requires
26
127
  }))
27
128
  };
28
129
  }
@@ -37,30 +138,38 @@ async function loadPlatformModule(platform) {
37
138
  const packageMap = {
38
139
  qwen: "packages/platform-qwen/dist/index.js",
39
140
  codex: "packages/platform-codex/dist/index.js",
40
- qoder: "packages/platform-qoder/dist/index.js"
141
+ claude: "packages/platform-claude/dist/index.js",
142
+ opencode: "packages/platform-opencode/dist/index.js"
41
143
  };
42
144
  return importWorkspaceDistModule(packageMap[platform]);
43
145
  }
44
146
  function createGenerationPlan(platform, platformModule, manifest) {
147
+ const extensionVersion = getCliVersion();
45
148
  switch (platform) {
46
149
  case "qwen":
47
150
  if (!platformModule.createQwenGenerationPlan) {
48
151
  throw new Error("Qwen 平台包未导出 createQwenGenerationPlan()");
49
152
  }
50
- return finalizePlan(platformModule.createQwenGenerationPlan(manifest, { manifestSource: manifest.source }));
153
+ return finalizePlan(platformModule.createQwenGenerationPlan(manifest, { manifestSource: manifest.source, extensionVersion }));
51
154
  case "codex":
52
155
  if (!platformModule.createCodexGenerationPlan) {
53
156
  throw new Error("Codex 平台包未导出 createCodexGenerationPlan()");
54
157
  }
55
- return finalizePlan(platformModule.createCodexGenerationPlan(manifest, { manifestSource: manifest.source }));
56
- case "qoder":
57
- if (!platformModule.createQoderGenerationPlan) {
58
- throw new Error("Qoder 平台包未导出 createQoderGenerationPlan()");
158
+ return finalizePlan(platformModule.createCodexGenerationPlan(manifest, { manifestSource: manifest.source, extensionVersion }));
159
+ case "claude":
160
+ if (!platformModule.createClaudeGenerationPlan) {
161
+ throw new Error("Claude 平台包未导出 createClaudeGenerationPlan()");
59
162
  }
60
- return finalizePlan(platformModule.createQoderGenerationPlan(manifest, { manifestSource: manifest.source }));
163
+ return finalizePlan(platformModule.createClaudeGenerationPlan(manifest, { manifestSource: manifest.source, extensionVersion }));
164
+ case "opencode":
165
+ if (!platformModule.createOpenCodeGenerationPlan) {
166
+ throw new Error("OpenCode 平台包未导出 createOpenCodeGenerationPlan()");
167
+ }
168
+ return finalizePlan(platformModule.createOpenCodeGenerationPlan(manifest, { manifestSource: manifest.source, extensionVersion }));
61
169
  }
62
170
  }
63
- function createInstallPlan(platform, platformModule, manifest, destinationRoot, overwrite) {
171
+ function createInstallPlan(platform, platformModule, manifest, destinationRoot, scope, overwrite) {
172
+ const extensionVersion = getCliVersion();
64
173
  switch (platform) {
65
174
  case "qwen":
66
175
  if (!platformModule.createQwenInstallPlan) {
@@ -69,7 +178,9 @@ function createInstallPlan(platform, platformModule, manifest, destinationRoot,
69
178
  return finalizePlan(platformModule.createQwenInstallPlan(manifest, {
70
179
  manifestSource: manifest.source,
71
180
  destinationRoot,
72
- overwrite
181
+ scope,
182
+ overwrite,
183
+ extensionVersion,
73
184
  }));
74
185
  case "codex":
75
186
  if (!platformModule.createCodexInstallPlan) {
@@ -78,16 +189,31 @@ function createInstallPlan(platform, platformModule, manifest, destinationRoot,
78
189
  return finalizePlan(platformModule.createCodexInstallPlan(manifest, {
79
190
  manifestSource: manifest.source,
80
191
  destinationRoot,
81
- overwrite
192
+ scope,
193
+ overwrite,
194
+ extensionVersion,
195
+ }));
196
+ case "claude":
197
+ if (!platformModule.createClaudeInstallPlan) {
198
+ throw new Error("Claude 平台包未导出 createClaudeInstallPlan()");
199
+ }
200
+ return finalizePlan(platformModule.createClaudeInstallPlan(manifest, {
201
+ manifestSource: manifest.source,
202
+ destinationRoot,
203
+ scope,
204
+ overwrite,
205
+ extensionVersion,
82
206
  }));
83
- case "qoder":
84
- if (!platformModule.createQoderInstallPlan) {
85
- throw new Error("Qoder 平台包未导出 createQoderInstallPlan()");
207
+ case "opencode":
208
+ if (!platformModule.createOpenCodeInstallPlan) {
209
+ throw new Error("OpenCode 平台包未导出 createOpenCodeInstallPlan()");
86
210
  }
87
- return finalizePlan(platformModule.createQoderInstallPlan(manifest, {
211
+ return finalizePlan(platformModule.createOpenCodeInstallPlan(manifest, {
88
212
  manifestSource: manifest.source,
89
213
  destinationRoot,
90
- overwrite
214
+ scope,
215
+ overwrite,
216
+ extensionVersion,
91
217
  }));
92
218
  }
93
219
  }
@@ -97,6 +223,10 @@ function resolveOverwriteMode(force) {
97
223
  function resolveOutputFormat(json) {
98
224
  return json ? "json" : "text";
99
225
  }
226
+ function mergeHints(...hints) {
227
+ const merged = hints.filter(Boolean);
228
+ return merged.length > 0 ? merged.join(";") : undefined;
229
+ }
100
230
  function resolveScopeFromSelector(opts) {
101
231
  return normalizeInstallSelector(opts).mode;
102
232
  }
@@ -128,6 +258,10 @@ function formatActionLabel(action) {
128
258
  return "安装";
129
259
  case "update":
130
260
  return "更新";
261
+ case "repair":
262
+ return "修复";
263
+ case "uninstall":
264
+ return "卸载";
131
265
  }
132
266
  }
133
267
  function formatRootLabel(action, root, metadata) {
@@ -149,30 +283,121 @@ function formatStatusLabel(kind) {
149
283
  return "已漂移";
150
284
  }
151
285
  }
286
+ function formatInstallMethodLabel(method) {
287
+ return method === "qwen-cli" ? "官方 qwen extensions CLI" : "直接写入";
288
+ }
289
+ function formatInstallSourceLabel(source) {
290
+ return source === "github-repo" ? "GitHub 扩展仓库" : "本地 bundle";
291
+ }
292
+ function formatBundleTypeLabel(type) {
293
+ return type === "release-bundle" ? "发布态扩展包" : "开发态源包";
294
+ }
295
+ function formatScopeFlag(scope, root) {
296
+ switch (scope) {
297
+ case "global":
298
+ return " --global";
299
+ case "project":
300
+ return " --project";
301
+ case "dir":
302
+ return ` --dir ${JSON.stringify(root)}`;
303
+ }
304
+ }
305
+ function buildNextStep(action, target, root, options) {
306
+ const scopeFlag = formatScopeFlag(options?.scope ?? "project", root);
307
+ switch (action) {
308
+ case "generate":
309
+ return `下一步:如需写入平台目录,运行 \`zc platform install ${target} --project\`、\`--global\` 或 \`--dir <path>\`。`;
310
+ case "install":
311
+ return options?.noop
312
+ ? `下一步:当前已是目标状态;如需确认细节,运行 \`zc platform status ${target}${scopeFlag} --json\`。`
313
+ : `下一步:运行 \`zc platform status ${target}${scopeFlag}\` 确认安装状态。`;
314
+ case "update":
315
+ return options?.noop
316
+ ? "下一步:当前已经是最新版本,无需额外操作。"
317
+ : `下一步:运行 \`zc platform status ${target}${scopeFlag}\` 确认更新结果。`;
318
+ case "repair":
319
+ return options?.noop
320
+ ? "下一步:当前安装健康,无需修复。"
321
+ : `下一步:运行 \`zc platform doctor ${target}${scopeFlag}\` 复查健康度。`;
322
+ case "uninstall":
323
+ return `下一步:如需重新安装,运行 \`zc platform install ${target}${scopeFlag}\`。`;
324
+ case "where":
325
+ return `下一步:运行 \`zc platform install ${target}${scopeFlag}\` 执行安装,或追加 \`--plan --json\` 先看计划。`;
326
+ case "status":
327
+ switch (options?.status) {
328
+ case "not-installed":
329
+ return `下一步:运行 \`zc platform install ${target}${scopeFlag}\`。`;
330
+ case "update-available":
331
+ return `下一步:运行 \`zc platform update ${target}${scopeFlag}\`。`;
332
+ case "drifted":
333
+ return `下一步:先运行 \`zc platform doctor ${target}${scopeFlag}\`,再按结果选择 \`repair\` 或带 \`--force\` 的 \`update\`。`;
334
+ case "up-to-date":
335
+ return "下一步:当前已是最新状态,无需动作。";
336
+ default:
337
+ return null;
338
+ }
339
+ case "doctor":
340
+ switch (options?.health) {
341
+ case "healthy":
342
+ return "下一步:未发现需要处理的问题。";
343
+ case "warning":
344
+ return `下一步:优先运行 \`zc platform repair ${target}${scopeFlag}\`,再复查状态。`;
345
+ case "broken":
346
+ return `下一步:先运行 \`zc platform repair ${target}${scopeFlag}\`;如仍异常,再查看 \`zc platform status ${target}${scopeFlag} --json\`。`;
347
+ default:
348
+ return null;
349
+ }
350
+ }
351
+ }
152
352
  function summarizeResult(action, target, root, result, metadata) {
153
353
  const mode = result.dryRun ? "预演完成" : "完成";
154
- return [
354
+ const lines = [
155
355
  `${target} ${formatActionLabel(action)}${mode}`,
156
356
  formatRootLabel(action, root, metadata),
157
357
  ...(metadata?.status ? [`状态:${metadata.status}`] : []),
358
+ ...(metadata?.installMethod ? [`安装方式:${formatInstallMethodLabel(metadata.installMethod)}`] : []),
359
+ ...(metadata?.installSource ? [`安装来源:${formatInstallSourceLabel(metadata.installSource)}`] : []),
360
+ ...(metadata?.sourceRef ? [`来源:${metadata.sourceRef}`] : []),
361
+ ...(metadata?.bundleType ? [`Bundle 类型:${formatBundleTypeLabel(metadata.bundleType)}`] : []),
362
+ ...(metadata?.bundlePath ? [`Bundle 目录:${metadata.bundlePath}`] : []),
158
363
  ...(metadata?.receiptPath ? [`回执:${metadata.receiptPath}`] : []),
159
- ...(metadata?.zcVersion ? [`zc 版本:${metadata.zcVersion}`] : []),
160
- ...(metadata?.contentFingerprint ? [`内容指纹:${metadata.contentFingerprint}`] : []),
161
364
  ...(metadata?.hint ? [`提示:${metadata.hint}`] : []),
162
365
  metadata?.noop
163
366
  ? "无需写入,当前安装已满足目标状态。"
164
367
  : `新增 ${result.created},覆盖 ${result.overwritten},未变更 ${result.unchanged}${result.dryRun ? `,跳过写入 ${result.skipped}` : ""}`,
165
- ].join("\n");
368
+ ];
369
+ const nextStep = buildNextStep(action, target, root, {
370
+ scope: metadata?.scope,
371
+ status: metadata?.status,
372
+ noop: metadata?.noop,
373
+ });
374
+ if (nextStep) {
375
+ lines.push(nextStep);
376
+ }
377
+ return lines.join("\n");
166
378
  }
167
379
  function summarizePlan(action, target, root, plan, metadata) {
168
- return [
380
+ const lines = [
169
381
  `${target} ${formatActionLabel(action)}计划`,
170
382
  formatRootLabel(action, root, metadata),
171
383
  ...(metadata?.status ? [`状态:${metadata.status}`] : []),
384
+ ...(metadata?.installSource ? [`安装来源:${formatInstallSourceLabel(metadata.installSource)}`] : []),
385
+ ...(metadata?.sourceRef ? [`来源:${metadata.sourceRef}`] : []),
386
+ ...(metadata?.bundleType ? [`Bundle 类型:${formatBundleTypeLabel(metadata.bundleType)}`] : []),
387
+ ...(metadata?.bundlePath ? [`Bundle 目录:${metadata.bundlePath}`] : []),
172
388
  ...(metadata?.hint ? [`提示:${metadata.hint}`] : []),
389
+ ...summarizeCapability(plan),
173
390
  `产物数量:${plan.artifacts.length}`,
174
391
  ...plan.artifacts.map((artifact) => `- ${artifact.path}`),
175
- ].join("\n");
392
+ ];
393
+ const nextStep = buildNextStep(action, target, root, {
394
+ scope: metadata?.scope,
395
+ status: metadata?.status,
396
+ });
397
+ if (nextStep) {
398
+ lines.push(nextStep);
399
+ }
400
+ return lines.join("\n");
176
401
  }
177
402
  function buildPlanPayload(action, target, root, plan, metadata) {
178
403
  return {
@@ -185,12 +410,23 @@ function buildPlanPayload(action, target, root, plan, metadata) {
185
410
  autoResolvedRoot: metadata?.autoResolvedRoot ?? false,
186
411
  hint: metadata?.hint ?? null,
187
412
  status: metadata?.status ?? null,
413
+ installSource: metadata?.installSource ?? null,
414
+ sourceRef: metadata?.sourceRef ?? null,
415
+ bundleType: metadata?.bundleType ?? null,
416
+ bundlePath: metadata?.bundlePath ?? null,
417
+ capability: getPlanCapabilitySummary(plan),
188
418
  artifactCount: plan.artifacts.length,
189
419
  contentFingerprint: plan.metadata?.fingerprint.value ?? null,
190
420
  overwrite: "overwrite" in plan ? plan.overwrite : null,
191
421
  artifacts: plan.artifacts,
192
422
  };
193
423
  }
424
+ function parseGenerateBundleType(value) {
425
+ if (value === "release-bundle" || value === "release") {
426
+ return "release-bundle";
427
+ }
428
+ throw new InvalidArgumentError(`不支持的 bundle 类型:${value}。当前仅支持:release-bundle`);
429
+ }
194
430
  function buildResultPayload(action, target, root, result, metadata) {
195
431
  return {
196
432
  mode: "result",
@@ -201,6 +437,11 @@ function buildResultPayload(action, target, root, result, metadata) {
201
437
  rootSource: metadata?.rootSource ?? (metadata?.autoResolvedRoot ? "project-root" : "explicit"),
202
438
  autoResolvedRoot: metadata?.autoResolvedRoot ?? false,
203
439
  hint: metadata?.hint ?? null,
440
+ installMethod: metadata?.installMethod ?? "filesystem",
441
+ installSource: metadata?.installSource ?? null,
442
+ sourceRef: metadata?.sourceRef ?? null,
443
+ bundleType: metadata?.bundleType ?? null,
444
+ bundlePath: metadata?.bundlePath ?? null,
204
445
  receiptPath: metadata?.receiptPath ?? null,
205
446
  zcVersion: metadata?.zcVersion ?? null,
206
447
  status: metadata?.status ?? null,
@@ -209,15 +450,71 @@ function buildResultPayload(action, target, root, result, metadata) {
209
450
  ...result,
210
451
  };
211
452
  }
453
+ function shouldPreferQwenOfficialCli(target, scope) {
454
+ return target === "qwen" && scope === "global";
455
+ }
456
+ function shouldPreferQwenOfficialRepoInstall(target, scope) {
457
+ return shouldPreferQwenOfficialCli(target, scope);
458
+ }
459
+ function estimateManagedInstallResult(plan, status) {
460
+ if (status.kind === "not-installed") {
461
+ return {
462
+ created: plan.artifacts.length,
463
+ overwritten: 0,
464
+ unchanged: 0,
465
+ skipped: 0,
466
+ dryRun: false,
467
+ };
468
+ }
469
+ let created = 0;
470
+ let overwritten = 0;
471
+ let unchanged = 0;
472
+ for (const artifact of status.artifacts) {
473
+ if (artifact.plannedSha256 === null) {
474
+ continue;
475
+ }
476
+ if (artifact.actualSha256 === artifact.plannedSha256) {
477
+ unchanged += 1;
478
+ continue;
479
+ }
480
+ if (artifact.actualSha256 === null) {
481
+ created += 1;
482
+ continue;
483
+ }
484
+ overwritten += 1;
485
+ }
486
+ return {
487
+ created,
488
+ overwritten,
489
+ unchanged,
490
+ skipped: 0,
491
+ dryRun: false,
492
+ };
493
+ }
212
494
  function summarizeWhere(target, root, metadata) {
213
- return [
495
+ const lines = [
214
496
  `${target} 安装目标`,
215
497
  `范围:${metadata.scope}`,
216
498
  `解析来源:${metadata.rootSource}`,
217
499
  ...(metadata.marker ? [`命中标记:${metadata.marker}`] : []),
218
500
  `目录:${root}`,
501
+ ...(metadata.capability
502
+ ? [
503
+ `命名空间:${metadata.capability.namespace}`,
504
+ `入口形式:${metadata.capability.exposure.entryPattern}`,
505
+ `安装面:${metadata.capability.surfaces.map((surface) => formatSurfaceLabel(surface)).join("、")}`,
506
+ `示例映射:${metadata.capability.exposure.examples.join(";")}`,
507
+ ]
508
+ : []),
219
509
  ...(metadata.hint ? [`提示:${metadata.hint}`] : []),
220
- ].join("\n");
510
+ ];
511
+ const nextStep = buildNextStep("where", target, root, {
512
+ scope: metadata.scope,
513
+ });
514
+ if (nextStep) {
515
+ lines.push(nextStep);
516
+ }
517
+ return lines.join("\n");
221
518
  }
222
519
  function buildWherePayload(target, root, metadata) {
223
520
  return {
@@ -228,6 +525,7 @@ function buildWherePayload(target, root, metadata) {
228
525
  rootSource: metadata.rootSource,
229
526
  marker: metadata.marker ?? null,
230
527
  hint: metadata.hint ?? null,
528
+ capability: metadata.capability ?? null,
231
529
  };
232
530
  }
233
531
  function reportConflict(error, target, destinationRoot) {
@@ -240,19 +538,33 @@ function reportConflict(error, target, destinationRoot) {
240
538
  console.error("如需覆盖,请追加 --force。");
241
539
  }
242
540
  function summarizeStatus(target, root, status, metadata) {
243
- return [
541
+ const lines = [
244
542
  `${target} 安装状态`,
245
543
  `范围:${metadata.scope}`,
246
544
  `目录:${root}`,
247
545
  `状态:${status.kind}(${formatStatusLabel(status.kind)})`,
248
546
  `回执:${status.receiptPath}`,
249
- ...(status.installedZcVersion ? [`已安装 zc 版本:${status.installedZcVersion}`] : []),
250
- ...(metadata.zcVersion ? [`当前 zc 版本:${metadata.zcVersion}`] : []),
251
- ...(status.installedContentFingerprint ? [`已安装内容指纹:${status.installedContentFingerprint}`] : []),
252
- ...(status.contentFingerprint ? [`当前内容指纹:${status.contentFingerprint}`] : []),
547
+ ...(metadata.installMethod ? [`安装方式:${formatInstallMethodLabel(metadata.installMethod)}`] : []),
548
+ ...(metadata.installSource ? [`安装来源:${formatInstallSourceLabel(metadata.installSource)}`] : []),
549
+ ...(metadata.sourceRef ? [`来源:${metadata.sourceRef}`] : []),
550
+ ...(metadata.bundleType ? [`Bundle 类型:${formatBundleTypeLabel(metadata.bundleType)}`] : []),
551
+ ...(metadata.bundlePath ? [`Bundle 目录:${metadata.bundlePath}`] : []),
552
+ ...(metadata.recommendedInstallMethod ? [`推荐安装方式:${formatInstallMethodLabel(metadata.recommendedInstallMethod)}`] : []),
553
+ ...(metadata.recommendedInstallSource ? [`推荐来源:${formatInstallSourceLabel(metadata.recommendedInstallSource)}`] : []),
554
+ ...(metadata.recommendedSourceRef ? [`推荐来源地址:${metadata.recommendedSourceRef}`] : []),
555
+ ...(metadata.recommendedBundleType ? [`推荐 Bundle:${formatBundleTypeLabel(metadata.recommendedBundleType)}`] : []),
556
+ ...(metadata.recommendedBundlePath ? [`推荐 Bundle 目录:${metadata.recommendedBundlePath}`] : []),
253
557
  `跟踪产物:${status.summary.trackedArtifacts},漂移:${status.summary.driftedArtifacts},缺失:${status.summary.missingArtifacts},待更新:${status.summary.plannedChanges}`,
254
558
  ...(metadata.hint ? [`提示:${metadata.hint}`] : []),
255
- ].join("\n");
559
+ ];
560
+ const nextStep = buildNextStep("status", target, root, {
561
+ scope: metadata.scope,
562
+ status: status.kind,
563
+ });
564
+ if (nextStep) {
565
+ lines.push(nextStep);
566
+ }
567
+ return lines.join("\n");
256
568
  }
257
569
  function buildStatusPayload(target, root, status, metadata) {
258
570
  return {
@@ -262,6 +574,17 @@ function buildStatusPayload(target, root, status, metadata) {
262
574
  root,
263
575
  rootSource: metadata.rootSource,
264
576
  hint: metadata.hint ?? null,
577
+ capability: getPlanCapabilitySummary(metadata.plan),
578
+ installMethod: metadata.installMethod ?? null,
579
+ installSource: metadata.installSource ?? null,
580
+ sourceRef: metadata.sourceRef ?? null,
581
+ bundleType: metadata.bundleType ?? null,
582
+ bundlePath: metadata.bundlePath ?? null,
583
+ recommendedInstallMethod: metadata.recommendedInstallMethod ?? null,
584
+ recommendedInstallSource: metadata.recommendedInstallSource ?? null,
585
+ recommendedSourceRef: metadata.recommendedSourceRef ?? null,
586
+ recommendedBundleType: metadata.recommendedBundleType ?? null,
587
+ recommendedBundlePath: metadata.recommendedBundlePath ?? null,
265
588
  status: status.kind,
266
589
  receiptPath: status.receiptPath,
267
590
  zcVersion: metadata.zcVersion ?? null,
@@ -272,37 +595,143 @@ function buildStatusPayload(target, root, status, metadata) {
272
595
  artifacts: status.artifacts,
273
596
  };
274
597
  }
598
+ function summarizeDoctor(target, root, status, doctor, metadata) {
599
+ const lines = [
600
+ `${target} 安装诊断`,
601
+ `范围:${metadata.scope}`,
602
+ `目录:${root}`,
603
+ `状态:${status.kind}(${formatStatusLabel(status.kind)})`,
604
+ `健康度:${doctor.health}`,
605
+ ...(doctor.issues.length > 0
606
+ ? doctor.issues.flatMap((issue) => [
607
+ `- [${issue.severity}] ${issue.code}: ${issue.message}`,
608
+ ...(issue.paths && issue.paths.length > 0 ? issue.paths.map((path) => ` - ${path}`) : []),
609
+ ])
610
+ : ["- 未发现需要处理的问题。"]),
611
+ ...(metadata.hint ? [`提示:${metadata.hint}`] : []),
612
+ ];
613
+ const nextStep = buildNextStep("doctor", target, root, {
614
+ scope: metadata.scope,
615
+ status: status.kind,
616
+ health: doctor.health,
617
+ });
618
+ if (nextStep) {
619
+ lines.push(nextStep);
620
+ }
621
+ return lines.join("\n");
622
+ }
623
+ function buildDoctorPayload(target, root, status, doctor, metadata) {
624
+ return {
625
+ mode: "doctor",
626
+ target,
627
+ scope: metadata.scope,
628
+ root,
629
+ rootSource: metadata.rootSource,
630
+ hint: metadata.hint ?? null,
631
+ capability: getPlanCapabilitySummary(metadata.plan),
632
+ status: status.kind,
633
+ health: doctor.health,
634
+ receiptPath: status.receiptPath,
635
+ issues: doctor.issues,
636
+ summary: status.summary,
637
+ };
638
+ }
639
+ function summarizeUninstall(target, root, result, metadata) {
640
+ const lines = [
641
+ `${target} 卸载完成`,
642
+ formatRootLabel("uninstall", root, metadata),
643
+ ...(metadata.installMethod ? [`安装方式:${formatInstallMethodLabel(metadata.installMethod)}`] : []),
644
+ ...(metadata.installSource ? [`安装来源:${formatInstallSourceLabel(metadata.installSource)}`] : []),
645
+ ...(metadata.sourceRef ? [`来源:${metadata.sourceRef}`] : []),
646
+ ...(metadata.bundlePath ? [`Bundle 目录:${metadata.bundlePath}`] : []),
647
+ `回执:${metadata.receiptPath}`,
648
+ ...(metadata.hint ? [`提示:${metadata.hint}`] : []),
649
+ `移除受管产物 ${result.removedArtifacts},原本缺失 ${result.missingArtifacts}`,
650
+ `Bundle:${result.bundleRemoved ? "已删除" : result.bundleMissing ? "本就不存在" : "未涉及"}`,
651
+ `回执:${result.receiptRemoved ? "已删除" : result.receiptMissing ? "本就不存在" : "未涉及"}`,
652
+ ];
653
+ const nextStep = buildNextStep("uninstall", target, root, {
654
+ scope: metadata.scope,
655
+ });
656
+ if (nextStep) {
657
+ lines.push(nextStep);
658
+ }
659
+ return lines.join("\n");
660
+ }
661
+ function buildUninstallPayload(target, root, result, metadata) {
662
+ return {
663
+ mode: "result",
664
+ action: "uninstall",
665
+ target,
666
+ root,
667
+ scope: metadata.scope ?? "project",
668
+ rootSource: metadata.rootSource ?? (metadata.autoResolvedRoot ? "project-root" : "explicit"),
669
+ autoResolvedRoot: metadata.autoResolvedRoot ?? false,
670
+ hint: metadata.hint ?? null,
671
+ installMethod: metadata.installMethod ?? null,
672
+ installSource: metadata.installSource ?? null,
673
+ sourceRef: metadata.sourceRef ?? null,
674
+ bundlePath: metadata.bundlePath ?? null,
675
+ receiptPath: metadata.receiptPath,
676
+ ...result,
677
+ };
678
+ }
275
679
  export async function runPlatformGenerate(target, opts) {
276
680
  const format = resolveOutputFormat(opts.json);
277
681
  const outputRoot = opts.dir ? resolve(opts.dir) : resolveWorkspacePath(`.generated/${target}`);
278
682
  try {
279
683
  const manifest = await loadToolkitManifest();
280
684
  const platformModule = await loadPlatformModule(target);
281
- const plan = createGenerationPlan(target, platformModule, manifest);
685
+ let plan = createGenerationPlan(target, platformModule, manifest);
686
+ let bundleType;
687
+ let bundlePath;
688
+ if (opts.bundle) {
689
+ if (target !== "qwen") {
690
+ throw new Error(`${target} 暂不支持 bundle 导出。当前仅 qwen 支持 --bundle release-bundle。`);
691
+ }
692
+ const installPlan = createInstallPlan(target, platformModule, manifest, outputRoot, "dir", resolveOverwriteMode(opts.force));
693
+ bundleType = opts.bundle;
694
+ bundlePath = outputRoot;
695
+ plan = {
696
+ ...installPlan,
697
+ artifacts: toQwenOfficialCliReleaseArtifacts(installPlan, outputRoot),
698
+ };
699
+ }
282
700
  if (opts.plan) {
283
- emitOutput(format, buildPlanPayload("generate", target, outputRoot, {
284
- ...plan,
285
- artifacts: plan.artifacts.map((artifact) => ({
286
- path: join(outputRoot, artifact.path),
287
- content: artifact.content
288
- }))
289
- }), summarizePlan("generate", target, outputRoot, {
290
- ...plan,
291
- artifacts: plan.artifacts.map((artifact) => ({
292
- path: join(outputRoot, artifact.path),
293
- content: artifact.content
294
- }))
701
+ const outputPlan = bundleType
702
+ ? plan
703
+ : {
704
+ ...plan,
705
+ artifacts: plan.artifacts.map((artifact) => ({
706
+ path: join(outputRoot, artifact.path),
707
+ content: artifact.content,
708
+ })),
709
+ };
710
+ emitOutput(format, buildPlanPayload("generate", target, outputRoot, outputPlan, {
711
+ bundleType,
712
+ bundlePath,
713
+ }), summarizePlan("generate", target, outputRoot, outputPlan, {
714
+ bundleType,
715
+ bundlePath,
295
716
  }));
296
717
  return;
297
718
  }
298
- const result = await writeArtifacts(plan.artifacts.map((artifact) => ({
299
- path: join(outputRoot, artifact.path),
300
- content: artifact.content
301
- })), {
719
+ const result = await writeArtifacts((bundleType
720
+ ? plan.artifacts
721
+ : plan.artifacts.map((artifact) => ({
722
+ path: join(outputRoot, artifact.path),
723
+ content: artifact.content,
724
+ }))), {
302
725
  dryRun: false,
303
726
  overwrite: resolveOverwriteMode(opts.force)
304
727
  });
305
- emitOutput(format, buildResultPayload("generate", target, outputRoot, result), summarizeResult("generate", target, outputRoot, result));
728
+ emitOutput(format, buildResultPayload("generate", target, outputRoot, result, {
729
+ bundleType,
730
+ bundlePath,
731
+ }), summarizeResult("generate", target, outputRoot, result, {
732
+ bundleType,
733
+ bundlePath,
734
+ }));
306
735
  }
307
736
  catch (error) {
308
737
  emitPlatformError(format, target, "generate", error instanceof Error ? `${target} 生成失败:${error.message}` : `${target} 生成失败。`);
@@ -315,9 +744,29 @@ function getUpdateOverwriteMode(status, force) {
315
744
  }
316
745
  return resolveOverwriteMode(force);
317
746
  }
747
+ async function removeOptionalManagedPath(path) {
748
+ if (!path) {
749
+ return {
750
+ removed: false,
751
+ missing: false,
752
+ };
753
+ }
754
+ if (!(await pathExists(path))) {
755
+ return {
756
+ removed: false,
757
+ missing: true,
758
+ };
759
+ }
760
+ await removeManagedPaths([path]);
761
+ return {
762
+ removed: true,
763
+ missing: false,
764
+ };
765
+ }
318
766
  export async function runPlatformInstall(target, opts) {
319
767
  const format = resolveOutputFormat(opts.json);
320
768
  let destinationRoot = "";
769
+ let fallbackHint;
321
770
  try {
322
771
  const scope = resolveScopeFromSelector(opts);
323
772
  const targetResolution = await resolveInstallTarget(target, {
@@ -331,20 +780,128 @@ export async function runPlatformInstall(target, opts) {
331
780
  const overwrite = resolveOverwriteMode(opts.force);
332
781
  const manifest = await loadToolkitManifest();
333
782
  const platformModule = await loadPlatformModule(target);
334
- const plan = createInstallPlan(target, platformModule, manifest, destinationRoot, overwrite);
783
+ const plan = createInstallPlan(target, platformModule, manifest, destinationRoot, scope, overwrite);
784
+ const qwenReleaseBundlePath = shouldPreferQwenOfficialCli(target, scope)
785
+ ? resolveQwenOfficialCliReleaseBundleDir(plan)
786
+ : null;
787
+ const qwenInstallSource = shouldPreferQwenOfficialRepoInstall(target, scope) ? "github-repo" : "local-bundle";
335
788
  if (opts.plan) {
336
789
  emitOutput(format, buildPlanPayload("install", target, destinationRoot, plan, {
337
790
  autoResolvedRoot,
338
791
  rootSource: targetResolution.source,
339
792
  hint: targetResolution.hint,
340
793
  scope,
794
+ installSource: target === "qwen" && scope === "global" ? qwenInstallSource : null,
795
+ sourceRef: target === "qwen" && scope === "global" && qwenInstallSource === "github-repo" ? qwenOfficialExtensionRepoUrl : null,
796
+ bundleType: target === "qwen" && scope === "global" && qwenInstallSource === "local-bundle" ? "release-bundle" : null,
797
+ bundlePath: target === "qwen" && scope === "global" && qwenInstallSource === "local-bundle" ? qwenReleaseBundlePath : null,
341
798
  }), summarizePlan("install", target, destinationRoot, plan, {
342
799
  autoResolvedRoot,
343
800
  rootSource: targetResolution.source,
344
801
  hint: targetResolution.hint,
802
+ scope,
803
+ installSource: target === "qwen" && scope === "global" ? qwenInstallSource : null,
804
+ sourceRef: target === "qwen" && scope === "global" && qwenInstallSource === "github-repo" ? qwenOfficialExtensionRepoUrl : null,
805
+ bundleType: target === "qwen" && scope === "global" && qwenInstallSource === "local-bundle" ? "release-bundle" : null,
806
+ bundlePath: target === "qwen" && scope === "global" && qwenInstallSource === "local-bundle" ? qwenReleaseBundlePath : null,
345
807
  }));
346
808
  return;
347
809
  }
810
+ if (shouldPreferQwenOfficialCli(target, scope)) {
811
+ const status = await resolvePlatformInstallStatus(plan);
812
+ if (status.kind === "drifted" && !opts.force) {
813
+ emitPlatformError(format, target, "install", `${target} 安装目录已漂移。请先运行 \`zc platform status ${target}\` 检查差异,确认后追加 \`--force\` 再安装。`, {
814
+ root: destinationRoot,
815
+ receiptPath: status.receiptPath,
816
+ status: status.kind,
817
+ });
818
+ process.exitCode = 1;
819
+ return;
820
+ }
821
+ try {
822
+ let releaseBundleDir = null;
823
+ if (format === "text") {
824
+ console.log(`正在调用官方命令:qwen extensions ${status.kind === "not-installed" ? "install" : "update"} …`);
825
+ }
826
+ if (status.kind === "not-installed") {
827
+ if (qwenInstallSource === "github-repo") {
828
+ await installQwenExtensionFromOfficialRepoWithCli(qwenOfficialExtensionRepoUrl);
829
+ }
830
+ else {
831
+ const releaseBundle = await syncQwenOfficialCliReleaseBundle(plan);
832
+ releaseBundleDir = releaseBundle.bundleDir;
833
+ await installQwenExtensionWithOfficialCli(releaseBundle.bundleDir);
834
+ }
835
+ }
836
+ else if (status.kind !== "up-to-date") {
837
+ if (qwenInstallSource === "github-repo") {
838
+ await updateQwenExtensionWithOfficialCli(plan.capability?.extension?.name ?? "zc-toolkit");
839
+ }
840
+ else {
841
+ const releaseBundle = await syncQwenOfficialCliReleaseBundle(plan);
842
+ releaseBundleDir = releaseBundle.bundleDir;
843
+ await uninstallQwenExtensionWithOfficialCli(releaseBundle.extensionName);
844
+ await relinkQwenExtensionWithOfficialCli(releaseBundle.bundleDir);
845
+ }
846
+ }
847
+ await writePlatformInstallReceiptForPlan(plan, {
848
+ installedAt: new Date().toISOString(),
849
+ zcVersion: getCliVersion(),
850
+ installMethod: "qwen-cli",
851
+ installSource: qwenInstallSource,
852
+ sourceRef: qwenInstallSource === "github-repo" ? qwenOfficialExtensionRepoUrl : undefined,
853
+ bundleType: qwenInstallSource === "local-bundle" ? "release-bundle" : undefined,
854
+ bundlePath: qwenInstallSource === "local-bundle" ? releaseBundleDir ?? qwenReleaseBundlePath ?? undefined : undefined,
855
+ });
856
+ const result = status.kind === "up-to-date"
857
+ ? {
858
+ created: 0,
859
+ overwritten: 0,
860
+ unchanged: plan.artifacts.length,
861
+ skipped: 0,
862
+ dryRun: false,
863
+ }
864
+ : estimateManagedInstallResult(plan, status);
865
+ emitOutput(format, buildResultPayload("install", target, destinationRoot, result, {
866
+ autoResolvedRoot,
867
+ rootSource: targetResolution.source,
868
+ hint: targetResolution.hint,
869
+ scope,
870
+ receiptPath: resolvePlatformInstallReceiptPath(plan),
871
+ zcVersion: getCliVersion(),
872
+ contentFingerprint: plan.metadata?.fingerprint.value ?? null,
873
+ status: status.kind === "up-to-date" ? status.kind : "installed",
874
+ noop: status.kind === "up-to-date",
875
+ installMethod: "qwen-cli",
876
+ installSource: qwenInstallSource,
877
+ sourceRef: qwenInstallSource === "github-repo" ? qwenOfficialExtensionRepoUrl : null,
878
+ bundleType: qwenInstallSource === "local-bundle" ? "release-bundle" : null,
879
+ bundlePath: qwenInstallSource === "local-bundle" ? qwenReleaseBundlePath : null,
880
+ }), summarizeResult("install", target, destinationRoot, result, {
881
+ autoResolvedRoot,
882
+ rootSource: targetResolution.source,
883
+ hint: targetResolution.hint,
884
+ scope,
885
+ receiptPath: resolvePlatformInstallReceiptPath(plan),
886
+ zcVersion: getCliVersion(),
887
+ contentFingerprint: plan.metadata?.fingerprint.value ?? null,
888
+ status: status.kind === "up-to-date" ? `${status.kind}(${formatStatusLabel(status.kind)})` : "installed",
889
+ noop: status.kind === "up-to-date",
890
+ installMethod: "qwen-cli",
891
+ installSource: qwenInstallSource,
892
+ sourceRef: qwenInstallSource === "github-repo" ? qwenOfficialExtensionRepoUrl : null,
893
+ bundleType: qwenInstallSource === "local-bundle" ? "release-bundle" : null,
894
+ bundlePath: qwenInstallSource === "local-bundle" ? qwenReleaseBundlePath : null,
895
+ }));
896
+ return;
897
+ }
898
+ catch (error) {
899
+ if (!(error instanceof QwenOfficialCliUnavailableError)) {
900
+ throw error;
901
+ }
902
+ fallbackHint = "未检测到 qwen CLI,已回退为直接写入官方扩展目录。";
903
+ }
904
+ }
348
905
  const result = await writeArtifacts(plan.artifacts.map((artifact) => ({
349
906
  path: artifact.path,
350
907
  content: artifact.content
@@ -359,20 +916,31 @@ export async function runPlatformInstall(target, opts) {
359
916
  emitOutput(format, buildResultPayload("install", target, destinationRoot, result, {
360
917
  autoResolvedRoot,
361
918
  rootSource: targetResolution.source,
362
- hint: targetResolution.hint,
919
+ hint: mergeHints(targetResolution.hint, fallbackHint),
363
920
  scope,
364
921
  receiptPath: resolvePlatformInstallReceiptPath(plan),
365
922
  zcVersion: getCliVersion(),
366
923
  contentFingerprint: plan.metadata?.fingerprint.value ?? null,
367
924
  status: "installed",
925
+ installMethod: "filesystem",
926
+ installSource: null,
927
+ sourceRef: null,
928
+ bundleType: null,
929
+ bundlePath: qwenReleaseBundlePath,
368
930
  }), summarizeResult("install", target, destinationRoot, result, {
369
931
  autoResolvedRoot,
370
932
  rootSource: targetResolution.source,
371
- hint: targetResolution.hint,
933
+ hint: mergeHints(targetResolution.hint, fallbackHint),
934
+ scope,
372
935
  receiptPath: resolvePlatformInstallReceiptPath(plan),
373
936
  zcVersion: getCliVersion(),
374
937
  contentFingerprint: plan.metadata?.fingerprint.value ?? null,
375
938
  status: "installed",
939
+ installMethod: "filesystem",
940
+ installSource: null,
941
+ sourceRef: null,
942
+ bundleType: undefined,
943
+ bundlePath: qwenReleaseBundlePath ?? undefined,
376
944
  }));
377
945
  }
378
946
  catch (error) {
@@ -398,22 +966,53 @@ export async function runPlatformStatus(target, opts) {
398
966
  const destinationRoot = resolve(targetResolution.root);
399
967
  const manifest = await loadToolkitManifest();
400
968
  const platformModule = await loadPlatformModule(target);
401
- const plan = createInstallPlan(target, platformModule, manifest, destinationRoot, "error");
969
+ const plan = createInstallPlan(target, platformModule, manifest, destinationRoot, scope, "error");
402
970
  const status = await resolvePlatformInstallStatus(plan);
403
971
  const zcVersion = getCliVersion();
404
- emitOutput(format, buildStatusPayload(target, destinationRoot, {
405
- ...status,
406
- zcVersion,
407
- }, {
972
+ const installMethod = status.receipt ? (status.receipt.installMethod ?? "filesystem") : undefined;
973
+ const installSource = status.receipt?.installSource ?? undefined;
974
+ const sourceRef = status.receipt?.sourceRef ?? undefined;
975
+ const bundleType = status.receipt?.bundleType ?? undefined;
976
+ const bundlePath = status.receipt?.bundlePath ?? undefined;
977
+ const recommendedInstallMethod = shouldPreferQwenOfficialCli(target, scope) ? "qwen-cli" : undefined;
978
+ const recommendedInstallSource = shouldPreferQwenOfficialRepoInstall(target, scope) ? "github-repo" : undefined;
979
+ const recommendedSourceRef = recommendedInstallSource === "github-repo" ? qwenOfficialExtensionRepoUrl : undefined;
980
+ const recommendedBundleType = shouldPreferQwenOfficialCli(target, scope) ? "release-bundle" : undefined;
981
+ const recommendedBundlePath = shouldPreferQwenOfficialCli(target, scope)
982
+ ? resolveQwenOfficialCliReleaseBundleDir(plan)
983
+ : undefined;
984
+ emitOutput(format, buildStatusPayload(target, destinationRoot, status, {
408
985
  scope,
409
986
  rootSource: targetResolution.source,
410
987
  hint: targetResolution.hint,
411
988
  zcVersion,
989
+ plan,
990
+ installMethod,
991
+ installSource,
992
+ sourceRef,
993
+ bundleType,
994
+ bundlePath,
995
+ recommendedInstallMethod,
996
+ recommendedInstallSource,
997
+ recommendedSourceRef,
998
+ recommendedBundleType,
999
+ recommendedBundlePath,
412
1000
  }), summarizeStatus(target, destinationRoot, status, {
413
1001
  scope,
414
1002
  rootSource: targetResolution.source,
415
1003
  hint: targetResolution.hint,
416
1004
  zcVersion,
1005
+ plan,
1006
+ installMethod,
1007
+ installSource,
1008
+ sourceRef,
1009
+ bundleType,
1010
+ bundlePath,
1011
+ recommendedInstallMethod,
1012
+ recommendedInstallSource,
1013
+ recommendedSourceRef,
1014
+ recommendedBundleType,
1015
+ recommendedBundlePath,
417
1016
  }));
418
1017
  }
419
1018
  catch (error) {
@@ -424,6 +1023,7 @@ export async function runPlatformStatus(target, opts) {
424
1023
  export async function runPlatformUpdate(target, opts) {
425
1024
  const format = resolveOutputFormat(opts.json);
426
1025
  let destinationRoot = "";
1026
+ let fallbackHint;
427
1027
  try {
428
1028
  const scope = resolveScopeFromSelector(opts);
429
1029
  const targetResolution = await resolveInstallTarget(target, {
@@ -436,9 +1036,13 @@ export async function runPlatformUpdate(target, opts) {
436
1036
  destinationRoot = resolve(targetResolution.root);
437
1037
  const manifest = await loadToolkitManifest();
438
1038
  const platformModule = await loadPlatformModule(target);
439
- const statusPlan = createInstallPlan(target, platformModule, manifest, destinationRoot, "error");
1039
+ const statusPlan = createInstallPlan(target, platformModule, manifest, destinationRoot, scope, "error");
440
1040
  const status = await resolvePlatformInstallStatus(statusPlan);
441
1041
  const zcVersion = getCliVersion();
1042
+ const qwenReleaseBundlePath = shouldPreferQwenOfficialCli(target, scope)
1043
+ ? resolveQwenOfficialCliReleaseBundleDir(statusPlan)
1044
+ : undefined;
1045
+ const qwenInstallSource = shouldPreferQwenOfficialRepoInstall(target, scope) ? "github-repo" : "local-bundle";
442
1046
  if (status.kind === "not-installed") {
443
1047
  emitPlatformError(format, target, "update", `${target} 尚未安装到该目录。请先运行 \`zc platform install ${target}\`。`, {
444
1048
  root: destinationRoot,
@@ -465,15 +1069,26 @@ export async function runPlatformUpdate(target, opts) {
465
1069
  contentFingerprint: status.contentFingerprint ?? null,
466
1070
  status: status.kind,
467
1071
  noop: true,
1072
+ installMethod: target === "qwen" && scope === "global" ? "qwen-cli" : undefined,
1073
+ installSource: target === "qwen" && scope === "global" ? qwenInstallSource : null,
1074
+ sourceRef: target === "qwen" && scope === "global" && qwenInstallSource === "github-repo" ? qwenOfficialExtensionRepoUrl : null,
1075
+ bundleType: target === "qwen" && scope === "global" && qwenInstallSource === "local-bundle" ? "release-bundle" : null,
1076
+ bundlePath: target === "qwen" && scope === "global" && qwenInstallSource === "local-bundle" ? qwenReleaseBundlePath ?? null : null,
468
1077
  }), summarizeResult("update", target, destinationRoot, result, {
469
1078
  autoResolvedRoot,
470
1079
  rootSource: targetResolution.source,
471
1080
  hint: targetResolution.hint,
1081
+ scope,
472
1082
  receiptPath: status.receiptPath,
473
1083
  zcVersion,
474
1084
  contentFingerprint: status.contentFingerprint ?? null,
475
1085
  status: `${status.kind}(${formatStatusLabel(status.kind)})`,
476
1086
  noop: true,
1087
+ installMethod: target === "qwen" && scope === "global" ? "qwen-cli" : undefined,
1088
+ installSource: target === "qwen" && scope === "global" ? qwenInstallSource : null,
1089
+ sourceRef: target === "qwen" && scope === "global" && qwenInstallSource === "github-repo" ? qwenOfficialExtensionRepoUrl : null,
1090
+ bundleType: target === "qwen" && scope === "global" && qwenInstallSource === "local-bundle" ? "release-bundle" : undefined,
1091
+ bundlePath: target === "qwen" && scope === "global" && qwenInstallSource === "local-bundle" ? qwenReleaseBundlePath : undefined,
477
1092
  }));
478
1093
  return;
479
1094
  }
@@ -487,7 +1102,7 @@ export async function runPlatformUpdate(target, opts) {
487
1102
  return;
488
1103
  }
489
1104
  const overwrite = getUpdateOverwriteMode(status, opts.force);
490
- const plan = createInstallPlan(target, platformModule, manifest, destinationRoot, overwrite);
1105
+ const plan = createInstallPlan(target, platformModule, manifest, destinationRoot, scope, overwrite);
491
1106
  if (opts.plan) {
492
1107
  emitOutput(format, buildPlanPayload("update", target, destinationRoot, plan, {
493
1108
  autoResolvedRoot,
@@ -495,14 +1110,84 @@ export async function runPlatformUpdate(target, opts) {
495
1110
  hint: targetResolution.hint,
496
1111
  scope,
497
1112
  status: status.kind,
1113
+ installSource: target === "qwen" && scope === "global" ? qwenInstallSource : null,
1114
+ sourceRef: target === "qwen" && scope === "global" && qwenInstallSource === "github-repo" ? qwenOfficialExtensionRepoUrl : null,
1115
+ bundleType: target === "qwen" && scope === "global" && qwenInstallSource === "local-bundle" ? "release-bundle" : null,
1116
+ bundlePath: target === "qwen" && scope === "global" && qwenInstallSource === "local-bundle" ? qwenReleaseBundlePath ?? null : null,
498
1117
  }), summarizePlan("update", target, destinationRoot, plan, {
499
1118
  autoResolvedRoot,
500
1119
  rootSource: targetResolution.source,
501
1120
  hint: targetResolution.hint,
1121
+ scope,
502
1122
  status: `${status.kind}(${formatStatusLabel(status.kind)})`,
1123
+ installSource: target === "qwen" && scope === "global" ? qwenInstallSource : null,
1124
+ sourceRef: target === "qwen" && scope === "global" && qwenInstallSource === "github-repo" ? qwenOfficialExtensionRepoUrl : null,
1125
+ bundleType: target === "qwen" && scope === "global" && qwenInstallSource === "local-bundle" ? "release-bundle" : null,
1126
+ bundlePath: target === "qwen" && scope === "global" && qwenInstallSource === "local-bundle" ? qwenReleaseBundlePath ?? null : null,
503
1127
  }));
504
1128
  return;
505
1129
  }
1130
+ if (shouldPreferQwenOfficialCli(target, scope)) {
1131
+ try {
1132
+ if (format === "text") {
1133
+ console.log("正在调用官方命令:qwen extensions update …");
1134
+ }
1135
+ if (qwenInstallSource === "github-repo") {
1136
+ await updateQwenExtensionWithOfficialCli(plan.capability?.extension?.name ?? "zc-toolkit");
1137
+ }
1138
+ else {
1139
+ const releaseBundle = await syncQwenOfficialCliReleaseBundle(plan);
1140
+ await uninstallQwenExtensionWithOfficialCli(releaseBundle.extensionName);
1141
+ await relinkQwenExtensionWithOfficialCli(releaseBundle.bundleDir);
1142
+ }
1143
+ await writePlatformInstallReceiptForPlan(plan, {
1144
+ installedAt: new Date().toISOString(),
1145
+ zcVersion,
1146
+ installMethod: "qwen-cli",
1147
+ installSource: qwenInstallSource,
1148
+ sourceRef: qwenInstallSource === "github-repo" ? qwenOfficialExtensionRepoUrl : undefined,
1149
+ bundleType: qwenInstallSource === "local-bundle" ? "release-bundle" : undefined,
1150
+ bundlePath: qwenInstallSource === "local-bundle" ? qwenReleaseBundlePath ?? undefined : undefined,
1151
+ });
1152
+ const result = estimateManagedInstallResult(plan, status);
1153
+ emitOutput(format, buildResultPayload("update", target, destinationRoot, result, {
1154
+ autoResolvedRoot,
1155
+ rootSource: targetResolution.source,
1156
+ hint: targetResolution.hint,
1157
+ scope,
1158
+ receiptPath: resolvePlatformInstallReceiptPath(plan),
1159
+ zcVersion,
1160
+ contentFingerprint: plan.metadata?.fingerprint.value ?? null,
1161
+ status: status.kind,
1162
+ installMethod: "qwen-cli",
1163
+ installSource: qwenInstallSource,
1164
+ sourceRef: qwenInstallSource === "github-repo" ? qwenOfficialExtensionRepoUrl : null,
1165
+ bundleType: qwenInstallSource === "local-bundle" ? "release-bundle" : null,
1166
+ bundlePath: qwenInstallSource === "local-bundle" ? qwenReleaseBundlePath ?? null : null,
1167
+ }), summarizeResult("update", target, destinationRoot, result, {
1168
+ autoResolvedRoot,
1169
+ rootSource: targetResolution.source,
1170
+ hint: targetResolution.hint,
1171
+ scope,
1172
+ receiptPath: resolvePlatformInstallReceiptPath(plan),
1173
+ zcVersion,
1174
+ contentFingerprint: plan.metadata?.fingerprint.value ?? null,
1175
+ status: `${status.kind}(${formatStatusLabel(status.kind)})`,
1176
+ installMethod: "qwen-cli",
1177
+ installSource: qwenInstallSource,
1178
+ sourceRef: qwenInstallSource === "github-repo" ? qwenOfficialExtensionRepoUrl : null,
1179
+ bundleType: qwenInstallSource === "local-bundle" ? "release-bundle" : null,
1180
+ bundlePath: qwenInstallSource === "local-bundle" ? qwenReleaseBundlePath ?? null : null,
1181
+ }));
1182
+ return;
1183
+ }
1184
+ catch (error) {
1185
+ if (!(error instanceof QwenOfficialCliUnavailableError)) {
1186
+ throw error;
1187
+ }
1188
+ fallbackHint = "未检测到 qwen CLI,已回退为直接写入官方扩展目录。";
1189
+ }
1190
+ }
506
1191
  const result = await writeArtifacts(plan.artifacts.map((artifact) => ({
507
1192
  path: artifact.path,
508
1193
  content: artifact.content,
@@ -517,20 +1202,31 @@ export async function runPlatformUpdate(target, opts) {
517
1202
  emitOutput(format, buildResultPayload("update", target, destinationRoot, result, {
518
1203
  autoResolvedRoot,
519
1204
  rootSource: targetResolution.source,
520
- hint: targetResolution.hint,
1205
+ hint: mergeHints(targetResolution.hint, fallbackHint),
521
1206
  scope,
522
1207
  receiptPath: resolvePlatformInstallReceiptPath(plan),
523
1208
  zcVersion,
524
1209
  contentFingerprint: plan.metadata?.fingerprint.value ?? null,
525
1210
  status: status.kind,
1211
+ installMethod: "filesystem",
1212
+ installSource: null,
1213
+ sourceRef: null,
1214
+ bundleType: null,
1215
+ bundlePath: null,
526
1216
  }), summarizeResult("update", target, destinationRoot, result, {
527
1217
  autoResolvedRoot,
528
1218
  rootSource: targetResolution.source,
529
- hint: targetResolution.hint,
1219
+ hint: mergeHints(targetResolution.hint, fallbackHint),
1220
+ scope,
530
1221
  receiptPath: resolvePlatformInstallReceiptPath(plan),
531
1222
  zcVersion,
532
1223
  contentFingerprint: plan.metadata?.fingerprint.value ?? null,
533
1224
  status: `${status.kind}(${formatStatusLabel(status.kind)})`,
1225
+ installMethod: "filesystem",
1226
+ installSource: null,
1227
+ sourceRef: null,
1228
+ bundleType: undefined,
1229
+ bundlePath: undefined,
534
1230
  }));
535
1231
  }
536
1232
  catch (error) {
@@ -543,6 +1239,382 @@ export async function runPlatformUpdate(target, opts) {
543
1239
  process.exitCode = 1;
544
1240
  }
545
1241
  }
1242
+ export async function runPlatformUninstall(target, opts) {
1243
+ const format = resolveOutputFormat(opts.json);
1244
+ try {
1245
+ const scope = resolveScopeFromSelector(opts);
1246
+ const targetResolution = await resolveInstallTarget(target, {
1247
+ dir: opts.dir,
1248
+ cwd: process.cwd(),
1249
+ project: opts.project,
1250
+ global: opts.global,
1251
+ });
1252
+ const autoResolvedRoot = targetResolution.source !== "explicit";
1253
+ const destinationRoot = resolve(targetResolution.root);
1254
+ const manifest = await loadToolkitManifest();
1255
+ const platformModule = await loadPlatformModule(target);
1256
+ const plan = createInstallPlan(target, platformModule, manifest, destinationRoot, scope, "error");
1257
+ const status = await resolvePlatformInstallStatus(plan);
1258
+ if (!status.receipt) {
1259
+ emitPlatformError(format, target, "uninstall", `${target} 当前目录没有受管安装回执,拒绝自动卸载。请先运行 \`zc platform status ${target}\` 检查。`, {
1260
+ root: destinationRoot,
1261
+ receiptPath: status.receiptPath,
1262
+ status: status.kind,
1263
+ });
1264
+ process.exitCode = 1;
1265
+ return;
1266
+ }
1267
+ if (status.kind === "drifted" && !opts.force) {
1268
+ emitPlatformError(format, target, "uninstall", `${target} 安装目录已漂移。请先运行 \`zc platform doctor ${target}\` 或 \`zc platform status ${target}\` 检查,确认后追加 \`--force\` 再卸载。`, {
1269
+ root: destinationRoot,
1270
+ receiptPath: status.receiptPath,
1271
+ status: status.kind,
1272
+ });
1273
+ process.exitCode = 1;
1274
+ return;
1275
+ }
1276
+ const installMethod = status.receipt.installMethod ?? "filesystem";
1277
+ const installSource = status.receipt.installSource ?? null;
1278
+ const sourceRef = status.receipt.sourceRef ?? null;
1279
+ const bundlePath = status.receipt.bundlePath ?? null;
1280
+ if (opts.plan) {
1281
+ emitOutput(format, {
1282
+ mode: "plan",
1283
+ action: "uninstall",
1284
+ target,
1285
+ root: destinationRoot,
1286
+ scope,
1287
+ rootSource: targetResolution.source,
1288
+ autoResolvedRoot,
1289
+ hint: targetResolution.hint ?? null,
1290
+ status: status.kind,
1291
+ receiptPath: status.receiptPath,
1292
+ installMethod,
1293
+ installSource,
1294
+ sourceRef,
1295
+ bundlePath,
1296
+ artifactCount: status.receipt.artifacts.length,
1297
+ artifacts: status.receipt.artifacts.map((artifact) => artifact.path),
1298
+ }, [
1299
+ `${target} 卸载计划`,
1300
+ formatRootLabel("uninstall", destinationRoot, {
1301
+ autoResolvedRoot,
1302
+ rootSource: targetResolution.source,
1303
+ hint: targetResolution.hint,
1304
+ }),
1305
+ `状态:${status.kind}(${formatStatusLabel(status.kind)})`,
1306
+ `安装方式:${installMethod === "qwen-cli" ? "官方 qwen extensions CLI" : "直接写入"}`,
1307
+ ...(installSource ? [`安装来源:${installSource === "github-repo" ? "GitHub 扩展仓库" : "本地 bundle"}`] : []),
1308
+ ...(sourceRef ? [`来源:${sourceRef}`] : []),
1309
+ `回执:${status.receiptPath}`,
1310
+ ...(bundlePath ? [`Bundle 目录:${bundlePath}`] : []),
1311
+ `受管产物:${status.receipt.artifacts.length}`,
1312
+ ...status.receipt.artifacts.map((artifact) => `- ${artifact.path}`),
1313
+ ].join("\n"));
1314
+ return;
1315
+ }
1316
+ let artifactCleanup = { removed: 0, missing: 0 };
1317
+ if (target === "qwen" && installMethod === "qwen-cli") {
1318
+ const extensionName = plan.capability?.extension?.name ?? "zc-toolkit";
1319
+ if (format === "text") {
1320
+ console.log(`正在调用官方命令:qwen extensions uninstall ${extensionName} …`);
1321
+ }
1322
+ await uninstallQwenExtensionWithOfficialCli(extensionName);
1323
+ }
1324
+ else {
1325
+ artifactCleanup = await removeManagedPaths(status.receipt.artifacts.map((artifact) => artifact.path));
1326
+ }
1327
+ const bundleCleanup = await removeOptionalManagedPath(bundlePath);
1328
+ const receiptExisted = await pathExists(status.receiptPath);
1329
+ if (receiptExisted) {
1330
+ await deletePlatformInstallReceipt(status.receiptPath);
1331
+ }
1332
+ const result = {
1333
+ removedArtifacts: artifactCleanup.removed,
1334
+ missingArtifacts: artifactCleanup.missing,
1335
+ bundleRemoved: bundleCleanup.removed,
1336
+ bundleMissing: bundleCleanup.missing,
1337
+ receiptRemoved: receiptExisted,
1338
+ receiptMissing: !receiptExisted,
1339
+ };
1340
+ emitOutput(format, buildUninstallPayload(target, destinationRoot, result, {
1341
+ autoResolvedRoot,
1342
+ rootSource: targetResolution.source,
1343
+ hint: targetResolution.hint,
1344
+ scope,
1345
+ receiptPath: status.receiptPath,
1346
+ installMethod,
1347
+ installSource,
1348
+ sourceRef,
1349
+ bundlePath,
1350
+ }), summarizeUninstall(target, destinationRoot, result, {
1351
+ autoResolvedRoot,
1352
+ rootSource: targetResolution.source,
1353
+ hint: targetResolution.hint,
1354
+ scope,
1355
+ receiptPath: status.receiptPath,
1356
+ installMethod,
1357
+ installSource,
1358
+ sourceRef,
1359
+ bundlePath,
1360
+ }));
1361
+ }
1362
+ catch (error) {
1363
+ emitPlatformError(format, target, "uninstall", error instanceof Error ? `${target} 卸载失败:${error.message}` : `${target} 卸载失败。`);
1364
+ process.exitCode = 1;
1365
+ }
1366
+ }
1367
+ export async function runPlatformRepair(target, opts) {
1368
+ const format = resolveOutputFormat(opts.json);
1369
+ try {
1370
+ const scope = resolveScopeFromSelector(opts);
1371
+ const targetResolution = await resolveInstallTarget(target, {
1372
+ dir: opts.dir,
1373
+ cwd: process.cwd(),
1374
+ project: opts.project,
1375
+ global: opts.global,
1376
+ });
1377
+ const autoResolvedRoot = targetResolution.source !== "explicit";
1378
+ const destinationRoot = resolve(targetResolution.root);
1379
+ const manifest = await loadToolkitManifest();
1380
+ const platformModule = await loadPlatformModule(target);
1381
+ const statusPlan = createInstallPlan(target, platformModule, manifest, destinationRoot, scope, "error");
1382
+ const status = await resolvePlatformInstallStatus(statusPlan);
1383
+ if (!status.receipt) {
1384
+ emitPlatformError(format, target, "repair", `${target} 当前目录尚未建立受管安装状态。请先运行 \`zc platform install ${target}\`。`, {
1385
+ root: destinationRoot,
1386
+ receiptPath: status.receiptPath,
1387
+ });
1388
+ process.exitCode = 1;
1389
+ return;
1390
+ }
1391
+ const installMethod = status.receipt.installMethod ?? "filesystem";
1392
+ const installSource = status.receipt.installSource
1393
+ ?? (target === "qwen" && scope === "global" ? "github-repo" : undefined);
1394
+ const sourceRef = status.receipt.sourceRef
1395
+ ?? (installSource === "github-repo" ? qwenOfficialExtensionRepoUrl : undefined);
1396
+ const bundlePath = status.receipt.bundlePath
1397
+ ?? (shouldPreferQwenOfficialCli(target, scope) ? resolveQwenOfficialCliReleaseBundleDir(statusPlan) : null);
1398
+ const bundleMissing = installSource === "local-bundle" && bundlePath ? !(await pathExists(bundlePath)) : false;
1399
+ if (status.kind === "up-to-date" && !(target === "qwen" && installMethod === "qwen-cli" && bundleMissing)) {
1400
+ const result = {
1401
+ created: 0,
1402
+ overwritten: 0,
1403
+ unchanged: status.summary.trackedArtifacts,
1404
+ skipped: 0,
1405
+ dryRun: false,
1406
+ };
1407
+ emitOutput(format, buildResultPayload("repair", target, destinationRoot, result, {
1408
+ autoResolvedRoot,
1409
+ rootSource: targetResolution.source,
1410
+ hint: targetResolution.hint,
1411
+ scope,
1412
+ receiptPath: status.receiptPath,
1413
+ zcVersion: getCliVersion(),
1414
+ contentFingerprint: status.contentFingerprint ?? null,
1415
+ status: status.kind,
1416
+ noop: true,
1417
+ installMethod,
1418
+ installSource,
1419
+ sourceRef,
1420
+ bundleType: status.receipt.bundleType ?? null,
1421
+ bundlePath,
1422
+ }), summarizeResult("repair", target, destinationRoot, result, {
1423
+ autoResolvedRoot,
1424
+ rootSource: targetResolution.source,
1425
+ hint: targetResolution.hint,
1426
+ scope,
1427
+ receiptPath: status.receiptPath,
1428
+ zcVersion: getCliVersion(),
1429
+ contentFingerprint: status.contentFingerprint ?? null,
1430
+ status: `${status.kind}(${formatStatusLabel(status.kind)})`,
1431
+ noop: true,
1432
+ installMethod,
1433
+ installSource,
1434
+ sourceRef,
1435
+ bundleType: status.receipt.bundleType ?? undefined,
1436
+ bundlePath: bundlePath ?? undefined,
1437
+ }));
1438
+ return;
1439
+ }
1440
+ const overwrite = "force";
1441
+ const plan = createInstallPlan(target, platformModule, manifest, destinationRoot, scope, overwrite);
1442
+ if (opts.plan) {
1443
+ emitOutput(format, buildPlanPayload("repair", target, destinationRoot, plan, {
1444
+ autoResolvedRoot,
1445
+ rootSource: targetResolution.source,
1446
+ hint: targetResolution.hint,
1447
+ scope,
1448
+ status: status.kind,
1449
+ installSource: installSource ?? null,
1450
+ sourceRef: sourceRef ?? null,
1451
+ bundleType: status.receipt.bundleType ?? null,
1452
+ bundlePath: bundlePath ?? null,
1453
+ }), summarizePlan("repair", target, destinationRoot, plan, {
1454
+ autoResolvedRoot,
1455
+ rootSource: targetResolution.source,
1456
+ hint: targetResolution.hint,
1457
+ scope,
1458
+ status: `${status.kind}(${formatStatusLabel(status.kind)})`,
1459
+ installSource: installSource ?? null,
1460
+ sourceRef: sourceRef ?? null,
1461
+ bundleType: status.receipt.bundleType ?? null,
1462
+ bundlePath: bundlePath ?? null,
1463
+ }));
1464
+ return;
1465
+ }
1466
+ if (target === "qwen" && installMethod === "qwen-cli") {
1467
+ if (format === "text") {
1468
+ console.log(`正在调用官方命令:qwen extensions ${installSource === "github-repo" ? "update" : bundleMissing ? "link" : "relink"} …`);
1469
+ }
1470
+ let repairedBundlePath;
1471
+ if (installSource === "github-repo") {
1472
+ await updateQwenExtensionWithOfficialCli(plan.capability?.extension?.name ?? "zc-toolkit");
1473
+ }
1474
+ else {
1475
+ const releaseBundle = await syncQwenOfficialCliReleaseBundle(plan);
1476
+ repairedBundlePath = releaseBundle.bundleDir;
1477
+ if (bundleMissing) {
1478
+ await relinkQwenExtensionWithOfficialCli(releaseBundle.bundleDir);
1479
+ }
1480
+ else {
1481
+ await uninstallQwenExtensionWithOfficialCli(releaseBundle.extensionName);
1482
+ await relinkQwenExtensionWithOfficialCli(releaseBundle.bundleDir);
1483
+ }
1484
+ }
1485
+ await writePlatformInstallReceiptForPlan(plan, {
1486
+ installedAt: new Date().toISOString(),
1487
+ zcVersion: getCliVersion(),
1488
+ installMethod: "qwen-cli",
1489
+ installSource,
1490
+ sourceRef,
1491
+ bundleType: installSource === "local-bundle" ? "release-bundle" : undefined,
1492
+ bundlePath: installSource === "local-bundle" ? repairedBundlePath ?? bundlePath ?? undefined : undefined,
1493
+ });
1494
+ const result = status.kind === "up-to-date"
1495
+ ? {
1496
+ created: 0,
1497
+ overwritten: 0,
1498
+ unchanged: plan.artifacts.length,
1499
+ skipped: 0,
1500
+ dryRun: false,
1501
+ }
1502
+ : estimateManagedInstallResult(plan, status);
1503
+ emitOutput(format, buildResultPayload("repair", target, destinationRoot, result, {
1504
+ autoResolvedRoot,
1505
+ rootSource: targetResolution.source,
1506
+ hint: targetResolution.hint,
1507
+ scope,
1508
+ receiptPath: resolvePlatformInstallReceiptPath(plan),
1509
+ zcVersion: getCliVersion(),
1510
+ contentFingerprint: plan.metadata?.fingerprint.value ?? null,
1511
+ status: status.kind,
1512
+ installMethod: "qwen-cli",
1513
+ installSource,
1514
+ sourceRef,
1515
+ bundleType: installSource === "local-bundle" ? "release-bundle" : null,
1516
+ bundlePath: installSource === "local-bundle" ? repairedBundlePath ?? bundlePath ?? null : null,
1517
+ }), summarizeResult("repair", target, destinationRoot, result, {
1518
+ autoResolvedRoot,
1519
+ rootSource: targetResolution.source,
1520
+ hint: targetResolution.hint,
1521
+ scope,
1522
+ receiptPath: resolvePlatformInstallReceiptPath(plan),
1523
+ zcVersion: getCliVersion(),
1524
+ contentFingerprint: plan.metadata?.fingerprint.value ?? null,
1525
+ status: `${status.kind}(${formatStatusLabel(status.kind)})`,
1526
+ installMethod: "qwen-cli",
1527
+ installSource,
1528
+ sourceRef,
1529
+ bundleType: installSource === "local-bundle" ? "release-bundle" : null,
1530
+ bundlePath: installSource === "local-bundle" ? repairedBundlePath ?? bundlePath ?? null : null,
1531
+ }));
1532
+ return;
1533
+ }
1534
+ const result = await writeArtifacts(plan.artifacts.map((artifact) => ({
1535
+ path: artifact.path,
1536
+ content: artifact.content,
1537
+ })), {
1538
+ dryRun: false,
1539
+ overwrite,
1540
+ });
1541
+ await writePlatformInstallReceiptForPlan(plan, {
1542
+ installedAt: new Date().toISOString(),
1543
+ zcVersion: getCliVersion(),
1544
+ installMethod,
1545
+ installSource,
1546
+ sourceRef,
1547
+ bundleType: status.receipt.bundleType,
1548
+ bundlePath: status.receipt.bundlePath,
1549
+ });
1550
+ emitOutput(format, buildResultPayload("repair", target, destinationRoot, result, {
1551
+ autoResolvedRoot,
1552
+ rootSource: targetResolution.source,
1553
+ hint: targetResolution.hint,
1554
+ scope,
1555
+ receiptPath: resolvePlatformInstallReceiptPath(plan),
1556
+ zcVersion: getCliVersion(),
1557
+ contentFingerprint: plan.metadata?.fingerprint.value ?? null,
1558
+ status: status.kind,
1559
+ installMethod,
1560
+ installSource,
1561
+ sourceRef,
1562
+ bundleType: status.receipt.bundleType ?? null,
1563
+ bundlePath: status.receipt.bundlePath ?? null,
1564
+ }), summarizeResult("repair", target, destinationRoot, result, {
1565
+ autoResolvedRoot,
1566
+ rootSource: targetResolution.source,
1567
+ hint: targetResolution.hint,
1568
+ scope,
1569
+ receiptPath: resolvePlatformInstallReceiptPath(plan),
1570
+ zcVersion: getCliVersion(),
1571
+ contentFingerprint: plan.metadata?.fingerprint.value ?? null,
1572
+ status: `${status.kind}(${formatStatusLabel(status.kind)})`,
1573
+ installMethod,
1574
+ installSource,
1575
+ sourceRef,
1576
+ bundleType: status.receipt.bundleType ?? undefined,
1577
+ bundlePath: status.receipt.bundlePath ?? undefined,
1578
+ }));
1579
+ }
1580
+ catch (error) {
1581
+ emitPlatformError(format, target, "repair", error instanceof Error ? `${target} 修复失败:${error.message}` : `${target} 修复失败。`);
1582
+ process.exitCode = 1;
1583
+ }
1584
+ }
1585
+ export async function runPlatformDoctor(target, opts) {
1586
+ const format = resolveOutputFormat(opts.json);
1587
+ try {
1588
+ const scope = resolveScopeFromSelector(opts);
1589
+ const targetResolution = await resolveInstallTarget(target, {
1590
+ dir: opts.dir,
1591
+ cwd: process.cwd(),
1592
+ project: opts.project,
1593
+ global: opts.global,
1594
+ });
1595
+ const destinationRoot = resolve(targetResolution.root);
1596
+ const manifest = await loadToolkitManifest();
1597
+ const platformModule = await loadPlatformModule(target);
1598
+ const plan = createInstallPlan(target, platformModule, manifest, destinationRoot, scope, "error");
1599
+ const status = await resolvePlatformInstallStatus(plan);
1600
+ const doctor = await resolvePlatformInstallDoctor(plan, status);
1601
+ emitOutput(format, buildDoctorPayload(target, destinationRoot, status, doctor, {
1602
+ scope,
1603
+ rootSource: targetResolution.source,
1604
+ hint: targetResolution.hint,
1605
+ plan,
1606
+ }), summarizeDoctor(target, destinationRoot, status, doctor, {
1607
+ scope,
1608
+ rootSource: targetResolution.source,
1609
+ hint: targetResolution.hint,
1610
+ plan,
1611
+ }));
1612
+ }
1613
+ catch (error) {
1614
+ emitPlatformError(format, target, "doctor", error instanceof Error ? `${target} 诊断失败:${error.message}` : `${target} 诊断失败。`);
1615
+ process.exitCode = 1;
1616
+ }
1617
+ }
546
1618
  export async function runPlatformWhere(target, opts) {
547
1619
  const format = resolveOutputFormat(opts.json);
548
1620
  try {
@@ -554,16 +1626,21 @@ export async function runPlatformWhere(target, opts) {
554
1626
  global: opts.global,
555
1627
  });
556
1628
  const root = resolve(targetResolution.root);
1629
+ const manifest = await loadToolkitManifest();
1630
+ const platformModule = await loadPlatformModule(target);
1631
+ const plan = createInstallPlan(target, platformModule, manifest, root, scope, "error");
557
1632
  emitOutput(format, buildWherePayload(target, root, {
558
1633
  scope,
559
1634
  rootSource: targetResolution.source,
560
1635
  marker: targetResolution.marker,
561
1636
  hint: targetResolution.hint,
1637
+ capability: getPlanCapabilitySummary(plan),
562
1638
  }), summarizeWhere(target, root, {
563
1639
  scope,
564
1640
  rootSource: targetResolution.source,
565
1641
  marker: targetResolution.marker,
566
1642
  hint: targetResolution.hint,
1643
+ capability: getPlanCapabilitySummary(plan),
567
1644
  }));
568
1645
  }
569
1646
  catch (error) {
@@ -578,58 +1655,89 @@ function parsePlatformName(value) {
578
1655
  throw new InvalidArgumentError(`不支持的平台:${value}。可选值:${platformNames.join(" | ")}`);
579
1656
  }
580
1657
  export function registerPlatformCommand(program) {
581
- const platform = program.command("platform").description("平台生成和安装命令");
1658
+ const platform = program.command("platform").description("查看、安装、更新和诊断平台内容");
582
1659
  platform
583
1660
  .command("generate")
584
1661
  .alias("g")
585
- .description("根据工具包清单生成平台产物")
586
- .argument("<target>", "目标平台 (qwen|codex|qoder)", parsePlatformName)
1662
+ .description("导出平台内容或 Qwen 发布 bundle")
1663
+ .argument("<target>", "目标平台 (qwen|codex|claude|opencode)", parsePlatformName)
587
1664
  .option("-d, --dir <dir>", "输出目录")
588
- .option("--plan", "只输出产物计划,不落盘")
589
- .option("-j, --json", "直接输出 JSON")
1665
+ .option("-b, --bundle <type>", "导出指定 bundle 布局(当前仅 qwen: release-bundle)", parseGenerateBundleType)
1666
+ .option("--plan", "只查看生成计划,不写文件")
1667
+ .option("-j, --json", "输出 JSON")
590
1668
  .option("-f, --force", "覆盖目标目录中已有但内容不同的产物")
591
1669
  .action(runPlatformGenerate);
592
1670
  platform
593
1671
  .command("install")
594
1672
  .alias("i")
595
- .description("根据工具包清单生成并安装平台产物")
596
- .argument("<target>", "目标平台 (qwen|codex|qoder)", parsePlatformName)
597
- .option("-d, --dir <dir>", "显式安装目录")
1673
+ .description("把平台内容安装到项目、用户级或指定目录")
1674
+ .argument("<target>", "目标平台 (qwen|codex|claude|opencode)", parsePlatformName)
1675
+ .option("-d, --dir <dir>", "安装到指定目录")
598
1676
  .option("-p, --project", "安装到当前目录向上解析出的最近项目根")
599
- .option("-g, --global", "安装到官方文档定义的默认全局位置")
600
- .option("--plan", "只输出安装计划,不落盘")
601
- .option("-j, --json", "直接输出 JSON")
1677
+ .option("-g, --global", "安装到官方文档定义的用户级默认位置")
1678
+ .option("--plan", "只查看安装计划,不写文件")
1679
+ .option("-j, --json", "输出 JSON")
602
1680
  .option("-f, --force", "覆盖目标目录中已有但内容不同的产物")
603
1681
  .action(runPlatformInstall);
604
1682
  platform
605
1683
  .command("where")
606
1684
  .alias("w")
607
- .description("解析平台安装目录,不执行写入")
608
- .argument("<target>", "目标平台 (qwen|codex|qoder)", parsePlatformName)
609
- .option("-d, --dir <dir>", "显式安装目录")
1685
+ .description("查看平台内容会安装到哪里")
1686
+ .argument("<target>", "目标平台 (qwen|codex|claude|opencode)", parsePlatformName)
1687
+ .option("-d, --dir <dir>", "指定目录")
610
1688
  .option("-p, --project", "解析最近项目根")
611
1689
  .option("-g, --global", "解析官方文档定义的默认全局位置")
612
- .option("-j, --json", "直接输出 JSON")
1690
+ .option("-j, --json", "输出 JSON")
613
1691
  .action(runPlatformWhere);
614
1692
  platform
615
1693
  .command("status")
616
- .description("读取安装回执并检查平台内容状态")
617
- .argument("<target>", "目标平台 (qwen|codex|qoder)", parsePlatformName)
618
- .option("-d, --dir <dir>", "显式安装目录")
1694
+ .description("查看是否已安装、是否可更新、是否漂移")
1695
+ .argument("<target>", "目标平台 (qwen|codex|claude|opencode)", parsePlatformName)
1696
+ .option("-d, --dir <dir>", "指定目录")
619
1697
  .option("-p, --project", "解析最近项目根")
620
1698
  .option("-g, --global", "解析官方文档定义的默认全局位置")
621
- .option("-j, --json", "直接输出 JSON")
1699
+ .option("-j, --json", "输出 JSON")
622
1700
  .action(runPlatformStatus);
623
1701
  platform
624
1702
  .command("update")
625
- .description("基于安装回执更新平台产物")
626
- .argument("<target>", "目标平台 (qwen|codex|qoder)", parsePlatformName)
627
- .option("-d, --dir <dir>", "显式安装目录")
1703
+ .description("更新已安装的平台内容")
1704
+ .argument("<target>", "目标平台 (qwen|codex|claude|opencode)", parsePlatformName)
1705
+ .option("-d, --dir <dir>", "指定目录")
628
1706
  .option("-p, --project", "解析最近项目根")
629
1707
  .option("-g, --global", "解析官方文档定义的默认全局位置")
630
- .option("--plan", "只输出更新计划,不落盘")
631
- .option("-j, --json", "直接输出 JSON")
1708
+ .option("--plan", "只查看更新计划,不写文件")
1709
+ .option("-j, --json", "输出 JSON")
632
1710
  .option("-f, --force", "覆盖已漂移的已安装产物")
633
1711
  .action(runPlatformUpdate);
1712
+ platform
1713
+ .command("uninstall")
1714
+ .description("卸载受管平台内容并删除安装记录")
1715
+ .argument("<target>", "目标平台 (qwen|codex|claude|opencode)", parsePlatformName)
1716
+ .option("-d, --dir <dir>", "指定目录")
1717
+ .option("-p, --project", "解析最近项目根")
1718
+ .option("-g, --global", "解析官方文档定义的默认全局位置")
1719
+ .option("--plan", "只查看卸载计划,不写文件")
1720
+ .option("-j, --json", "输出 JSON")
1721
+ .option("-f, --force", "允许卸载已漂移的受管内容")
1722
+ .action(runPlatformUninstall);
1723
+ platform
1724
+ .command("repair")
1725
+ .description("修复漂移、缺失或官方 CLI 失配的安装")
1726
+ .argument("<target>", "目标平台 (qwen|codex|claude|opencode)", parsePlatformName)
1727
+ .option("-d, --dir <dir>", "指定目录")
1728
+ .option("-p, --project", "解析最近项目根")
1729
+ .option("-g, --global", "解析官方文档定义的默认全局位置")
1730
+ .option("--plan", "只查看修复计划,不写文件")
1731
+ .option("-j, --json", "输出 JSON")
1732
+ .action(runPlatformRepair);
1733
+ platform
1734
+ .command("doctor")
1735
+ .description("诊断当前平台安装的健康度和下一步建议")
1736
+ .argument("<target>", "目标平台 (qwen|codex|claude|opencode)", parsePlatformName)
1737
+ .option("-d, --dir <dir>", "指定目录")
1738
+ .option("-p, --project", "解析最近项目根")
1739
+ .option("-g, --global", "解析官方文档定义的默认全局位置")
1740
+ .option("-j, --json", "输出 JSON")
1741
+ .action(runPlatformDoctor);
634
1742
  }
635
1743
  //# sourceMappingURL=platform.js.map