zinkee 0.1.35 → 0.1.36

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zinkee",
3
- "version": "0.1.35",
3
+ "version": "0.1.36",
4
4
  "description": "CLI for Zinkee API v2",
5
5
  "type": "module",
6
6
  "bin": {
@@ -56,7 +56,28 @@ export function extractExampleRequest(
56
56
  const cmdPath = findCommandPath(operands, commandRegistry);
57
57
 
58
58
  if (!cmdPath) {
59
- throw new CliError("invalid_cli_usage", 'Provide a command after "--example".');
59
+ const typed = operands.map((operand) => operand.token).join(" ");
60
+
61
+ if (typed.length === 0) {
62
+ throw new CliError("invalid_cli_usage", 'Provide a command after "--example".');
63
+ }
64
+
65
+ // The token(s) didn't resolve to a runnable command. If they form the prefix
66
+ // of one or more registered commands, the user named a command group (e.g.
67
+ // "schemas") — list its subcommands instead of the generic error.
68
+ const subcommands = Object.keys(commandRegistry).filter((name) =>
69
+ name.startsWith(`${typed} `),
70
+ );
71
+
72
+ if (subcommands.length > 0) {
73
+ const list = subcommands.map((name) => ` zinkee --example ${name}`).join("\n");
74
+ throw new CliError(
75
+ "invalid_cli_usage",
76
+ `"${typed}" is a command group, not a runnable command. Available subcommands:\n${list}`,
77
+ );
78
+ }
79
+
80
+ throw new CliError("invalid_cli_usage", `Unknown command "${typed}".`);
60
81
  }
61
82
 
62
83
  const remainingTokens = userArgs.slice(cmdPath.lastArgvIndex + 1);
package/src/index.test.ts CHANGED
@@ -114,6 +114,32 @@ describe("project bootstrap", () => {
114
114
  });
115
115
  });
116
116
 
