zinkee 0.1.43 → 0.1.45

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 (94) hide show
  1. package/README.md +9 -4
  2. package/dist/chunk-MHEVRMDX.js +1230 -0
  3. package/dist/chunk-MHEVRMDX.js.map +1 -0
  4. package/{src/utils/examples.ts → dist/examples-E6FFEVBE.js} +856 -1141
  5. package/dist/examples-E6FFEVBE.js.map +1 -0
  6. package/dist/index.js +1145 -8456
  7. package/dist/index.js.map +1 -1
  8. package/package.json +6 -3
  9. package/.github/workflows/npm-publish.yml +0 -77
  10. package/.github/workflows/pr-checks.yml +0 -36
  11. package/AGENTS.md +0 -110
  12. package/docs/cli-contract.md +0 -41
  13. package/docs/npm-release.md +0 -64
  14. package/docs/superpowers/plans/2026-03-24-zinkee-cli-implementation.md +0 -837
  15. package/docs/superpowers/plans/2026-03-25-cli-backend-error-contract.md +0 -503
  16. package/docs/superpowers/plans/2026-03-26-display-freeform-create.md +0 -389
  17. package/docs/superpowers/specs/2026-03-24-zinkee-cli-backend-blockers.md +0 -172
  18. package/docs/superpowers/specs/2026-03-24-zinkee-cli-design.md +0 -1576
  19. package/docs/superpowers/specs/2026-03-24-zinkee-cli-e2e-checklist.md +0 -215
  20. package/docs/superpowers/specs/2026-03-24-zinkee-cli-e2e-design.md +0 -492
  21. package/docs/superpowers/specs/2026-03-24-zinkee-cli-e2e-status.md +0 -307
  22. package/docs/superpowers/specs/2026-07-30-cli-pr-checks-design.md +0 -37
  23. package/src/api/automations.ts +0 -404
  24. package/src/api/comments.ts +0 -51
  25. package/src/api/displays.ts +0 -337
  26. package/src/api/document-templates.ts +0 -110
  27. package/src/api/files.ts +0 -50
  28. package/src/api/formulas.test.ts +0 -65
  29. package/src/api/formulas.ts +0 -67
  30. package/src/api/logs.ts +0 -34
  31. package/src/api/navigation.ts +0 -70
  32. package/src/api/records.ts +0 -184
  33. package/src/api/schemas.ts +0 -148
  34. package/src/api/teamspace.ts +0 -110
  35. package/src/cli-examples.ts +0 -130
  36. package/src/cli-runner.ts +0 -95
  37. package/src/client.test.ts +0 -189
  38. package/src/client.ts +0 -269
  39. package/src/command-registry.ts +0 -882
  40. package/src/commands/automations.test.ts +0 -1030
  41. package/src/commands/automations.ts +0 -2102
  42. package/src/commands/comments.test.ts +0 -214
  43. package/src/commands/comments.ts +0 -303
  44. package/src/commands/config.test.ts +0 -81
  45. package/src/commands/config.ts +0 -150
  46. package/src/commands/displays.test.ts +0 -1105
  47. package/src/commands/displays.ts +0 -1442
  48. package/src/commands/document-templates.test.ts +0 -569
  49. package/src/commands/document-templates.ts +0 -563
  50. package/src/commands/files.test.ts +0 -284
  51. package/src/commands/files.ts +0 -280
  52. package/src/commands/formulas.test.ts +0 -194
  53. package/src/commands/formulas.ts +0 -243
  54. package/src/commands/logs.test.ts +0 -123
  55. package/src/commands/logs.ts +0 -159
  56. package/src/commands/navigation.test.ts +0 -211
  57. package/src/commands/navigation.ts +0 -348
  58. package/src/commands/profiles.test.ts +0 -191
  59. package/src/commands/profiles.ts +0 -303
  60. package/src/commands/records.test.ts +0 -860
  61. package/src/commands/records.ts +0 -883
  62. package/src/commands/schemas.test.ts +0 -1252
  63. package/src/commands/schemas.ts +0 -890
  64. package/src/commands/teamspace.test.ts +0 -229
  65. package/src/commands/teamspace.ts +0 -546
  66. package/src/completion/engine.test.ts +0 -138
  67. package/src/completion/engine.ts +0 -168
  68. package/src/completion/install.test.ts +0 -179
  69. package/src/completion/install.ts +0 -260
  70. package/src/completion/runtime.ts +0 -150
  71. package/src/completion/scripts.ts +0 -91
  72. package/src/config.test.ts +0 -362
  73. package/src/config.ts +0 -294
  74. package/src/index.test.ts +0 -217
  75. package/src/index.ts +0 -8
  76. package/src/parsers/expressions.test.ts +0 -95
  77. package/src/parsers/expressions.ts +0 -128
  78. package/src/parsers/kv.test.ts +0 -35
  79. package/src/parsers/kv.ts +0 -49
  80. package/src/parsers/selectors.test.ts +0 -23
  81. package/src/parsers/selectors.ts +0 -29
  82. package/src/program.ts +0 -64
  83. package/src/runtime-context.ts +0 -103
  84. package/src/types.ts +0 -76
  85. package/src/utils/argv-rewrite.test.ts +0 -149
  86. package/src/utils/argv-rewrite.ts +0 -269
  87. package/src/utils/errors.test.ts +0 -85
  88. package/src/utils/errors.ts +0 -191
  89. package/src/utils/examples.test.ts +0 -374
  90. package/src/utils/output.test.ts +0 -65
  91. package/src/utils/output.ts +0 -154
  92. package/src/utils/schema-fields.ts +0 -1016
  93. package/tsconfig.json +0 -20
  94. package/tsup.config.ts +0 -13
