@zmice/zc 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (252) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +201 -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__/surface.test.js +13 -1
  6. package/dist/cli/__tests__/surface.test.js.map +1 -1
  7. package/dist/cli/__tests__/toolkit.test.js +35 -0
  8. package/dist/cli/__tests__/toolkit.test.js.map +1 -1
  9. package/dist/cli/index.d.ts +1 -0
  10. package/dist/cli/index.d.ts.map +1 -1
  11. package/dist/cli/index.js +16 -5
  12. package/dist/cli/index.js.map +1 -1
  13. package/dist/cli/platform.d.ts +15 -1
  14. package/dist/cli/platform.d.ts.map +1 -1
  15. package/dist/cli/platform.js +1195 -87
  16. package/dist/cli/platform.js.map +1 -1
  17. package/dist/cli/toolkit.d.ts.map +1 -1
  18. package/dist/cli/toolkit.js +26 -1
  19. package/dist/cli/toolkit.js.map +1 -1
  20. package/dist/platform-state/doctor.d.ts +3 -0
  21. package/dist/platform-state/doctor.d.ts.map +1 -0
  22. package/dist/platform-state/doctor.js +96 -0
  23. package/dist/platform-state/doctor.js.map +1 -0
  24. package/dist/platform-state/index.d.ts +2 -1
  25. package/dist/platform-state/index.d.ts.map +1 -1
  26. package/dist/platform-state/index.js +1 -0
  27. package/dist/platform-state/index.js.map +1 -1
  28. package/dist/platform-state/receipt.d.ts +5 -0
  29. package/dist/platform-state/receipt.d.ts.map +1 -1
  30. package/dist/platform-state/receipt.js +5 -0
  31. package/dist/platform-state/receipt.js.map +1 -1
  32. package/dist/platform-state/types.d.ts +16 -0
  33. package/dist/platform-state/types.d.ts.map +1 -1
  34. package/dist/utils/install-target.d.ts +1 -1
  35. package/dist/utils/install-target.d.ts.map +1 -1
  36. package/dist/utils/install-target.js +16 -6
  37. package/dist/utils/install-target.js.map +1 -1
  38. package/dist/utils/install-target.test.js +19 -10
  39. package/dist/utils/install-target.test.js.map +1 -1
  40. package/dist/utils/platform-install-cleanup.d.ts +7 -0
  41. package/dist/utils/platform-install-cleanup.d.ts.map +1 -0
  42. package/dist/utils/platform-install-cleanup.js +34 -0
  43. package/dist/utils/platform-install-cleanup.js.map +1 -0
  44. package/dist/utils/platform-install-cleanup.test.d.ts +2 -0
  45. package/dist/utils/platform-install-cleanup.test.d.ts.map +1 -0
  46. package/dist/utils/platform-install-cleanup.test.js +30 -0
  47. package/dist/utils/platform-install-cleanup.test.js.map +1 -0
  48. package/dist/utils/platform-install-receipt.d.ts +1 -0
  49. package/dist/utils/platform-install-receipt.d.ts.map +1 -1
  50. package/dist/utils/platform-install-receipt.js +10 -2
  51. package/dist/utils/platform-install-receipt.js.map +1 -1
  52. package/dist/utils/platform-install-receipt.test.js +30 -2
  53. package/dist/utils/platform-install-receipt.test.js.map +1 -1
  54. package/dist/utils/qwen-extension-cli.d.ts +52 -0
  55. package/dist/utils/qwen-extension-cli.d.ts.map +1 -0
  56. package/dist/utils/qwen-extension-cli.js +169 -0
  57. package/dist/utils/qwen-extension-cli.js.map +1 -0
  58. package/dist/utils/qwen-extension-cli.test.d.ts +2 -0
  59. package/dist/utils/qwen-extension-cli.test.d.ts.map +1 -0
  60. package/dist/utils/qwen-extension-cli.test.js +100 -0
  61. package/dist/utils/qwen-extension-cli.test.js.map +1 -0
  62. package/package.json +5 -4
  63. package/vendor/node_modules/@zmice/platform-core/dist/index.d.ts +54 -1
  64. package/vendor/node_modules/@zmice/platform-core/dist/index.d.ts.map +1 -1
  65. package/vendor/node_modules/@zmice/platform-core/dist/index.js +53 -0
  66. package/vendor/node_modules/@zmice/platform-core/dist/index.js.map +1 -1
  67. package/vendor/node_modules/@zmice/platform-core/dist/index.test.js +1 -1
  68. package/vendor/node_modules/@zmice/platform-core/dist/index.test.js.map +1 -1
  69. package/vendor/node_modules/@zmice/platform-core/package.json +1 -1
  70. package/vendor/packages/platform-claude/dist/generate.d.ts +2 -0
  71. package/vendor/packages/platform-claude/dist/generate.d.ts.map +1 -0
  72. package/vendor/packages/platform-claude/dist/generate.js +2 -0
  73. package/vendor/packages/platform-claude/dist/generate.js.map +1 -0
  74. package/vendor/packages/platform-claude/dist/index.d.ts +50 -0
  75. package/vendor/packages/platform-claude/dist/index.d.ts.map +1 -0
  76. package/vendor/packages/platform-claude/dist/index.js +250 -0
  77. package/vendor/packages/platform-claude/dist/index.js.map +1 -0
  78. package/vendor/packages/platform-claude/dist/index.test.js +81 -0
  79. package/vendor/packages/platform-claude/dist/index.test.js.map +1 -0
  80. package/vendor/packages/platform-claude/dist/install.d.ts +2 -0
  81. package/vendor/packages/platform-claude/dist/install.d.ts.map +1 -0
  82. package/vendor/packages/platform-claude/dist/install.js +2 -0
  83. package/vendor/packages/platform-claude/dist/install.js.map +1 -0
  84. package/vendor/packages/platform-claude/package.json +46 -0
  85. package/vendor/packages/platform-claude/templates/.gitkeep +1 -0
  86. package/vendor/packages/platform-claude/templates/CLAUDE.md +1 -0
  87. package/vendor/packages/platform-codex/dist/index.d.ts +36 -2
  88. package/vendor/packages/platform-codex/dist/index.d.ts.map +1 -1
  89. package/vendor/packages/platform-codex/dist/index.js +231 -6
  90. package/vendor/packages/platform-codex/dist/index.js.map +1 -1
  91. package/vendor/packages/platform-codex/dist/index.test.js +40 -10
  92. package/vendor/packages/platform-codex/dist/index.test.js.map +1 -1
  93. package/vendor/packages/platform-opencode/dist/generate.d.ts +2 -0
  94. package/vendor/packages/platform-opencode/dist/generate.d.ts.map +1 -0
  95. package/vendor/packages/platform-opencode/dist/generate.js +2 -0
  96. package/vendor/packages/platform-opencode/dist/generate.js.map +1 -0
  97. package/vendor/packages/platform-opencode/dist/index.d.ts +46 -0
  98. package/vendor/packages/platform-opencode/dist/index.d.ts.map +1 -0
  99. package/vendor/packages/platform-opencode/dist/index.js +308 -0
  100. package/vendor/packages/platform-opencode/dist/index.js.map +1 -0
  101. package/vendor/packages/platform-opencode/dist/index.test.d.ts +2 -0
  102. package/vendor/packages/platform-opencode/dist/index.test.d.ts.map +1 -0
  103. package/vendor/packages/platform-opencode/dist/index.test.js +106 -0
  104. package/vendor/packages/platform-opencode/dist/index.test.js.map +1 -0
  105. package/vendor/packages/platform-opencode/dist/install.d.ts +2 -0
  106. package/vendor/packages/platform-opencode/dist/install.d.ts.map +1 -0
  107. package/vendor/packages/platform-opencode/dist/install.js +2 -0
  108. package/vendor/packages/platform-opencode/dist/install.js.map +1 -0
  109. package/vendor/packages/{platform-qoder → platform-opencode}/package.json +2 -2
  110. package/vendor/packages/platform-opencode/templates/AGENTS.md +1 -0
  111. package/vendor/packages/platform-qwen/dist/index.d.ts +55 -2
  112. package/vendor/packages/platform-qwen/dist/index.d.ts.map +1 -1
  113. package/vendor/packages/platform-qwen/dist/index.js +229 -11
  114. package/vendor/packages/platform-qwen/dist/index.js.map +1 -1
  115. package/vendor/packages/platform-qwen/dist/index.test.js +54 -16
  116. package/vendor/packages/platform-qwen/dist/index.test.js.map +1 -1
  117. package/vendor/packages/toolkit/dist/loaders.test.js +1 -1
  118. package/vendor/packages/toolkit/dist/loaders.test.js.map +1 -1
  119. package/vendor/packages/toolkit/dist/manifests.test.js +29 -2
  120. package/vendor/packages/toolkit/dist/manifests.test.js.map +1 -1
  121. package/vendor/packages/toolkit/dist/query/toolkit-query.d.ts +4 -6
  122. package/vendor/packages/toolkit/dist/query/toolkit-query.d.ts.map +1 -1
  123. package/vendor/packages/toolkit/dist/query/toolkit-query.js +99 -1
  124. package/vendor/packages/toolkit/dist/query/toolkit-query.js.map +1 -1
  125. package/vendor/packages/toolkit/dist/query.test.js +209 -0
  126. package/vendor/packages/toolkit/dist/query.test.js.map +1 -1
  127. package/vendor/packages/toolkit/dist/schema/asset-meta.d.ts.map +1 -1
  128. package/vendor/packages/toolkit/dist/schema/asset-meta.js +105 -1
  129. package/vendor/packages/toolkit/dist/schema/asset-meta.js.map +1 -1
  130. package/vendor/packages/toolkit/dist/types.d.ts +41 -1
  131. package/vendor/packages/toolkit/dist/types.d.ts.map +1 -1
  132. package/vendor/packages/toolkit/dist/types.js +26 -1
  133. package/vendor/packages/toolkit/dist/types.js.map +1 -1
  134. package/vendor/packages/toolkit/package.json +1 -1
  135. package/vendor/packages/toolkit/src/content/agents/architect/meta.yaml +2 -1
  136. package/vendor/packages/toolkit/src/content/agents/backend-specialist/meta.yaml +2 -1
  137. package/vendor/packages/toolkit/src/content/agents/code-reviewer/meta.yaml +2 -1
  138. package/vendor/packages/toolkit/src/content/agents/frontend-specialist/meta.yaml +2 -1
  139. package/vendor/packages/toolkit/src/content/agents/performance-engineer/meta.yaml +2 -1
  140. package/vendor/packages/toolkit/src/content/agents/product-owner/meta.yaml +2 -1
  141. package/vendor/packages/toolkit/src/content/agents/security-auditor/meta.yaml +2 -1
  142. package/vendor/packages/toolkit/src/content/agents/test-engineer/meta.yaml +2 -1
  143. package/vendor/packages/toolkit/src/content/commands/api/meta.yaml +2 -1
  144. package/vendor/packages/toolkit/src/content/commands/build/body.md +15 -20
  145. package/vendor/packages/toolkit/src/content/commands/build/meta.yaml +12 -1
  146. package/vendor/packages/toolkit/src/content/commands/careful/body.md +21 -11
  147. package/vendor/packages/toolkit/src/content/commands/careful/meta.yaml +16 -1
  148. package/vendor/packages/toolkit/src/content/commands/ci/meta.yaml +2 -1
  149. package/vendor/packages/toolkit/src/content/commands/commit/meta.yaml +2 -1
  150. package/vendor/packages/toolkit/src/content/commands/ctx-health/body.md +16 -16
  151. package/vendor/packages/toolkit/src/content/commands/ctx-health/meta.yaml +11 -1
  152. package/vendor/packages/toolkit/src/content/commands/debug/body.md +16 -17
  153. package/vendor/packages/toolkit/src/content/commands/debug/meta.yaml +12 -1
  154. package/vendor/packages/toolkit/src/content/commands/doc/body.md +15 -16
  155. package/vendor/packages/toolkit/src/content/commands/doc/meta.yaml +11 -1
  156. package/vendor/packages/toolkit/src/content/commands/freeze/body.md +20 -9
  157. package/vendor/packages/toolkit/src/content/commands/freeze/meta.yaml +16 -1
  158. package/vendor/packages/toolkit/src/content/commands/guard/body.md +21 -10
  159. package/vendor/packages/toolkit/src/content/commands/guard/meta.yaml +16 -1
  160. package/vendor/packages/toolkit/src/content/commands/idea/body.md +15 -16
  161. package/vendor/packages/toolkit/src/content/commands/idea/meta.yaml +12 -1
  162. package/vendor/packages/toolkit/src/content/commands/learn/meta.yaml +2 -1
  163. package/vendor/packages/toolkit/src/content/commands/migrate/meta.yaml +2 -1
  164. package/vendor/packages/toolkit/src/content/commands/onboard/body.md +15 -17
  165. package/vendor/packages/toolkit/src/content/commands/onboard/meta.yaml +11 -1
  166. package/vendor/packages/toolkit/src/content/commands/perf/meta.yaml +2 -1
  167. package/vendor/packages/toolkit/src/content/commands/plan-review/body.md +21 -20
  168. package/vendor/packages/toolkit/src/content/commands/plan-review/meta.yaml +12 -1
  169. package/vendor/packages/toolkit/src/content/commands/product-analysis/body.md +52 -0
  170. package/vendor/packages/toolkit/src/content/commands/product-analysis/meta.yaml +35 -0
  171. package/vendor/packages/toolkit/src/content/commands/qa/meta.yaml +2 -1
  172. package/vendor/packages/toolkit/src/content/commands/quality-review/body.md +13 -18
  173. package/vendor/packages/toolkit/src/content/commands/quality-review/meta.yaml +13 -1
  174. package/vendor/packages/toolkit/src/content/commands/retro/meta.yaml +2 -1
  175. package/vendor/packages/toolkit/src/content/commands/sdd-tdd/body.md +29 -29
  176. package/vendor/packages/toolkit/src/content/commands/sdd-tdd/meta.yaml +11 -1
  177. package/vendor/packages/toolkit/src/content/commands/secure/meta.yaml +2 -1
  178. package/vendor/packages/toolkit/src/content/commands/ship/body.md +16 -11
  179. package/vendor/packages/toolkit/src/content/commands/ship/meta.yaml +11 -1
  180. package/vendor/packages/toolkit/src/content/commands/simplify/meta.yaml +2 -1
  181. package/vendor/packages/toolkit/src/content/commands/spec/body.md +16 -21
  182. package/vendor/packages/toolkit/src/content/commands/spec/meta.yaml +12 -1
  183. package/vendor/packages/toolkit/src/content/commands/start/body.md +148 -0
  184. package/vendor/packages/toolkit/src/content/commands/start/meta.yaml +55 -0
  185. package/vendor/packages/toolkit/src/content/commands/task-plan/body.md +13 -18
  186. package/vendor/packages/toolkit/src/content/commands/task-plan/meta.yaml +12 -1
  187. package/vendor/packages/toolkit/src/content/commands/ui/meta.yaml +2 -1
  188. package/vendor/packages/toolkit/src/content/commands/verify/body.md +12 -17
  189. package/vendor/packages/toolkit/src/content/commands/verify/meta.yaml +15 -1
  190. package/vendor/packages/toolkit/src/content/skills/api-and-interface-design/meta.yaml +2 -1
  191. package/vendor/packages/toolkit/src/content/skills/brainstorming-and-design/meta.yaml +2 -1
  192. package/vendor/packages/toolkit/src/content/skills/branch-finish-and-cleanup/meta.yaml +2 -1
  193. package/vendor/packages/toolkit/src/content/skills/browser-qa-testing/meta.yaml +2 -1
  194. package/vendor/packages/toolkit/src/content/skills/ci-cd-and-automation/meta.yaml +2 -1
  195. package/vendor/packages/toolkit/src/content/skills/code-review-and-quality/meta.yaml +2 -1
  196. package/vendor/packages/toolkit/src/content/skills/code-simplification/meta.yaml +2 -1
  197. package/vendor/packages/toolkit/src/content/skills/codebase-onboarding/body.md +6 -3
  198. package/vendor/packages/toolkit/src/content/skills/codebase-onboarding/meta.yaml +2 -1
  199. package/vendor/packages/toolkit/src/content/skills/context-budget-audit/meta.yaml +2 -1
  200. package/vendor/packages/toolkit/src/content/skills/context-engineering/body.md +7 -5
  201. package/vendor/packages/toolkit/src/content/skills/context-engineering/meta.yaml +2 -1
  202. package/vendor/packages/toolkit/src/content/skills/continuous-learning/body.md +15 -15
  203. package/vendor/packages/toolkit/src/content/skills/continuous-learning/meta.yaml +2 -1
  204. package/vendor/packages/toolkit/src/content/skills/debugging-and-error-recovery/body.md +9 -6
  205. package/vendor/packages/toolkit/src/content/skills/debugging-and-error-recovery/meta.yaml +2 -1
  206. package/vendor/packages/toolkit/src/content/skills/deprecation-and-migration/meta.yaml +2 -1
  207. package/vendor/packages/toolkit/src/content/skills/developer-experience-audit/meta.yaml +2 -1
  208. package/vendor/packages/toolkit/src/content/skills/documentation-and-adrs/body.md +7 -11
  209. package/vendor/packages/toolkit/src/content/skills/documentation-and-adrs/meta.yaml +2 -1
  210. package/vendor/packages/toolkit/src/content/skills/engineering-principles/meta.yaml +2 -1
  211. package/vendor/packages/toolkit/src/content/skills/frontend-ui-engineering/meta.yaml +2 -1
  212. package/vendor/packages/toolkit/src/content/skills/git-workflow-and-versioning/meta.yaml +2 -1
  213. package/vendor/packages/toolkit/src/content/skills/idea-refine/body.md +31 -160
  214. package/vendor/packages/toolkit/src/content/skills/idea-refine/meta.yaml +2 -1
  215. package/vendor/packages/toolkit/src/content/skills/incremental-implementation/meta.yaml +2 -1
  216. package/vendor/packages/toolkit/src/content/skills/multi-perspective-review/meta.yaml +2 -1
  217. package/vendor/packages/toolkit/src/content/skills/parallel-agent-dispatch/meta.yaml +2 -1
  218. package/vendor/packages/toolkit/src/content/skills/performance-optimization/meta.yaml +2 -1
  219. package/vendor/packages/toolkit/src/content/skills/planning-and-task-breakdown/meta.yaml +2 -1
  220. package/vendor/packages/toolkit/src/content/skills/release-documentation-sync/meta.yaml +2 -1
  221. package/vendor/packages/toolkit/src/content/skills/review-response-and-resolution/meta.yaml +2 -1
  222. package/vendor/packages/toolkit/src/content/skills/safety-guardrails/body.md +6 -2
  223. package/vendor/packages/toolkit/src/content/skills/safety-guardrails/meta.yaml +2 -1
  224. package/vendor/packages/toolkit/src/content/skills/sdd-tdd-workflow/meta.yaml +2 -1
  225. package/vendor/packages/toolkit/src/content/skills/security-and-hardening/meta.yaml +2 -1
  226. package/vendor/packages/toolkit/src/content/skills/shipping-and-launch/body.md +7 -11
  227. package/vendor/packages/toolkit/src/content/skills/shipping-and-launch/meta.yaml +2 -1
  228. package/vendor/packages/toolkit/src/content/skills/source-driven-development/meta.yaml +2 -1
  229. package/vendor/packages/toolkit/src/content/skills/spec-driven-development/meta.yaml +2 -1
  230. package/vendor/packages/toolkit/src/content/skills/sprint-retrospective/meta.yaml +2 -1
  231. package/vendor/packages/toolkit/src/content/skills/subagent-driven-development/meta.yaml +2 -1
  232. package/vendor/packages/toolkit/src/content/skills/team-orchestration/meta.yaml +2 -1
  233. package/vendor/packages/toolkit/src/content/skills/test-driven-development/meta.yaml +2 -1
  234. package/vendor/packages/toolkit/src/content/skills/using-agent-skills/meta.yaml +2 -1
  235. package/vendor/packages/toolkit/src/content/skills/verification-before-completion/meta.yaml +2 -1
  236. package/vendor/packages/platform-qoder/dist/generate.d.ts +0 -2
  237. package/vendor/packages/platform-qoder/dist/generate.d.ts.map +0 -1
  238. package/vendor/packages/platform-qoder/dist/generate.js +0 -2
  239. package/vendor/packages/platform-qoder/dist/generate.js.map +0 -1
  240. package/vendor/packages/platform-qoder/dist/index.d.ts +0 -15
  241. package/vendor/packages/platform-qoder/dist/index.d.ts.map +0 -1
  242. package/vendor/packages/platform-qoder/dist/index.js +0 -46
  243. package/vendor/packages/platform-qoder/dist/index.js.map +0 -1
  244. package/vendor/packages/platform-qoder/dist/index.test.js +0 -38
  245. package/vendor/packages/platform-qoder/dist/index.test.js.map +0 -1
  246. package/vendor/packages/platform-qoder/dist/install.d.ts +0 -2
  247. package/vendor/packages/platform-qoder/dist/install.d.ts.map +0 -1
  248. package/vendor/packages/platform-qoder/dist/install.js +0 -2
  249. package/vendor/packages/platform-qoder/dist/install.js.map +0 -1
  250. package/vendor/packages/platform-qoder/templates/instructions.md +0 -7
  251. /package/vendor/packages/{platform-qoder → platform-claude}/dist/index.test.d.ts +0 -0
  252. /package/vendor/packages/{platform-qoder → platform-claude}/dist/index.test.d.ts.map +0 -0