117
+ it("rejects a command group by listing all its subcommands", () => {
118
+ let message = "";
119
+ try {
120
+ extractExampleRequest(["node", "zinkee", "--example", "schemas"]);
121
+ } catch (error) {
122
+ message = (error as Error).message;
123
+ }
124
+
125
+ expect(message).toContain('"schemas" is a command group');
126
+ expect(message).toContain("zinkee --example schemas list");
127
+ expect(message).toContain("zinkee --example schemas get");
128
+ expect(message).toContain("zinkee --example schemas fields create");
129
+ });
130
+
131
+ it("reports an unknown command after --example", () => {
132
+ expect(() =>
133
+ extractExampleRequest(["node", "zinkee", "--example", "frobnicate"]),
134
+ ).toThrowError('Unknown command "frobnicate".');
135
+ });
136
+
137
+ it("still asks for a command when --example has no operand", () => {
138
+ expect(() => extractExampleRequest(["node", "zinkee", "--example"])).toThrowError(
139
+ 'Provide a command after "--example".',
140
+ );
141
+ });
142
+
117
143
  it("shows field examples filtered by type", async () => {
118
144
  let output = "";
119
145
 
@@ -334,6 +334,22 @@ describe("getCommandExamples", () => {
334
334
  expect(getCommandExamples("config validate")[0]?.response).toContain('"valid": true');
335
335
  });
336
336
 
337
+ it("wraps example responses in the { data, meta } JSON envelope", () => {
338
+ const listExample = getCommandExamples("schemas list")[0];
339
+ const parsed = JSON.parse(listExample?.response ?? "{}");
340
+
341
+ expect(parsed).toHaveProperty("data");
342
+ expect(parsed).toHaveProperty("meta");
343
+ expect(parsed.meta).toMatchObject({ command: "schemas list" });
344
+ expect(Array.isArray(parsed.data)).toBe(true);
345
+
346
+ // get/detail commands wrap a single object under data, not an array
347
+ const getExample = getCommandExamples("schemas get")[0];
348
+ const parsedGet = JSON.parse(getExample?.response ?? "{}");
349
+ expect(Array.isArray(parsedGet.data)).toBe(false);
350
+ expect(parsedGet.data).toHaveProperty("fields");
351
+ });
352
+
337
353
  it.each(Object.keys(commandRegistry))(
338
354
  "returns at least one example for %s",
339
355
  (commandName) => {
@@ -2,6 +2,7 @@ import {
2
2
  getSchemaFieldTypeDefinitions,
3
3
  resolveSchemaFieldType,
4
4
  } from "./schema-fields.js";
5
+ import { buildJsonSuccess } from "./output.js";
5
6
 
6
7
  export interface CommandExample {
7
8
  command: string;
@@ -2243,7 +2244,7 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
2243
2244
  "required": false,
2244
2245
  "system": false,
2245
2246
  "config": {
2246
- "formulaText": "date_format(d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90, \"AAAA-MM\")",
2247
+ "formulaText": "date_format(d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90, \\"AAAA-MM\\")",
2247
2248
  "uiFormatKind": "date",
2248
2249
  "status": "ACTIVE",
2249
2250
  "defaultValue": null,
@@ -4336,11 +4337,37 @@ export function getCommandExamples(
4336
4337
  commandName: string,
4337
4338
  filters: { type?: string } = {},
4338
4339
  ): readonly CommandExample[] {
4339
- if (commandName === "schemas fields create") {
4340
- return buildSchemaFieldCreateExamples(filters.type);
4340
+ const examples =
4341
+ commandName === "schemas fields create"
4342
+ ? buildSchemaFieldCreateExamples(filters.type)
4343
+ : (specificExamples[commandName] ?? fallbackExamples(commandName));
4344
+
4345
+ return examples.map((example) => withResponseEnvelope(example, commandName));
4346
+ }
4347
+
4348
+ // The CLI's --json output wraps every payload in a { data, meta } envelope (see
4349
+ // buildJsonSuccess in ./output). Example "response" bodies are authored as the
4350
+ // bare data payload for readability, so we wrap them here to match what the
4351
+ // command actually prints. Non-JSON responses (if any) are left untouched.
4352
+ function withResponseEnvelope(
4353
+ example: CommandExample,
4354
+ commandName: string,
4355
+ ): CommandExample {
4356
+ if (example.response === undefined) {
4357
+ return example;
4341
4358
  }
4342
4359
 
4343
- return specificExamples[commandName] ?? fallbackExamples(commandName);
4360
+ let payload: unknown;
4361
+ try {
4362
+ payload = JSON.parse(example.response);
4363
+ } catch {
4364
+ return example;
4365
+ }
4366
+
4367
+ return {
4368
+ ...example,
4369
+ response: JSON.stringify(buildJsonSuccess(payload, { command: commandName }), null, 2),
4370
+ };
4344
4371
  }
4345
4372
 
4346
4373
  export function getResolvedCommandExamples(
@@ -1,70 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(npm test *)",
5
- "Bash(npm run *)",
6
- "Bash(pnpm typecheck *)",
7
- "Bash(pnpm test *)",
8
- "Bash(npx tsc *)",
9
- "Read(//home/guillermo/dev/z2-backend/api/src/main/java/com/zinkee/api/domain/model/v2/log/**)",
10
- "Read(//home/guillermo/dev/z2-backend/**)",
11
- "Bash(grep *)",
12
- "Bash(npx vitest *)",
13
- "Bash(npx tsx *)",
14
- "Bash(node dist/index.js --help)",
15
- "Bash(gh repo *)",
16
- "WebFetch(domain:github.com)",
17
- "Bash(git config *)",
18
- "Read(//home/guillermo/.config/**)",
19
- "Read(//home/guillermo/**)",
20
- "Bash(curl *)",
21
- "Bash(node dist/index.js --show-completion zsh)",
22
- "Bash(node *)",
23
- "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee\" COMP_CWORD=1 node *)",
24
- "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee schemas\" COMP_CWORD=2 node *)",
25
- "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee schemas fields\" COMP_CWORD=3 node dist/index.js)",
26
- "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee schemas fields cr\" COMP_CWORD=3 node dist/index.js)",
27
- "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee schemas list --j\" COMP_CWORD=3 node dist/index.js)",
28
- "Bash(rm -rf /tmp/zinkee-install)",
29
- "Bash(mkdir -p /tmp/zinkee-install)",
30
- "Bash(HOME=/tmp/zinkee-install SHELL=/bin/zsh node dist/index.js --install-completion)",
31
- "Read(//tmp/**)",
32
- "Read(//tmp/zinkee-install/**)",
33
- "Bash(rm -rf /tmp/zinkee-install-bash)",
34
- "Bash(mkdir -p /tmp/zinkee-install-bash)",
35
- "Bash(HOME=/tmp/zinkee-install-bash SHELL=/bin/bash node dist/index.js --install-completion)",
36
- "Bash(rm -rf /tmp/zinkee-install-fish)",
37
- "Bash(mkdir -p /tmp/zinkee-install-fish)",
38
- "Bash(_ZINKEE_COMPLETE=zsh_complete node dist/index.js)",
39
- "Bash(echo \"exit: $?\")",
40
- "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee schemas\" COMP_CWORD=abc node dist/index.js)",
41
- "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee config show --foo --bar baz quux ?\" COMP_CWORD=10 node dist/index.js)",
42
- "Bash(git -C /home/guillermo/dev/cli status)",
43
- "Bash(git -C /home/guillermo/dev/cli branch --show-current)",
44
- "Bash(git -C /home/guillermo/dev/cli diff --stat)",
45
- "Bash(git fetch *)",
46
- "Bash(pnpm exec *)",
47
- "Bash(echo \"=== exit $? \\(grep\\) ===\")",
48
- "Bash(grep -rn \"resourceType\" src/)",
49
- "Bash(grep -rn \"automation-folders/\\\\${\\\\|/automations:move\\\\|{folderId}/automations\" src/)",
50
- "Bash(grep -rn \"navigation resources move.*--type\\\\|resourceType\" docs/ README.md)",
51
- "Bash(zinkee --version)",
52
- "Bash(zinkee --json profiles list)",
53
- "Bash(zinkee displays *)",
54
- "Bash(chmod +x /tmp/audit_search.sh)",
55
- "Bash(/tmp/audit_search.sh)",
56
- "Bash(head -60 CLAUDE.md)",
57
- "Bash(head -40 AGENTS.md)",
58
- "Bash(xargs cat)",
59
- "Bash(./gradlew :api:test --tests \"com.zinkee.api.service.v2.data.DataV2TranslatorTest\" --tests \"com.zinkee.api.service.v2.data.DataV2ServiceTest\" --tests \"com.zinkee.api.domain.model.v2.data.DataV2PatchRecordRequestTest\")",
60
- "Bash(./gradlew :api:test --tests \"com.zinkee.api.service.v2.data.DataV2ServiceTest\" --tests \"com.zinkee.api.domain.model.v2.data.DataV2PatchRecordRequestTest\")",
61
- "Bash(./gradlew :api:spotlessApply)",
62
- "Bash(./gradlew :api:test :api:spotbugsMain spotlessCheck)",
63
- "Bash(./gradlew :api:spotbugsMain)",
64
- "Bash(./gradlew spotlessCheck)",
65
- "Bash(git --no-pager diff --stat)",
66
- "Bash(git --no-pager diff -- src/commands/records.ts src/api/records.ts)",
67
- "Bash(echo \"===EXIT: $?===\")"
68
- ]
69
- }
70
- }