@@ -1,563 +0,0 @@
1
- import { readFileSync, writeFileSync } from "node:fs";
2
- import { basename } from "node:path";
3
- import type { Writable } from "node:stream";
4
-
5
- import { Command, InvalidArgumentError } from "commander";
6
-
7
- import {
8
- DocumentTemplatesApi,
9
- type ApiDocumentTemplate,
10
- type CreateDocumentTemplateInput,
11
- type UpdateDocumentTemplateInput,
12
- } from "../api/document-templates.js";
13
- import { ApiClient } from "../client.js";
14
- import { defaultConfigPath, readRuntimeConfig } from "../config.js";
15
- import {
16
- normalizeUuidOrSlug,
17
- type NormalizedUuidOrSlug,
18
- } from "../parsers/selectors.js";
19
- import { resolveRuntimeContext } from "../runtime-context.js";
20
- import type { JsonObject, RuntimeOverrides } from "../types.js";
21
- import { CliError } from "../utils/errors.js";
22
- import { buildJsonSuccess, printTable } from "../utils/output.js";
23
-
24
- interface CommandIo {
25
- write(chunk: string | Uint8Array): unknown;
26
- }
27
-
28
- export interface RegisterDocumentTemplatesCommandsOptions {
29
- configPath?: string;
30
- stdout?: CommandIo;
31
- }
32
-
33
- interface GlobalOptions extends RuntimeOverrides {}
34
-
35
- interface TemplateCreateCommandOptions {
36
- name?: string;
37
- raw?: string;
38
- rawFile?: string;
39
- }
40
-
41
- interface TemplateUpdateCommandOptions {
42
- name?: string;
43
- }
44
-
45
- interface AssetAddCommandOptions {
46
- name?: string;
47
- }
48
-
49
- interface AssetDownloadCommandOptions {
50
- output?: string;
51
- }
52
-
53
- function getCommandIo(stdout: CommandIo | undefined): CommandIo {
54
- return stdout ?? (process.stdout as Writable);
55
- }
56
-
57
- function writeLine(stdout: CommandIo, value: string): void {
58
- stdout.write(`${value}\n`);
59
- }
60
-
61
- function writeBinary(stdout: CommandIo, value: ArrayBuffer): void {
62
- stdout.write(Buffer.from(value));
63
- }
64
-
65
- function getGlobalOptions(command: Command): GlobalOptions {
66
- return command.optsWithGlobals<GlobalOptions>();
67
- }
68
-
69
- function emitJson(
70
- stdout: CommandIo,
71
- commandName: string,
72
- data: unknown,
73
- configPath: string,
74
- meta: Record<string, unknown> = {},
75
- ): void {
76
- writeLine(
77
- stdout,
78
- JSON.stringify(buildJsonSuccess(data, { command: commandName, configPath, ...meta })),
79
- );
80
- }
81
-
82
- function toConfigurationError(filePath: string, error: unknown): never {
83
- if (error instanceof CliError) {
84
- throw error;
85
- }
86
-
87
- if (
88
- typeof error === "object" &&
89
- error !== null &&
90
- "code" in error &&
91
- error.code === "ENOENT"
92
- ) {
93
- throw new CliError("configuration_error", `Config file not found at ${filePath}.`);
94
- }
95
-
96
- if (error instanceof Error) {
97
- throw new CliError("configuration_error", error.message);
98
- }
99
-
100
- throw error;
101
- }
102
-
103
- function createDocumentTemplatesApi(
104
- command: Command,
105
- filePath: string,
106
- ): { api: DocumentTemplatesApi; json: boolean; readOnly: boolean } {
107
- try {
108
- const config = readRuntimeConfig(filePath);
109
- const runtime = resolveRuntimeContext(config, getGlobalOptions(command));
110
-
111
- if (!runtime.baseUrl) {
112
- throw new CliError(
113
- "configuration_error",
114
- `Resolved profile "${runtime.profile}" is missing a base URL.`,
115
- );
116
- }
117
-
118
- return {
119
- api: new DocumentTemplatesApi(
120
- new ApiClient({
121
- baseUrl: runtime.baseUrl,
122
- apiKey: runtime.apiKey,
123
- }),
124
- ),
125
- json: runtime.json,
126
- readOnly: runtime.readOnly,
127
- };
128
- } catch (error) {
129
- toConfigurationError(filePath, error);
130
- }
131
- }
132
-
133
- function ensureWritable(
134
- commandName: string,
135
- readOnly: boolean,
136
- commandMode: "write" | "destructive",
137
- ): void {
138
- if (readOnly) {
139
- throw new CliError(
140
- "command_not_allowed_in_read_only_mode",
141
- `Command "${commandName}" is not allowed in read-only mode.`,
142
- {
143
- commandMode,
144
- executionMode: "read-only",
145
- },
146
- );
147
- }
148
- }
149
-
150
- function parseUuidOrSlugSelector(input: string): NormalizedUuidOrSlug {
151
- try {
152
- return normalizeUuidOrSlug(input);
153
- } catch (error) {
154
- const message = error instanceof Error ? error.message : "Invalid selector.";
155
- throw new InvalidArgumentError(message);
156
- }
157
- }
158
-
159
- function isJsonObject(value: unknown): value is JsonObject {
160
- return typeof value === "object" && value !== null && !Array.isArray(value);
161
- }
162
-
163
- function isEmptyObject(value: object): boolean {
164
- return Object.keys(value).length === 0;
165
- }
166
-
167
- function parseJsonValue(input: string, sourceLabel: string): unknown {
168
- try {
169
- return JSON.parse(input);
170
- } catch (error) {
171
- const message = error instanceof Error ? error.message : "Invalid JSON.";
172
- throw new CliError(
173
- "invalid_cli_usage",
174
- `Failed to parse JSON from ${sourceLabel}: ${message}`,
175
- );
176
- }
177
- }
178
-
179
- function readTextFile(filePath: string, label: string): string {
180
- try {
181
- return readFileSync(filePath, "utf8");
182
- } catch (error) {
183
- const message = error instanceof Error ? error.message : "Unable to read file.";
184
- throw new CliError(
185
- "invalid_cli_usage",
186
- `Failed to read ${label} from ${filePath}: ${message}`,
187
- );
188
- }
189
- }
190
-
191
- function readJsonObjectOption(
192
- raw: string | undefined,
193
- rawFile: string | undefined,
194
- rawLabel: string,
195
- rawFileLabel: string,
196
- ): JsonObject {
197
- if (raw && rawFile) {
198
- throw new CliError(
199
- "invalid_cli_usage",
200
- `Provide either "${rawLabel}" or "${rawFileLabel}", not both.`,
201
- );
202
- }
203
-
204
- let parsed: unknown;
205
-
206
- if (raw) {
207
- parsed = parseJsonValue(raw, rawLabel);
208
- } else if (rawFile) {
209
- parsed = parseJsonValue(readTextFile(rawFile, rawFileLabel), `${rawFileLabel} ${rawFile}`);
210
- } else {
211
- return {};
212
- }
213
-
214
- if (!isJsonObject(parsed)) {
215
- throw new CliError(
216
- "invalid_cli_usage",
217
- `Expected ${raw ? rawLabel : rawFileLabel} to contain a JSON object.`,
218
- );
219
- }
220
-
221
- return parsed;
222
- }
223
-
224
- function readLocalFile(filePath: string): Buffer {
225
- try {
226
- return readFileSync(filePath);
227
- } catch (error) {
228
- const message = error instanceof Error ? error.message : "Unable to read file.";
229
- throw new CliError("invalid_cli_usage", `Failed to read file at ${filePath}: ${message}`);
230
- }
231
- }
232
-
233
- function writeDownloadedFile(outputPath: string, value: ArrayBuffer): void {
234
- try {
235
- writeFileSync(outputPath, Buffer.from(value));
236
- } catch (error) {
237
- const message = error instanceof Error ? error.message : "Unable to write file.";
238
- throw new CliError(
239
- "invalid_cli_usage",
240
- `Failed to write downloaded file to ${outputPath}: ${message}`,
241
- );
242
- }
243
- }
244
-
245
- function templateRows(templates: readonly ApiDocumentTemplate[]): Record<string, unknown>[] {
246
- return templates.map((template) => ({
247
- id: template.id ?? "",
248
- name: template.name ?? "",
249
- assetCount: Array.isArray(template.assets) ? template.assets.length : 0,
250
- updatedAt: template.updatedAt ?? "",
251
- }));
252
- }
253
-
254
- function resolveTemplate(
255
- templates: readonly ApiDocumentTemplate[],
256
- selector: NormalizedUuidOrSlug,
257
- ): ApiDocumentTemplate {
258
- if (selector.kind === "uuid") {
259
- const match = templates.find((template) => template.id === selector.value);
260
-
261
- if (match) {
262
- return match;
263
- }
264
-
265
- throw new CliError(
266
- "invalid_cli_usage",
267
- `Document template "${selector.value}" was not found.`,
268
- );
269
- }
270
-
271
- const matches = templates.filter((template) => template.name === selector.value);
272
-
273
- if (matches.length === 1) {
274
- return matches[0] as ApiDocumentTemplate;
275
- }
276
-
277
- if (matches.length > 1) {
278
- throw new CliError(
279
- "invalid_cli_usage",
280
- `Document template "${selector.value}" is ambiguous. Found ${matches.length} matches.`,
281
- );
282
- }
283
-
284
- throw new CliError(
285
- "invalid_cli_usage",
286
- `Document template "${selector.value}" was not found.`,
287
- );
288
- }
289
-
290
- async function resolveTemplateSelector(
291
- api: DocumentTemplatesApi,
292
- selector: NormalizedUuidOrSlug,
293
- ): Promise<NormalizedUuidOrSlug> {
294
- if (selector.kind === "uuid") {
295
- return selector;
296
- }
297
-
298
- const templates = await api.listTemplates();
299
- const resolved = resolveTemplate(templates, selector);
300
-
301
- if (typeof resolved.id !== "string" || resolved.id.length === 0) {
302
- throw new CliError(
303
- "invalid_cli_usage",
304
- `Document template "${selector.value}" is missing an id in the API response.`,
305
- );
306
- }
307
-
308
- return { kind: "uuid", value: resolved.id };
309
- }
310
-
311
- function buildCreateInput(
312
- options: TemplateCreateCommandOptions,
313
- ): CreateDocumentTemplateInput {
314
- const raw = readJsonObjectOption(options.raw, options.rawFile, "--raw", "--raw-file");
315
- const input: JsonObject = { ...raw };
316
-
317
- if (options.name !== undefined) {
318
- input.name = options.name;
319
- }
320
-
321
- if (typeof input.name !== "string" || input.name.trim().length === 0) {
322
- throw new CliError("invalid_cli_usage", 'Provide template name via "--name".');
323
- }
324
-
325
- if (input.assets === undefined) {
326
- input.assets = [];
327
- }
328
-
329
- return input as unknown as CreateDocumentTemplateInput;
330
- }
331
-
332
- function buildUpdateInput(
333
- options: TemplateUpdateCommandOptions,
334
- ): UpdateDocumentTemplateInput {
335
- const input: UpdateDocumentTemplateInput = {};
336
-
337
- if (options.name !== undefined) {
338
- input.name = options.name;
339
- }
340
-
341
- if (isEmptyObject(input as object)) {
342
- throw new CliError("invalid_cli_usage", 'Provide template updates via "--name".');
343
- }
344
-
345
- return input;
346
- }
347
-
348
- export function registerDocumentTemplatesCommands(
349
- program: Command,
350
- options: RegisterDocumentTemplatesCommandsOptions = {},
351
- ): void {
352
- const filePath = options.configPath ?? defaultConfigPath;
353
- const stdout = getCommandIo(options.stdout);
354
- const templates = program
355
- .command("document-templates")
356
- .description("Manage document templates and their assets");
357
-
358
- templates
359
- .command("list")
360
- .description("List document templates")
361
- .action(async function action(this: Command) {
362
- const { api, json } = createDocumentTemplatesApi(this, filePath);
363
- const data = await api.listTemplates();
364
-
365
- if (json) {
366
- emitJson(stdout, "document-templates list", data, filePath);
367
- return;
368
- }
369
-
370
- printTable(templateRows(data), ["id", "name", "assetCount", "updatedAt"], stdout);
371
- });
372
-
373
- templates
374
- .command("get")
375
- .description("Get a document template by UUID or exact name")
376
- .argument("<template>", "template UUID or exact name", parseUuidOrSlugSelector)
377
- .action(async function action(this: Command, template: NormalizedUuidOrSlug) {
378
- const { api, json } = createDocumentTemplatesApi(this, filePath);
379
- const list = await api.listTemplates();
380
- const data = resolveTemplate(list, template);
381
-
382
- if (json) {
383
- emitJson(stdout, "document-templates get", data, filePath);
384
- return;
385
- }
386
-
387
- printTable([data as Record<string, unknown>], undefined, stdout);
388
- });
389
-
390
- templates
391
- .command("create")
392
- .description("Create a document template")
393
- .option("--name <name>", "template name")
394
- .option("--raw <json>", "raw create JSON payload")
395
- .option("--raw-file <path>", "path to raw create JSON payload")
396
- .action(async function action(
397
- this: Command,
398
- commandOptions: TemplateCreateCommandOptions,
399
- ) {
400
- const { api, json, readOnly } = createDocumentTemplatesApi(this, filePath);
401
- ensureWritable("document-templates create", readOnly, "write");
402
- const data = await api.createTemplate(buildCreateInput(commandOptions));
403
-
404
- if (json) {
405
- emitJson(stdout, "document-templates create", data, filePath);
406
- return;
407
- }
408
-
409
- writeLine(stdout, `Created document template "${String(data.name ?? commandOptions.name)}".`);
410
- });
411
-
412
- templates
413
- .command("update")
414
- .description("Rename a document template")
415
- .argument("<template>", "template UUID or exact name", parseUuidOrSlugSelector)
416
- .option("--name <name>", "new template name")
417
- .action(async function action(
418
- this: Command,
419
- template: NormalizedUuidOrSlug,
420
- commandOptions: TemplateUpdateCommandOptions,
421
- ) {
422
- const { api, json, readOnly } = createDocumentTemplatesApi(this, filePath);
423
- ensureWritable("document-templates update", readOnly, "write");
424
- const resolved = await resolveTemplateSelector(api, template);
425
- const data = await api.updateTemplate(resolved, buildUpdateInput(commandOptions));
426
-
427
- if (json) {
428
- emitJson(stdout, "document-templates update", data, filePath);
429
- return;
430
- }
431
-
432
- writeLine(stdout, `Updated document template "${String(data.name ?? template.value)}".`);
433
- });
434
-
435
- templates
436
- .command("delete")
437
- .description("Delete a document template (and its assets)")
438
- .argument("<template>", "template UUID or exact name", parseUuidOrSlugSelector)
439
- .action(async function action(this: Command, template: NormalizedUuidOrSlug) {
440
- const { api, json, readOnly } = createDocumentTemplatesApi(this, filePath);
441
- ensureWritable("document-templates delete", readOnly, "destructive");
442
- const resolved = await resolveTemplateSelector(api, template);
443
- const data = await api.deleteTemplate(resolved);
444
-
445
- if (json) {
446
- emitJson(stdout, "document-templates delete", data, filePath);
447
- return;
448
- }
449
-
450
- writeLine(stdout, `Deleted document template "${template.value}".`);
451
- });
452
-
453
- const assets = templates.command("assets").description("Manage document template assets");
454
-
455
- assets
456
- .command("add")
457
- .description("Upload an asset file to a document template")
458
- .argument("<template>", "template UUID or exact name", parseUuidOrSlugSelector)
459
- .argument("<path>", "path to the local file")
460
- .option("--name <name>", "override the asset display name")
461
- .action(async function action(
462
- this: Command,
463
- template: NormalizedUuidOrSlug,
464
- localPath: string,
465
- commandOptions: AssetAddCommandOptions,
466
- ) {
467
- const { api, json, readOnly } = createDocumentTemplatesApi(this, filePath);
468
- ensureWritable("document-templates assets add", readOnly, "write");
469
-
470
- const contents = readLocalFile(localPath);
471
- const formData = new FormData();
472
- formData.append("file", new Blob([contents]), basename(localPath));
473
-
474
- if (commandOptions.name !== undefined) {
475
- formData.append("name", commandOptions.name);
476
- }
477
-
478
- const resolved = await resolveTemplateSelector(api, template);
479
- const data = await api.addAsset(resolved, formData);
480
-
481
- if (json) {
482
- emitJson(stdout, "document-templates assets add", data, filePath);
483
- return;
484
- }
485
-
486
- writeLine(
487
- stdout,
488
- `Added asset "${commandOptions.name ?? basename(localPath)}" to template "${template.value}".`,
489
- );
490
- });
491
-
492
- assets
493
- .command("delete")
494
- .description("Delete one asset from a document template")
495
- .argument("<template>", "template UUID or exact name", parseUuidOrSlugSelector)
496
- .argument("<asset>", "asset UUID")
497
- .action(async function action(
498
- this: Command,
499
- template: NormalizedUuidOrSlug,
500
- assetId: string,
501
- ) {
502
- const { api, json, readOnly } = createDocumentTemplatesApi(this, filePath);
503
- ensureWritable("document-templates assets delete", readOnly, "destructive");
504
- const resolved = await resolveTemplateSelector(api, template);
505
- const data = await api.deleteAsset(resolved, assetId);
506
-
507
- if (json) {
508
- emitJson(stdout, "document-templates assets delete", data, filePath);
509
- return;
510
- }
511
-
512
- writeLine(stdout, `Deleted asset "${assetId}" from template "${template.value}".`);
513
- });
514
-
515
- assets
516
- .command("download")
517
- .description("Download the raw bytes of a document template asset")
518
- .argument("<template>", "template UUID or exact name", parseUuidOrSlugSelector)
519
- .argument("<asset>", "asset UUID")
520
- .option("--output <path>", "write the downloaded bytes to a path")
521
- .action(async function action(
522
- this: Command,
523
- template: NormalizedUuidOrSlug,
524
- assetId: string,
525
- commandOptions: AssetDownloadCommandOptions,
526
- ) {
527
- const { api, json } = createDocumentTemplatesApi(this, filePath);
528
-
529
- if (json && !commandOptions.output) {
530
- throw new CliError(
531
- "invalid_cli_usage",
532
- 'Provide "--output" when using "--json" with "document-templates assets download".',
533
- );
534
- }
535
-
536
- const resolved = await resolveTemplateSelector(api, template);
537
- const data = await api.downloadAsset(resolved, assetId);
538
-
539
- if (commandOptions.output) {
540
- writeDownloadedFile(commandOptions.output, data);
541
-
542
- if (json) {
543
- emitJson(
544
- stdout,
545
- "document-templates assets download",
546
- {
547
- template: resolved.value,
548
- asset: assetId,
549
- output: commandOptions.output,
550
- bytes: data.byteLength,
551
- },
552
- filePath,
553
- );
554
- return;
555
- }
556
-
557
- writeLine(stdout, `Downloaded asset to "${commandOptions.output}".`);
558
- return;
559
- }
560
-
561
- writeBinary(stdout, data);
562
- });
563
- }