@@ -8,16 +8,30 @@ const platformMocks = vi.hoisted(() => ({
8
8
  }
9
9
  },
10
10
  createQwenGenerationPlan: vi.fn(),
11
+ createQwenInstallPlan: vi.fn(),
11
12
  createCodexInstallPlan: vi.fn(),
12
- createQoderInstallPlan: vi.fn(),
13
+ createClaudeInstallPlan: vi.fn(),
14
+ createOpenCodeInstallPlan: vi.fn(),
13
15
  loadToolkitManifest: vi.fn(),
14
16
  importWorkspaceDistModule: vi.fn(),
15
17
  normalizeInstallSelector: vi.fn(),
18
+ pathExists: vi.fn(),
16
19
  resolveInstallTarget: vi.fn(),
20
+ resolvePlatformInstallDoctor: vi.fn(),
17
21
  resolvePlatformInstallReceiptPath: vi.fn(),
18
22
  resolvePlatformInstallStatus: vi.fn(),
23
+ removeManagedPaths: vi.fn(),
24
+ deletePlatformInstallReceipt: vi.fn(),
19
25
  writeArtifacts: vi.fn(),
20
26
  writePlatformInstallReceiptForPlan: vi.fn(),
27
+ syncQwenOfficialCliSourceBundle: vi.fn(),
28
+ syncQwenOfficialCliReleaseBundle: vi.fn(),
29
+ toQwenOfficialCliReleaseArtifacts: vi.fn(),
30
+ installQwenExtensionFromOfficialRepoWithCli: vi.fn(),
31
+ installQwenExtensionWithOfficialCli: vi.fn(),
32
+ uninstallQwenExtensionWithOfficialCli: vi.fn(),
33
+ updateQwenExtensionWithOfficialCli: vi.fn(),
34
+ relinkQwenExtensionWithOfficialCli: vi.fn(),
21
35
  }));
