@zmice/zc 0.2.6 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +430 -420
- package/dist/cli/__tests__/platform.test.js +158 -89
- package/dist/cli/__tests__/platform.test.js.map +1 -1
- package/dist/cli/__tests__/surface.test.js +1 -1
- package/dist/cli/__tests__/surface.test.js.map +1 -1
- package/dist/cli/platform.d.ts.map +1 -1
- package/dist/cli/platform.js +92 -10
- package/dist/cli/platform.js.map +1 -1
- package/dist/cli/setup.d.ts +3 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +41 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/node_modules/@zmice/platform-core/dist/index.test.js +5 -3
- package/dist/node_modules/@zmice/platform-core/dist/index.test.js.map +1 -1
- package/dist/runtime/worktree-manager.js +2 -2
- package/dist/runtime/worktree-manager.js.map +1 -1
- package/dist/utils/codex-config-merge.d.ts +3 -0
- package/dist/utils/codex-config-merge.d.ts.map +1 -0
- package/dist/utils/codex-config-merge.js +43 -0
- package/dist/utils/codex-config-merge.js.map +1 -0
- package/dist/utils/codex-config-merge.test.d.ts +2 -0
- package/dist/utils/codex-config-merge.test.d.ts.map +1 -0
- package/dist/utils/codex-config-merge.test.js +64 -0
- package/dist/utils/codex-config-merge.test.js.map +1 -0
- package/dist/utils/install-target.test.js +3 -2
- package/dist/utils/install-target.test.js.map +1 -1
- package/dist/utils/qwen-extension-cli.d.ts.map +1 -1
- package/dist/utils/qwen-extension-cli.js +4 -4
- package/dist/utils/qwen-extension-cli.js.map +1 -1
- package/dist/utils/qwen-extension-cli.test.js +9 -6
- package/dist/utils/qwen-extension-cli.test.js.map +1 -1
- package/dist/utils/workspace.js +1 -1
- package/dist/utils/workspace.js.map +1 -1
- package/dist/utils/workspace.test.js +14 -0
- package/dist/utils/workspace.test.js.map +1 -1
- package/package.json +3 -3
- package/vendor/node_modules/@zmice/platform-core/dist/index.test.js +5 -3
- package/vendor/node_modules/@zmice/platform-core/dist/index.test.js.map +1 -1
- package/vendor/packages/platform-claude/dist/index.js +75 -75
- package/vendor/packages/platform-claude/dist/index.test.js +11 -8
- package/vendor/packages/platform-claude/dist/index.test.js.map +1 -1
- package/vendor/packages/platform-codex/dist/index.d.ts.map +1 -1
- package/vendor/packages/platform-codex/dist/index.js +262 -165
- package/vendor/packages/platform-codex/dist/index.js.map +1 -1
- package/vendor/packages/platform-codex/dist/index.test.js +42 -20
- package/vendor/packages/platform-codex/dist/index.test.js.map +1 -1
- package/vendor/packages/platform-opencode/dist/index.js +75 -75
- package/vendor/packages/platform-opencode/dist/index.test.js +19 -15
- package/vendor/packages/platform-opencode/dist/index.test.js.map +1 -1
- package/vendor/packages/platform-qwen/dist/index.js +75 -75
- package/vendor/packages/platform-qwen/dist/index.test.js +9 -7
- package/vendor/packages/platform-qwen/dist/index.test.js.map +1 -1
- package/vendor/packages/toolkit/src/content/agents/architect/body.md +42 -42
- package/vendor/packages/toolkit/src/content/agents/code-reviewer/body.md +41 -41
- package/vendor/packages/toolkit/src/content/agents/product-owner/body.md +40 -40
- package/vendor/packages/toolkit/src/content/commands/plan-review/body.md +31 -31
- package/vendor/packages/toolkit/src/content/commands/start/body.md +197 -197
- package/vendor/packages/toolkit/src/content/commands/start/meta.yaml +55 -55
- package/vendor/packages/toolkit/src/content/skills/branch-finish-and-cleanup/body.md +172 -172
- package/vendor/packages/toolkit/src/content/skills/browser-qa-testing/body.md +111 -111
- package/vendor/packages/toolkit/src/content/skills/ci-cd-and-automation/body.md +86 -86
- package/vendor/packages/toolkit/src/content/skills/code-review-and-quality/body.md +140 -140
- package/vendor/packages/toolkit/src/content/skills/code-simplification/body.md +80 -80
- package/vendor/packages/toolkit/src/content/skills/context-engineering/body.md +67 -67
- package/vendor/packages/toolkit/src/content/skills/continuous-learning/body.md +102 -102
- package/vendor/packages/toolkit/src/content/skills/multi-perspective-review/body.md +81 -81
- package/vendor/packages/toolkit/src/content/skills/parallel-agent-dispatch/body.md +113 -113
- package/vendor/packages/toolkit/src/content/skills/performance-optimization/body.md +75 -75
- package/vendor/packages/toolkit/src/content/skills/planning-and-task-breakdown/body.md +83 -83
- package/vendor/packages/toolkit/src/content/skills/sdd-tdd-workflow/body.md +95 -95
- package/vendor/packages/toolkit/src/content/skills/sprint-retrospective/body.md +99 -99
- package/vendor/packages/toolkit/src/content/skills/team-orchestration/body.md +126 -126
- package/vendor/packages/toolkit/src/content/skills/test-driven-development/body.md +78 -78
- package/vendor/packages/toolkit/src/content/skills/using-agent-skills/body.md +193 -193
- package/vendor/references/upstreams.yaml +94 -94
|
@@ -1,5 +1,7 @@
|
|
|
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);
|
|
3
5
|
const platformMocks = vi.hoisted(() => ({
|
|
4
6
|
ArtifactConflictError: class ArtifactConflictError extends Error {
|
|
5
7
|
conflicts;
|
|
@@ -224,15 +226,15 @@ describe("platform CLI", () => {
|
|
|
224
226
|
root: options.dir ?? options.cwd ?? process.cwd(),
|
|
225
227
|
source: options.dir ? "explicit" : "cwd",
|
|
226
228
|
}));
|
|
227
|
-
platformMocks.resolvePlatformInstallReceiptPath.mockImplementation((plan) => (
|
|
229
|
+
platformMocks.resolvePlatformInstallReceiptPath.mockImplementation((plan) => (join(plan.destinationRoot, ".zc", "platform-state", `${plan.platform}.install-receipt.json`)));
|
|
228
230
|
platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
|
|
229
231
|
kind: "up-to-date",
|
|
230
232
|
platform: "codex",
|
|
231
|
-
receiptPath: "/tmp/install
|
|
233
|
+
receiptPath: join(abs("/tmp/install"), ".zc", "platform-state", "codex.install-receipt.json"),
|
|
232
234
|
receipt: {
|
|
233
235
|
schemaVersion: 1,
|
|
234
236
|
platform: "codex",
|
|
235
|
-
destinationRoot: "/tmp/install",
|
|
237
|
+
destinationRoot: abs("/tmp/install"),
|
|
236
238
|
manifestSource: "/repo/packages/toolkit/src/content",
|
|
237
239
|
overwrite: "error",
|
|
238
240
|
installedAt: "2026-04-19T12:00:00.000Z",
|
|
@@ -264,18 +266,18 @@ describe("platform CLI", () => {
|
|
|
264
266
|
platformMocks.deletePlatformInstallReceipt.mockResolvedValue(undefined);
|
|
265
267
|
platformMocks.writePlatformInstallReceiptForPlan.mockResolvedValue({});
|
|
266
268
|
platformMocks.syncQwenOfficialCliSourceBundle.mockResolvedValue({
|
|
267
|
-
sourceDir: "/tmp/qwen-source",
|
|
269
|
+
sourceDir: abs("/tmp/qwen-source"),
|
|
268
270
|
extensionName: "zc-toolkit",
|
|
269
271
|
artifactCount: 1,
|
|
270
272
|
});
|
|
271
273
|
platformMocks.syncQwenOfficialCliReleaseBundle.mockResolvedValue({
|
|
272
|
-
bundleDir: "/tmp/qwen-release",
|
|
274
|
+
bundleDir: abs("/tmp/qwen-release"),
|
|
273
275
|
extensionName: "zc-toolkit",
|
|
274
276
|
artifactCount: 1,
|
|
275
277
|
});
|
|
276
278
|
platformMocks.toQwenOfficialCliReleaseArtifacts.mockImplementation((_plan, bundleDir) => [
|
|
277
|
-
{ path:
|
|
278
|
-
{ path:
|
|
279
|
+
{ path: join(bundleDir, "QWEN.md"), content: "# context" },
|
|
280
|
+
{ path: join(bundleDir, "commands/zc/start.md"), content: "# start" },
|
|
279
281
|
]);
|
|
280
282
|
platformMocks.installQwenExtensionFromOfficialRepoWithCli.mockResolvedValue(undefined);
|
|
281
283
|
platformMocks.installQwenExtensionWithOfficialCli.mockResolvedValue(undefined);
|
|
@@ -284,6 +286,7 @@ describe("platform CLI", () => {
|
|
|
284
286
|
platformMocks.relinkQwenExtensionWithOfficialCli.mockResolvedValue(undefined);
|
|
285
287
|
});
|
|
286
288
|
it("uses safe overwrite defaults for platform generate writes", async () => {
|
|
289
|
+
const outputRoot = abs("/tmp/out");
|
|
287
290
|
platformMocks.createQwenGenerationPlan.mockReturnValue(createGenerationPlan([{ path: "QWEN.md", content: "# context" }]));
|
|
288
291
|
platformMocks.writeArtifacts.mockResolvedValue({
|
|
289
292
|
created: 1,
|
|
@@ -293,9 +296,10 @@ describe("platform CLI", () => {
|
|
|
293
296
|
dryRun: false,
|
|
294
297
|
});
|
|
295
298
|
await runPlatformGenerate("qwen", { dir: "/tmp/out" });
|
|
296
|
-
expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: "
|
|
299
|
+
expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: join(outputRoot, "QWEN.md"), content: "# context" }], { dryRun: false, overwrite: "error" });
|
|
297
300
|
});
|
|
298
301
|
it("prints a JSON plan without writing files when generate uses --plan", async () => {
|
|
302
|
+
const outputRoot = abs("/tmp/out");
|
|
299
303
|
platformMocks.createQwenGenerationPlan.mockReturnValue(createGenerationPlan([{ path: "QWEN.md", content: "# context" }]));
|
|
300
304
|
const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
301
305
|
await runPlatformGenerate("qwen", { dir: "/tmp/out", plan: true, json: true });
|
|
@@ -305,17 +309,18 @@ describe("platform CLI", () => {
|
|
|
305
309
|
mode: "plan",
|
|
306
310
|
action: "generate",
|
|
307
311
|
target: "qwen",
|
|
308
|
-
root:
|
|
312
|
+
root: outputRoot,
|
|
309
313
|
artifactCount: 1,
|
|
310
|
-
artifacts: [{ path: "
|
|
314
|
+
artifacts: [{ path: join(outputRoot, "QWEN.md"), content: "# context" }],
|
|
311
315
|
}));
|
|
312
316
|
logSpy.mockRestore();
|
|
313
317
|
});
|
|
314
318
|
it("exports a standalone qwen release bundle during generate", async () => {
|
|
319
|
+
const bundleRoot = abs("/tmp/zc-toolkit");
|
|
315
320
|
platformMocks.createQwenGenerationPlan.mockReturnValue(createGenerationPlan([{ path: "QWEN.md", content: "# context" }]));
|
|
316
|
-
platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan(
|
|
317
|
-
{ path: "
|
|
318
|
-
{ path: "
|
|
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" },
|
|
319
324
|
]));
|
|
320
325
|
platformMocks.writeArtifacts.mockResolvedValue({
|
|
321
326
|
created: 2,
|
|
@@ -326,15 +331,16 @@ describe("platform CLI", () => {
|
|
|
326
331
|
});
|
|
327
332
|
await runPlatformGenerate("qwen", { dir: "/tmp/zc-toolkit", bundle: "release-bundle" });
|
|
328
333
|
expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([
|
|
329
|
-
{ path: "
|
|
330
|
-
{ path: "
|
|
334
|
+
{ path: join(bundleRoot, "QWEN.md"), content: "# context" },
|
|
335
|
+
{ path: join(bundleRoot, "commands/zc/start.md"), content: "# start" },
|
|
331
336
|
], { dryRun: false, overwrite: "error" });
|
|
332
337
|
});
|
|
333
338
|
it("prints qwen release bundle plan paths without native extension nesting", async () => {
|
|
339
|
+
const bundleRoot = abs("/tmp/zc-toolkit");
|
|
334
340
|
platformMocks.createQwenGenerationPlan.mockReturnValue(createGenerationPlan([{ path: "QWEN.md", content: "# context" }]));
|
|
335
|
-
platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan(
|
|
336
|
-
{ path: "
|
|
337
|
-
{ path: "
|
|
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" },
|
|
338
344
|
]));
|
|
339
345
|
const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
340
346
|
await runPlatformGenerate("qwen", {
|
|
@@ -348,12 +354,12 @@ describe("platform CLI", () => {
|
|
|
348
354
|
mode: "plan",
|
|
349
355
|
action: "generate",
|
|
350
356
|
target: "qwen",
|
|
351
|
-
root:
|
|
357
|
+
root: bundleRoot,
|
|
352
358
|
bundleType: "release-bundle",
|
|
353
|
-
bundlePath:
|
|
359
|
+
bundlePath: bundleRoot,
|
|
354
360
|
artifacts: [
|
|
355
|
-
{ path: "
|
|
356
|
-
{ path: "
|
|
361
|
+
{ path: join(bundleRoot, "QWEN.md"), content: "# context" },
|
|
362
|
+
{ path: join(bundleRoot, "commands/zc/start.md"), content: "# start" },
|
|
357
363
|
],
|
|
358
364
|
}));
|
|
359
365
|
logSpy.mockRestore();
|
|
@@ -373,21 +379,22 @@ describe("platform CLI", () => {
|
|
|
373
379
|
matchedAssets: [],
|
|
374
380
|
capability: {
|
|
375
381
|
namespace: "zc",
|
|
376
|
-
surfaces: ["plugin-dir", "skills-dir", "agents-dir"],
|
|
377
|
-
entryFile:
|
|
382
|
+
surfaces: ["entry-file", "plugin-dir", "skills-dir", "agents-dir"],
|
|
383
|
+
entryFile: ".codex/AGENTS.md",
|
|
378
384
|
commandsDir: null,
|
|
379
|
-
skillsDir: "skills",
|
|
385
|
+
skillsDir: ".codex/plugins/zc-toolkit/skills",
|
|
380
386
|
agentsDir: ".codex/agents",
|
|
381
387
|
extensionDir: null,
|
|
382
388
|
},
|
|
383
389
|
artifacts: [
|
|
384
390
|
{ path: ".agents/plugins/marketplace.json", content: "{}" },
|
|
391
|
+
{ path: ".codex/AGENTS.md", content: "# plugin entry" },
|
|
385
392
|
{ path: ".codex/plugins/zc-toolkit/.codex-plugin/plugin.json", content: "{}" },
|
|
386
393
|
{ path: ".codex/agents/zc-code-reviewer.toml", content: "name = \"zc_code_reviewer\"\n" },
|
|
387
394
|
],
|
|
388
395
|
});
|
|
389
396
|
platformMocks.writeArtifacts.mockResolvedValue({
|
|
390
|
-
created:
|
|
397
|
+
created: 4,
|
|
391
398
|
overwritten: 0,
|
|
392
399
|
unchanged: 0,
|
|
393
400
|
skipped: 0,
|
|
@@ -399,12 +406,14 @@ describe("platform CLI", () => {
|
|
|
399
406
|
});
|
|
400
407
|
expect(platformMocks.createCodexMarketplaceGenerationPlan).toHaveBeenCalledWith(expect.any(Object), expect.objectContaining({ scope: "global" }));
|
|
401
408
|
expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([
|
|
402
|
-
{ path:
|
|
403
|
-
{ path:
|
|
404
|
-
{ path:
|
|
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" },
|
|
405
413
|
], { dryRun: false, overwrite: "error" });
|
|
406
414
|
});
|
|
407
415
|
it("exports codex marketplace to the resolved project root with --project", async () => {
|
|
416
|
+
const projectRoot = join("/repo", "project");
|
|
408
417
|
platformMocks.resolveInstallTarget.mockResolvedValue({
|
|
409
418
|
root: "/repo/project",
|
|
410
419
|
source: "project-root",
|
|
@@ -424,11 +433,12 @@ describe("platform CLI", () => {
|
|
|
424
433
|
matchedAssets: [],
|
|
425
434
|
artifacts: [
|
|
426
435
|
{ path: ".agents/plugins/marketplace.json", content: "{}" },
|
|
427
|
-
{ path: ".
|
|
436
|
+
{ path: "AGENTS.md", content: "# plugin entry" },
|
|
437
|
+
{ path: "plugins/zc-toolkit/.codex-plugin/plugin.json", content: "{}" },
|
|
428
438
|
],
|
|
429
439
|
});
|
|
430
440
|
platformMocks.writeArtifacts.mockResolvedValue({
|
|
431
|
-
created:
|
|
441
|
+
created: 3,
|
|
432
442
|
overwritten: 0,
|
|
433
443
|
unchanged: 0,
|
|
434
444
|
skipped: 0,
|
|
@@ -441,11 +451,13 @@ describe("platform CLI", () => {
|
|
|
441
451
|
expect(platformMocks.resolveInstallTarget).toHaveBeenCalledWith("codex", { project: true });
|
|
442
452
|
expect(platformMocks.createCodexMarketplaceGenerationPlan).toHaveBeenCalledWith(expect.any(Object), expect.objectContaining({ scope: "project" }));
|
|
443
453
|
expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([
|
|
444
|
-
{ path: "
|
|
445
|
-
{ path: "
|
|
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: "{}" },
|
|
446
457
|
], { dryRun: false, overwrite: "error" });
|
|
447
458
|
});
|
|
448
459
|
it("uses a short codex plugin command for the project marketplace by default", async () => {
|
|
460
|
+
const projectRoot = join("/repo", "project");
|
|
449
461
|
platformMocks.resolveInstallTarget.mockResolvedValue({
|
|
450
462
|
root: "/repo/project",
|
|
451
463
|
source: "project-root",
|
|
@@ -465,11 +477,12 @@ describe("platform CLI", () => {
|
|
|
465
477
|
matchedAssets: [],
|
|
466
478
|
artifacts: [
|
|
467
479
|
{ path: ".agents/plugins/marketplace.json", content: "{}" },
|
|
468
|
-
{ path: ".
|
|
480
|
+
{ path: "AGENTS.md", content: "# plugin entry" },
|
|
481
|
+
{ path: "plugins/zc-toolkit/.codex-plugin/plugin.json", content: "{}" },
|
|
469
482
|
],
|
|
470
483
|
});
|
|
471
484
|
platformMocks.writeArtifacts.mockResolvedValue({
|
|
472
|
-
created:
|
|
485
|
+
created: 3,
|
|
473
486
|
overwritten: 0,
|
|
474
487
|
unchanged: 0,
|
|
475
488
|
skipped: 0,
|
|
@@ -479,8 +492,9 @@ describe("platform CLI", () => {
|
|
|
479
492
|
expect(platformMocks.resolveInstallTarget).toHaveBeenCalledWith("codex", { project: true });
|
|
480
493
|
expect(platformMocks.createCodexMarketplaceGenerationPlan).toHaveBeenCalledWith(expect.any(Object), expect.objectContaining({ scope: "project" }));
|
|
481
494
|
expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([
|
|
482
|
-
{ path: "
|
|
483
|
-
{ path: "
|
|
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: "{}" },
|
|
484
498
|
], { dryRun: false, overwrite: "error" });
|
|
485
499
|
});
|
|
486
500
|
it("uses the personal marketplace for codex plugin when --global is explicit", async () => {
|
|
@@ -498,11 +512,12 @@ describe("platform CLI", () => {
|
|
|
498
512
|
matchedAssets: [],
|
|
499
513
|
artifacts: [
|
|
500
514
|
{ path: ".agents/plugins/marketplace.json", content: "{}" },
|
|
515
|
+
{ path: ".codex/AGENTS.md", content: "# plugin entry" },
|
|
501
516
|
{ path: ".codex/plugins/zc-toolkit/.codex-plugin/plugin.json", content: "{}" },
|
|
502
517
|
],
|
|
503
518
|
});
|
|
504
519
|
platformMocks.writeArtifacts.mockResolvedValue({
|
|
505
|
-
created:
|
|
520
|
+
created: 3,
|
|
506
521
|
overwritten: 0,
|
|
507
522
|
unchanged: 0,
|
|
508
523
|
skipped: 0,
|
|
@@ -512,12 +527,52 @@ describe("platform CLI", () => {
|
|
|
512
527
|
expect(platformMocks.resolveInstallTarget).not.toHaveBeenCalled();
|
|
513
528
|
expect(platformMocks.createCodexMarketplaceGenerationPlan).toHaveBeenCalledWith(expect.any(Object), expect.objectContaining({ scope: "global" }));
|
|
514
529
|
expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([
|
|
515
|
-
{ path:
|
|
516
|
-
{ path:
|
|
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: "{}" },
|
|
517
533
|
], { dryRun: false, overwrite: "error" });
|
|
518
534
|
});
|
|
535
|
+
it("cleans the generated Codex plugin skills directory on force writes", async () => {
|
|
536
|
+
platformMocks.createCodexGenerationPlan.mockReturnValue({
|
|
537
|
+
platform: "codex",
|
|
538
|
+
packageName: "@zmice/platform-codex",
|
|
539
|
+
manifestSource: "/repo/packages/toolkit/src/content#generatedAt=2026-04-19T12:00:00.000Z",
|
|
540
|
+
matchedAssets: [],
|
|
541
|
+
artifacts: [],
|
|
542
|
+
});
|
|
543
|
+
platformMocks.createCodexMarketplaceGenerationPlan.mockReturnValue({
|
|
544
|
+
platform: "codex",
|
|
545
|
+
packageName: "@zmice/platform-codex",
|
|
546
|
+
manifestSource: "/repo/packages/toolkit/src/content#generatedAt=2026-04-19T12:00:00.000Z",
|
|
547
|
+
matchedAssets: [],
|
|
548
|
+
artifacts: [
|
|
549
|
+
{ path: ".agents/plugins/marketplace.json", content: "{}" },
|
|
550
|
+
{ path: ".codex/AGENTS.md", content: "# plugin entry" },
|
|
551
|
+
{ path: ".codex/plugins/zc-toolkit/.codex-plugin/plugin.json", content: "{}" },
|
|
552
|
+
{ path: ".codex/plugins/zc-toolkit/skills/start/SKILL.md", content: "# start" },
|
|
553
|
+
],
|
|
554
|
+
});
|
|
555
|
+
platformMocks.writeArtifacts.mockResolvedValue({
|
|
556
|
+
created: 4,
|
|
557
|
+
overwritten: 0,
|
|
558
|
+
unchanged: 0,
|
|
559
|
+
skipped: 0,
|
|
560
|
+
dryRun: false,
|
|
561
|
+
});
|
|
562
|
+
await runPlatformPlugin("codex", { global: true, force: true });
|
|
563
|
+
expect(platformMocks.removeManagedPaths).toHaveBeenCalledWith([
|
|
564
|
+
join(homedir(), ".codex/plugins/zc-toolkit/skills"),
|
|
565
|
+
]);
|
|
566
|
+
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" },
|
|
571
|
+
], { dryRun: false, overwrite: "force" });
|
|
572
|
+
});
|
|
519
573
|
it("uses safe overwrite defaults for platform install and writes a receipt", async () => {
|
|
520
|
-
|
|
574
|
+
const installRoot = abs("/tmp/install");
|
|
575
|
+
platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", installRoot, [{ path: join(installRoot, "AGENTS.md"), content: "# agents" }]));
|
|
521
576
|
platformMocks.writeArtifacts.mockResolvedValue({
|
|
522
577
|
created: 1,
|
|
523
578
|
overwritten: 0,
|
|
@@ -527,19 +582,20 @@ describe("platform CLI", () => {
|
|
|
527
582
|
});
|
|
528
583
|
await runPlatformInstall("codex", { dir: "/tmp/install" });
|
|
529
584
|
expect(platformMocks.createCodexInstallPlan).toHaveBeenCalledWith(expect.anything(), expect.objectContaining({
|
|
530
|
-
destinationRoot:
|
|
585
|
+
destinationRoot: installRoot,
|
|
531
586
|
scope: "dir",
|
|
532
587
|
overwrite: "error",
|
|
533
588
|
}));
|
|
534
|
-
expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: "
|
|
589
|
+
expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: join(installRoot, "AGENTS.md"), content: "# agents" }], { dryRun: false, overwrite: "error" });
|
|
535
590
|
expect(platformMocks.writePlatformInstallReceiptForPlan).toHaveBeenCalledWith(expect.objectContaining({
|
|
536
|
-
destinationRoot:
|
|
591
|
+
destinationRoot: installRoot,
|
|
537
592
|
}), expect.objectContaining({
|
|
538
593
|
zcVersion: expect.any(String),
|
|
539
594
|
}));
|
|
540
595
|
});
|
|
541
596
|
it("forwards force installs to artifact writes", async () => {
|
|
542
|
-
|
|
597
|
+
const installRoot = abs("/tmp/install");
|
|
598
|
+
platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", installRoot, [{ path: join(installRoot, "AGENTS.md"), content: "# agents" }]));
|
|
543
599
|
platformMocks.writeArtifacts.mockResolvedValue({
|
|
544
600
|
created: 0,
|
|
545
601
|
overwritten: 1,
|
|
@@ -548,10 +604,11 @@ describe("platform CLI", () => {
|
|
|
548
604
|
dryRun: false,
|
|
549
605
|
});
|
|
550
606
|
await runPlatformInstall("codex", { dir: "/tmp/install", force: true });
|
|
551
|
-
expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: "
|
|
607
|
+
expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: join(installRoot, "AGENTS.md"), content: "# agents" }], { dryRun: false, overwrite: "force" });
|
|
552
608
|
});
|
|
553
609
|
it("uses the resolved project root when install target is omitted", async () => {
|
|
554
|
-
|
|
610
|
+
const projectRoot = abs("/workspace/project");
|
|
611
|
+
platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", projectRoot, [{ path: join(projectRoot, "AGENTS.md"), content: "# agents" }]));
|
|
555
612
|
platformMocks.writeArtifacts.mockResolvedValue({
|
|
556
613
|
created: 1,
|
|
557
614
|
overwritten: 0,
|
|
@@ -573,14 +630,15 @@ describe("platform CLI", () => {
|
|
|
573
630
|
global: undefined,
|
|
574
631
|
});
|
|
575
632
|
expect(platformMocks.createCodexInstallPlan).toHaveBeenCalledWith(expect.anything(), expect.objectContaining({
|
|
576
|
-
destinationRoot:
|
|
633
|
+
destinationRoot: projectRoot,
|
|
577
634
|
scope: "project",
|
|
578
635
|
}));
|
|
579
636
|
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("安装目录自动解析(project-root)"));
|
|
580
637
|
logSpy.mockRestore();
|
|
581
638
|
});
|
|
582
639
|
it("prints a JSON install plan without writing files when install uses --plan", async () => {
|
|
583
|
-
|
|
640
|
+
const installRoot = abs("/tmp/install");
|
|
641
|
+
platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", installRoot, [{ path: join(installRoot, "AGENTS.md"), content: "# agents" }], "dir", "error"));
|
|
584
642
|
const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
585
643
|
await runPlatformInstall("codex", { dir: "/tmp/install", plan: true, json: true });
|
|
586
644
|
expect(platformMocks.writeArtifacts).not.toHaveBeenCalled();
|
|
@@ -589,14 +647,14 @@ describe("platform CLI", () => {
|
|
|
589
647
|
mode: "plan",
|
|
590
648
|
action: "install",
|
|
591
649
|
target: "codex",
|
|
592
|
-
root:
|
|
650
|
+
root: installRoot,
|
|
593
651
|
scope: "dir",
|
|
594
652
|
rootSource: "explicit",
|
|
595
653
|
artifactCount: 1,
|
|
596
654
|
overwrite: "error",
|
|
597
655
|
artifacts: expect.arrayContaining([
|
|
598
656
|
expect.objectContaining({
|
|
599
|
-
path: "
|
|
657
|
+
path: join(installRoot, "AGENTS.md"),
|
|
600
658
|
content: "# agents",
|
|
601
659
|
}),
|
|
602
660
|
]),
|
|
@@ -604,21 +662,22 @@ describe("platform CLI", () => {
|
|
|
604
662
|
logSpy.mockRestore();
|
|
605
663
|
});
|
|
606
664
|
it("prints platform status from receipt and current plan", async () => {
|
|
665
|
+
const installRoot = abs("/tmp/install");
|
|
607
666
|
const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
608
667
|
platformMocks.resolveInstallTarget.mockResolvedValue({
|
|
609
668
|
root: "/tmp/install",
|
|
610
669
|
source: "explicit",
|
|
611
670
|
});
|
|
612
|
-
platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex",
|
|
671
|
+
platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", installRoot, [{ path: join(installRoot, "AGENTS.md"), content: "# agents" }]));
|
|
613
672
|
await runPlatformStatus("codex", { dir: "/tmp/install", json: true });
|
|
614
673
|
expect(platformMocks.resolvePlatformInstallStatus).toHaveBeenCalledWith(expect.objectContaining({
|
|
615
|
-
destinationRoot:
|
|
674
|
+
destinationRoot: installRoot,
|
|
616
675
|
}));
|
|
617
676
|
const payload = JSON.parse(logSpy.mock.calls[0]?.[0] ?? "{}");
|
|
618
677
|
expect(payload).toEqual(expect.objectContaining({
|
|
619
678
|
mode: "status",
|
|
620
679
|
target: "codex",
|
|
621
|
-
root:
|
|
680
|
+
root: installRoot,
|
|
622
681
|
status: "up-to-date",
|
|
623
682
|
installedContentFingerprint: "installed-fingerprint",
|
|
624
683
|
contentFingerprint: "current-fingerprint",
|
|
@@ -626,32 +685,34 @@ describe("platform CLI", () => {
|
|
|
626
685
|
logSpy.mockRestore();
|
|
627
686
|
});
|
|
628
687
|
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");
|
|
629
690
|
const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
630
691
|
platformMocks.resolveInstallTarget.mockResolvedValue({
|
|
631
692
|
root: "/home/test/.qwen",
|
|
632
693
|
source: "official-global",
|
|
633
694
|
hint: "Qwen 官方文档定义用户级配置目录为 `~/.qwen`。",
|
|
634
695
|
});
|
|
635
|
-
platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan(
|
|
696
|
+
platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan(qwenRoot, [{ path: join(qwenRoot, "extensions/zc-toolkit/QWEN.md"), content: "# context" }], "global"));
|
|
636
697
|
platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
|
|
637
698
|
kind: "up-to-date",
|
|
638
699
|
platform: "qwen",
|
|
639
|
-
receiptPath: "
|
|
700
|
+
receiptPath: join(qwenRoot, ".zc/platform-state/qwen.install-receipt.json"),
|
|
640
701
|
receipt: {
|
|
641
702
|
schemaVersion: 1,
|
|
642
703
|
platform: "qwen",
|
|
643
|
-
destinationRoot:
|
|
704
|
+
destinationRoot: qwenRoot,
|
|
644
705
|
manifestSource: "/repo/packages/toolkit/src/content",
|
|
645
706
|
overwrite: "error",
|
|
646
707
|
installedAt: "2026-04-19T12:00:00.000Z",
|
|
647
708
|
installMethod: "filesystem",
|
|
648
709
|
installSource: "local-bundle",
|
|
649
|
-
sourceRef:
|
|
710
|
+
sourceRef: qwenBundleRoot,
|
|
650
711
|
bundleType: "release-bundle",
|
|
651
|
-
bundlePath:
|
|
712
|
+
bundlePath: qwenBundleRoot,
|
|
652
713
|
artifacts: [
|
|
653
714
|
{
|
|
654
|
-
path: "
|
|
715
|
+
path: join(qwenRoot, "extensions/zc-toolkit/QWEN.md"),
|
|
655
716
|
sha256: "sha",
|
|
656
717
|
bytes: 9,
|
|
657
718
|
},
|
|
@@ -672,26 +733,27 @@ describe("platform CLI", () => {
|
|
|
672
733
|
expect(payload).toEqual(expect.objectContaining({
|
|
673
734
|
mode: "status",
|
|
674
735
|
target: "qwen",
|
|
675
|
-
root:
|
|
736
|
+
root: qwenRoot,
|
|
676
737
|
installMethod: "filesystem",
|
|
677
738
|
installSource: "local-bundle",
|
|
678
|
-
sourceRef:
|
|
739
|
+
sourceRef: qwenBundleRoot,
|
|
679
740
|
bundleType: "release-bundle",
|
|
680
|
-
bundlePath:
|
|
741
|
+
bundlePath: qwenBundleRoot,
|
|
681
742
|
recommendedInstallMethod: "qwen-cli",
|
|
682
743
|
recommendedInstallSource: "github-repo",
|
|
683
744
|
recommendedSourceRef: "https://github.com/zmice/zc-qwen-extension.git",
|
|
684
745
|
recommendedBundleType: "release-bundle",
|
|
685
|
-
recommendedBundlePath: "
|
|
746
|
+
recommendedBundlePath: expect.stringContaining("zc-toolkit"),
|
|
686
747
|
}));
|
|
687
748
|
logSpy.mockRestore();
|
|
688
749
|
});
|
|
689
750
|
it("prints update plan when status shows update-available", async () => {
|
|
751
|
+
const installRoot = abs("/tmp/install");
|
|
690
752
|
const logSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
691
753
|
platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
|
|
692
754
|
kind: "update-available",
|
|
693
755
|
platform: "codex",
|
|
694
|
-
receiptPath: "
|
|
756
|
+
receiptPath: join(installRoot, ".zc/platform-state/codex.install-receipt.json"),
|
|
695
757
|
receipt: null,
|
|
696
758
|
contentFingerprint: "current-fingerprint",
|
|
697
759
|
installedContentFingerprint: "installed-fingerprint",
|
|
@@ -703,7 +765,7 @@ describe("platform CLI", () => {
|
|
|
703
765
|
},
|
|
704
766
|
artifacts: [],
|
|
705
767
|
});
|
|
706
|
-
platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex",
|
|
768
|
+
platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", installRoot, [{ path: join(installRoot, "AGENTS.md"), content: "# agents v2" }], "dir", "error"));
|
|
707
769
|
await runPlatformUpdate("codex", { dir: "/tmp/install", plan: true, json: true });
|
|
708
770
|
expect(platformMocks.writeArtifacts).not.toHaveBeenCalled();
|
|
709
771
|
const payload = JSON.parse(logSpy.mock.calls[0]?.[0] ?? "{}");
|
|
@@ -712,15 +774,16 @@ describe("platform CLI", () => {
|
|
|
712
774
|
action: "update",
|
|
713
775
|
target: "codex",
|
|
714
776
|
status: "update-available",
|
|
715
|
-
root:
|
|
777
|
+
root: installRoot,
|
|
716
778
|
}));
|
|
717
779
|
logSpy.mockRestore();
|
|
718
780
|
});
|
|
719
781
|
it("treats update-available as managed overwrite and refreshes the receipt", async () => {
|
|
782
|
+
const installRoot = abs("/tmp/install");
|
|
720
783
|
platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
|
|
721
784
|
kind: "update-available",
|
|
722
785
|
platform: "codex",
|
|
723
|
-
receiptPath: "
|
|
786
|
+
receiptPath: join(installRoot, ".zc/platform-state/codex.install-receipt.json"),
|
|
724
787
|
receipt: null,
|
|
725
788
|
contentFingerprint: "current-fingerprint",
|
|
726
789
|
installedContentFingerprint: "installed-fingerprint",
|
|
@@ -732,7 +795,7 @@ describe("platform CLI", () => {
|
|
|
732
795
|
},
|
|
733
796
|
artifacts: [],
|
|
734
797
|
});
|
|
735
|
-
platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex",
|
|
798
|
+
platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", installRoot, [{ path: join(installRoot, "AGENTS.md"), content: "# agents v2" }], "dir", "error"));
|
|
736
799
|
platformMocks.writeArtifacts.mockResolvedValue({
|
|
737
800
|
created: 0,
|
|
738
801
|
overwritten: 1,
|
|
@@ -742,10 +805,10 @@ describe("platform CLI", () => {
|
|
|
742
805
|
});
|
|
743
806
|
await runPlatformUpdate("codex", { dir: "/tmp/install" });
|
|
744
807
|
expect(platformMocks.createCodexInstallPlan).toHaveBeenLastCalledWith(expect.anything(), expect.objectContaining({
|
|
745
|
-
destinationRoot:
|
|
808
|
+
destinationRoot: installRoot,
|
|
746
809
|
overwrite: "force",
|
|
747
810
|
}));
|
|
748
|
-
expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: "
|
|
811
|
+
expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: join(installRoot, "AGENTS.md"), content: "# agents v2" }], { dryRun: false, overwrite: "force" });
|
|
749
812
|
expect(platformMocks.writePlatformInstallReceiptForPlan).toHaveBeenCalled();
|
|
750
813
|
});
|
|
751
814
|
it("reports a no-op update when the installation is already up-to-date", async () => {
|
|
@@ -811,7 +874,8 @@ describe("platform CLI", () => {
|
|
|
811
874
|
errorSpy.mockRestore();
|
|
812
875
|
});
|
|
813
876
|
it("passes global scope through install target resolution and exposes official path hints", async () => {
|
|
814
|
-
|
|
877
|
+
const claudeRoot = abs("/home/test/.claude");
|
|
878
|
+
platformMocks.createClaudeInstallPlan.mockReturnValue(createInstallPlan("claude", claudeRoot, [{ path: join(claudeRoot, "CLAUDE.md"), content: "# claude" }]));
|
|
815
879
|
platformMocks.writeArtifacts.mockResolvedValue({
|
|
816
880
|
created: 1,
|
|
817
881
|
overwritten: 0,
|
|
@@ -833,14 +897,15 @@ describe("platform CLI", () => {
|
|
|
833
897
|
global: true,
|
|
834
898
|
});
|
|
835
899
|
expect(platformMocks.createClaudeInstallPlan).toHaveBeenCalledWith(expect.anything(), expect.objectContaining({
|
|
836
|
-
destinationRoot:
|
|
900
|
+
destinationRoot: claudeRoot,
|
|
837
901
|
scope: "global",
|
|
838
902
|
}));
|
|
839
903
|
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("提示:Claude Code 官方文档定义用户级 memory 文件位于 `~/.claude/CLAUDE.md`。"));
|
|
840
904
|
logSpy.mockRestore();
|
|
841
905
|
});
|
|
842
906
|
it("prefers the official qwen extensions CLI for global installs", async () => {
|
|
843
|
-
|
|
907
|
+
const qwenRoot = abs("/home/test/.qwen");
|
|
908
|
+
platformMocks.createQwenInstallPlan.mockReturnValue(createQwenInstallPlan(qwenRoot, [{ path: join(qwenRoot, "extensions/zc-toolkit/QWEN.md"), content: "# context" }], "global"));
|
|
844
909
|
platformMocks.resolveInstallTarget.mockResolvedValue({
|
|
845
910
|
root: "/home/test/.qwen",
|
|
846
911
|
source: "official-global",
|
|
@@ -849,7 +914,7 @@ describe("platform CLI", () => {
|
|
|
849
914
|
platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
|
|
850
915
|
kind: "not-installed",
|
|
851
916
|
platform: "qwen",
|
|
852
|
-
receiptPath: "
|
|
917
|
+
receiptPath: join(qwenRoot, ".zc/platform-state/qwen.install-receipt.json"),
|
|
853
918
|
receipt: null,
|
|
854
919
|
contentFingerprint: "current-fingerprint",
|
|
855
920
|
installedContentFingerprint: undefined,
|
|
@@ -869,7 +934,8 @@ describe("platform CLI", () => {
|
|
|
869
934
|
expect(platformMocks.writeArtifacts).not.toHaveBeenCalled();
|
|
870
935
|
});
|
|
871
936
|
it("prints a JSON install plan with scope metadata", async () => {
|
|
872
|
-
|
|
937
|
+
const codexRoot = abs("/home/test/.codex");
|
|
938
|
+
platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", codexRoot, [{ path: join(codexRoot, "AGENTS.md"), content: "# agents" }], "global", "error"));
|
|
873
939
|
platformMocks.resolveInstallTarget.mockResolvedValue({
|
|
874
940
|
root: "/home/test/.codex",
|
|
875
941
|
source: "official-global",
|
|
@@ -883,7 +949,7 @@ describe("platform CLI", () => {
|
|
|
883
949
|
action: "install",
|
|
884
950
|
target: "codex",
|
|
885
951
|
scope: "global",
|
|
886
|
-
root:
|
|
952
|
+
root: codexRoot,
|
|
887
953
|
rootSource: "official-global",
|
|
888
954
|
hint: "Codex 官方文档将 Codex home(默认 `~/.codex`)定义为全局级 `AGENTS.md` 的位置。",
|
|
889
955
|
}));
|
|
@@ -1008,22 +1074,23 @@ describe("platform CLI", () => {
|
|
|
1008
1074
|
expect(platformMocks.deletePlatformInstallReceipt).toHaveBeenCalledWith("/home/test/.qwen/.zc/platform-state/qwen.install-receipt.json");
|
|
1009
1075
|
});
|
|
1010
1076
|
it("repairs drifted filesystem installs by rewriting managed artifacts", async () => {
|
|
1011
|
-
|
|
1077
|
+
const installRoot = abs("/tmp/install");
|
|
1078
|
+
platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", installRoot, [{ path: join(installRoot, "AGENTS.md"), content: "# agents repaired" }]));
|
|
1012
1079
|
platformMocks.resolvePlatformInstallStatus.mockResolvedValue({
|
|
1013
1080
|
kind: "drifted",
|
|
1014
1081
|
platform: "codex",
|
|
1015
|
-
receiptPath: "
|
|
1082
|
+
receiptPath: join(installRoot, ".zc/platform-state/codex.install-receipt.json"),
|
|
1016
1083
|
receipt: {
|
|
1017
1084
|
schemaVersion: 1,
|
|
1018
1085
|
platform: "codex",
|
|
1019
|
-
destinationRoot:
|
|
1086
|
+
destinationRoot: installRoot,
|
|
1020
1087
|
manifestSource: "/repo/packages/toolkit/src/content",
|
|
1021
1088
|
overwrite: "error",
|
|
1022
1089
|
installedAt: "2026-04-19T12:00:00.000Z",
|
|
1023
1090
|
installMethod: "filesystem",
|
|
1024
1091
|
artifacts: [
|
|
1025
1092
|
{
|
|
1026
|
-
path: "
|
|
1093
|
+
path: join(installRoot, "AGENTS.md"),
|
|
1027
1094
|
sha256: "old-sha",
|
|
1028
1095
|
bytes: 8,
|
|
1029
1096
|
},
|
|
@@ -1039,7 +1106,7 @@ describe("platform CLI", () => {
|
|
|
1039
1106
|
},
|
|
1040
1107
|
artifacts: [
|
|
1041
1108
|
{
|
|
1042
|
-
path: "
|
|
1109
|
+
path: join(installRoot, "AGENTS.md"),
|
|
1043
1110
|
receiptSha256: "old-sha",
|
|
1044
1111
|
actualSha256: "drifted-sha",
|
|
1045
1112
|
plannedSha256: "new-sha",
|
|
@@ -1057,10 +1124,10 @@ describe("platform CLI", () => {
|
|
|
1057
1124
|
});
|
|
1058
1125
|
await runPlatformRepair("codex", { dir: "/tmp/install" });
|
|
1059
1126
|
expect(platformMocks.createCodexInstallPlan).toHaveBeenLastCalledWith(expect.anything(), expect.objectContaining({
|
|
1060
|
-
destinationRoot:
|
|
1127
|
+
destinationRoot: installRoot,
|
|
1061
1128
|
overwrite: "force",
|
|
1062
1129
|
}));
|
|
1063
|
-
expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: "
|
|
1130
|
+
expect(platformMocks.writeArtifacts).toHaveBeenCalledWith([{ path: join(installRoot, "AGENTS.md"), content: "# agents repaired" }], { dryRun: false, overwrite: "force" });
|
|
1064
1131
|
expect(platformMocks.writePlatformInstallReceiptForPlan).toHaveBeenCalled();
|
|
1065
1132
|
});
|
|
1066
1133
|
it("prints platform doctor health and issues", async () => {
|
|
@@ -1119,7 +1186,8 @@ describe("platform CLI", () => {
|
|
|
1119
1186
|
logSpy.mockRestore();
|
|
1120
1187
|
});
|
|
1121
1188
|
it("prints resolved install targets via platform where", async () => {
|
|
1122
|
-
|
|
1189
|
+
const codexRoot = abs("/home/test/.codex");
|
|
1190
|
+
platformMocks.createCodexInstallPlan.mockReturnValue(createInstallPlan("codex", codexRoot, [{ path: join(codexRoot, "AGENTS.md"), content: "# agents" }], "global"));
|
|
1123
1191
|
platformMocks.resolveInstallTarget.mockResolvedValue({
|
|
1124
1192
|
root: "/home/test/.codex",
|
|
1125
1193
|
source: "official-global",
|
|
@@ -1138,7 +1206,7 @@ describe("platform CLI", () => {
|
|
|
1138
1206
|
mode: "where",
|
|
1139
1207
|
target: "codex",
|
|
1140
1208
|
scope: "global",
|
|
1141
|
-
root:
|
|
1209
|
+
root: codexRoot,
|
|
1142
1210
|
rootSource: "official-global",
|
|
1143
1211
|
capability: expect.objectContaining({
|
|
1144
1212
|
namespace: "zc",
|
|
@@ -1148,12 +1216,13 @@ describe("platform CLI", () => {
|
|
|
1148
1216
|
logSpy.mockRestore();
|
|
1149
1217
|
});
|
|
1150
1218
|
it("resolves qwen global scope to the user-level ~/.qwen directory", async () => {
|
|
1219
|
+
const qwenRoot = abs("/home/test/.qwen");
|
|
1151
1220
|
platformMocks.createQwenInstallPlan.mockReturnValue({
|
|
1152
1221
|
platform: "qwen",
|
|
1153
1222
|
packageName: "@zmice/platform-qwen",
|
|
1154
1223
|
manifestSource: "/repo/packages/toolkit/src/content#generatedAt=2026-04-19T12:00:00.000Z",
|
|
1155
1224
|
matchedAssets: [],
|
|
1156
|
-
destinationRoot:
|
|
1225
|
+
destinationRoot: qwenRoot,
|
|
1157
1226
|
scope: "global",
|
|
1158
1227
|
overwrite: "error",
|
|
1159
1228
|
capability: {
|
|
@@ -1165,7 +1234,7 @@ describe("platform CLI", () => {
|
|
|
1165
1234
|
agentsDir: "agents",
|
|
1166
1235
|
extensionDir: "extensions/zc-toolkit",
|
|
1167
1236
|
},
|
|
1168
|
-
artifacts: [{ path: "
|
|
1237
|
+
artifacts: [{ path: join(qwenRoot, "extensions/zc-toolkit/QWEN.md"), content: "# context" }],
|
|
1169
1238
|
});
|
|
1170
1239
|
platformMocks.resolveInstallTarget.mockResolvedValue({
|
|
1171
1240
|
root: "/home/test/.qwen",
|
|
@@ -1179,7 +1248,7 @@ describe("platform CLI", () => {
|
|
|
1179
1248
|
mode: "where",
|
|
1180
1249
|
target: "qwen",
|
|
1181
1250
|
scope: "global",
|
|
1182
|
-
root:
|
|
1251
|
+
root: qwenRoot,
|
|
1183
1252
|
rootSource: "official-global",
|
|
1184
1253
|
hint: "Qwen 官方文档定义用户级配置目录为 `~/.qwen`,并在官方帮助文档中给出 Qwen CLI 的用户级 `QWEN.md` 位置为 `~/.qwen/QWEN.md`。",
|
|
1185
1254
|
}));
|