zinkee 0.1.23 → 0.1.25

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.
@@ -385,7 +385,7 @@ export function registerTeamspaceCommands(
385
385
  folders
386
386
  .command("list")
387
387
  .description("List teamspace folders")
388
- .option("--include-resources", "include nested resources")
388
+ .option("--include-resources", "include the published resources inside each folder")
389
389
  .action(async function action(this: Command, commandOptions: FolderListCommandOptions) {
390
390
  const { api, json } = createTeamspaceApi(this, filePath);
391
391
  const data = await api.listFolders(Boolean(commandOptions.includeResources));
@@ -402,7 +402,7 @@ export function registerTeamspaceCommands(
402
402
  .command("get")
403
403
  .description("Get a teamspace folder by exact name or UUID")
404
404
  .argument("<folder>", "folder UUID or exact name", parseUuidOrSlugSelector)
405
- .option("--include-resources", "include nested resources")
405
+ .option("--include-resources", "include the published resources inside each folder")
406
406
  .action(async function action(
407
407
  this: Command,
408
408
  folder: NormalizedUuidOrSlug,
@@ -425,9 +425,9 @@ export function registerTeamspaceCommands(
425
425
  .command("create")
426
426
  .description("Create a teamspace folder")
427
427
  .requiredOption("--name <name>", "folder name")
428
- .option("--order <n>", "folder order", parseNonNegativeInteger)
429
- .option("--props <json>", "folder properties payload")
430
- .option("--props-file <path>", "path to a folder properties JSON payload")
428
+ .option("--order <n>", "display order (lower values appear first)", parseNonNegativeInteger)
429
+ .option("--props <json>", "additionalProperties JSON: free-form client metadata, e.g. {\"icon\":\"folder-users\",\"color\":\"gold\"}")
430
+ .option("--props-file <path>", "path to a file with the additionalProperties JSON")
431
431
  .action(async function action(
432
432
  this: Command,
433
433
  commandOptions: FolderCreateCommandOptions,
@@ -450,9 +450,9 @@ export function registerTeamspaceCommands(
450
450
  .description("Update a teamspace folder")
451
451
  .argument("<folder>", "folder UUID or exact name", parseUuidOrSlugSelector)
452
452
  .option("--name <name>", "folder name")
453
- .option("--order <n>", "folder order", parseNonNegativeInteger)
454
- .option("--props <json>", "folder properties payload")
455
- .option("--props-file <path>", "path to a folder properties JSON payload")
453
+ .option("--order <n>", "display order (lower values appear first)", parseNonNegativeInteger)
454
+ .option("--props <json>", "additionalProperties JSON: free-form client metadata, e.g. {\"icon\":\"folder-users\",\"color\":\"gold\"}")
455
+ .option("--props-file <path>", "path to a file with the additionalProperties JSON")
456
456
  .action(async function action(
457
457
  this: Command,
458
458
  folder: NormalizedUuidOrSlug,
@@ -495,9 +495,15 @@ export function registerTeamspaceCommands(
495
495
 
496
496
  resources
497
497
  .command("publish")
498
- .description("Publish a resource to a teamspace folder")
499
- .argument("<resource>", "resource UUID or exact name", parseUuidOrSlugSelector)
500
- .requiredOption("--to <folder>", "target folder", parseUuidOrSlugSelector)
498
+ .description(
499
+ "Publish a resource to a teamspace folder. Publishing an already-published resource moves it to the new folder.",
500
+ )
501
+ .argument("<resource>", "schema UUID, schema slug, or display UUID", parseUuidOrSlugSelector)
502
+ .requiredOption(
503
+ "--to <folder>",
504
+ "target folder UUID or exact name (root folder UUID is 00000000-0000-0000-0000-000000000000)",
505
+ parseUuidOrSlugSelector,
506
+ )
501
507
  .action(async function action(
502
508
  this: Command,
503
509
  resource: NormalizedUuidOrSlug,
@@ -522,8 +528,8 @@ export function registerTeamspaceCommands(
522
528
 
523
529
  resources
524
530
  .command("unpublish")
525
- .description("Unpublish a resource from teamspace")
526
- .argument("<resource>", "resource UUID or exact name", parseUuidOrSlugSelector)
531
+ .description("Unpublish a resource from teamspace (removes it from its shared folder)")
532
+ .argument("<resource>", "schema UUID, schema slug, or display UUID", parseUuidOrSlugSelector)
527
533
  .action(async function action(this: Command, resource: NormalizedUuidOrSlug) {
528
534
  const { api, json, readOnly } = createTeamspaceApi(this, filePath);
529
535
  ensureWritable("teamspace resources unpublish", readOnly, "write");
package/src/program.ts CHANGED
@@ -6,6 +6,7 @@ import { registerConfigCommands } from "./commands/config.js";
6
6
  import { registerAutomationsCommands } from "./commands/automations.js";
7
7
  import { registerCommentsCommands } from "./commands/comments.js";
8
8
  import { registerDisplaysCommands } from "./commands/displays.js";
9
+ import { registerDocumentTemplatesCommands } from "./commands/document-templates.js";
9
10
  import { registerFilesCommands } from "./commands/files.js";
10
11
  import { registerLogsCommands } from "./commands/logs.js";
11
12
  import { registerNavigationCommands } from "./commands/navigation.js";
@@ -48,6 +49,7 @@ export function buildProgram(options: BuildProgramOptions = {}): Command {
48
49
  registerAutomationsCommands(program, options);
49
50
  registerConfigCommands(program, options);
50
51
  registerDisplaysCommands(program, options);
52
+ registerDocumentTemplatesCommands(program, options);
51
53
  registerFilesCommands(program, options);
52
54
  registerNavigationCommands(program, options);
53
55
  registerSchemasCommands(program, options);
@@ -211,14 +211,23 @@ describe("getCommandExamples", () => {
211
211
  expect(rawPayloads.some((raw) => raw.includes('"dynamicOption": "thisMonth"'))).toBe(true);
212
212
  });
213
213
 
214
- it("covers SCHEMA, WORKFLOW and DISPLAY variants in navigation resources move", () => {
214
+ it("documents navigation resources move as schema-only with no resourceType", () => {
215
215
  const examples = getCommandExamples("navigation resources move");
216
216
  const rawPayloads = examples.map((example) => example.raw ?? "");
217
217
 
218
- expect(examples.length).toBeGreaterThanOrEqual(5);
219
- for (const resourceType of ["SCHEMA", "WORKFLOW", "DISPLAY", "SCHEDULE"]) {
220
- expect(rawPayloads.some((raw) => raw.includes(`"resourceType": "${resourceType}"`))).toBe(true);
218
+ expect(examples.length).toBeGreaterThanOrEqual(2);
219
+ // Navigation only moves schemas now, so the payload no longer carries a
220
+ // resourceType and the example commands must not pass --type.
221
+ for (const raw of rawPayloads) {
222
+ expect(raw).not.toContain("resourceType");
221
223
  }
224
+ for (const example of examples) {
225
+ expect(example.command).not.toContain("--type");
226
+ }
227
+ // Covers moving into a folder and back to the root folder.
228
+ expect(
229
+ rawPayloads.some((raw) => raw.includes('"targetFolderId": "00000000-0000-0000-0000-000000000000"')),
230
+ ).toBe(true);
222
231
  });
223
232
 
224
233
  it("covers slug and UUID variants in teamspace resources publish", () => {
@@ -818,12 +818,12 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
818
818
  ]),
819
819
  "navigation resources move": buildCommandExamples([
820
820
  {
821
- description: "Move a schema into a navigation folder.",
821
+ description:
822
+ "Move a schema into a navigation folder. Only schemas can be moved; the navigation menu holds databases.",
822
823
  command:
823
- 'zinkee --json navigation resources move 2eb8bdcf-6d9c-4fbb-9018-7fa8180f4c5e --type SCHEMA --to Sales',
824
+ 'zinkee --json navigation resources move 2eb8bdcf-6d9c-4fbb-9018-7fa8180f4c5e --to Sales',
824
825
  raw: `{
825
826
  "resourceId": "2eb8bdcf-6d9c-4fbb-9018-7fa8180f4c5e",
826
- "resourceType": "SCHEMA",
827
827
  "targetFolderId": "84a0fca4-37ef-4c83-a8ed-9ef67ad9324a"
828
828
  }`,
829
829
  response: `{
@@ -832,43 +832,12 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
832
832
  }`,
833
833
  },
834
834
  {
835
- description: "Move a workflow.",
836
- command:
837
- 'zinkee --json navigation resources move 3f8a2c1b-9d4e-4a5b-8c6d-7e8f90123456 --type WORKFLOW --to Operations',
838
- raw: `{
839
- "resourceId": "3f8a2c1b-9d4e-4a5b-8c6d-7e8f90123456",
840
- "resourceType": "WORKFLOW",
841
- "targetFolderId": "b8c9d0e1-f2a3-4b5c-6d7e-8f9012345678"
842
- }`,
843
- },
844
- {
845
- description: "Move a display.",
835
+ description: "Move a schema back to the root folder (root is always UUID 00000000-0000-0000-0000-000000000000).",
846
836
  command:
847
- 'zinkee --json navigation resources move 0f6f062f-1478-4df2-96a1-c495d037d260 --type DISPLAY --to Operations',
848
- raw: `{
849
- "resourceId": "0f6f062f-1478-4df2-96a1-c495d037d260",
850
- "resourceType": "DISPLAY",
851
- "targetFolderId": "b8c9d0e1-f2a3-4b5c-6d7e-8f9012345678"
852
- }`,
853
- },
854
- {
855
- description: "Move a resource back to the root folder (root is always UUID 00000000-0000-0000-0000-000000000000).",
856
- command:
857
- 'zinkee --json navigation resources move 5223cbc8-8c6c-4694-93bc-dd176364df9b --type SCHEMA --to 00000000-0000-0000-0000-000000000000',
837
+ 'zinkee --json navigation resources move 5223cbc8-8c6c-4694-93bc-dd176364df9b --to 00000000-0000-0000-0000-000000000000',
858
838
  raw: `{
859
839
  "resourceId": "5223cbc8-8c6c-4694-93bc-dd176364df9b",
860
- "resourceType": "SCHEMA",
861
840
  "targetFolderId": "00000000-0000-0000-0000-000000000000"
862
- }`,
863
- },
864
- {
865
- description: "Move a schedule resource.",
866
- command:
867
- 'zinkee --json navigation resources move a1b2c3d4-e5f6-7890-1234-567890abcdef --type SCHEDULE --to Operations',
868
- raw: `{
869
- "resourceId": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
870
- "resourceType": "SCHEDULE",
871
- "targetFolderId": "b8c9d0e1-f2a3-4b5c-6d7e-8f9012345678"
872
841
  }`,
873
842
  },
874
843
  ]),
@@ -2421,7 +2390,7 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
2421
2390
  "resources": [
2422
2391
  {
2423
2392
  "id": "2eb8bdcf-6d9c-4fbb-9018-7fa8180f4c5e",
2424
- "name": "Contacts",
2393
+ "name": "Customer records",
2425
2394
  "type": "SCHEMA",
2426
2395
  "isInSpace": false,
2427
2396
  "additionalProperties": {}
@@ -2445,19 +2414,10 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
2445
2414
  "resources": [
2446
2415
  {
2447
2416
  "id": "3f8a2c1b-9d4e-4a5b-8c6d-7e8f90123456",
2448
- "name": "Quote approval",
2449
- "type": "WORKFLOW",
2417
+ "name": "Shipments",
2418
+ "type": "SCHEMA",
2450
2419
  "isInSpace": false,
2451
2420
  "additionalProperties": {}
2452
- },
2453
- {
2454
- "id": "0f6f062f-1478-4df2-96a1-c495d037d260",
2455
- "name": "Executive Revenue",
2456
- "type": "DISPLAY",
2457
- "isInSpace": true,
2458
- "additionalProperties": {
2459
- "pinned": true
2460
- }
2461
2421
  }
2462
2422
  ],
2463
2423
  "additionalProperties": {
@@ -2504,8 +2464,13 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
2504
2464
  "name": "Shared Dashboards",
2505
2465
  "order": 1,
2506
2466
  "isRoot": false,
2507
- "resourceCount": 1,
2467
+ "resourceCount": 2,
2508
2468
  "resources": [
2469
+ {
2470
+ "id": "2eb8bdcf-6d9c-4fbb-9018-7fa8180f4c5e",
2471
+ "name": "Customer records",
2472
+ "type": "SCHEMA"
2473
+ },
2509
2474
  {
2510
2475
  "id": "0f6f062f-1478-4df2-96a1-c495d037d260",
2511
2476
  "name": "Executive Revenue",
@@ -2727,6 +2692,85 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
2727
2692
  command: "zinkee --json displays delete 0f6f062f-1478-4df2-96a1-c495d037d260",
2728
2693
  },
2729
2694
  ]),
2695
+ "displays folders list": buildCommandExamples([
2696
+ {
2697
+ description: "List flat display folders (non-root folders plus the root bucket).",
2698
+ command: "zinkee --json displays folders list",
2699
+ response: `[
2700
+ {
2701
+ "id": "e7a1c3d2-5f4b-4a6c-9d8e-1f2a3b4c5d6e",
2702
+ "name": "Executive Dashboards",
2703
+ "isRoot": false,
2704
+ "displayCount": 2
2705
+ },
2706
+ {
2707
+ "id": "8b22282b-3db3-4dd7-87f7-b29365dcf3f6",
2708
+ "name": null,
2709
+ "isRoot": true,
2710
+ "displayCount": 4
2711
+ }
2712
+ ]`,
2713
+ },
2714
+ ]),
2715
+ "displays folders create": buildCommandExamples([
2716
+ {
2717
+ description: "Create one flat display folder.",
2718
+ command: 'zinkee --json displays folders create --name "Executive Dashboards"',
2719
+ raw: `{
2720
+ "name": "Executive Dashboards"
2721
+ }`,
2722
+ response: `{
2723
+ "id": "e7a1c3d2-5f4b-4a6c-9d8e-1f2a3b4c5d6e",
2724
+ "name": "Executive Dashboards",
2725
+ "isRoot": false,
2726
+ "displayCount": 0
2727
+ }`,
2728
+ },
2729
+ ]),
2730
+ "displays folders update": buildCommandExamples([
2731
+ {
2732
+ description: "Rename a display folder. The folder argument accepts a UUID or an exact name.",
2733
+ command:
2734
+ 'zinkee --json displays folders update "Executive Dashboards" --name "Executive Dashboards (2026)"',
2735
+ raw: `{
2736
+ "name": "Executive Dashboards (2026)"
2737
+ }`,
2738
+ response: `{
2739
+ "id": "e7a1c3d2-5f4b-4a6c-9d8e-1f2a3b4c5d6e",
2740
+ "name": "Executive Dashboards (2026)",
2741
+ "isRoot": false,
2742
+ "displayCount": 2
2743
+ }`,
2744
+ },
2745
+ ]),
2746
+ "displays folders delete": buildCommandExamples([
2747
+ {
2748
+ description: "Delete a non-root display folder. Its displays move back to the root folder.",
2749
+ command: 'zinkee --json displays folders delete "Executive Dashboards"',
2750
+ response: `{
2751
+ "id": "e7a1c3d2-5f4b-4a6c-9d8e-1f2a3b4c5d6e",
2752
+ "name": "Executive Dashboards",
2753
+ "isRoot": false,
2754
+ "displayCount": 2
2755
+ }`,
2756
+ },
2757
+ ]),
2758
+ "displays folders move": buildCommandExamples([
2759
+ {
2760
+ description: "Move one display into a target folder by exact folder name.",
2761
+ command:
2762
+ 'zinkee --json displays folders move 0f6f062f-1478-4df2-96a1-c495d037d260 --to "Executive Dashboards"',
2763
+ raw: `{
2764
+ "displayId": "0f6f062f-1478-4df2-96a1-c495d037d260",
2765
+ "targetFolderId": "e7a1c3d2-5f4b-4a6c-9d8e-1f2a3b4c5d6e"
2766
+ }`,
2767
+ response: `{
2768
+ "id": "e7a1c3d2-5f4b-4a6c-9d8e-1f2a3b4c5d6e",
2769
+ "name": "Executive Dashboards",
2770
+ "isRoot": false
2771
+ }`,
2772
+ },
2773
+ ]),
2730
2774
  "displays layout get": buildCommandExamples([
2731
2775
  {
2732
2776
  description: "Get the layout block of a display (template + tabs/freeformLayouts/slots).",
@@ -3797,7 +3841,8 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
3797
3841
  description: "Move one automation into a target folder by exact folder name.",
3798
3842
  command: 'zinkee --json automations folders move automation-1 --to "Codex Frontend Demo"',
3799
3843
  raw: `{
3800
- "automationId": "automation-1"
3844
+ "automationId": "automation-1",
3845
+ "targetFolderId": "cdfc14e3-3169-4ffb-8d9b-b11858a9240f"
3801
3846
  }`,
3802
3847
  response: `{
3803
3848
  "id": "cdfc14e3-3169-4ffb-8d9b-b11858a9240f",
@@ -3806,6 +3851,191 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
3806
3851
  }`,
3807
3852
  },
3808
3853
  ]),
3854
+ "document-templates list": buildCommandExamples([
3855
+ {
3856
+ description:
3857
+ "List every document template in the workspace. Each asset's link is a relative path to the asset download endpoint, ready to call without composition.",
3858
+ command: "zinkee --json document-templates list",
3859
+ response: `[
3860
+ {
3861
+ "id": "7c4a8d3f-1b2e-4a5c-9d6e-1f2a3b4c5d6e",
3862
+ "name": "Quarterly report",
3863
+ "assets": [
3864
+ {
3865
+ "id": "9e8d7c6b-5a4f-3e2d-1c0b-9a8b7c6d5e4f",
3866
+ "name": "Requirements.docx",
3867
+ "link": "/api/v2/document-templates/7c4a8d3f-1b2e-4a5c-9d6e-1f2a3b4c5d6e/assets/9e8d7c6b-5a4f-3e2d-1c0b-9a8b7c6d5e4f/download"
3868
+ }
3869
+ ],
3870
+ "createdAt": "2026-01-15T10:00:00Z",
3871
+ "updatedAt": "2026-01-20T14:30:00Z",
3872
+ "createdBy": "creator@example.com",
3873
+ "updatedBy": "updater@example.com"
3874
+ }
3875
+ ]`,
3876
+ },
3877
+ ]),
3878
+ "document-templates get": buildCommandExamples([
3879
+ {
3880
+ description:
3881
+ "Look up one template by UUID. The CLI filters the list endpoint locally (the backend does not expose a get-one route).",
3882
+ command:
3883
+ "zinkee --json document-templates get 7c4a8d3f-1b2e-4a5c-9d6e-1f2a3b4c5d6e",
3884
+ response: `{
3885
+ "id": "7c4a8d3f-1b2e-4a5c-9d6e-1f2a3b4c5d6e",
3886
+ "name": "Quarterly report",
3887
+ "assets": [
3888
+ {
3889
+ "id": "9e8d7c6b-5a4f-3e2d-1c0b-9a8b7c6d5e4f",
3890
+ "name": "Requirements.docx",
3891
+ "link": "/api/v2/document-templates/7c4a8d3f-1b2e-4a5c-9d6e-1f2a3b4c5d6e/assets/9e8d7c6b-5a4f-3e2d-1c0b-9a8b7c6d5e4f/download"
3892
+ }
3893
+ ],
3894
+ "createdAt": "2026-01-15T10:00:00Z",
3895
+ "updatedAt": "2026-01-20T14:30:00Z",
3896
+ "createdBy": "creator@example.com",
3897
+ "updatedBy": "creator@example.com"
3898
+ }`,
3899
+ },
3900
+ {
3901
+ description:
3902
+ "Look up by exact template name. Names are unique within the workspace; ambiguity is reported as an error.",
3903
+ command: 'zinkee --json document-templates get "Quarterly report"',
3904
+ },
3905
+ ]),
3906
+ "document-templates create": buildCommandExamples([
3907
+ {
3908
+ description:
3909
+ "Typical create: empty template by name. Assets are uploaded afterwards via document-templates assets add.",
3910
+ command: 'zinkee --json document-templates create --name "Quarterly report"',
3911
+ raw: `{
3912
+ "name": "Quarterly report",
3913
+ "assets": []
3914
+ }`,
3915
+ response: `{
3916
+ "id": "7c4a8d3f-1b2e-4a5c-9d6e-1f2a3b4c5d6e",
3917
+ "name": "Quarterly report",
3918
+ "assets": [],
3919
+ "createdAt": "2026-01-15T10:00:00Z",
3920
+ "updatedAt": "2026-01-15T10:00:00Z",
3921
+ "createdBy": "creator@example.com",
3922
+ "updatedBy": "creator@example.com"
3923
+ }`,
3924
+ },
3925
+ {
3926
+ description:
3927
+ "Create with pre-existing asset records via --raw. Used for import/migration flows where the assets already exist elsewhere; the typical UX is to create empty and upload via assets add.",
3928
+ command:
3929
+ `zinkee --json document-templates create --raw '{"name":"Annual report","assets":[{"id":"9e8d7c6b-5a4f-3e2d-1c0b-9a8b7c6d5e4f","name":"Cover.docx","link":"/existing/cover.docx"},{"id":"3f2e1d0c-9b8a-7654-3210-fedcba987654","name":"Appendix.docx","link":"/existing/appendix.docx"}]}'`,
3930
+ raw: `{
3931
+ "name": "Annual report",
3932
+ "assets": [
3933
+ {
3934
+ "id": "9e8d7c6b-5a4f-3e2d-1c0b-9a8b7c6d5e4f",
3935
+ "name": "Cover.docx",
3936
+ "link": "/existing/cover.docx"
3937
+ },
3938
+ {
3939
+ "id": "3f2e1d0c-9b8a-7654-3210-fedcba987654",
3940
+ "name": "Appendix.docx",
3941
+ "link": "/existing/appendix.docx"
3942
+ }
3943
+ ]
3944
+ }`,
3945
+ },
3946
+ ]),
3947
+ "document-templates update": buildCommandExamples([
3948
+ {
3949
+ description:
3950
+ "Rename a template. The template argument accepts a UUID or an exact current name. Only the name is updatable through this endpoint; assets are managed via the assets subcommands.",
3951
+ command:
3952
+ 'zinkee --json document-templates update "Quarterly report" --name "Annual report"',
3953
+ raw: `{
3954
+ "name": "Annual report"
3955
+ }`,
3956
+ response: `{
3957
+ "id": "7c4a8d3f-1b2e-4a5c-9d6e-1f2a3b4c5d6e",
3958
+ "name": "Annual report",
3959
+ "assets": [
3960
+ {
3961
+ "id": "9e8d7c6b-5a4f-3e2d-1c0b-9a8b7c6d5e4f",
3962
+ "name": "Requirements.docx",
3963
+ "link": "/api/v2/document-templates/7c4a8d3f-1b2e-4a5c-9d6e-1f2a3b4c5d6e/assets/9e8d7c6b-5a4f-3e2d-1c0b-9a8b7c6d5e4f/download"
3964
+ }
3965
+ ],
3966
+ "createdAt": "2026-01-15T10:00:00Z",
3967
+ "updatedAt": "2026-01-22T09:15:00Z",
3968
+ "createdBy": "creator@example.com",
3969
+ "updatedBy": "updater@example.com"
3970
+ }`,
3971
+ },
3972
+ ]),
3973
+ "document-templates delete": buildCommandExamples([
3974
+ {
3975
+ description:
3976
+ "Delete a template and remove its asset files from storage. Record fields that reference previously generated documents are not modified.",
3977
+ command:
3978
+ "zinkee --json document-templates delete 7c4a8d3f-1b2e-4a5c-9d6e-1f2a3b4c5d6e",
3979
+ response: `{
3980
+ "id": "7c4a8d3f-1b2e-4a5c-9d6e-1f2a3b4c5d6e",
3981
+ "deleted": true
3982
+ }`,
3983
+ },
3984
+ ]),
3985
+ "document-templates assets add": buildCommandExamples([
3986
+ {
3987
+ description:
3988
+ "Upload a local file as an asset of a template. The CLI sends a multipart form with a part named \"file\"; the asset display name defaults to the uploaded filename.",
3989
+ command:
3990
+ 'zinkee --json document-templates assets add "Quarterly report" ./contract.docx',
3991
+ response: `{
3992
+ "id": "7c4a8d3f-1b2e-4a5c-9d6e-1f2a3b4c5d6e",
3993
+ "name": "Quarterly report",
3994
+ "assets": [
3995
+ {
3996
+ "id": "9e8d7c6b-5a4f-3e2d-1c0b-9a8b7c6d5e4f",
3997
+ "name": "contract.docx",
3998
+ "link": "/api/v2/document-templates/7c4a8d3f-1b2e-4a5c-9d6e-1f2a3b4c5d6e/assets/9e8d7c6b-5a4f-3e2d-1c0b-9a8b7c6d5e4f/download"
3999
+ }
4000
+ ],
4001
+ "createdAt": "2026-01-15T10:00:00Z",
4002
+ "updatedAt": "2026-01-22T09:15:00Z",
4003
+ "createdBy": "creator@example.com",
4004
+ "updatedBy": "updater@example.com"
4005
+ }`,
4006
+ },
4007
+ {
4008
+ description:
4009
+ "Override the asset display name with --name (otherwise the uploaded filename is used).",
4010
+ command:
4011
+ 'zinkee --json document-templates assets add "Quarterly report" ./contract.docx --name "Customer Contract"',
4012
+ },
4013
+ ]),
4014
+ "document-templates assets delete": buildCommandExamples([
4015
+ {
4016
+ description: "Delete one asset from a template and remove its file from storage.",
4017
+ command:
4018
+ "zinkee --json document-templates assets delete 7c4a8d3f-1b2e-4a5c-9d6e-1f2a3b4c5d6e 9e8d7c6b-5a4f-3e2d-1c0b-9a8b7c6d5e4f",
4019
+ response: `{
4020
+ "id": "9e8d7c6b-5a4f-3e2d-1c0b-9a8b7c6d5e4f",
4021
+ "deleted": true
4022
+ }`,
4023
+ },
4024
+ ]),
4025
+ "document-templates assets download": buildCommandExamples([
4026
+ {
4027
+ description:
4028
+ "Download asset bytes to disk. The CLI streams the raw bytes to --output; in --json mode --output is required and the JSON envelope only carries metadata.",
4029
+ command:
4030
+ "zinkee --json document-templates assets download 7c4a8d3f-1b2e-4a5c-9d6e-1f2a3b4c5d6e 9e8d7c6b-5a4f-3e2d-1c0b-9a8b7c6d5e4f --output ./contract.docx",
4031
+ },
4032
+ {
4033
+ description:
4034
+ "Stream asset bytes to stdout (omit --json and --output). Useful for piping into other tools.",
4035
+ command:
4036
+ "zinkee document-templates assets download 7c4a8d3f-1b2e-4a5c-9d6e-1f2a3b4c5d6e 9e8d7c6b-5a4f-3e2d-1c0b-9a8b7c6d5e4f > contract.docx",
4037
+ },
4038
+ ]),
3809
4039
  };
3810
4040
 
3811
4041
  function fallbackExamples(commandName: string): readonly CommandExample[] {