22
36
  vi.mock("../../utils/workspace.js", () => ({
23
37
  ArtifactConflictError: platformMocks.ArtifactConflictError,
@@ -32,11 +46,33 @@ vi.mock("../../utils/install-target.js", () => ({
32
46
  vi.mock("../../platform-state/status.js", () => ({
33
47
  resolvePlatformInstallStatus: platformMocks.resolvePlatformInstallStatus,
34
48
  }));
49
+ vi.mock("../../platform-state/doctor.js", () => ({
50
+ resolvePlatformInstallDoctor: platformMocks.resolvePlatformInstallDoctor,
51
+ }));
35
52
  vi.mock("../../utils/platform-install-receipt.js", () => ({
53
+ deletePlatformInstallReceipt: platformMocks.deletePlatformInstallReceipt,
36
54
  resolvePlatformInstallReceiptPath: platformMocks.resolvePlatformInstallReceiptPath,
37
55
  writePlatformInstallReceiptForPlan: platformMocks.writePlatformInstallReceiptForPlan,
38
56
  }));
39
- import { runPlatformGenerate, runPlatformInstall, runPlatformStatus, runPlatformUpdate, runPlatformWhere, } from "../platform.js";
57
+ vi.mock("../../utils/platform-install-cleanup.js", () => ({
58
+ pathExists: platformMocks.pathExists,
59
+ removeManagedPaths: platformMocks.removeManagedPaths,
60
+ }));
61
+ vi.mock("../../utils/qwen-extension-cli.js", () => ({
62
+ QwenOfficialCliUnavailableError: class QwenOfficialCliUnavailableError extends Error {
63
+ },
64
+ qwenOfficialExtensionRepoUrl: "https://github.com/zmice/zc-qwen-extension.git",
65
+ syncQwenOfficialCliSourceBundle: platformMocks.syncQwenOfficialCliSourceBundle,
66
+ syncQwenOfficialCliReleaseBundle: platformMocks.syncQwenOfficialCliReleaseBundle,
67
+ toQwenOfficialCliReleaseArtifacts: platformMocks.toQwenOfficialCliReleaseArtifacts,
68
+ resolveQwenOfficialCliReleaseBundleDir: vi.fn((plan) => (`${plan.destinationRoot}/.zc/platform-bundles/qwen/zc-toolkit`)),
69
+ installQwenExtensionFromOfficialRepoWithCli: platformMocks.installQwenExtensionFromOfficialRepoWithCli,
70
+ installQwenExtensionWithOfficialCli: platformMocks.installQwenExtensionWithOfficialCli,
71
+ uninstallQwenExtensionWithOfficialCli: platformMocks.uninstallQwenExtensionWithOfficialCli,
72
+ updateQwenExtensionWithOfficialCli: platformMocks.updateQwenExtensionWithOfficialCli,
73
+ relinkQwenExtensionWithOfficialCli: platformMocks.relinkQwenExtensionWithOfficialCli,
74
+ }));
75
+ import { runPlatformGenerate, runPlatformInstall, runPlatformDoctor, runPlatformRepair, runPlatformStatus, runPlatformUninstall, runPlatformUpdate, runPlatformWhere, } from "../platform.js";
40
76
  function createGenerationPlan(artifacts) {
41
77
  return {
42
78
  platform: "qwen",
@@ -46,14 +82,62 @@ function createGenerationPlan(artifacts) {
46
82
  artifacts,
47
83
  };
48
84
  }
49
- function createInstallPlan(platform, destinationRoot, artifacts, overwrite = "error") {
85
+ function createInstallPlan(platform, destinationRoot, artifacts, scope = "dir", overwrite = "error") {
86
+ const capability = platform === "codex"
87
+ ? {
88
+ namespace: "zc",
89
+ surfaces: ["entry-file", "skills-dir"],
90
+ entryFile: "AGENTS.md",
91
+ commandsDir: null,
92
+ skillsDir: "skills",
93
+ agentsDir: null,
94
+ extensionDir: null,
95
+ }
96
+ : {
97
+ namespace: "zc",
98
+ surfaces: ["entry-file", "commands-dir", "skills-dir", "agents-dir"],
99
+ entryFile: "AGENTS.md",
100
+ commandsDir: "commands",
101
+ skillsDir: "skills",
102
+ agentsDir: "agents",
103
+ extensionDir: null,
104
+ };
50
105
  return {
51
106
  platform,
52
- packageName: platform === "codex" ? "@zmice/platform-codex" : "@zmice/platform-qoder",
107
+ packageName: platform === "codex" ? "@zmice/platform-codex" : "@zmice/platform-claude",
108
+ manifestSource: "/repo/packages/toolkit/src/content#generatedAt=2026-04-19T12:00:00.000Z",
109
+ matchedAssets: [],
110
+ destinationRoot,
111
+ scope,
112
+ overwrite,
113
+ capability,
114
+ artifacts,
115
+ };
116
+ }
117
+ function createQwenInstallPlan(destinationRoot, artifacts, scope = "dir", overwrite = "error") {
118
+ return {
119
+ platform: "qwen",
120
+ packageName: "@zmice/platform-qwen",
53
121
  manifestSource: "/repo/packages/toolkit/src/content#generatedAt=2026-04-19T12:00:00.000Z",
54
122
  matchedAssets: [],
55
123
  destinationRoot,
124
+ scope,
56
125
  overwrite,
126
+ capability: {
127
+ namespace: "zc",
128
+ surfaces: ["entry-file", "commands-dir", "skills-dir", "agents-dir", "extension-dir"],
129
+ entryFile: "QWEN.md",
130
+ commandsDir: "commands/zc",
131
+ skillsDir: "skills",
132
+ agentsDir: "agents",
133
+ extensionDir: "extensions/zc-toolkit",
134
+ extension: {
135
+ relativeDir: "extensions",
136
+ name: "zc-toolkit",
137
+ manifestFile: "qwen-extension.json",
138
+ contextFileName: "QWEN.md",
139
+ },
140
+ },
57
141
  artifacts,
58
142
  };
59
143
  }
@@ -61,16 +145,30 @@ describe("platform CLI", () => {
61
145
  beforeEach(() => {
62
146
  process.exitCode = undefined;
63
147
  platformMocks.createQwenGenerationPlan.mockReset();
148
+ platformMocks.createQwenInstallPlan.mockReset();
64
149
  platformMocks.createCodexInstallPlan.mockReset();
65
- platformMocks.createQoderInstallPlan.mockReset();
150
+ platformMocks.createClaudeInstallPlan.mockReset();
151
+ platformMocks.createOpenCodeInstallPlan.mockReset();
66
152
  platformMocks.loadToolkitManifest.mockReset();
67
153
  platformMocks.importWorkspaceDistModule.mockReset();
68
154
  platformMocks.normalizeInstallSelector.mockReset();
155
+ platformMocks.pathExists.mockReset();
69
156
  platformMocks.resolveInstallTarget.mockReset();
157
+ platformMocks.resolvePlatformInstallDoctor.mockReset();
70
158
  platformMocks.resolvePlatformInstallReceiptPath.mockReset();
71
159
  platformMocks.resolvePlatformInstallStatus.mockReset();
160
+ platformMocks.removeManagedPaths.mockReset();
161
+ platformMocks.deletePlatformInstallReceipt.mockReset();
72
162
  platformMocks.writeArtifacts.mockReset();
73
163
  platformMocks.writePlatformInstallReceiptForPlan.mockReset();
164
+ platformMocks.syncQwenOfficialCliSourceBundle.mockReset();
165
+ platformMocks.syncQwenOfficialCliReleaseBundle.mockReset();
166
+ platformMocks.toQwenOfficialCliReleaseArtifacts.mockReset();
167
+ platformMocks.installQwenExtensionFromOfficialRepoWithCli.mockReset();
168
+ platformMocks.installQwenExtensionWithOfficialCli.mockReset();
169
+ platformMocks.uninstallQwenExtensionWithOfficialCli.mockReset();
170
+ platformMocks.updateQwenExtensionWithOfficialCli.mockReset();
171
+ platformMocks.relinkQwenExtensionWithOfficialCli.mockReset();
74
172
  platformMocks.loadToolkitManifest.mockResolvedValue({
75
173
  generatedAt: "2026-04-19T12:00:00.000Z",
76
174
  contentRoot: "/repo/packages/toolkit/src/content",
@@ -80,6 +178,7 @@ describe("platform CLI", () => {
80
178
  body: "body",
81
179
  meta: {
82
180
  kind: "skill",
181
+ name: "alpha",
83
182
  title: "Alpha",
84
183
  description: "desc",
85
184
  platforms: ["qwen", "codex"],
@@ -92,13 +191,19 @@ describe("platform CLI", () => {
92
191
  return { loadToolkitManifest: platformMocks.loadToolkitManifest };
93
192
  }
94
193
  if (relativePath === "packages/platform-qwen/dist/index.js") {
95
- return { createQwenGenerationPlan: platformMocks.createQwenGenerationPlan };
194
+ return {
195
+ createQwenGenerationPlan: platformMocks.createQwenGenerationPlan,
196
+ createQwenInstallPlan: platformMocks.createQwenInstallPlan,
197
+ };
96
198
  }
97
199
  if (relativePath === "packages/platform-codex/dist/index.js") {
98
200
  return { createCodexInstallPlan: platformMocks.createCodexInstallPlan };
99
201
  }
100
- if (relativePath === "packages/platform-qoder/dist/index.js") {
101
- return { createQoderInstallPlan: platformMocks.createQoderInstallPlan };
202
+ if (relativePath === "packages/platform-claude/dist/index.js") {
203
+ return { createClaudeInstallPlan: platformMocks.createClaudeInstallPlan };
204
+ }
205
+ if (relativePath === "packages/platform-opencode/dist/index.js") {
206
+ return { createOpenCodeInstallPlan: platformMocks.createOpenCodeInstallPlan };
102
207
  }
103
208
  throw new Error(`unexpected import: ${relativePath}`);
104
209
  });
@@ -137,7 +242,37 @@ describe("platform CLI", () => {
137
242
  },
138
243
  artifacts: [],
139
244
  });
245
+ platformMocks.resolvePlatformInstallDoctor.mockResolvedValue({
246
+ platform: "codex",
247
+ health: "healthy",
248
+ issues: [],
249
+ });
250
+ platformMocks.pathExists.mockResolvedValue(true);
251
+ platformMocks.removeManagedPaths.mockResolvedValue({
252
+ removed: 1,
253
+ missing: 0,
254
+ });
255
+ platformMocks.deletePlatformInstallReceipt.mockResolvedValue(undefined);
140
256
  platformMocks.writePlatformInstallReceiptForPlan.mockResolvedValue({});
257
+ platformMocks.syncQwenOfficialCliSourceBundle.mockResolvedValue({
258
+ sourceDir: "/tmp/qwen-source",
259
+ extensionName: "zc-toolkit",
260
+ artifactCount: 1,
261
+ });
262
+ platformMocks.syncQwenOfficialCliReleaseBundle.mockResolvedValue({
263
+ bundleDir: "/tmp/qwen-release",
264
+ extensionName: "zc-toolkit",
265
+ artifactCount: 1,
266
+ });
267
+ platformMocks.toQwenOfficialCliReleaseArtifacts.mockImplementation((_plan, bundleDir) => [
268
+ { path: `${bundleDir}/QWEN.md`, content: "# context" },
269
+ { path: `${bundleDir}/commands/zc/start.md`, content: "# start" },
270
+ ]);
271
+ platformMocks.installQwenExtensionFromOfficialRepoWithCli.mockResolvedValue(undefined);
272
+ platformMocks.installQwenExtensionWithOfficialCli.mockResolvedValue(undefined);
273
+ platformMocks.uninstallQwenExtensionWithOfficialCli.mockResolvedValue(undefined);
274
+ platformMocks.updateQwenExtensionWithOfficialCli.mockResolvedValue(undefined);
275
+ platformMocks.relinkQwenExtensionWithOfficialCli.mockResolvedValue(undefined);
141
276
  });
142
277
  it("uses safe overwrite defaults for platform generate writes", async () => {
143
278
  platformMocks.createQwenGenerationPlan.mockReturnValue(createGenerationPlan([{ path: "QWEN.md", content: "# context" }]));
@@ -167,6 +302,53 @@ describe("platform CLI", () => {
167
302
  }));
168
303
  logSpy.mockRestore();
169
304
  });
305
+ it("exports a standalone qwen release bundle during generate", async () => {
306
+ platformMocks.createQwenGenerationPlan.mockReturnValue(createGenerationPlan([{ path: "QWEN.md", content: "# context" }]));
307
+ platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan("/tmp/zc-toolkit", [
308
+ { path: "/tmp/zc-toolkit/extensions/zc-toolkit/QWEN.md", content: "# context" },
309
+ { path: "/tmp/zc-toolkit/extensions/zc-toolkit/commands/zc/start.md", content: "# start" },
310
+ ]));
311
+ platformMocks.writeArtifacts.mockResolvedValue({
312
+ created: 2,
313
+ overwritten: 0,
314
+ unchanged: 0,
315
+ skipped: 0,
316
+ dryRun: false,
317
+ });
318
+ await runPlatformGenerate("qwen", { dir: "/tmp/zc-toolkit", bundle: "release-bundle" });
319
+ expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([
320
+ { path: "/tmp/zc-toolkit/QWEN.md", content: "# context" },
321
+ { path: "/tmp/zc-toolkit/commands/zc/start.md", content: "# start" },
322
+ ], { dryRun: false, overwrite: "error" });
323
+ });
324
+ it("prints qwen release bundle plan paths without native extension nesting", async () => {
325
+ platformMocks.createQwenGenerationPlan.mockReturnValue(createGenerationPlan([{ path: "QWEN.md", content: "# context" }]));
326
+ platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan("/tmp/zc-toolkit", [
327
+ { path: "/tmp/zc-toolkit/extensions/zc-toolkit/QWEN.md", content: "# context" },
328
+ { path: "/tmp/zc-toolkit/extensions/zc-toolkit/commands/zc/start.md", content: "# start" },
329
+ ]));
330
+ const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
331
+ await runPlatformGenerate("qwen", {
332
+ dir: "/tmp/zc-toolkit",
333
+ bundle: "release-bundle",
334
+ plan: true,
335
+ json: true,
336
+ });
337
+ const payload = JSON.parse(logSpy.mock.calls[0]?.[0] ?? "{}");
338
+ expect(payload).toEqual(expect.objectContaining({
339
+ mode: "plan",
340
+ action: "generate",
341
+ target: "qwen",
342
+ root: "/tmp/zc-toolkit",
343
+ bundleType: "release-bundle",
344
+ bundlePath: "/tmp/zc-toolkit",
345
+ artifacts: [
346
+ { path: "/tmp/zc-toolkit/QWEN.md", content: "# context" },
347
+ { path: "/tmp/zc-toolkit/commands/zc/start.md", content: "# start" },
348
+ ],
349
+ }));
350
+ logSpy.mockRestore();
351
+ });
170
352
  it("uses safe overwrite defaults for platform install and writes a receipt", async () => {
171
353
  platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/tmp/install", [{ path: "/tmp/install/AGENTS.md", content: "# agents" }]));
172
354
  platformMocks.writeArtifacts.mockResolvedValue({
@@ -179,6 +361,7 @@ describe("platform CLI", () => {
179
361
  await runPlatformInstall("codex", { dir: "/tmp/install" });
180
362
  expect(platformMocks.createCodexInstallPlan).toHaveBeenCalledWith(expect.anything(), expect.objectContaining({
181
363
  destinationRoot: "/tmp/install",
364
+ scope: "dir",
182
365
  overwrite: "error",
183
366
  }));
184
367
  expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: "/tmp/install/AGENTS.md", content: "# agents" }], { dryRun: false, overwrite: "error" });
@@ -224,12 +407,13 @@ describe("platform CLI", () => {
224
407
  });
225
408
  expect(platformMocks.createCodexInstallPlan).toHaveBeenCalledWith(expect.anything(), expect.objectContaining({
226
409
  destinationRoot: "/workspace/project",
410
+ scope: "project",
227
411
  }));
228
412
  expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("安装目录自动解析(project-root)"));
229
413
  logSpy.mockRestore();
230
414
  });
231
415
  it("prints a JSON install plan without writing files when install uses --plan", async () => {
232
- platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/tmp/install", [{ path: "/tmp/install/AGENTS.md", content: "# agents" }], "error"));
416
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/tmp/install", [{ path: "/tmp/install/AGENTS.md", content: "# agents" }], "dir", "error"));
233
417
  const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
234
418
  await runPlatformInstall("codex", { dir: "/tmp/install", plan: true, json: true });
235
419
  expect(platformMocks.writeArtifacts).not.toHaveBeenCalled();
@@ -274,6 +458,67 @@ describe("platform CLI", () => {
274
458
  }));
275
459
  logSpy.mockRestore();
276
460
  });
461
+ it("prints qwen platform status json with installed metadata from receipt", async () => {
462
+ const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
463
+ platformMocks.resolveInstallTarget.mockResolvedValue({
464
+ root: "/home/test/.qwen",
465
+ source: "official-global",
466
+ hint: "Qwen 官方文档定义用户级配置目录为 `~/.qwen`。",
467
+ });
468
+ platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan("/home/test/.qwen", [{ path: "/home/test/.qwen/extensions/zc-toolkit/QWEN.md", content: "# context" }], "global"));
469
+ platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
470
+ kind: "up-to-date",
471
+ platform: "qwen",
472
+ receiptPath: "/home/test/.qwen/.zc/platform-state/qwen.install-receipt.json",
473
+ receipt: {
474
+ schemaVersion: 1,
475
+ platform: "qwen",
476
+ destinationRoot: "/home/test/.qwen",
477
+ manifestSource: "/repo/packages/toolkit/src/content",
478
+ overwrite: "error",
479
+ installedAt: "2026-04-19T12:00:00.000Z",
480
+ installMethod: "filesystem",
481
+ installSource: "local-bundle",
482
+ sourceRef: "/tmp/qwen-release/zc-toolkit",
483
+ bundleType: "release-bundle",
484
+ bundlePath: "/tmp/qwen-release/zc-toolkit",
485
+ artifacts: [
486
+ {
487
+ path: "/home/test/.qwen/extensions/zc-toolkit/QWEN.md",
488
+ sha256: "sha",
489
+ bytes: 9,
490
+ },
491
+ ],
492
+ },
493
+ contentFingerprint: "current-fingerprint",
494
+ installedContentFingerprint: "current-fingerprint",
495
+ summary: {
496
+ trackedArtifacts: 1,
497
+ driftedArtifacts: 0,
498
+ missingArtifacts: 0,
499
+ plannedChanges: 0,
500
+ },
501
+ artifacts: [],
502
+ });
503
+ await runPlatformStatus("qwen", { global: true, json: true });
504
+ const payload = JSON.parse(logSpy.mock.calls[0]?.[0] ?? "{}");
505
+ expect(payload).toEqual(expect.objectContaining({
506
+ mode: "status",
507
+ target: "qwen",
508
+ root: "/home/test/.qwen",
509
+ installMethod: "filesystem",
510
+ installSource: "local-bundle",
511
+ sourceRef: "/tmp/qwen-release/zc-toolkit",
512
+ bundleType: "release-bundle",
513
+ bundlePath: "/tmp/qwen-release/zc-toolkit",
514
+ recommendedInstallMethod: "qwen-cli",
515
+ recommendedInstallSource: "github-repo",
516
+ recommendedSourceRef: "https://github.com/zmice/zc-qwen-extension.git",
517
+ recommendedBundleType: "release-bundle",
518
+ recommendedBundlePath: "/home/test/.qwen/.zc/platform-bundles/qwen/zc-toolkit",
519
+ }));
520
+ logSpy.mockRestore();
521
+ });
277
522
  it("prints update plan when status shows update-available", async () => {
278
523
  const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
279
524
  platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
@@ -291,7 +536,7 @@ describe("platform CLI", () => {
291
536
  },
292
537
  artifacts: [],
293
538
  });
294
- platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/tmp/install", [{ path: "/tmp/install/AGENTS.md", content: "# agents v2" }], "error"));
539
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/tmp/install", [{ path: "/tmp/install/AGENTS.md", content: "# agents v2" }], "dir", "error"));
295
540
  await runPlatformUpdate("codex", { dir: "/tmp/install", plan: true, json: true });
296
541
  expect(platformMocks.writeArtifacts).not.toHaveBeenCalled();
297
542
  const payload = JSON.parse(logSpy.mock.calls[0]?.[0] ?? "{}");
@@ -320,7 +565,7 @@ describe("platform CLI", () => {
320
565
  },
321
566
  artifacts: [],
322
567
  });
323
- platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/tmp/install", [{ path: "/tmp/install/AGENTS.md", content: "# agents v2" }], "error"));
568
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/tmp/install", [{ path: "/tmp/install/AGENTS.md", content: "# agents v2" }], "dir", "error"));
324
569
  platformMocks.writeArtifacts.mockResolvedValue({
325
570
  created: 0,
326
571
  overwritten: 1,
@@ -399,7 +644,7 @@ describe("platform CLI", () => {
399
644
  errorSpy.mockRestore();
400
645
  });
401
646
  it("passes global scope through install target resolution and exposes official path hints", async () => {
402
- platformMocks.createQoderInstallPlan.mockReturnValue(createInstallPlan("qoder", "/home/test/.qoder", [{ path: "/home/test/.qoder/AGENTS.md", content: "# agents" }]));
647
+ platformMocks.createClaudeInstallPlan.mockReturnValue(createInstallPlan("claude", "/home/test/.claude", [{ path: "/home/test/.claude/CLAUDE.md", content: "# claude" }]));
403
648
  platformMocks.writeArtifacts.mockResolvedValue({
404
649
  created: 1,
405
650
  overwritten: 0,
@@ -409,29 +654,59 @@ describe("platform CLI", () => {
409
654
  });
410
655
  const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
411
656
  platformMocks.resolveInstallTarget.mockResolvedValue({
412
- root: "/home/test/.qoder",
657
+ root: "/home/test/.claude",
413
658
  source: "official-global",
414
- hint: "Qoder 官方文档定义用户级 memory 文件位于 `~/.qoder/AGENTS.md`。",
659
+ hint: "Claude Code 官方文档定义用户级 memory 文件位于 `~/.claude/CLAUDE.md`。",
415
660
  });
416
- await runPlatformInstall("qoder", { global: true });
417
- expect(platformMocks.resolveInstallTarget).toHaveBeenCalledWith("qoder", {
661
+ await runPlatformInstall("claude", { global: true });
662
+ expect(platformMocks.resolveInstallTarget).toHaveBeenCalledWith("claude", {
418
663
  dir: undefined,
419
664
  cwd: process.cwd(),
420
665
  project: undefined,
421
666
  global: true,
422
667
  });
423
- expect(platformMocks.createQoderInstallPlan).toHaveBeenCalledWith(expect.anything(), expect.objectContaining({
424
- destinationRoot: "/home/test/.qoder",
668
+ expect(platformMocks.createClaudeInstallPlan).toHaveBeenCalledWith(expect.anything(), expect.objectContaining({
669
+ destinationRoot: "/home/test/.claude",
670
+ scope: "global",
425
671
  }));
426
- expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("提示:Qoder 官方文档定义用户级 memory 文件位于 `~/.qoder/AGENTS.md`。"));
672
+ expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("提示:Claude Code 官方文档定义用户级 memory 文件位于 `~/.claude/CLAUDE.md`。"));
427
673
  logSpy.mockRestore();
428
674
  });
675
+ it("prefers the official qwen extensions CLI for global installs", async () => {
676
+ platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan("/home/test/.qwen", [{ path: "/home/test/.qwen/extensions/zc-toolkit/QWEN.md", content: "# context" }], "global"));
677
+ platformMocks.resolveInstallTarget.mockResolvedValue({
678
+ root: "/home/test/.qwen",
679
+ source: "official-global",
680
+ hint: "Qwen 官方文档定义用户级配置目录为 `~/.qwen`。",
681
+ });
682
+ platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
683
+ kind: "not-installed",
684
+ platform: "qwen",
685
+ receiptPath: "/home/test/.qwen/.zc/platform-state/qwen.install-receipt.json",
686
+ receipt: null,
687
+ contentFingerprint: "current-fingerprint",
688
+ installedContentFingerprint: undefined,
689
+ summary: {
690
+ trackedArtifacts: 0,
691
+ driftedArtifacts: 0,
692
+ missingArtifacts: 0,
693
+ plannedChanges: 0,
694
+ },
695
+ artifacts: [],
696
+ });
697
+ await runPlatformInstall("qwen", { global: true });
698
+ expect(platformMocks.installQwenExtensionFromOfficialRepoWithCli).toHaveBeenCalledWith("https://github.com/zmice/zc-qwen-extension.git");
699
+ expect(platformMocks.syncQwenOfficialCliReleaseBundle).not.toHaveBeenCalled();
700
+ expect(platformMocks.installQwenExtensionWithOfficialCli).not.toHaveBeenCalled();
701
+ expect(platformMocks.relinkQwenExtensionWithOfficialCli).not.toHaveBeenCalled();
702
+ expect(platformMocks.writeArtifacts).not.toHaveBeenCalled();
703
+ });
429
704
  it("prints a JSON install plan with scope metadata", async () => {
430
- platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/home/test", [{ path: "/home/test/AGENTS.md", content: "# agents" }], "error"));
705
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/home/test/.codex", [{ path: "/home/test/.codex/AGENTS.md", content: "# agents" }], "global", "error"));
431
706
  platformMocks.resolveInstallTarget.mockResolvedValue({
432
- root: "/home/test",
707
+ root: "/home/test/.codex",
433
708
  source: "official-global",
434
- hint: "Codex 官方文档将 `~` 视为 AGENTS.md 的典型用户级位置。",
709
+ hint: "Codex 官方文档将 Codex home(默认 `~/.codex`)定义为全局级 `AGENTS.md` 的位置。",
435
710
  });
436
711
  const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
437
712
  await runPlatformInstall("codex", { global: true, plan: true, json: true });
@@ -441,17 +716,247 @@ describe("platform CLI", () => {
441
716
  action: "install",
442
717
  target: "codex",
443
718
  scope: "global",
444
- root: "/home/test",
719
+ root: "/home/test/.codex",
445
720
  rootSource: "official-global",
446
- hint: "Codex 官方文档将 `~` 视为 AGENTS.md 的典型用户级位置。",
721
+ hint: "Codex 官方文档将 Codex home(默认 `~/.codex`)定义为全局级 `AGENTS.md` 的位置。",
722
+ }));
723
+ logSpy.mockRestore();
724
+ });
725
+ it("prefers the official qwen extensions CLI for global updates", async () => {
726
+ platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan("/home/test/.qwen", [{ path: "/home/test/.qwen/extensions/zc-toolkit/QWEN.md", content: "# context v2" }], "global"));
727
+ platformMocks.resolveInstallTarget.mockResolvedValue({
728
+ root: "/home/test/.qwen",
729
+ source: "official-global",
730
+ hint: "Qwen 官方文档定义用户级配置目录为 `~/.qwen`。",
731
+ });
732
+ platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
733
+ kind: "update-available",
734
+ platform: "qwen",
735
+ receiptPath: "/home/test/.qwen/.zc/platform-state/qwen.install-receipt.json",
736
+ receipt: null,
737
+ contentFingerprint: "current-fingerprint",
738
+ installedContentFingerprint: "installed-fingerprint",
739
+ summary: {
740
+ trackedArtifacts: 1,
741
+ driftedArtifacts: 0,
742
+ missingArtifacts: 0,
743
+ plannedChanges: 1,
744
+ },
745
+ artifacts: [
746
+ {
747
+ path: "/home/test/.qwen/extensions/zc-toolkit/QWEN.md",
748
+ receiptSha256: "old",
749
+ actualSha256: "old",
750
+ plannedSha256: "new",
751
+ matchesReceiptOnDisk: true,
752
+ differsFromPlan: true,
753
+ },
754
+ ],
755
+ });
756
+ await runPlatformUpdate("qwen", { global: true });
757
+ expect(platformMocks.syncQwenOfficialCliReleaseBundle).not.toHaveBeenCalled();
758
+ expect(platformMocks.updateQwenExtensionWithOfficialCli).toHaveBeenCalledWith("zc-toolkit");
759
+ expect(platformMocks.uninstallQwenExtensionWithOfficialCli).not.toHaveBeenCalled();
760
+ expect(platformMocks.relinkQwenExtensionWithOfficialCli).not.toHaveBeenCalled();
761
+ expect(platformMocks.writeArtifacts).not.toHaveBeenCalled();
762
+ });
763
+ it("uninstalls managed filesystem artifacts from the receipt", async () => {
764
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/tmp/install", [{ path: "/tmp/install/AGENTS.md", content: "# agents" }]));
765
+ platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
766
+ kind: "up-to-date",
767
+ platform: "codex",
768
+ receiptPath: "/tmp/install/.zc/platform-state/codex.install-receipt.json",
769
+ receipt: {
770
+ schemaVersion: 1,
771
+ platform: "codex",
772
+ destinationRoot: "/tmp/install",
773
+ manifestSource: "/repo/packages/toolkit/src/content",
774
+ overwrite: "error",
775
+ installedAt: "2026-04-19T12:00:00.000Z",
776
+ installMethod: "filesystem",
777
+ artifacts: [
778
+ {
779
+ path: "/tmp/install/AGENTS.md",
780
+ sha256: "sha",
781
+ bytes: 8,
782
+ },
783
+ ],
784
+ },
785
+ contentFingerprint: "current-fingerprint",
786
+ installedContentFingerprint: "current-fingerprint",
787
+ summary: {
788
+ trackedArtifacts: 1,
789
+ driftedArtifacts: 0,
790
+ missingArtifacts: 0,
791
+ plannedChanges: 0,
792
+ },
793
+ artifacts: [],
794
+ });
795
+ await runPlatformUninstall("codex", { dir: "/tmp/install" });
796
+ expect(platformMocks.removeManagedPaths).toHaveBeenCalledWith(["/tmp/install/AGENTS.md"]);
797
+ expect(platformMocks.deletePlatformInstallReceipt).toHaveBeenCalledWith("/tmp/install/.zc/platform-state/codex.install-receipt.json");
798
+ });
799
+ it("prefers official qwen uninstall for qwen-cli managed installs", async () => {
800
+ platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan("/home/test/.qwen", [{ path: "/home/test/.qwen/extensions/zc-toolkit/QWEN.md", content: "# context" }], "global"));
801
+ platformMocks.resolveInstallTarget.mockResolvedValue({
802
+ root: "/home/test/.qwen",
803
+ source: "official-global",
804
+ hint: "Qwen 官方文档定义用户级配置目录为 `~/.qwen`。",
805
+ });
806
+ platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
807
+ kind: "up-to-date",
808
+ platform: "qwen",
809
+ receiptPath: "/home/test/.qwen/.zc/platform-state/qwen.install-receipt.json",
810
+ receipt: {
811
+ schemaVersion: 1,
812
+ platform: "qwen",
813
+ destinationRoot: "/home/test/.qwen",
814
+ manifestSource: "/repo/packages/toolkit/src/content",
815
+ overwrite: "error",
816
+ installedAt: "2026-04-19T12:00:00.000Z",
817
+ installMethod: "qwen-cli",
818
+ installSource: "github-repo",
819
+ sourceRef: "https://github.com/zmice/zc-qwen-extension.git",
820
+ artifacts: [
821
+ {
822
+ path: "/home/test/.qwen/extensions/zc-toolkit/QWEN.md",
823
+ sha256: "sha",
824
+ bytes: 9,
825
+ },
826
+ ],
827
+ },
828
+ contentFingerprint: "current-fingerprint",
829
+ installedContentFingerprint: "current-fingerprint",
830
+ summary: {
831
+ trackedArtifacts: 1,
832
+ driftedArtifacts: 0,
833
+ missingArtifacts: 0,
834
+ plannedChanges: 0,
835
+ },
836
+ artifacts: [],
837
+ });
838
+ await runPlatformUninstall("qwen", { global: true });
839
+ expect(platformMocks.uninstallQwenExtensionWithOfficialCli).toHaveBeenCalledWith("zc-toolkit");
840
+ expect(platformMocks.removeManagedPaths).not.toHaveBeenCalled();
841
+ expect(platformMocks.deletePlatformInstallReceipt).toHaveBeenCalledWith("/home/test/.qwen/.zc/platform-state/qwen.install-receipt.json");
842
+ });
843
+ it("repairs drifted filesystem installs by rewriting managed artifacts", async () => {
844
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/tmp/install", [{ path: "/tmp/install/AGENTS.md", content: "# agents repaired" }]));
845
+ platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
846
+ kind: "drifted",
847
+ platform: "codex",
848
+ receiptPath: "/tmp/install/.zc/platform-state/codex.install-receipt.json",
849
+ receipt: {
850
+ schemaVersion: 1,
851
+ platform: "codex",
852
+ destinationRoot: "/tmp/install",
853
+ manifestSource: "/repo/packages/toolkit/src/content",
854
+ overwrite: "error",
855
+ installedAt: "2026-04-19T12:00:00.000Z",
856
+ installMethod: "filesystem",
857
+ artifacts: [
858
+ {
859
+ path: "/tmp/install/AGENTS.md",
860
+ sha256: "old-sha",
861
+ bytes: 8,
862
+ },
863
+ ],
864
+ },
865
+ contentFingerprint: "current-fingerprint",
866
+ installedContentFingerprint: "old-fingerprint",
867
+ summary: {
868
+ trackedArtifacts: 1,
869
+ driftedArtifacts: 1,
870
+ missingArtifacts: 0,
871
+ plannedChanges: 0,
872
+ },
873
+ artifacts: [
874
+ {
875
+ path: "/tmp/install/AGENTS.md",
876
+ receiptSha256: "old-sha",
877
+ actualSha256: "drifted-sha",
878
+ plannedSha256: "new-sha",
879
+ matchesReceiptOnDisk: false,
880
+ differsFromPlan: true,
881
+ },
882
+ ],
883
+ });
884
+ platformMocks.writeArtifacts.mockResolvedValue({
885
+ created: 0,
886
+ overwritten: 1,
887
+ unchanged: 0,
888
+ skipped: 0,
889
+ dryRun: false,
890
+ });
891
+ await runPlatformRepair("codex", { dir: "/tmp/install" });
892
+ expect(platformMocks.createCodexInstallPlan).toHaveBeenLastCalledWith(expect.anything(), expect.objectContaining({
893
+ destinationRoot: "/tmp/install",
894
+ overwrite: "force",
895
+ }));
896
+ expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: "/tmp/install/AGENTS.md", content: "# agents repaired" }], { dryRun: false, overwrite: "force" });
897
+ expect(platformMocks.writePlatformInstallReceiptForPlan).toHaveBeenCalled();
898
+ });
899
+ it("prints platform doctor health and issues", async () => {
900
+ const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
901
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/tmp/install", [{ path: "/tmp/install/AGENTS.md", content: "# agents" }]));
902
+ platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
903
+ kind: "drifted",
904
+ platform: "codex",
905
+ receiptPath: "/tmp/install/.zc/platform-state/codex.install-receipt.json",
906
+ receipt: {
907
+ schemaVersion: 1,
908
+ platform: "codex",
909
+ destinationRoot: "/tmp/install",
910
+ manifestSource: "/repo/packages/toolkit/src/content",
911
+ overwrite: "error",
912
+ installedAt: "2026-04-19T12:00:00.000Z",
913
+ installMethod: "filesystem",
914
+ artifacts: [],
915
+ },
916
+ contentFingerprint: "current-fingerprint",
917
+ installedContentFingerprint: "old-fingerprint",
918
+ summary: {
919
+ trackedArtifacts: 1,
920
+ driftedArtifacts: 1,
921
+ missingArtifacts: 1,
922
+ plannedChanges: 0,
923
+ },
924
+ artifacts: [],
925
+ });
926
+ platformMocks.resolvePlatformInstallDoctor.mockResolvedValue({
927
+ platform: "codex",
928
+ health: "broken",
929
+ issues: [
930
+ {
931
+ code: "drifted-artifacts",
932
+ severity: "broken",
933
+ message: "受管产物和回执记录不一致,安装目录已漂移。",
934
+ paths: ["/tmp/install/AGENTS.md"],
935
+ },
936
+ ],
937
+ });
938
+ await runPlatformDoctor("codex", { dir: "/tmp/install", json: true });
939
+ const payload = JSON.parse(logSpy.mock.calls[0]?.[0] ?? "{}");
940
+ expect(payload).toEqual(expect.objectContaining({
941
+ mode: "doctor",
942
+ target: "codex",
943
+ health: "broken",
944
+ status: "drifted",
945
+ issues: [
946
+ expect.objectContaining({
947
+ code: "drifted-artifacts",
948
+ severity: "broken",
949
+ }),
950
+ ],
447
951
  }));
