@zmice/zc 0.2.8 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +430 -430
  2. package/dist/cli/__tests__/platform.test.js +89 -112
  3. package/dist/cli/__tests__/platform.test.js.map +1 -1
  4. package/dist/cli/__tests__/surface.test.js +1 -1
  5. package/dist/cli/__tests__/surface.test.js.map +1 -1
  6. package/dist/cli/platform.d.ts.map +1 -1
  7. package/dist/cli/platform.js +5 -62
  8. package/dist/cli/platform.js.map +1 -1
  9. package/dist/node_modules/@zmice/platform-core/dist/index.test.js +3 -5
  10. package/dist/node_modules/@zmice/platform-core/dist/index.test.js.map +1 -1
  11. package/dist/runtime/worktree-manager.js +2 -2
  12. package/dist/runtime/worktree-manager.js.map +1 -1
  13. package/dist/utils/install-target.test.js +2 -3
  14. package/dist/utils/install-target.test.js.map +1 -1
  15. package/dist/utils/qwen-extension-cli.d.ts.map +1 -1
  16. package/dist/utils/qwen-extension-cli.js +4 -4
  17. package/dist/utils/qwen-extension-cli.js.map +1 -1
  18. package/dist/utils/qwen-extension-cli.test.js +6 -9
  19. package/dist/utils/qwen-extension-cli.test.js.map +1 -1
  20. package/dist/utils/workspace.js +1 -1
  21. package/dist/utils/workspace.js.map +1 -1
  22. package/dist/utils/workspace.test.js +0 -14
  23. package/dist/utils/workspace.test.js.map +1 -1
  24. package/package.json +5 -5
  25. package/vendor/node_modules/@zmice/platform-core/dist/index.test.js +3 -5
  26. package/vendor/node_modules/@zmice/platform-core/dist/index.test.js.map +1 -1
  27. package/vendor/packages/platform-claude/dist/index.js +75 -75
  28. package/vendor/packages/platform-claude/dist/index.test.js +8 -11
  29. package/vendor/packages/platform-claude/dist/index.test.js.map +1 -1
  30. package/vendor/packages/platform-codex/dist/index.js +194 -194
  31. package/vendor/packages/platform-codex/dist/index.test.js +13 -16
  32. package/vendor/packages/platform-codex/dist/index.test.js.map +1 -1
  33. package/vendor/packages/platform-opencode/dist/index.js +75 -75
  34. package/vendor/packages/platform-opencode/dist/index.test.js +15 -19
  35. package/vendor/packages/platform-opencode/dist/index.test.js.map +1 -1
  36. package/vendor/packages/platform-qwen/dist/index.js +75 -75
  37. package/vendor/packages/platform-qwen/dist/index.test.js +7 -9
  38. package/vendor/packages/platform-qwen/dist/index.test.js.map +1 -1
  39. package/vendor/packages/toolkit/dist/content-lint.test.js +161 -1
  40. package/vendor/packages/toolkit/dist/content-lint.test.js.map +1 -1
  41. package/vendor/packages/toolkit/dist/lint/content-lint.d.ts.map +1 -1
  42. package/vendor/packages/toolkit/dist/lint/content-lint.js +183 -2
  43. package/vendor/packages/toolkit/dist/lint/content-lint.js.map +1 -1
  44. package/vendor/packages/toolkit/dist/manifests.test.js +9 -0
  45. package/vendor/packages/toolkit/dist/manifests.test.js.map +1 -1
  46. package/vendor/packages/toolkit/src/content/agents/architect/body.md +42 -42
  47. package/vendor/packages/toolkit/src/content/agents/code-reviewer/body.md +41 -41
  48. package/vendor/packages/toolkit/src/content/agents/product-owner/body.md +40 -40
  49. package/vendor/packages/toolkit/src/content/commands/plan-review/body.md +42 -31
  50. package/vendor/packages/toolkit/src/content/commands/start/body.md +236 -197
  51. package/vendor/packages/toolkit/src/content/commands/start/meta.yaml +55 -55
  52. package/vendor/packages/toolkit/src/content/skills/branch-finish-and-cleanup/body.md +172 -172
  53. package/vendor/packages/toolkit/src/content/skills/browser-qa-testing/body.md +111 -111
  54. package/vendor/packages/toolkit/src/content/skills/ci-cd-and-automation/body.md +86 -86
  55. package/vendor/packages/toolkit/src/content/skills/code-review-and-quality/body.md +140 -140
  56. package/vendor/packages/toolkit/src/content/skills/code-simplification/body.md +80 -80
  57. package/vendor/packages/toolkit/src/content/skills/context-engineering/body.md +67 -67
  58. package/vendor/packages/toolkit/src/content/skills/continuous-learning/body.md +102 -102
  59. package/vendor/packages/toolkit/src/content/skills/documentation-and-adrs/body.md +8 -6
  60. package/vendor/packages/toolkit/src/content/skills/engineering-principles/body.md +10 -5
  61. package/vendor/packages/toolkit/src/content/skills/git-workflow-and-versioning/body.md +9 -9
  62. package/vendor/packages/toolkit/src/content/skills/multi-perspective-review/body.md +129 -81
  63. package/vendor/packages/toolkit/src/content/skills/parallel-agent-dispatch/body.md +143 -113
  64. package/vendor/packages/toolkit/src/content/skills/performance-optimization/body.md +75 -75
  65. package/vendor/packages/toolkit/src/content/skills/planning-and-task-breakdown/body.md +162 -83
  66. package/vendor/packages/toolkit/src/content/skills/sdd-tdd-workflow/body.md +130 -95
  67. package/vendor/packages/toolkit/src/content/skills/sprint-retrospective/body.md +99 -99
  68. package/vendor/packages/toolkit/src/content/skills/subagent-driven-development/body.md +49 -7
  69. package/vendor/packages/toolkit/src/content/skills/team-orchestration/body.md +133 -126
  70. package/vendor/packages/toolkit/src/content/skills/test-driven-development/body.md +78 -78
  71. package/vendor/packages/toolkit/src/content/skills/using-agent-skills/body.md +193 -193
  72. package/vendor/references/upstreams.yaml +94 -94
  73. package/dist/cli/setup.d.ts +0 -3
  74. package/dist/cli/setup.d.ts.map +0 -1
  75. package/dist/cli/setup.js +0 -41
  76. package/dist/cli/setup.js.map +0 -1
  77. package/dist/utils/codex-config-merge.d.ts +0 -3
  78. package/dist/utils/codex-config-merge.d.ts.map +0 -1
  79. package/dist/utils/codex-config-merge.js +0 -43
  80. package/dist/utils/codex-config-merge.js.map +0 -1
  81. package/dist/utils/codex-config-merge.test.d.ts +0 -2
  82. package/dist/utils/codex-config-merge.test.d.ts.map +0 -1
  83. package/dist/utils/codex-config-merge.test.js +0 -64
  84. package/dist/utils/codex-config-merge.test.js.map +0 -1