448
952
  logSpy.mockRestore();
449
953
  });
450
954
  it("prints resolved install targets via platform where", async () => {
955
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/home/test/.codex", [{ path: "/home/test/.codex/AGENTS.md", content: "# agents" }], "global"));
451
956
  platformMocks.resolveInstallTarget.mockResolvedValue({
452
- root: "/home/test",
957
+ root: "/home/test/.codex",
453
958
  source: "official-global",
454
- hint: "Codex 官方文档将 `~` 视为 AGENTS.md 的典型用户级位置。",
959
+ hint: "Codex 官方文档将 Codex home(默认 `~/.codex`)定义为全局级 `AGENTS.md` 的位置。",
455
960
  });
456
961
  const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
457
962
  await runPlatformWhere("codex", { global: true, json: true });
@@ -466,18 +971,52 @@ describe("platform CLI", () => {
466
971
  mode: "where",
467
972
  target: "codex",
468
973
  scope: "global",
469
- root: "/home/test",
974
+ root: "/home/test/.codex",
470
975
  rootSource: "official-global",
976
+ capability: expect.objectContaining({
977
+ namespace: "zc",
978
+ surfaces: ["entry-file", "skills-dir"],
979
+ }),
471
980
  }));
472
981
  logSpy.mockRestore();
473
982
  });