@@ -1,7 +1,5 @@
1
1
  import { beforeEach, describe, expect, it, vi } from "vitest";
2
2
  import { homedir } from "node:os";
3
- import { join, resolve } from "node:path";
4
- const abs = (path) => resolve(path);
5
3
  const platformMocks = vi.hoisted(() => ({
6
4
  ArtifactConflictError: class ArtifactConflictError extends Error {
7
5
  conflicts;
@@ -226,15 +224,15 @@ describe("platform CLI", () => {
226
224
  root: options.dir ?? options.cwd ?? process.cwd(),
227
225
  source: options.dir ? "explicit" : "cwd",
228
226
  }));
229
- platformMocks.resolvePlatformInstallReceiptPath.mockImplementation((plan) => (join(plan.destinationRoot, ".zc", "platform-state", `${plan.platform}.install-receipt.json`)));
227
+ platformMocks.resolvePlatformInstallReceiptPath.mockImplementation((plan) => (`${plan.destinationRoot}/.zc/platform-state/${plan.platform}.install-receipt.json`));
230
228
  platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
231
229
  kind: "up-to-date",
232
230
  platform: "codex",
233
- receiptPath: join(abs("/tmp/install"), ".zc", "platform-state", "codex.install-receipt.json"),
231
+ receiptPath: "/tmp/install/.zc/platform-state/codex.install-receipt.json",
234
232
  receipt: {
235
233
  schemaVersion: 1,
236
234
  platform: "codex",
237
- destinationRoot: abs("/tmp/install"),
235
+ destinationRoot: "/tmp/install",
238
236
  manifestSource: "/repo/packages/toolkit/src/content",
239
237
  overwrite: "error",
240
238
  installedAt: "2026-04-19T12:00:00.000Z",
@@ -266,18 +264,18 @@ describe("platform CLI", () => {
266
264
  platformMocks.deletePlatformInstallReceipt.mockResolvedValue(undefined);
267
265
  platformMocks.writePlatformInstallReceiptForPlan.mockResolvedValue({});
268
266
  platformMocks.syncQwenOfficialCliSourceBundle.mockResolvedValue({
269
- sourceDir: abs("/tmp/qwen-source"),
267
+ sourceDir: "/tmp/qwen-source",
270
268
  extensionName: "zc-toolkit",
271
269
  artifactCount: 1,
272
270
  });
273
271
  platformMocks.syncQwenOfficialCliReleaseBundle.mockResolvedValue({
274
- bundleDir: abs("/tmp/qwen-release"),
272
+ bundleDir: "/tmp/qwen-release",
275
273
  extensionName: "zc-toolkit",
276
274
  artifactCount: 1,
277
275
  });
278
276
  platformMocks.toQwenOfficialCliReleaseArtifacts.mockImplementation((_plan, bundleDir) => [
279
- { path: join(bundleDir, "QWEN.md"), content: "# context" },
280
- { path: join(bundleDir, "commands/zc/start.md"), content: "# start" },
277
+ { path: `${bundleDir}/QWEN.md`, content: "# context" },
278
+ { path: `${bundleDir}/commands/zc/start.md`, content: "# start" },
281
279
  ]);
282
280
  platformMocks.installQwenExtensionFromOfficialRepoWithCli.mockResolvedValue(undefined);
283
281
  platformMocks.installQwenExtensionWithOfficialCli.mockResolvedValue(undefined);
@@ -286,7 +284,6 @@ describe("platform CLI", () => {
286
284
  platformMocks.relinkQwenExtensionWithOfficialCli.mockResolvedValue(undefined);
287
285
  });
288
286
  it("uses safe overwrite defaults for platform generate writes", async () => {
289
- const outputRoot = abs("/tmp/out");
290
287
  platformMocks.createQwenGenerationPlan.mockReturnValue(createGenerationPlan([{ path: "QWEN.md", content: "# context" }]));
291
288
  platformMocks.writeArtifacts.mockResolvedValue({
292
289
  created: 1,
@@ -296,10 +293,9 @@ describe("platform CLI", () => {
296
293
  dryRun: false,
297
294
  });
298
295
  await runPlatformGenerate("qwen", { dir: "/tmp/out" });
299
- expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: join(outputRoot, "QWEN.md"), content: "# context" }], { dryRun: false, overwrite: "error" });
296
+ expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: "/tmp/out/QWEN.md", content: "# context" }], { dryRun: false, overwrite: "error" });
300
297
  });
301
298
  it("prints a JSON plan without writing files when generate uses --plan", async () => {
302
- const outputRoot = abs("/tmp/out");
303
299
  platformMocks.createQwenGenerationPlan.mockReturnValue(createGenerationPlan([{ path: "QWEN.md", content: "# context" }]));
304
300
  const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
305
301
  await runPlatformGenerate("qwen", { dir: "/tmp/out", plan: true, json: true });
@@ -309,18 +305,17 @@ describe("platform CLI", () => {
309
305
  mode: "plan",
310
306
  action: "generate",
311
307
  target: "qwen",
312
- root: outputRoot,
308
+ root: "/tmp/out",
313
309
  artifactCount: 1,
314
- artifacts: [{ path: join(outputRoot, "QWEN.md"), content: "# context" }],
310
+ artifacts: [{ path: "/tmp/out/QWEN.md", content: "# context" }],
315
311
  }));
316
312
  logSpy.mockRestore();
317
313
  });
318
314
  it("exports a standalone qwen release bundle during generate", async () => {
319
- const bundleRoot = abs("/tmp/zc-toolkit");
320
315
  platformMocks.createQwenGenerationPlan.mockReturnValue(createGenerationPlan([{ path: "QWEN.md", content: "# context" }]));
321
- platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan(bundleRoot, [
322
- { path: join(bundleRoot, "extensions/zc-toolkit/QWEN.md"), content: "# context" },
323
- { path: join(bundleRoot, "extensions/zc-toolkit/commands/zc/start.md"), content: "# start" },
316
+ platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan("/tmp/zc-toolkit", [
317
+ { path: "/tmp/zc-toolkit/extensions/zc-toolkit/QWEN.md", content: "# context" },
318
+ { path: "/tmp/zc-toolkit/extensions/zc-toolkit/commands/zc/start.md", content: "# start" },
324
319
  ]));
325
320
  platformMocks.writeArtifacts.mockResolvedValue({
326
321
  created: 2,
@@ -331,16 +326,15 @@ describe("platform CLI", () => {
331
326
  });
332
327
  await runPlatformGenerate("qwen", { dir: "/tmp/zc-toolkit", bundle: "release-bundle" });
333
328
  expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([
334
- { path: join(bundleRoot, "QWEN.md"), content: "# context" },
335
- { path: join(bundleRoot, "commands/zc/start.md"), content: "# start" },
329
+ { path: "/tmp/zc-toolkit/QWEN.md", content: "# context" },
330
+ { path: "/tmp/zc-toolkit/commands/zc/start.md", content: "# start" },
336
331
  ], { dryRun: false, overwrite: "error" });
337
332
  });
338
333
  it("prints qwen release bundle plan paths without native extension nesting", async () => {
339
- const bundleRoot = abs("/tmp/zc-toolkit");
340
334
  platformMocks.createQwenGenerationPlan.mockReturnValue(createGenerationPlan([{ path: "QWEN.md", content: "# context" }]));
341
- platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan(bundleRoot, [
342
- { path: join(bundleRoot, "extensions/zc-toolkit/QWEN.md"), content: "# context" },
343
- { path: join(bundleRoot, "extensions/zc-toolkit/commands/zc/start.md"), content: "# start" },
335
+ platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan("/tmp/zc-toolkit", [
336
+ { path: "/tmp/zc-toolkit/extensions/zc-toolkit/QWEN.md", content: "# context" },
337
+ { path: "/tmp/zc-toolkit/extensions/zc-toolkit/commands/zc/start.md", content: "# start" },
344
338
  ]));
345
339
  const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
346
340
  await runPlatformGenerate("qwen", {
@@ -354,12 +348,12 @@ describe("platform CLI", () => {
354
348
  mode: "plan",
355
349
  action: "generate",
356
350
  target: "qwen",
357
- root: bundleRoot,
351
+ root: "/tmp/zc-toolkit",
358
352
  bundleType: "release-bundle",
359
- bundlePath: bundleRoot,
353
+ bundlePath: "/tmp/zc-toolkit",
360
354
  artifacts: [
361
- { path: join(bundleRoot, "QWEN.md"), content: "# context" },
362
- { path: join(bundleRoot, "commands/zc/start.md"), content: "# start" },
355
+ { path: "/tmp/zc-toolkit/QWEN.md", content: "# context" },
356
+ { path: "/tmp/zc-toolkit/commands/zc/start.md", content: "# start" },
363
357
  ],
364
358
  }));
365
359
  logSpy.mockRestore();
@@ -406,14 +400,13 @@ describe("platform CLI", () => {
406
400
  });
407
401
  expect(platformMocks.createCodexMarketplaceGenerationPlan).toHaveBeenCalledWith(expect.any(Object), expect.objectContaining({ scope: "global" }));
408
402
  expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([
409
- { path: join(homedir(), ".agents/plugins/marketplace.json"), content: "{}" },
410
- { path: join(homedir(), ".codex/AGENTS.md"), content: "# plugin entry" },
411
- { path: join(homedir(), ".codex/plugins/zc-toolkit/.codex-plugin/plugin.json"), content: "{}" },
412
- { path: join(homedir(), ".codex/agents/zc-code-reviewer.toml"), content: "name = \"zc_code_reviewer\"\n" },
403
+ { path: `${homedir()}/.agents/plugins/marketplace.json`, content: "{}" },
404
+ { path: `${homedir()}/.codex/AGENTS.md`, content: "# plugin entry" },
405
+ { path: `${homedir()}/.codex/plugins/zc-toolkit/.codex-plugin/plugin.json`, content: "{}" },
406
+ { path: `${homedir()}/.codex/agents/zc-code-reviewer.toml`, content: "name = \"zc_code_reviewer\"\n" },
413
407
  ], { dryRun: false, overwrite: "error" });
414
408
  });
415
409
  it("exports codex marketplace to the resolved project root with --project", async () => {
416
- const projectRoot = join("/repo", "project");
417
410
  platformMocks.resolveInstallTarget.mockResolvedValue({
418
411
  root: "/repo/project",
419
412
  source: "project-root",
@@ -451,13 +444,12 @@ describe("platform CLI", () => {
451
444
  expect(platformMocks.resolveInstallTarget).toHaveBeenCalledWith("codex", { project: true });
452
445
  expect(platformMocks.createCodexMarketplaceGenerationPlan).toHaveBeenCalledWith(expect.any(Object), expect.objectContaining({ scope: "project" }));
453
446
  expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([
454
- { path: join(projectRoot, ".agents/plugins/marketplace.json"), content: "{}" },
455
- { path: join(projectRoot, "AGENTS.md"), content: "# plugin entry" },
456
- { path: join(projectRoot, "plugins/zc-toolkit/.codex-plugin/plugin.json"), content: "{}" },
447
+ { path: "/repo/project/.agents/plugins/marketplace.json", content: "{}" },
448
+ { path: "/repo/project/AGENTS.md", content: "# plugin entry" },
449
+ { path: "/repo/project/plugins/zc-toolkit/.codex-plugin/plugin.json", content: "{}" },
457
450
  ], { dryRun: false, overwrite: "error" });
458
451
  });
459
452
  it("uses a short codex plugin command for the project marketplace by default", async () => {
460
- const projectRoot = join("/repo", "project");
461
453
  platformMocks.resolveInstallTarget.mockResolvedValue({
462
454
  root: "/repo/project",
463
455
  source: "project-root",
@@ -492,9 +484,9 @@ describe("platform CLI", () => {
492
484
  expect(platformMocks.resolveInstallTarget).toHaveBeenCalledWith("codex", { project: true });
493
485
  expect(platformMocks.createCodexMarketplaceGenerationPlan).toHaveBeenCalledWith(expect.any(Object), expect.objectContaining({ scope: "project" }));
494
486
  expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([
495
- { path: join(projectRoot, ".agents/plugins/marketplace.json"), content: "{}" },
496
- { path: join(projectRoot, "AGENTS.md"), content: "# plugin entry" },
497
- { path: join(projectRoot, "plugins/zc-toolkit/.codex-plugin/plugin.json"), content: "{}" },
487
+ { path: "/repo/project/.agents/plugins/marketplace.json", content: "{}" },
488
+ { path: "/repo/project/AGENTS.md", content: "# plugin entry" },
489
+ { path: "/repo/project/plugins/zc-toolkit/.codex-plugin/plugin.json", content: "{}" },
498
490
  ], { dryRun: false, overwrite: "error" });
499
491
  });
500
492
  it("uses the personal marketplace for codex plugin when --global is explicit", async () => {
@@ -527,9 +519,9 @@ describe("platform CLI", () => {
527
519
  expect(platformMocks.resolveInstallTarget).not.toHaveBeenCalled();
528
520
  expect(platformMocks.createCodexMarketplaceGenerationPlan).toHaveBeenCalledWith(expect.any(Object), expect.objectContaining({ scope: "global" }));
529
521
  expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([
530
- { path: join(homedir(), ".agents/plugins/marketplace.json"), content: "{}" },
531
- { path: join(homedir(), ".codex/AGENTS.md"), content: "# plugin entry" },
532
- { path: join(homedir(), ".codex/plugins/zc-toolkit/.codex-plugin/plugin.json"), content: "{}" },
522
+ { path: `${homedir()}/.agents/plugins/marketplace.json`, content: "{}" },
523
+ { path: `${homedir()}/.codex/AGENTS.md`, content: "# plugin entry" },
524
+ { path: `${homedir()}/.codex/plugins/zc-toolkit/.codex-plugin/plugin.json`, content: "{}" },
533
525
  ], { dryRun: false, overwrite: "error" });
534
526
  });
535
527
  it("cleans the generated Codex plugin skills directory on force writes", async () => {
@@ -561,18 +553,17 @@ describe("platform CLI", () => {
561
553
  });
562
554
  await runPlatformPlugin("codex", { global: true, force: true });
563
555
  expect(platformMocks.removeManagedPaths).toHaveBeenCalledWith([
564
- join(homedir(), ".codex/plugins/zc-toolkit/skills"),
556
+ `${homedir()}/.codex/plugins/zc-toolkit/skills`,
565
557
  ]);
566
558
  expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([
567
- { path: join(homedir(), ".agents/plugins/marketplace.json"), content: "{}" },
568
- { path: join(homedir(), ".codex/AGENTS.md"), content: "# plugin entry" },
569
- { path: join(homedir(), ".codex/plugins/zc-toolkit/.codex-plugin/plugin.json"), content: "{}" },
570
- { path: join(homedir(), ".codex/plugins/zc-toolkit/skills/start/SKILL.md"), content: "# start" },
559
+ { path: `${homedir()}/.agents/plugins/marketplace.json`, content: "{}" },
560
+ { path: `${homedir()}/.codex/AGENTS.md`, content: "# plugin entry" },
561
+ { path: `${homedir()}/.codex/plugins/zc-toolkit/.codex-plugin/plugin.json`, content: "{}" },
562
+ { path: `${homedir()}/.codex/plugins/zc-toolkit/skills/start/SKILL.md`, content: "# start" },
571
563
  ], { dryRun: false, overwrite: "force" });
572
564
  });
573
565
  it("uses safe overwrite defaults for platform install and writes a receipt", async () => {
574
- const installRoot = abs("/tmp/install");
575
- platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", installRoot, [{ path: join(installRoot, "AGENTS.md"), content: "# agents" }]));
566
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/tmp/install", [{ path: "/tmp/install/AGENTS.md", content: "# agents" }]));
576
567
  platformMocks.writeArtifacts.mockResolvedValue({
577
568
  created: 1,
578
569
  overwritten: 0,
@@ -582,20 +573,19 @@ describe("platform CLI", () => {
582
573
  });
583
574
  await runPlatformInstall("codex", { dir: "/tmp/install" });
584
575
  expect(platformMocks.createCodexInstallPlan).toHaveBeenCalledWith(expect.anything(), expect.objectContaining({
585
- destinationRoot: installRoot,
576
+ destinationRoot: "/tmp/install",
586
577
  scope: "dir",
587
578
  overwrite: "error",
588
579
  }));
589
- expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: join(installRoot, "AGENTS.md"), content: "# agents" }], { dryRun: false, overwrite: "error" });
580
+ expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: "/tmp/install/AGENTS.md", content: "# agents" }], { dryRun: false, overwrite: "error" });
590
581
  expect(platformMocks.writePlatformInstallReceiptForPlan).toHaveBeenCalledWith(expect.objectContaining({
591
- destinationRoot: installRoot,
582
+ destinationRoot: "/tmp/install",
592
583
  }), expect.objectContaining({
593
584
  zcVersion: expect.any(String),
594
585
  }));
595
586
  });
596
587
  it("forwards force installs to artifact writes", async () => {
597
- const installRoot = abs("/tmp/install");
598
- platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", installRoot, [{ path: join(installRoot, "AGENTS.md"), content: "# agents" }]));
588
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/tmp/install", [{ path: "/tmp/install/AGENTS.md", content: "# agents" }]));
599
589
  platformMocks.writeArtifacts.mockResolvedValue({
600
590
  created: 0,
601
591
  overwritten: 1,
@@ -604,11 +594,10 @@ describe("platform CLI", () => {
604
594
  dryRun: false,
605
595
  });
606
596
  await runPlatformInstall("codex", { dir: "/tmp/install", force: true });
607
- expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: join(installRoot, "AGENTS.md"), content: "# agents" }], { dryRun: false, overwrite: "force" });
597
+ expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: "/tmp/install/AGENTS.md", content: "# agents" }], { dryRun: false, overwrite: "force" });
608
598
  });
609
599
  it("uses the resolved project root when install target is omitted", async () => {
610
- const projectRoot = abs("/workspace/project");
611
- platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", projectRoot, [{ path: join(projectRoot, "AGENTS.md"), content: "# agents" }]));
600
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/workspace/project", [{ path: "/workspace/project/AGENTS.md", content: "# agents" }]));
612
601
  platformMocks.writeArtifacts.mockResolvedValue({
613
602
  created: 1,
614
603
  overwritten: 0,
@@ -630,15 +619,14 @@ describe("platform CLI", () => {
630
619
  global: undefined,
631
620
  });
632
621
  expect(platformMocks.createCodexInstallPlan).toHaveBeenCalledWith(expect.anything(), expect.objectContaining({
633
- destinationRoot: projectRoot,
622
+ destinationRoot: "/workspace/project",
634
623
  scope: "project",
635
624
  }));
636
625
  expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("安装目录自动解析(project-root)"));
637
626
  logSpy.mockRestore();
638
627
  });
639
628
  it("prints a JSON install plan without writing files when install uses --plan", async () => {
640
- const installRoot = abs("/tmp/install");
641
- platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", installRoot, [{ path: join(installRoot, "AGENTS.md"), content: "# agents" }], "dir", "error"));
629
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/tmp/install", [{ path: "/tmp/install/AGENTS.md", content: "# agents" }], "dir", "error"));
642
630
  const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
643
631
  await runPlatformInstall("codex", { dir: "/tmp/install", plan: true, json: true });
644
632
  expect(platformMocks.writeArtifacts).not.toHaveBeenCalled();
@@ -647,14 +635,14 @@ describe("platform CLI", () => {
647
635
  mode: "plan",
648
636
  action: "install",
649
637
  target: "codex",
650
- root: installRoot,
638
+ root: "/tmp/install",
651
639
  scope: "dir",
652
640
  rootSource: "explicit",
653
641
  artifactCount: 1,
654
642
  overwrite: "error",
655
643
  artifacts: expect.arrayContaining([
656
644
  expect.objectContaining({
657
- path: join(installRoot, "AGENTS.md"),
645
+ path: "/tmp/install/AGENTS.md",
658
646
  content: "# agents",
659
647
  }),
660
648
  ]),
@@ -662,22 +650,21 @@ describe("platform CLI", () => {
662
650
  logSpy.mockRestore();
663
651
  });
664
652
  it("prints platform status from receipt and current plan", async () => {
665
- const installRoot = abs("/tmp/install");
666
653
  const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
667
654
  platformMocks.resolveInstallTarget.mockResolvedValue({
668
655
  root: "/tmp/install",
669
656
  source: "explicit",
670
657
  });
671
- platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", installRoot, [{ path: join(installRoot, "AGENTS.md"), content: "# agents" }]));
658
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/tmp/install", [{ path: "/tmp/install/AGENTS.md", content: "# agents" }]));
672
659
  await runPlatformStatus("codex", { dir: "/tmp/install", json: true });
673
660
  expect(platformMocks.resolvePlatformInstallStatus).toHaveBeenCalledWith(expect.objectContaining({
674
- destinationRoot: installRoot,
661
+ destinationRoot: "/tmp/install",
675
662
  }));
676
663
  const payload = JSON.parse(logSpy.mock.calls[0]?.[0] ?? "{}");
677
664
  expect(payload).toEqual(expect.objectContaining({
678
665
  mode: "status",
679
666
  target: "codex",
680
- root: installRoot,
667
+ root: "/tmp/install",
681
668
  status: "up-to-date",
682
669
  installedContentFingerprint: "installed-fingerprint",
683
670
  contentFingerprint: "current-fingerprint",
@@ -685,34 +672,32 @@ describe("platform CLI", () => {
685
672
  logSpy.mockRestore();
686
673
  });
687
674
  it("prints qwen platform status json with installed metadata from receipt", async () => {
688
- const qwenRoot = abs("/home/test/.qwen");
689
- const qwenBundleRoot = abs("/tmp/qwen-release/zc-toolkit");
690
675
  const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
691
676
  platformMocks.resolveInstallTarget.mockResolvedValue({
692
677
  root: "/home/test/.qwen",
693
678
  source: "official-global",
694
679
  hint: "Qwen 官方文档定义用户级配置目录为 `~/.qwen`。",
695
680
  });
696
- platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan(qwenRoot, [{ path: join(qwenRoot, "extensions/zc-toolkit/QWEN.md"), content: "# context" }], "global"));
681
+ platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan("/home/test/.qwen", [{ path: "/home/test/.qwen/extensions/zc-toolkit/QWEN.md", content: "# context" }], "global"));
697
682
  platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
698
683
  kind: "up-to-date",
699
684
  platform: "qwen",
700
- receiptPath: join(qwenRoot, ".zc/platform-state/qwen.install-receipt.json"),
685
+ receiptPath: "/home/test/.qwen/.zc/platform-state/qwen.install-receipt.json",
701
686
  receipt: {
702
687
  schemaVersion: 1,
703
688
  platform: "qwen",
704
- destinationRoot: qwenRoot,
689
+ destinationRoot: "/home/test/.qwen",
705
690
  manifestSource: "/repo/packages/toolkit/src/content",
706
691
  overwrite: "error",
707
692
  installedAt: "2026-04-19T12:00:00.000Z",
708
693
  installMethod: "filesystem",
709
694
  installSource: "local-bundle",
710
- sourceRef: qwenBundleRoot,
695
+ sourceRef: "/tmp/qwen-release/zc-toolkit",
711
696
  bundleType: "release-bundle",
712
- bundlePath: qwenBundleRoot,
697
+ bundlePath: "/tmp/qwen-release/zc-toolkit",
713
698
  artifacts: [
714
699
  {
715
- path: join(qwenRoot, "extensions/zc-toolkit/QWEN.md"),
700
+ path: "/home/test/.qwen/extensions/zc-toolkit/QWEN.md",
716
701
  sha256: "sha",
717
702
  bytes: 9,
718
703
  },
@@ -733,27 +718,26 @@ describe("platform CLI", () => {
733
718
  expect(payload).toEqual(expect.objectContaining({
734
719
  mode: "status",
735
720
  target: "qwen",
736
- root: qwenRoot,
721
+ root: "/home/test/.qwen",
737
722
  installMethod: "filesystem",
738
723
  installSource: "local-bundle",
739
- sourceRef: qwenBundleRoot,
724
+ sourceRef: "/tmp/qwen-release/zc-toolkit",
740
725
  bundleType: "release-bundle",
741
- bundlePath: qwenBundleRoot,
726
+ bundlePath: "/tmp/qwen-release/zc-toolkit",
742
727
  recommendedInstallMethod: "qwen-cli",
743
728
  recommendedInstallSource: "github-repo",
744
729
  recommendedSourceRef: "https://github.com/zmice/zc-qwen-extension.git",
745
730
  recommendedBundleType: "release-bundle",
746
- recommendedBundlePath: expect.stringContaining("zc-toolkit"),
731
+ recommendedBundlePath: "/home/test/.qwen/.zc/platform-bundles/qwen/zc-toolkit",
747
732
  }));
748
733
  logSpy.mockRestore();
749
734
  });
750
735
  it("prints update plan when status shows update-available", async () => {
751
- const installRoot = abs("/tmp/install");
752
736
  const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
753
737
  platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
754
738
  kind: "update-available",
755
739
  platform: "codex",
756
- receiptPath: join(installRoot, ".zc/platform-state/codex.install-receipt.json"),
740
+ receiptPath: "/tmp/install/.zc/platform-state/codex.install-receipt.json",
757
741
  receipt: null,
758
742
  contentFingerprint: "current-fingerprint",
759
743
  installedContentFingerprint: "installed-fingerprint",
@@ -765,7 +749,7 @@ describe("platform CLI", () => {
765
749
  },
766
750
  artifacts: [],
767
751
  });
768
- platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", installRoot, [{ path: join(installRoot, "AGENTS.md"), content: "# agents v2" }], "dir", "error"));
752
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/tmp/install", [{ path: "/tmp/install/AGENTS.md", content: "# agents v2" }], "dir", "error"));
769
753
  await runPlatformUpdate("codex", { dir: "/tmp/install", plan: true, json: true });
770
754
  expect(platformMocks.writeArtifacts).not.toHaveBeenCalled();
771
755
  const payload = JSON.parse(logSpy.mock.calls[0]?.[0] ?? "{}");
@@ -774,16 +758,15 @@ describe("platform CLI", () => {
774
758
  action: "update",
775
759
  target: "codex",
776
760
  status: "update-available",
777
- root: installRoot,
761
+ root: "/tmp/install",
778
762
  }));
779
763
  logSpy.mockRestore();
780
764
  });
781
765
  it("treats update-available as managed overwrite and refreshes the receipt", async () => {
782
- const installRoot = abs("/tmp/install");
783
766
  platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
784
767
  kind: "update-available",
785
768
  platform: "codex",
786
- receiptPath: join(installRoot, ".zc/platform-state/codex.install-receipt.json"),
769
+ receiptPath: "/tmp/install/.zc/platform-state/codex.install-receipt.json",
787
770
  receipt: null,
788
771
  contentFingerprint: "current-fingerprint",
789
772
  installedContentFingerprint: "installed-fingerprint",
@@ -795,7 +778,7 @@ describe("platform CLI", () => {
795
778
  },
796
779
  artifacts: [],
797
780
  });
798
- platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", installRoot, [{ path: join(installRoot, "AGENTS.md"), content: "# agents v2" }], "dir", "error"));
781
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/tmp/install", [{ path: "/tmp/install/AGENTS.md", content: "# agents v2" }], "dir", "error"));
799
782
  platformMocks.writeArtifacts.mockResolvedValue({
800
783
  created: 0,
801
784
  overwritten: 1,
@@ -805,10 +788,10 @@ describe("platform CLI", () => {
805
788
  });
806
789
  await runPlatformUpdate("codex", { dir: "/tmp/install" });
807
790
  expect(platformMocks.createCodexInstallPlan).toHaveBeenLastCalledWith(expect.anything(), expect.objectContaining({
808
- destinationRoot: installRoot,
791
+ destinationRoot: "/tmp/install",
809
792
  overwrite: "force",
810
793
  }));
811
- expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: join(installRoot, "AGENTS.md"), content: "# agents v2" }], { dryRun: false, overwrite: "force" });
794
+ expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: "/tmp/install/AGENTS.md", content: "# agents v2" }], { dryRun: false, overwrite: "force" });
812
795
  expect(platformMocks.writePlatformInstallReceiptForPlan).toHaveBeenCalled();
813
796
  });
814
797
  it("reports a no-op update when the installation is already up-to-date", async () => {
@@ -874,8 +857,7 @@ describe("platform CLI", () => {
874
857
  errorSpy.mockRestore();
875
858
  });
876
859
  it("passes global scope through install target resolution and exposes official path hints", async () => {
877
- const claudeRoot = abs("/home/test/.claude");
878
- platformMocks.createClaudeInstallPlan.mockReturnValue(createInstallPlan("claude", claudeRoot, [{ path: join(claudeRoot, "CLAUDE.md"), content: "# claude" }]));
860
+ platformMocks.createClaudeInstallPlan.mockReturnValue(createInstallPlan("claude", "/home/test/.claude", [{ path: "/home/test/.claude/CLAUDE.md", content: "# claude" }]));
879
861
  platformMocks.writeArtifacts.mockResolvedValue({
880
862
  created: 1,
881
863
  overwritten: 0,
@@ -897,15 +879,14 @@ describe("platform CLI", () => {
897
879
  global: true,
898
880
  });
899
881
  expect(platformMocks.createClaudeInstallPlan).toHaveBeenCalledWith(expect.anything(), expect.objectContaining({
900
- destinationRoot: claudeRoot,
882
+ destinationRoot: "/home/test/.claude",
901
883
  scope: "global",
902
884
  }));
903
885
  expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("提示:Claude Code 官方文档定义用户级 memory 文件位于 `~/.claude/CLAUDE.md`。"));
904
886
  logSpy.mockRestore();
905
887
  });
906
888
  it("prefers the official qwen extensions CLI for global installs", async () => {
907
- const qwenRoot = abs("/home/test/.qwen");
908
- platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan(qwenRoot, [{ path: join(qwenRoot, "extensions/zc-toolkit/QWEN.md"), content: "# context" }], "global"));
889
+ platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan("/home/test/.qwen", [{ path: "/home/test/.qwen/extensions/zc-toolkit/QWEN.md", content: "# context" }], "global"));
909
890
  platformMocks.resolveInstallTarget.mockResolvedValue({
910
891
  root: "/home/test/.qwen",
911
892
  source: "official-global",
@@ -914,7 +895,7 @@ describe("platform CLI", () => {
914
895
  platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
915
896
  kind: "not-installed",
916
897
  platform: "qwen",
917
- receiptPath: join(qwenRoot, ".zc/platform-state/qwen.install-receipt.json"),
898
+ receiptPath: "/home/test/.qwen/.zc/platform-state/qwen.install-receipt.json",
918
899
  receipt: null,
919
900
  contentFingerprint: "current-fingerprint",
920
901
  installedContentFingerprint: undefined,
@@ -934,8 +915,7 @@ describe("platform CLI", () => {
934
915
  expect(platformMocks.writeArtifacts).not.toHaveBeenCalled();
935
916
  });
936
917
  it("prints a JSON install plan with scope metadata", async () => {
937
- const codexRoot = abs("/home/test/.codex");
938
- platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", codexRoot, [{ path: join(codexRoot, "AGENTS.md"), content: "# agents" }], "global", "error"));
918
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/home/test/.codex", [{ path: "/home/test/.codex/AGENTS.md", content: "# agents" }], "global", "error"));
939
919
  platformMocks.resolveInstallTarget.mockResolvedValue({
940
920
  root: "/home/test/.codex",
941
921
  source: "official-global",
@@ -949,7 +929,7 @@ describe("platform CLI", () => {
949
929
  action: "install",
950
930
  target: "codex",
951
931
  scope: "global",
952
- root: codexRoot,
932
+ root: "/home/test/.codex",
953
933
  rootSource: "official-global",
954
934
  hint: "Codex 官方文档将 Codex home(默认 `~/.codex`)定义为全局级 `AGENTS.md` 的位置。",
955
935
  }));
@@ -1074,23 +1054,22 @@ describe("platform CLI", () => {
1074
1054
  expect(platformMocks.deletePlatformInstallReceipt).toHaveBeenCalledWith("/home/test/.qwen/.zc/platform-state/qwen.install-receipt.json");
1075
1055
  });
1076
1056
  it("repairs drifted filesystem installs by rewriting managed artifacts", async () => {
1077
- const installRoot = abs("/tmp/install");
1078
- platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", installRoot, [{ path: join(installRoot, "AGENTS.md"), content: "# agents repaired" }]));
1057
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/tmp/install", [{ path: "/tmp/install/AGENTS.md", content: "# agents repaired" }]));
1079
1058
  platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
1080
1059
  kind: "drifted",
1081
1060
  platform: "codex",
1082
- receiptPath: join(installRoot, ".zc/platform-state/codex.install-receipt.json"),
1061
+ receiptPath: "/tmp/install/.zc/platform-state/codex.install-receipt.json",
1083
1062
  receipt: {
1084
1063
  schemaVersion: 1,
1085
1064
  platform: "codex",
1086
- destinationRoot: installRoot,
1065
+ destinationRoot: "/tmp/install",
1087
1066
  manifestSource: "/repo/packages/toolkit/src/content",
1088
1067
  overwrite: "error",
1089
1068
  installedAt: "2026-04-19T12:00:00.000Z",
1090
1069
  installMethod: "filesystem",
1091
1070
  artifacts: [
1092
1071
  {
1093
- path: join(installRoot, "AGENTS.md"),
1072
+ path: "/tmp/install/AGENTS.md",
1094
1073
  sha256: "old-sha",
1095
1074
  bytes: 8,
1096
1075
  },
@@ -1106,7 +1085,7 @@ describe("platform CLI", () => {
1106
1085
  },
1107
1086
  artifacts: [
1108
1087
  {
1109
- path: join(installRoot, "AGENTS.md"),
1088
+ path: "/tmp/install/AGENTS.md",
1110
1089
  receiptSha256: "old-sha",
1111
1090
  actualSha256: "drifted-sha",
1112
1091
  plannedSha256: "new-sha",
@@ -1124,10 +1103,10 @@ describe("platform CLI", () => {
1124
1103
  });
1125
1104
  await runPlatformRepair("codex", { dir: "/tmp/install" });
1126
1105
  expect(platformMocks.createCodexInstallPlan).toHaveBeenLastCalledWith(expect.anything(), expect.objectContaining({
1127
- destinationRoot: installRoot,
1106
+ destinationRoot: "/tmp/install",
1128
1107
  overwrite: "force",
1129
1108
  }));
1130
- expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: join(installRoot, "AGENTS.md"), content: "# agents repaired" }], { dryRun: false, overwrite: "force" });
1109
+ expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: "/tmp/install/AGENTS.md", content: "# agents repaired" }], { dryRun: false, overwrite: "force" });
1131
1110
  expect(platformMocks.writePlatformInstallReceiptForPlan).toHaveBeenCalled();
1132
1111
  });
1133
1112
  it("prints platform doctor health and issues", async () => {
@@ -1186,8 +1165,7 @@ describe("platform CLI", () => {
1186
1165
  logSpy.mockRestore();
1187
1166
  });
1188
1167
  it("prints resolved install targets via platform where", async () => {
1189
- const codexRoot = abs("/home/test/.codex");
1190
- platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", codexRoot, [{ path: join(codexRoot, "AGENTS.md"), content: "# agents" }], "global"));
1168
+ platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", "/home/test/.codex", [{ path: "/home/test/.codex/AGENTS.md", content: "# agents" }], "global"));
1191
1169
  platformMocks.resolveInstallTarget.mockResolvedValue({
1192
1170
  root: "/home/test/.codex",
1193
1171
  source: "official-global",
@@ -1206,7 +1184,7 @@ describe("platform CLI", () => {
1206
1184
  mode: "where",
1207
1185
  target: "codex",
1208
1186
  scope: "global",
1209
- root: codexRoot,
1187
+ root: "/home/test/.codex",
1210
1188
  rootSource: "official-global",
1211
1189
  capability: expect.objectContaining({
1212
1190
  namespace: "zc",
@@ -1216,13 +1194,12 @@ describe("platform CLI", () => {
1216
1194
  logSpy.mockRestore();
1217
1195
  });
1218
1196
  it("resolves qwen global scope to the user-level ~/.qwen directory", async () => {
1219
- const qwenRoot = abs("/home/test/.qwen");
1220
1197
  platformMocks.createQwenInstallPlan.mockReturnValue({
1221
1198
  platform: "qwen",
1222
1199
  packageName: "@zmice/platform-qwen",
1223
1200
  manifestSource: "/repo/packages/toolkit/src/content#generatedAt=2026-04-19T12:00:00.000Z",
1224
1201
  matchedAssets: [],
1225
- destinationRoot: qwenRoot,
1202
+ destinationRoot: "/home/test/.qwen",
1226
1203
  scope: "global",
1227
1204
  overwrite: "error",
1228
1205
  capability: {
@@ -1234,7 +1211,7 @@ describe("platform CLI", () => {
1234
1211
  agentsDir: "agents",
1235
1212
  extensionDir: "extensions/zc-toolkit",
1236
1213
  },
1237
- artifacts: [{ path: join(qwenRoot, "extensions/zc-toolkit/QWEN.md"), content: "# context" }],
1214
+ artifacts: [{ path: "/home/test/.qwen/extensions/zc-toolkit/QWEN.md", content: "# context" }],
1238
1215
  });
1239
1216
  platformMocks.resolveInstallTarget.mockResolvedValue({
1240
1217
  root: "/home/test/.qwen",
@@ -1248,7 +1225,7 @@ describe("platform CLI", () => {
1248
1225
  mode: "where",
1249
1226
  target: "qwen",
1250
1227
  scope: "global",
1251
- root: qwenRoot,
1228
+ root: "/home/test/.qwen",
1252
1229
  rootSource: "official-global",
1253
1230
  hint: "Qwen 官方文档定义用户级配置目录为 `~/.qwen`,并在官方帮助文档中给出 Qwen CLI 的用户级 `QWEN.md` 位置为 `~/.qwen/QWEN.md`。",
1254
1231
  }));