474
- it("prints a friendly qwen global resolution error instead of throwing", async () => {
475
- platformMocks.resolveInstallTarget.mockRejectedValue(new Error("Qwen 官方文档未给出全局 `QWEN.md` 默认位置。请显式传入 `--dir <path>`。"));
476
- const errorSpy = vi.spyOn(console, "error").mockImplementation(() => { });
477
- await runPlatformWhere("qwen", { global: true });
478
- expect(errorSpy).toHaveBeenCalledWith("qwen 目录解析失败:Qwen 官方文档未给出全局 `QWEN.md` 默认位置。请显式传入 `--dir <path>`。");
479
- expect(process.exitCode).toBe(1);
480
- errorSpy.mockRestore();
983
+ it("resolves qwen global scope to the user-level ~/.qwen directory", async () => {
984
+ platformMocks.createQwenInstallPlan.mockReturnValue({
985
+ platform: "qwen",
986
+ packageName: "@zmice/platform-qwen",
987
+ manifestSource: "/repo/packages/toolkit/src/content#generatedAt=2026-04-19T12:00:00.000Z",
988
+ matchedAssets: [],
989
+ destinationRoot: "/home/test/.qwen",
990
+ scope: "global",
991
+ overwrite: "error",
992
+ capability: {
993
+ namespace: "zc",
994
+ surfaces: ["entry-file", "commands-dir", "skills-dir", "agents-dir", "extension-dir"],
995
+ entryFile: "QWEN.md",
996
+ commandsDir: "commands/zc",
997
+ skillsDir: "skills",
998
+ agentsDir: "agents",
999
+ extensionDir: "extensions/zc-toolkit",
1000
+ },
1001
+ artifacts: [{ path: "/home/test/.qwen/extensions/zc-toolkit/QWEN.md", content: "# context" }],
1002
+ });
1003
+ platformMocks.resolveInstallTarget.mockResolvedValue({
1004
+ root: "/home/test/.qwen",
1005
+ source: "official-global",
1006
+ hint: "Qwen 官方文档定义用户级配置目录为 `~/.qwen`,并在官方帮助文档中给出 Qwen CLI 的用户级 `QWEN.md` 位置为 `~/.qwen/QWEN.md`。",
1007
+ });
1008
+ const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1009
+ await runPlatformWhere("qwen", { global: true, json: true });
1010
+ const payload = JSON.parse(logSpy.mock.calls[0]?.[0] ?? "{}");
1011
+ expect(payload).toEqual(expect.objectContaining({
1012
+ mode: "where",
1013
+ target: "qwen",
1014
+ scope: "global",
1015
+ root: "/home/test/.qwen",
1016
+ rootSource: "official-global",
1017
+ hint: "Qwen 官方文档定义用户级配置目录为 `~/.qwen`,并在官方帮助文档中给出 Qwen CLI 的用户级 `QWEN.md` 位置为 `~/.qwen/QWEN.md`。",
1018
+ }));
1019
+ logSpy.mockRestore();
481
1020
  });
482
1021
  });
483
1022
  //# sourceMappingURL=platform.test.js.map