@constructive-io/graphql-codegen 4.0.2 → 4.1.1

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 (93) hide show
  1. package/cli/handler.d.ts +13 -0
  2. package/cli/handler.js +74 -0
  3. package/cli/index.js +11 -57
  4. package/core/codegen/barrel.d.ts +1 -0
  5. package/core/codegen/barrel.js +5 -2
  6. package/core/codegen/cli/arg-mapper.d.ts +4 -0
  7. package/core/codegen/cli/arg-mapper.js +117 -0
  8. package/core/codegen/cli/command-map-generator.d.ts +16 -0
  9. package/core/codegen/cli/command-map-generator.js +338 -0
  10. package/core/codegen/cli/custom-command-generator.d.ts +8 -0
  11. package/core/codegen/cli/custom-command-generator.js +155 -0
  12. package/core/codegen/cli/docs-generator.d.ts +26 -0
  13. package/core/codegen/cli/docs-generator.js +1399 -0
  14. package/core/codegen/cli/executor-generator.d.ts +11 -0
  15. package/core/codegen/cli/executor-generator.js +217 -0
  16. package/core/codegen/cli/index.d.ts +53 -0
  17. package/core/codegen/cli/index.js +153 -0
  18. package/core/codegen/cli/infra-generator.d.ts +9 -0
  19. package/core/codegen/cli/infra-generator.js +1195 -0
  20. package/core/codegen/cli/table-command-generator.d.ts +7 -0
  21. package/core/codegen/cli/table-command-generator.js +323 -0
  22. package/core/codegen/docs-utils.d.ts +30 -0
  23. package/core/codegen/docs-utils.js +122 -0
  24. package/core/codegen/hooks-docs-generator.d.ts +6 -0
  25. package/core/codegen/hooks-docs-generator.js +468 -0
  26. package/core/codegen/orm/docs-generator.d.ts +6 -0
  27. package/core/codegen/orm/docs-generator.js +416 -0
  28. package/core/codegen/target-docs-generator.d.ts +20 -0
  29. package/core/codegen/target-docs-generator.js +110 -0
  30. package/core/database/index.d.ts +0 -12
  31. package/core/database/index.js +2 -19
  32. package/core/generate.d.ts +34 -2
  33. package/core/generate.js +453 -12
  34. package/core/index.d.ts +0 -2
  35. package/core/index.js +0 -2
  36. package/core/introspect/source/database.js +2 -2
  37. package/core/introspect/source/pgpm-module.js +2 -2
  38. package/core/output/index.d.ts +1 -1
  39. package/core/output/index.js +1 -2
  40. package/core/output/writer.d.ts +0 -10
  41. package/core/output/writer.js +0 -31
  42. package/esm/cli/handler.d.ts +13 -0
  43. package/esm/cli/handler.js +71 -0
  44. package/esm/cli/index.js +11 -57
  45. package/esm/core/codegen/barrel.d.ts +1 -0
  46. package/esm/core/codegen/barrel.js +5 -2
  47. package/esm/core/codegen/cli/arg-mapper.d.ts +4 -0
  48. package/esm/core/codegen/cli/arg-mapper.js +80 -0
  49. package/esm/core/codegen/cli/command-map-generator.d.ts +16 -0
  50. package/esm/core/codegen/cli/command-map-generator.js +301 -0
  51. package/esm/core/codegen/cli/custom-command-generator.d.ts +8 -0
  52. package/esm/core/codegen/cli/custom-command-generator.js +119 -0
  53. package/esm/core/codegen/cli/docs-generator.d.ts +26 -0
  54. package/esm/core/codegen/cli/docs-generator.js +1387 -0
  55. package/esm/core/codegen/cli/executor-generator.d.ts +11 -0
  56. package/esm/core/codegen/cli/executor-generator.js +180 -0
  57. package/esm/core/codegen/cli/index.d.ts +53 -0
  58. package/esm/core/codegen/cli/index.js +128 -0
  59. package/esm/core/codegen/cli/infra-generator.d.ts +9 -0
  60. package/esm/core/codegen/cli/infra-generator.js +1156 -0
  61. package/esm/core/codegen/cli/table-command-generator.d.ts +7 -0
  62. package/esm/core/codegen/cli/table-command-generator.js +287 -0
  63. package/esm/core/codegen/docs-utils.d.ts +30 -0
  64. package/esm/core/codegen/docs-utils.js +112 -0
  65. package/esm/core/codegen/hooks-docs-generator.d.ts +6 -0
  66. package/esm/core/codegen/hooks-docs-generator.js +462 -0
  67. package/esm/core/codegen/orm/docs-generator.d.ts +6 -0
  68. package/esm/core/codegen/orm/docs-generator.js +410 -0
  69. package/esm/core/codegen/target-docs-generator.d.ts +20 -0
  70. package/esm/core/codegen/target-docs-generator.js +105 -0
  71. package/esm/core/database/index.d.ts +0 -12
  72. package/esm/core/database/index.js +1 -17
  73. package/esm/core/generate.d.ts +34 -2
  74. package/esm/core/generate.js +417 -12
  75. package/esm/core/index.d.ts +0 -2
  76. package/esm/core/index.js +0 -2
  77. package/esm/core/introspect/source/database.js +2 -2
  78. package/esm/core/introspect/source/pgpm-module.js +2 -2
  79. package/esm/core/output/index.d.ts +1 -1
  80. package/esm/core/output/index.js +1 -1
  81. package/esm/core/output/writer.d.ts +0 -10
  82. package/esm/core/output/writer.js +0 -30
  83. package/esm/generators/index.d.ts +0 -3
  84. package/esm/generators/index.js +0 -3
  85. package/esm/index.d.ts +4 -3
  86. package/esm/index.js +4 -2
  87. package/esm/types/config.d.ts +78 -0
  88. package/generators/index.d.ts +0 -3
  89. package/generators/index.js +0 -3
  90. package/index.d.ts +4 -3
  91. package/index.js +7 -2
  92. package/package.json +8 -7
  93. package/types/config.d.ts +78 -0
@@ -0,0 +1,1399 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveDocsConfig = void 0;
4
+ exports.generateReadme = generateReadme;
5
+ exports.generateAgentsDocs = generateAgentsDocs;
6
+ exports.getCliMcpTools = getCliMcpTools;
7
+ exports.generateSkills = generateSkills;
8
+ exports.generateMultiTargetReadme = generateMultiTargetReadme;
9
+ exports.generateMultiTargetAgentsDocs = generateMultiTargetAgentsDocs;
10
+ exports.getMultiTargetCliMcpTools = getMultiTargetCliMcpTools;
11
+ exports.generateMultiTargetSkills = generateMultiTargetSkills;
12
+ const komoji_1 = require("komoji");
13
+ const docs_utils_1 = require("../docs-utils");
14
+ const utils_1 = require("../utils");
15
+ var docs_utils_2 = require("../docs-utils");
16
+ Object.defineProperty(exports, "resolveDocsConfig", { enumerable: true, get: function () { return docs_utils_2.resolveDocsConfig; } });
17
+ function generateReadme(tables, customOperations, toolName) {
18
+ const lines = [];
19
+ lines.push(...(0, docs_utils_1.getReadmeHeader)(`${toolName} CLI`));
20
+ lines.push('## Setup');
21
+ lines.push('');
22
+ lines.push('```bash');
23
+ lines.push(`# Create a context pointing at your GraphQL endpoint`);
24
+ lines.push(`${toolName} context create production --endpoint https://api.example.com/graphql`);
25
+ lines.push('');
26
+ lines.push(`# Set the active context`);
27
+ lines.push(`${toolName} context use production`);
28
+ lines.push('');
29
+ lines.push(`# Authenticate`);
30
+ lines.push(`${toolName} auth set-token <your-token>`);
31
+ lines.push('```');
32
+ lines.push('');
33
+ lines.push('## Commands');
34
+ lines.push('');
35
+ lines.push('| Command | Description |');
36
+ lines.push('|---------|-------------|');
37
+ lines.push('| `context` | Manage API contexts (endpoints) |');
38
+ lines.push('| `auth` | Manage authentication tokens |');
39
+ for (const table of tables) {
40
+ const { singularName } = (0, utils_1.getTableNames)(table);
41
+ const kebab = (0, komoji_1.toKebabCase)(singularName);
42
+ lines.push(`| \`${kebab}\` | ${singularName} CRUD operations |`);
43
+ }
44
+ for (const op of customOperations) {
45
+ const kebab = (0, komoji_1.toKebabCase)(op.name);
46
+ lines.push(`| \`${kebab}\` | ${op.description || op.name} |`);
47
+ }
48
+ lines.push('');
49
+ lines.push('## Infrastructure Commands');
50
+ lines.push('');
51
+ lines.push('### `context`');
52
+ lines.push('');
53
+ lines.push('Manage named API contexts (kubectl-style).');
54
+ lines.push('');
55
+ lines.push('| Subcommand | Description |');
56
+ lines.push('|------------|-------------|');
57
+ lines.push('| `create <name> --endpoint <url>` | Create a new context |');
58
+ lines.push('| `list` | List all contexts |');
59
+ lines.push('| `use <name>` | Set the active context |');
60
+ lines.push('| `current` | Show current context |');
61
+ lines.push('| `delete <name>` | Delete a context |');
62
+ lines.push('');
63
+ lines.push(`Configuration is stored at \`~/.${toolName}/config/\`.`);
64
+ lines.push('');
65
+ lines.push('### `auth`');
66
+ lines.push('');
67
+ lines.push('Manage authentication tokens per context.');
68
+ lines.push('');
69
+ lines.push('| Subcommand | Description |');
70
+ lines.push('|------------|-------------|');
71
+ lines.push('| `set-token <token>` | Store bearer token for current context |');
72
+ lines.push('| `status` | Show auth status across all contexts |');
73
+ lines.push('| `logout` | Remove credentials for current context |');
74
+ lines.push('');
75
+ if (tables.length > 0) {
76
+ lines.push('## Table Commands');
77
+ lines.push('');
78
+ for (const table of tables) {
79
+ const { singularName } = (0, utils_1.getTableNames)(table);
80
+ const kebab = (0, komoji_1.toKebabCase)(singularName);
81
+ const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
82
+ const scalarFields = (0, utils_1.getScalarFields)(table);
83
+ const editableFields = (0, docs_utils_1.getEditableFields)(table);
84
+ lines.push(`### \`${kebab}\``);
85
+ lines.push('');
86
+ lines.push(`CRUD operations for ${table.name} records.`);
87
+ lines.push('');
88
+ lines.push('| Subcommand | Description |');
89
+ lines.push('|------------|-------------|');
90
+ lines.push(`| \`list\` | List all ${singularName} records |`);
91
+ lines.push(`| \`get\` | Get a ${singularName} by ${pk.name} |`);
92
+ lines.push(`| \`create\` | Create a new ${singularName} |`);
93
+ lines.push(`| \`update\` | Update an existing ${singularName} |`);
94
+ lines.push(`| \`delete\` | Delete a ${singularName} |`);
95
+ lines.push('');
96
+ lines.push('**Fields:**');
97
+ lines.push('');
98
+ lines.push('| Field | Type |');
99
+ lines.push('|-------|------|');
100
+ for (const f of scalarFields) {
101
+ lines.push(`| \`${f.name}\` | ${f.type.gqlType} |`);
102
+ }
103
+ lines.push('');
104
+ lines.push(`**Create fields:** ${editableFields.map((f) => `\`${f.name}\``).join(', ')}`);
105
+ lines.push('');
106
+ }
107
+ }
108
+ if (customOperations.length > 0) {
109
+ lines.push('## Custom Operations');
110
+ lines.push('');
111
+ for (const op of customOperations) {
112
+ const kebab = (0, komoji_1.toKebabCase)(op.name);
113
+ lines.push(`### \`${kebab}\``);
114
+ lines.push('');
115
+ lines.push(op.description || op.name);
116
+ lines.push('');
117
+ lines.push(`- **Type:** ${op.kind}`);
118
+ if (op.args.length > 0) {
119
+ lines.push('- **Arguments:**');
120
+ lines.push('');
121
+ lines.push(' | Argument | Type |');
122
+ lines.push(' |----------|------|');
123
+ for (const arg of op.args) {
124
+ lines.push(` | \`${arg.name}\` | ${(0, docs_utils_1.formatArgType)(arg)} |`);
125
+ }
126
+ }
127
+ else {
128
+ lines.push('- **Arguments:** none');
129
+ }
130
+ lines.push('');
131
+ }
132
+ }
133
+ lines.push('## Output');
134
+ lines.push('');
135
+ lines.push('All commands output JSON to stdout. Pipe to `jq` for formatting:');
136
+ lines.push('');
137
+ lines.push('```bash');
138
+ lines.push(`${toolName} car list | jq '.[]'`);
139
+ lines.push(`${toolName} car get --id <uuid> | jq '.'`);
140
+ lines.push('```');
141
+ lines.push('');
142
+ lines.push(...(0, docs_utils_1.getReadmeFooter)());
143
+ return {
144
+ fileName: 'README.md',
145
+ content: lines.join('\n'),
146
+ };
147
+ }
148
+ function generateAgentsDocs(tables, customOperations, toolName) {
149
+ const lines = [];
150
+ lines.push(`# ${toolName} CLI - Agent Reference`);
151
+ lines.push('');
152
+ lines.push('> @generated by @constructive-io/graphql-codegen - DO NOT EDIT');
153
+ lines.push('> This document is structured for LLM/agent consumption.');
154
+ lines.push('');
155
+ lines.push('## OVERVIEW');
156
+ lines.push('');
157
+ lines.push(`\`${toolName}\` is a CLI tool for interacting with a GraphQL API.`);
158
+ lines.push('All commands output JSON to stdout. All commands accept `--help` or `-h` for usage.');
159
+ lines.push(`Configuration is stored at \`~/.${toolName}/config/\` via appstash.`);
160
+ lines.push('');
161
+ lines.push('## PREREQUISITES');
162
+ lines.push('');
163
+ lines.push('Before running any data commands, you must:');
164
+ lines.push('');
165
+ lines.push(`1. Create a context: \`${toolName} context create <name> --endpoint <url>\``);
166
+ lines.push(`2. Activate it: \`${toolName} context use <name>\``);
167
+ lines.push(`3. Authenticate: \`${toolName} auth set-token <token>\``);
168
+ lines.push('');
169
+ lines.push('## TOOLS');
170
+ lines.push('');
171
+ lines.push('### TOOL: context');
172
+ lines.push('');
173
+ lines.push('Manage named API endpoint contexts (like kubectl contexts).');
174
+ lines.push('');
175
+ lines.push('```');
176
+ lines.push('SUBCOMMANDS:');
177
+ lines.push(` ${toolName} context create <name> --endpoint <url> Create a new context`);
178
+ lines.push(` ${toolName} context list List all contexts`);
179
+ lines.push(` ${toolName} context use <name> Set active context`);
180
+ lines.push(` ${toolName} context current Show active context`);
181
+ lines.push(` ${toolName} context delete <name> Delete a context`);
182
+ lines.push('');
183
+ lines.push('INPUT:');
184
+ lines.push(' name: string (required) - Context identifier');
185
+ lines.push(' endpoint: string (required for create) - GraphQL endpoint URL');
186
+ lines.push('');
187
+ lines.push('OUTPUT: JSON');
188
+ lines.push(' create: { name, endpoint }');
189
+ lines.push(' list: [{ name, endpoint, isCurrent, hasCredentials }]');
190
+ lines.push(' use: { name, endpoint }');
191
+ lines.push(' current: { name, endpoint }');
192
+ lines.push(' delete: { deleted: name }');
193
+ lines.push('```');
194
+ lines.push('');
195
+ lines.push('### TOOL: auth');
196
+ lines.push('');
197
+ lines.push('Manage authentication tokens per context.');
198
+ lines.push('');
199
+ lines.push('```');
200
+ lines.push('SUBCOMMANDS:');
201
+ lines.push(` ${toolName} auth set-token <token> Store bearer token for current context`);
202
+ lines.push(` ${toolName} auth status Show auth status for all contexts`);
203
+ lines.push(` ${toolName} auth logout Remove credentials for current context`);
204
+ lines.push('');
205
+ lines.push('INPUT:');
206
+ lines.push(' token: string (required for set-token) - Bearer token value');
207
+ lines.push('');
208
+ lines.push('OUTPUT: JSON');
209
+ lines.push(' set-token: { context, status: "authenticated" }');
210
+ lines.push(' status: [{ context, authenticated: boolean }]');
211
+ lines.push(' logout: { context, status: "logged out" }');
212
+ lines.push('```');
213
+ lines.push('');
214
+ for (const table of tables) {
215
+ const { singularName } = (0, utils_1.getTableNames)(table);
216
+ const kebab = (0, komoji_1.toKebabCase)(singularName);
217
+ const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
218
+ const scalarFields = (0, utils_1.getScalarFields)(table);
219
+ const editableFields = (0, docs_utils_1.getEditableFields)(table);
220
+ lines.push(`### TOOL: ${kebab}`);
221
+ lines.push('');
222
+ lines.push(`CRUD operations for ${table.name} records.`);
223
+ lines.push('');
224
+ lines.push('```');
225
+ lines.push('SUBCOMMANDS:');
226
+ lines.push(` ${toolName} ${kebab} list List all records`);
227
+ lines.push(` ${toolName} ${kebab} get --${pk.name} <value> Get one record`);
228
+ lines.push(` ${toolName} ${kebab} create ${editableFields.map((f) => `--${f.name} <value>`).join(' ')}`);
229
+ lines.push(` ${toolName} ${kebab} update --${pk.name} <value> ${editableFields.map((f) => `[--${f.name} <value>]`).join(' ')}`);
230
+ lines.push(` ${toolName} ${kebab} delete --${pk.name} <value> Delete one record`);
231
+ lines.push('');
232
+ lines.push('INPUT FIELDS:');
233
+ for (const f of scalarFields) {
234
+ const isPk = f.name === pk.name;
235
+ lines.push(` ${f.name}: ${f.type.gqlType}${isPk ? ' (primary key)' : ''}`);
236
+ }
237
+ lines.push('');
238
+ lines.push('EDITABLE FIELDS (for create/update):');
239
+ for (const f of editableFields) {
240
+ lines.push(` ${f.name}: ${f.type.gqlType}`);
241
+ }
242
+ lines.push('');
243
+ lines.push('OUTPUT: JSON');
244
+ lines.push(` list: [{ ${scalarFields.map((f) => f.name).join(', ')} }]`);
245
+ lines.push(` get: { ${scalarFields.map((f) => f.name).join(', ')} }`);
246
+ lines.push(` create: { ${scalarFields.map((f) => f.name).join(', ')} }`);
247
+ lines.push(` update: { ${scalarFields.map((f) => f.name).join(', ')} }`);
248
+ lines.push(` delete: { ${pk.name} }`);
249
+ lines.push('```');
250
+ lines.push('');
251
+ }
252
+ for (const op of customOperations) {
253
+ const kebab = (0, komoji_1.toKebabCase)(op.name);
254
+ lines.push(`### TOOL: ${kebab}`);
255
+ lines.push('');
256
+ lines.push(op.description || op.name);
257
+ lines.push('');
258
+ lines.push('```');
259
+ lines.push(`TYPE: ${op.kind}`);
260
+ if (op.args.length > 0) {
261
+ const flags = op.args.map((a) => `--${a.name} <value>`).join(' ');
262
+ lines.push(`USAGE: ${toolName} ${kebab} ${flags}`);
263
+ lines.push('');
264
+ lines.push('INPUT:');
265
+ for (const arg of op.args) {
266
+ lines.push(` ${arg.name}: ${(0, docs_utils_1.formatArgType)(arg)}`);
267
+ }
268
+ }
269
+ else {
270
+ lines.push(`USAGE: ${toolName} ${kebab}`);
271
+ lines.push('');
272
+ lines.push('INPUT: none');
273
+ }
274
+ lines.push('');
275
+ lines.push('OUTPUT: JSON');
276
+ lines.push('```');
277
+ lines.push('');
278
+ }
279
+ lines.push('## WORKFLOWS');
280
+ lines.push('');
281
+ lines.push('### Initial setup');
282
+ lines.push('');
283
+ lines.push('```bash');
284
+ lines.push(`${toolName} context create dev --endpoint http://localhost:5000/graphql`);
285
+ lines.push(`${toolName} context use dev`);
286
+ lines.push(`${toolName} auth set-token eyJhbGciOiJIUzI1NiIs...`);
287
+ lines.push('```');
288
+ lines.push('');
289
+ if (tables.length > 0) {
290
+ const firstTable = tables[0];
291
+ const { singularName } = (0, utils_1.getTableNames)(firstTable);
292
+ const kebab = (0, komoji_1.toKebabCase)(singularName);
293
+ const editableFields = (0, docs_utils_1.getEditableFields)(firstTable);
294
+ const pk = (0, utils_1.getPrimaryKeyInfo)(firstTable)[0];
295
+ lines.push(`### CRUD workflow (${kebab})`);
296
+ lines.push('');
297
+ lines.push('```bash');
298
+ lines.push(`# List all`);
299
+ lines.push(`${toolName} ${kebab} list`);
300
+ lines.push('');
301
+ lines.push(`# Create`);
302
+ lines.push(`${toolName} ${kebab} create ${editableFields.map((f) => `--${f.name} "value"`).join(' ')}`);
303
+ lines.push('');
304
+ lines.push(`# Get by ${pk.name}`);
305
+ lines.push(`${toolName} ${kebab} get --${pk.name} <value>`);
306
+ lines.push('');
307
+ lines.push(`# Update`);
308
+ lines.push(`${toolName} ${kebab} update --${pk.name} <value> --${editableFields[0]?.name || 'field'} "new-value"`);
309
+ lines.push('');
310
+ lines.push(`# Delete`);
311
+ lines.push(`${toolName} ${kebab} delete --${pk.name} <value>`);
312
+ lines.push('```');
313
+ lines.push('');
314
+ }
315
+ lines.push('### Piping output');
316
+ lines.push('');
317
+ lines.push('```bash');
318
+ lines.push(`# Pretty print`);
319
+ lines.push(`${toolName} car list | jq '.'`);
320
+ lines.push('');
321
+ lines.push(`# Extract field`);
322
+ lines.push(`${toolName} car list | jq '.[].id'`);
323
+ lines.push('');
324
+ lines.push(`# Count results`);
325
+ lines.push(`${toolName} car list | jq 'length'`);
326
+ lines.push('```');
327
+ lines.push('');
328
+ lines.push('## ERROR HANDLING');
329
+ lines.push('');
330
+ lines.push('All errors are written to stderr. Exit codes:');
331
+ lines.push('- `0`: Success');
332
+ lines.push('- `1`: Error (auth failure, not found, validation error, network error)');
333
+ lines.push('');
334
+ lines.push('Common errors:');
335
+ lines.push('- "No active context": Run `context use <name>` first');
336
+ lines.push('- "Not authenticated": Run `auth set-token <token>` first');
337
+ lines.push('- "Record not found": The requested ID does not exist');
338
+ lines.push('');
339
+ return {
340
+ fileName: 'AGENTS.md',
341
+ content: lines.join('\n'),
342
+ };
343
+ }
344
+ function getCliMcpTools(tables, customOperations, toolName) {
345
+ const tools = [];
346
+ tools.push({
347
+ name: `${toolName}_context_create`,
348
+ description: 'Create a named API context pointing at a GraphQL endpoint',
349
+ inputSchema: {
350
+ type: 'object',
351
+ properties: {
352
+ name: { type: 'string', description: 'Context name' },
353
+ endpoint: { type: 'string', description: 'GraphQL endpoint URL' },
354
+ },
355
+ required: ['name', 'endpoint'],
356
+ },
357
+ });
358
+ tools.push({
359
+ name: `${toolName}_context_list`,
360
+ description: 'List all configured API contexts',
361
+ inputSchema: { type: 'object', properties: {} },
362
+ });
363
+ tools.push({
364
+ name: `${toolName}_context_use`,
365
+ description: 'Set the active API context',
366
+ inputSchema: {
367
+ type: 'object',
368
+ properties: {
369
+ name: { type: 'string', description: 'Context name to activate' },
370
+ },
371
+ required: ['name'],
372
+ },
373
+ });
374
+ tools.push({
375
+ name: `${toolName}_context_current`,
376
+ description: 'Show the currently active API context',
377
+ inputSchema: { type: 'object', properties: {} },
378
+ });
379
+ tools.push({
380
+ name: `${toolName}_context_delete`,
381
+ description: 'Delete an API context',
382
+ inputSchema: {
383
+ type: 'object',
384
+ properties: {
385
+ name: { type: 'string', description: 'Context name to delete' },
386
+ },
387
+ required: ['name'],
388
+ },
389
+ });
390
+ tools.push({
391
+ name: `${toolName}_auth_set_token`,
392
+ description: 'Store a bearer token for the current context',
393
+ inputSchema: {
394
+ type: 'object',
395
+ properties: {
396
+ token: { type: 'string', description: 'Bearer token value' },
397
+ },
398
+ required: ['token'],
399
+ },
400
+ });
401
+ tools.push({
402
+ name: `${toolName}_auth_status`,
403
+ description: 'Show authentication status for all contexts',
404
+ inputSchema: { type: 'object', properties: {} },
405
+ });
406
+ tools.push({
407
+ name: `${toolName}_auth_logout`,
408
+ description: 'Remove credentials for the current context',
409
+ inputSchema: { type: 'object', properties: {} },
410
+ });
411
+ for (const table of tables) {
412
+ const { singularName } = (0, utils_1.getTableNames)(table);
413
+ const kebab = (0, komoji_1.toKebabCase)(singularName);
414
+ const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
415
+ const scalarFields = (0, utils_1.getScalarFields)(table);
416
+ const editableFields = (0, docs_utils_1.getEditableFields)(table);
417
+ tools.push({
418
+ name: `${toolName}_${kebab}_list`,
419
+ description: `List all ${table.name} records`,
420
+ inputSchema: { type: 'object', properties: {} },
421
+ });
422
+ tools.push({
423
+ name: `${toolName}_${kebab}_get`,
424
+ description: `Get a single ${table.name} record by ${pk.name}`,
425
+ inputSchema: {
426
+ type: 'object',
427
+ properties: {
428
+ [pk.name]: {
429
+ type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(pk.gqlType),
430
+ description: `${table.name} ${pk.name}`,
431
+ },
432
+ },
433
+ required: [pk.name],
434
+ },
435
+ });
436
+ const createProps = {};
437
+ for (const f of editableFields) {
438
+ createProps[f.name] = {
439
+ type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(f.type.gqlType),
440
+ description: `${table.name} ${f.name}`,
441
+ };
442
+ }
443
+ tools.push({
444
+ name: `${toolName}_${kebab}_create`,
445
+ description: `Create a new ${table.name} record`,
446
+ inputSchema: {
447
+ type: 'object',
448
+ properties: createProps,
449
+ required: editableFields.map((f) => f.name),
450
+ },
451
+ });
452
+ const updateProps = {
453
+ [pk.name]: {
454
+ type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(pk.gqlType),
455
+ description: `${table.name} ${pk.name}`,
456
+ },
457
+ };
458
+ for (const f of editableFields) {
459
+ updateProps[f.name] = {
460
+ type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(f.type.gqlType),
461
+ description: `${table.name} ${f.name}`,
462
+ };
463
+ }
464
+ tools.push({
465
+ name: `${toolName}_${kebab}_update`,
466
+ description: `Update an existing ${table.name} record`,
467
+ inputSchema: {
468
+ type: 'object',
469
+ properties: updateProps,
470
+ required: [pk.name],
471
+ },
472
+ });
473
+ tools.push({
474
+ name: `${toolName}_${kebab}_delete`,
475
+ description: `Delete a ${table.name} record by ${pk.name}`,
476
+ inputSchema: {
477
+ type: 'object',
478
+ properties: {
479
+ [pk.name]: {
480
+ type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(pk.gqlType),
481
+ description: `${table.name} ${pk.name}`,
482
+ },
483
+ },
484
+ required: [pk.name],
485
+ },
486
+ });
487
+ tools.push({
488
+ name: `${toolName}_${kebab}_fields`,
489
+ description: `List available fields for ${table.name}`,
490
+ inputSchema: { type: 'object', properties: {} },
491
+ _meta: {
492
+ fields: scalarFields.map((f) => ({
493
+ name: f.name,
494
+ type: f.type.gqlType,
495
+ editable: editableFields.some((ef) => ef.name === f.name),
496
+ primaryKey: f.name === pk.name,
497
+ })),
498
+ },
499
+ });
500
+ }
501
+ for (const op of customOperations) {
502
+ const kebab = (0, komoji_1.toKebabCase)(op.name);
503
+ const props = {};
504
+ const required = [];
505
+ for (const arg of op.args) {
506
+ const isRequired = arg.type.kind === 'NON_NULL';
507
+ const baseType = isRequired && arg.type.ofType ? arg.type.ofType : arg.type;
508
+ props[arg.name] = {
509
+ type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(baseType.name ?? 'String'),
510
+ description: arg.description || arg.name,
511
+ };
512
+ if (isRequired) {
513
+ required.push(arg.name);
514
+ }
515
+ }
516
+ tools.push({
517
+ name: `${toolName}_${kebab}`,
518
+ description: op.description || op.name,
519
+ inputSchema: {
520
+ type: 'object',
521
+ properties: props,
522
+ ...(required.length > 0 ? { required } : {}),
523
+ },
524
+ });
525
+ }
526
+ return tools;
527
+ }
528
+ function generateSkills(tables, customOperations, toolName) {
529
+ const files = [];
530
+ files.push({
531
+ fileName: 'skills/context.md',
532
+ content: (0, docs_utils_1.buildSkillFile)({
533
+ name: `${toolName}-context`,
534
+ description: `Manage API endpoint contexts for ${toolName}`,
535
+ usage: [
536
+ `${toolName} context create <name> --endpoint <url>`,
537
+ `${toolName} context list`,
538
+ `${toolName} context use <name>`,
539
+ `${toolName} context current`,
540
+ `${toolName} context delete <name>`,
541
+ ],
542
+ examples: [
543
+ {
544
+ description: 'Create and activate a context',
545
+ code: [
546
+ `${toolName} context create production --endpoint https://api.example.com/graphql`,
547
+ `${toolName} context use production`,
548
+ ],
549
+ },
550
+ {
551
+ description: 'List all contexts',
552
+ code: [`${toolName} context list`],
553
+ },
554
+ ],
555
+ }),
556
+ });
557
+ files.push({
558
+ fileName: 'skills/auth.md',
559
+ content: (0, docs_utils_1.buildSkillFile)({
560
+ name: `${toolName}-auth`,
561
+ description: `Manage authentication tokens for ${toolName}`,
562
+ usage: [
563
+ `${toolName} auth set-token <token>`,
564
+ `${toolName} auth status`,
565
+ `${toolName} auth logout`,
566
+ ],
567
+ examples: [
568
+ {
569
+ description: 'Authenticate with a token',
570
+ code: [`${toolName} auth set-token eyJhbGciOiJIUzI1NiIs...`],
571
+ },
572
+ {
573
+ description: 'Check auth status',
574
+ code: [`${toolName} auth status`],
575
+ },
576
+ ],
577
+ }),
578
+ });
579
+ for (const table of tables) {
580
+ const { singularName } = (0, utils_1.getTableNames)(table);
581
+ const kebab = (0, komoji_1.toKebabCase)(singularName);
582
+ const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
583
+ const editableFields = (0, docs_utils_1.getEditableFields)(table);
584
+ files.push({
585
+ fileName: `skills/${kebab}.md`,
586
+ content: (0, docs_utils_1.buildSkillFile)({
587
+ name: `${toolName}-${kebab}`,
588
+ description: `CRUD operations for ${table.name} records via ${toolName} CLI`,
589
+ usage: [
590
+ `${toolName} ${kebab} list`,
591
+ `${toolName} ${kebab} get --${pk.name} <value>`,
592
+ `${toolName} ${kebab} create ${editableFields.map((f) => `--${f.name} <value>`).join(' ')}`,
593
+ `${toolName} ${kebab} update --${pk.name} <value> ${editableFields.map((f) => `[--${f.name} <value>]`).join(' ')}`,
594
+ `${toolName} ${kebab} delete --${pk.name} <value>`,
595
+ ],
596
+ examples: [
597
+ {
598
+ description: `List all ${singularName} records`,
599
+ code: [`${toolName} ${kebab} list`],
600
+ },
601
+ {
602
+ description: `Create a ${singularName}`,
603
+ code: [
604
+ `${toolName} ${kebab} create ${editableFields.map((f) => `--${f.name} "value"`).join(' ')}`,
605
+ ],
606
+ },
607
+ {
608
+ description: `Get a ${singularName} by ${pk.name}`,
609
+ code: [`${toolName} ${kebab} get --${pk.name} <value>`],
610
+ },
611
+ {
612
+ description: `Update a ${singularName}`,
613
+ code: [
614
+ `${toolName} ${kebab} update --${pk.name} <value> --${editableFields[0]?.name || 'field'} "new-value"`,
615
+ ],
616
+ },
617
+ {
618
+ description: `Delete a ${singularName}`,
619
+ code: [`${toolName} ${kebab} delete --${pk.name} <value>`],
620
+ },
621
+ ],
622
+ }),
623
+ });
624
+ }
625
+ for (const op of customOperations) {
626
+ const kebab = (0, komoji_1.toKebabCase)(op.name);
627
+ const usage = op.args.length > 0
628
+ ? `${toolName} ${kebab} ${op.args.map((a) => `--${a.name} <value>`).join(' ')}`
629
+ : `${toolName} ${kebab}`;
630
+ files.push({
631
+ fileName: `skills/${kebab}.md`,
632
+ content: (0, docs_utils_1.buildSkillFile)({
633
+ name: `${toolName}-${kebab}`,
634
+ description: op.description || `Execute the ${op.name} ${op.kind}`,
635
+ usage: [usage],
636
+ examples: [
637
+ {
638
+ description: `Run ${op.name}`,
639
+ code: [usage],
640
+ },
641
+ ],
642
+ }),
643
+ });
644
+ }
645
+ return files;
646
+ }
647
+ function generateMultiTargetReadme(input) {
648
+ const { toolName, builtinNames, targets } = input;
649
+ const lines = [];
650
+ lines.push(...(0, docs_utils_1.getReadmeHeader)(`${toolName} CLI`));
651
+ lines.push('## Setup');
652
+ lines.push('');
653
+ lines.push('### Create a context');
654
+ lines.push('');
655
+ lines.push('A context stores per-target endpoint overrides for an environment (dev, staging, production).');
656
+ lines.push('Default endpoints are baked in from the codegen config, so local development works with zero configuration.');
657
+ lines.push('');
658
+ lines.push('```bash');
659
+ lines.push(`# Interactive - prompts for each target endpoint (defaults shown)`);
660
+ lines.push(`${toolName} ${builtinNames.context} create local`);
661
+ lines.push('');
662
+ lines.push(`# Non-interactive`);
663
+ lines.push(`${toolName} ${builtinNames.context} create production \\`);
664
+ for (let i = 0; i < targets.length; i++) {
665
+ const tgt = targets[i];
666
+ const continuation = i < targets.length - 1 ? ' \\' : '';
667
+ lines.push(` --${tgt.name}-endpoint https://${tgt.name}.prod.example.com/graphql${continuation}`);
668
+ }
669
+ lines.push('```');
670
+ lines.push('');
671
+ lines.push('### Activate a context');
672
+ lines.push('');
673
+ lines.push('```bash');
674
+ lines.push(`${toolName} ${builtinNames.context} use production`);
675
+ lines.push('```');
676
+ lines.push('');
677
+ lines.push('### Authenticate');
678
+ lines.push('');
679
+ lines.push('```bash');
680
+ lines.push(`${toolName} ${builtinNames.auth} set-token <your-token>`);
681
+ lines.push('```');
682
+ lines.push('');
683
+ const authTarget = targets.find((t) => t.isAuthTarget);
684
+ if (authTarget) {
685
+ const authMutation = authTarget.customOperations.find((op) => op.kind === 'mutation' && /login|sign.?in|auth/i.test(op.name));
686
+ if (authMutation) {
687
+ const kebab = (0, komoji_1.toKebabCase)(authMutation.name);
688
+ lines.push('Or authenticate via a login mutation (auto-saves token):');
689
+ lines.push('');
690
+ lines.push('```bash');
691
+ const flags = authMutation.args.map((a) => `--${a.name} <value>`).join(' ');
692
+ lines.push(`${toolName} ${authTarget.name}:${kebab} ${flags} --save-token`);
693
+ lines.push('```');
694
+ lines.push('');
695
+ }
696
+ }
697
+ lines.push('## API Targets');
698
+ lines.push('');
699
+ lines.push('| Target | Default Endpoint | Tables | Custom Operations |');
700
+ lines.push('|--------|-----------------|--------|-------------------|');
701
+ for (const tgt of targets) {
702
+ lines.push(`| \`${tgt.name}\` | ${tgt.endpoint} | ${tgt.tables.length} | ${tgt.customOperations.length} |`);
703
+ }
704
+ lines.push('');
705
+ lines.push('## Commands');
706
+ lines.push('');
707
+ lines.push('### Infrastructure');
708
+ lines.push('');
709
+ lines.push('| Command | Description |');
710
+ lines.push('|---------|-------------|');
711
+ lines.push(`| \`${builtinNames.context}\` | Manage API contexts (per-target endpoints) |`);
712
+ lines.push(`| \`${builtinNames.auth}\` | Manage authentication tokens |`);
713
+ lines.push('');
714
+ for (const tgt of targets) {
715
+ lines.push(`### ${tgt.name}`);
716
+ lines.push('');
717
+ lines.push('| Command | Description |');
718
+ lines.push('|---------|-------------|');
719
+ for (const table of tgt.tables) {
720
+ const { singularName } = (0, utils_1.getTableNames)(table);
721
+ const kebab = (0, komoji_1.toKebabCase)(singularName);
722
+ lines.push(`| \`${tgt.name}:${kebab}\` | ${singularName} CRUD operations |`);
723
+ }
724
+ for (const op of tgt.customOperations) {
725
+ const kebab = (0, komoji_1.toKebabCase)(op.name);
726
+ lines.push(`| \`${tgt.name}:${kebab}\` | ${op.description || op.name} |`);
727
+ }
728
+ lines.push('');
729
+ }
730
+ lines.push('## Infrastructure Commands');
731
+ lines.push('');
732
+ lines.push(`### \`${builtinNames.context}\``);
733
+ lines.push('');
734
+ lines.push('Manage named API contexts (kubectl-style). Each context stores per-target endpoint overrides.');
735
+ lines.push('');
736
+ lines.push('| Subcommand | Description |');
737
+ lines.push('|------------|-------------|');
738
+ lines.push('| `create <name>` | Create a new context (prompts for per-target endpoints) |');
739
+ lines.push('| `list` | List all contexts |');
740
+ lines.push('| `use <name>` | Set the active context |');
741
+ lines.push('| `current` | Show current context |');
742
+ lines.push('| `delete <name>` | Delete a context |');
743
+ lines.push('');
744
+ lines.push('Create options:');
745
+ lines.push('');
746
+ for (const tgt of targets) {
747
+ lines.push(`- \`--${tgt.name}-endpoint <url>\` (default: ${tgt.endpoint})`);
748
+ }
749
+ lines.push('');
750
+ lines.push(`Configuration is stored at \`~/.${toolName}/config/\`.`);
751
+ lines.push('');
752
+ lines.push(`### \`${builtinNames.auth}\``);
753
+ lines.push('');
754
+ lines.push('Manage authentication tokens per context. One shared token is used across all targets.');
755
+ lines.push('');
756
+ lines.push('| Subcommand | Description |');
757
+ lines.push('|------------|-------------|');
758
+ lines.push('| `set-token <token>` | Store bearer token for current context |');
759
+ lines.push('| `status` | Show auth status across all contexts |');
760
+ lines.push('| `logout` | Remove credentials for current context |');
761
+ lines.push('');
762
+ for (const tgt of targets) {
763
+ if (tgt.tables.length === 0 && tgt.customOperations.length === 0)
764
+ continue;
765
+ lines.push(`## ${tgt.name} Commands`);
766
+ lines.push('');
767
+ for (const table of tgt.tables) {
768
+ const { singularName } = (0, utils_1.getTableNames)(table);
769
+ const kebab = (0, komoji_1.toKebabCase)(singularName);
770
+ const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
771
+ const scalarFields = (0, utils_1.getScalarFields)(table);
772
+ const editableFields = (0, docs_utils_1.getEditableFields)(table);
773
+ lines.push(`### \`${tgt.name}:${kebab}\``);
774
+ lines.push('');
775
+ lines.push(`CRUD operations for ${table.name} records.`);
776
+ lines.push('');
777
+ lines.push('| Subcommand | Description |');
778
+ lines.push('|------------|-------------|');
779
+ lines.push(`| \`list\` | List all ${singularName} records |`);
780
+ lines.push(`| \`get\` | Get a ${singularName} by ${pk.name} |`);
781
+ lines.push(`| \`create\` | Create a new ${singularName} |`);
782
+ lines.push(`| \`update\` | Update an existing ${singularName} |`);
783
+ lines.push(`| \`delete\` | Delete a ${singularName} |`);
784
+ lines.push('');
785
+ lines.push('**Fields:**');
786
+ lines.push('');
787
+ lines.push('| Field | Type |');
788
+ lines.push('|-------|------|');
789
+ for (const f of scalarFields) {
790
+ lines.push(`| \`${f.name}\` | ${f.type.gqlType} |`);
791
+ }
792
+ lines.push('');
793
+ lines.push(`**Create fields:** ${editableFields.map((f) => `\`${f.name}\``).join(', ')}`);
794
+ lines.push('');
795
+ }
796
+ for (const op of tgt.customOperations) {
797
+ const kebab = (0, komoji_1.toKebabCase)(op.name);
798
+ lines.push(`### \`${tgt.name}:${kebab}\``);
799
+ lines.push('');
800
+ lines.push(op.description || op.name);
801
+ lines.push('');
802
+ lines.push(`- **Type:** ${op.kind}`);
803
+ if (op.args.length > 0) {
804
+ lines.push('- **Arguments:**');
805
+ lines.push('');
806
+ lines.push(' | Argument | Type |');
807
+ lines.push(' |----------|------|');
808
+ for (const arg of op.args) {
809
+ lines.push(` | \`${arg.name}\` | ${(0, docs_utils_1.formatArgType)(arg)} |`);
810
+ }
811
+ }
812
+ else {
813
+ lines.push('- **Arguments:** none');
814
+ }
815
+ if (tgt.isAuthTarget && op.kind === 'mutation') {
816
+ lines.push(`- **Flags:** \`--save-token\` auto-saves returned token to credentials`);
817
+ }
818
+ lines.push('');
819
+ }
820
+ }
821
+ lines.push('## Output');
822
+ lines.push('');
823
+ lines.push('All commands output JSON to stdout. Pipe to `jq` for formatting:');
824
+ lines.push('');
825
+ lines.push('```bash');
826
+ if (targets.length > 0 && targets[0].tables.length > 0) {
827
+ const tgt = targets[0];
828
+ const kebab = (0, komoji_1.toKebabCase)((0, utils_1.getTableNames)(tgt.tables[0]).singularName);
829
+ lines.push(`${toolName} ${tgt.name}:${kebab} list | jq '.[]'`);
830
+ lines.push(`${toolName} ${tgt.name}:${kebab} get --id <uuid> | jq '.'`);
831
+ }
832
+ lines.push('```');
833
+ lines.push('');
834
+ lines.push(...(0, docs_utils_1.getReadmeFooter)());
835
+ return {
836
+ fileName: 'README.md',
837
+ content: lines.join('\n'),
838
+ };
839
+ }
840
+ function generateMultiTargetAgentsDocs(input) {
841
+ const { toolName, builtinNames, targets } = input;
842
+ const lines = [];
843
+ lines.push(`# ${toolName} CLI - Agent Reference`);
844
+ lines.push('');
845
+ lines.push('> @generated by @constructive-io/graphql-codegen - DO NOT EDIT');
846
+ lines.push('> This document is structured for LLM/agent consumption.');
847
+ lines.push('');
848
+ lines.push('## OVERVIEW');
849
+ lines.push('');
850
+ lines.push(`\`${toolName}\` is a unified multi-target CLI for interacting with multiple GraphQL APIs.`);
851
+ lines.push('All commands output JSON to stdout. All commands accept `--help` or `-h` for usage.');
852
+ lines.push(`Configuration is stored at \`~/.${toolName}/config/\` via appstash.`);
853
+ lines.push('');
854
+ lines.push('TARGETS:');
855
+ for (const tgt of targets) {
856
+ lines.push(` ${tgt.name}: ${tgt.endpoint}`);
857
+ }
858
+ lines.push('');
859
+ lines.push('COMMAND FORMAT:');
860
+ lines.push(` ${toolName} <target>:<command> <subcommand> [flags] Target-specific commands`);
861
+ lines.push(` ${toolName} ${builtinNames.context} <subcommand> [flags] Context management`);
862
+ lines.push(` ${toolName} ${builtinNames.auth} <subcommand> [flags] Authentication`);
863
+ lines.push('');
864
+ lines.push('## PREREQUISITES');
865
+ lines.push('');
866
+ lines.push('Before running any data commands, you must:');
867
+ lines.push('');
868
+ lines.push(`1. Create a context: \`${toolName} ${builtinNames.context} create <name>\``);
869
+ lines.push(` (prompts for per-target endpoints, defaults baked from config)`);
870
+ lines.push(`2. Activate it: \`${toolName} ${builtinNames.context} use <name>\``);
871
+ lines.push(`3. Authenticate: \`${toolName} ${builtinNames.auth} set-token <token>\``);
872
+ lines.push('');
873
+ lines.push('For local development, create a context accepting all defaults:');
874
+ lines.push('');
875
+ lines.push('```bash');
876
+ lines.push(`${toolName} ${builtinNames.context} create local`);
877
+ lines.push(`${toolName} ${builtinNames.context} use local`);
878
+ lines.push(`${toolName} ${builtinNames.auth} set-token <token>`);
879
+ lines.push('```');
880
+ lines.push('');
881
+ lines.push('## TOOLS');
882
+ lines.push('');
883
+ lines.push(`### TOOL: ${builtinNames.context}`);
884
+ lines.push('');
885
+ lines.push('Manage named API endpoint contexts. Each context stores per-target endpoint overrides.');
886
+ lines.push('');
887
+ lines.push('```');
888
+ lines.push('SUBCOMMANDS:');
889
+ lines.push(` ${toolName} ${builtinNames.context} create <name> Create a new context`);
890
+ lines.push(` ${toolName} ${builtinNames.context} list List all contexts`);
891
+ lines.push(` ${toolName} ${builtinNames.context} use <name> Set active context`);
892
+ lines.push(` ${toolName} ${builtinNames.context} current Show active context`);
893
+ lines.push(` ${toolName} ${builtinNames.context} delete <name> Delete a context`);
894
+ lines.push('');
895
+ lines.push('CREATE OPTIONS:');
896
+ for (const tgt of targets) {
897
+ lines.push(` --${tgt.name}-endpoint: string (default: ${tgt.endpoint})`);
898
+ }
899
+ lines.push('');
900
+ lines.push('OUTPUT: JSON');
901
+ lines.push(' create: { name, endpoint, targets }');
902
+ lines.push(' list: [{ name, endpoint, isCurrent, hasCredentials }]');
903
+ lines.push(' use: { name, endpoint }');
904
+ lines.push(' current: { name, endpoint }');
905
+ lines.push(' delete: { deleted: name }');
906
+ lines.push('```');
907
+ lines.push('');
908
+ lines.push(`### TOOL: ${builtinNames.auth}`);
909
+ lines.push('');
910
+ lines.push('Manage authentication tokens per context. One shared token across all targets.');
911
+ lines.push('');
912
+ lines.push('```');
913
+ lines.push('SUBCOMMANDS:');
914
+ lines.push(` ${toolName} ${builtinNames.auth} set-token <token> Store bearer token for current context`);
915
+ lines.push(` ${toolName} ${builtinNames.auth} status Show auth status for all contexts`);
916
+ lines.push(` ${toolName} ${builtinNames.auth} logout Remove credentials for current context`);
917
+ lines.push('');
918
+ lines.push('INPUT:');
919
+ lines.push(' token: string (required for set-token) - Bearer token value');
920
+ lines.push('');
921
+ lines.push('OUTPUT: JSON');
922
+ lines.push(' set-token: { context, status: "authenticated" }');
923
+ lines.push(' status: [{ context, authenticated: boolean }]');
924
+ lines.push(' logout: { context, status: "logged out" }');
925
+ lines.push('```');
926
+ lines.push('');
927
+ for (const tgt of targets) {
928
+ for (const table of tgt.tables) {
929
+ const { singularName } = (0, utils_1.getTableNames)(table);
930
+ const kebab = (0, komoji_1.toKebabCase)(singularName);
931
+ const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
932
+ const scalarFields = (0, utils_1.getScalarFields)(table);
933
+ const editableFields = (0, docs_utils_1.getEditableFields)(table);
934
+ lines.push(`### TOOL: ${tgt.name}:${kebab}`);
935
+ lines.push('');
936
+ lines.push(`CRUD operations for ${table.name} records (${tgt.name} target).`);
937
+ lines.push('');
938
+ lines.push('```');
939
+ lines.push('SUBCOMMANDS:');
940
+ lines.push(` ${toolName} ${tgt.name}:${kebab} list List all records`);
941
+ lines.push(` ${toolName} ${tgt.name}:${kebab} get --${pk.name} <value> Get one record`);
942
+ lines.push(` ${toolName} ${tgt.name}:${kebab} create ${editableFields.map((f) => `--${f.name} <value>`).join(' ')}`);
943
+ lines.push(` ${toolName} ${tgt.name}:${kebab} update --${pk.name} <value> ${editableFields.map((f) => `[--${f.name} <value>]`).join(' ')}`);
944
+ lines.push(` ${toolName} ${tgt.name}:${kebab} delete --${pk.name} <value> Delete one record`);
945
+ lines.push('');
946
+ lines.push('INPUT FIELDS:');
947
+ for (const f of scalarFields) {
948
+ const isPk = f.name === pk.name;
949
+ lines.push(` ${f.name}: ${f.type.gqlType}${isPk ? ' (primary key)' : ''}`);
950
+ }
951
+ lines.push('');
952
+ lines.push('EDITABLE FIELDS (for create/update):');
953
+ for (const f of editableFields) {
954
+ lines.push(` ${f.name}: ${f.type.gqlType}`);
955
+ }
956
+ lines.push('');
957
+ lines.push('OUTPUT: JSON');
958
+ lines.push(` list: [{ ${scalarFields.map((f) => f.name).join(', ')} }]`);
959
+ lines.push(` get: { ${scalarFields.map((f) => f.name).join(', ')} }`);
960
+ lines.push(` create: { ${scalarFields.map((f) => f.name).join(', ')} }`);
961
+ lines.push(` update: { ${scalarFields.map((f) => f.name).join(', ')} }`);
962
+ lines.push(` delete: { ${pk.name} }`);
963
+ lines.push('```');
964
+ lines.push('');
965
+ }
966
+ for (const op of tgt.customOperations) {
967
+ const kebab = (0, komoji_1.toKebabCase)(op.name);
968
+ lines.push(`### TOOL: ${tgt.name}:${kebab}`);
969
+ lines.push('');
970
+ lines.push(op.description || op.name);
971
+ lines.push('');
972
+ lines.push('```');
973
+ lines.push(`TYPE: ${op.kind}`);
974
+ if (op.args.length > 0) {
975
+ const flags = op.args.map((a) => `--${a.name} <value>`).join(' ');
976
+ lines.push(`USAGE: ${toolName} ${tgt.name}:${kebab} ${flags}`);
977
+ lines.push('');
978
+ lines.push('INPUT:');
979
+ for (const arg of op.args) {
980
+ lines.push(` ${arg.name}: ${(0, docs_utils_1.formatArgType)(arg)}`);
981
+ }
982
+ }
983
+ else {
984
+ lines.push(`USAGE: ${toolName} ${tgt.name}:${kebab}`);
985
+ lines.push('');
986
+ lines.push('INPUT: none');
987
+ }
988
+ if (tgt.isAuthTarget && op.kind === 'mutation') {
989
+ lines.push('');
990
+ lines.push('FLAGS:');
991
+ lines.push(' --save-token: boolean - Auto-save returned token to credentials');
992
+ }
993
+ lines.push('');
994
+ lines.push('OUTPUT: JSON');
995
+ lines.push('```');
996
+ lines.push('');
997
+ }
998
+ }
999
+ lines.push('## WORKFLOWS');
1000
+ lines.push('');
1001
+ lines.push('### Initial setup');
1002
+ lines.push('');
1003
+ lines.push('```bash');
1004
+ lines.push(`${toolName} ${builtinNames.context} create dev`);
1005
+ lines.push(`${toolName} ${builtinNames.context} use dev`);
1006
+ lines.push(`${toolName} ${builtinNames.auth} set-token eyJhbGciOiJIUzI1NiIs...`);
1007
+ lines.push('```');
1008
+ lines.push('');
1009
+ lines.push('### Switch environment');
1010
+ lines.push('');
1011
+ lines.push('```bash');
1012
+ lines.push(`${toolName} ${builtinNames.context} create production \\`);
1013
+ for (let i = 0; i < targets.length; i++) {
1014
+ const tgt = targets[i];
1015
+ const continuation = i < targets.length - 1 ? ' \\' : '';
1016
+ lines.push(` --${tgt.name}-endpoint https://${tgt.name}.prod.example.com/graphql${continuation}`);
1017
+ }
1018
+ lines.push(`${toolName} ${builtinNames.context} use production`);
1019
+ lines.push('```');
1020
+ lines.push('');
1021
+ if (targets.length > 0 && targets[0].tables.length > 0) {
1022
+ const tgt = targets[0];
1023
+ const table = tgt.tables[0];
1024
+ const { singularName } = (0, utils_1.getTableNames)(table);
1025
+ const kebab = (0, komoji_1.toKebabCase)(singularName);
1026
+ const editableFields = (0, docs_utils_1.getEditableFields)(table);
1027
+ const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
1028
+ lines.push(`### CRUD workflow (${tgt.name}:${kebab})`);
1029
+ lines.push('');
1030
+ lines.push('```bash');
1031
+ lines.push(`${toolName} ${tgt.name}:${kebab} list`);
1032
+ lines.push(`${toolName} ${tgt.name}:${kebab} create ${editableFields.map((f) => `--${f.name} "value"`).join(' ')}`);
1033
+ lines.push(`${toolName} ${tgt.name}:${kebab} get --${pk.name} <value>`);
1034
+ lines.push(`${toolName} ${tgt.name}:${kebab} update --${pk.name} <value> --${editableFields[0]?.name || 'field'} "new-value"`);
1035
+ lines.push(`${toolName} ${tgt.name}:${kebab} delete --${pk.name} <value>`);
1036
+ lines.push('```');
1037
+ lines.push('');
1038
+ }
1039
+ lines.push('### Piping output');
1040
+ lines.push('');
1041
+ lines.push('```bash');
1042
+ if (targets.length > 0 && targets[0].tables.length > 0) {
1043
+ const tgt = targets[0];
1044
+ const kebab = (0, komoji_1.toKebabCase)((0, utils_1.getTableNames)(tgt.tables[0]).singularName);
1045
+ lines.push(`${toolName} ${tgt.name}:${kebab} list | jq '.'`);
1046
+ lines.push(`${toolName} ${tgt.name}:${kebab} list | jq '.[].id'`);
1047
+ lines.push(`${toolName} ${tgt.name}:${kebab} list | jq 'length'`);
1048
+ }
1049
+ lines.push('```');
1050
+ lines.push('');
1051
+ lines.push('## ERROR HANDLING');
1052
+ lines.push('');
1053
+ lines.push('All errors are written to stderr. Exit codes:');
1054
+ lines.push('- `0`: Success');
1055
+ lines.push('- `1`: Error (auth failure, not found, validation error, network error)');
1056
+ lines.push('');
1057
+ lines.push('Common errors:');
1058
+ lines.push(`- "No active context": Run \`${builtinNames.context} use <name>\` first`);
1059
+ lines.push(`- "Not authenticated": Run \`${builtinNames.auth} set-token <token>\` first`);
1060
+ lines.push('- "Unknown target": The target name is not recognized');
1061
+ lines.push('- "Record not found": The requested ID does not exist');
1062
+ lines.push('');
1063
+ return {
1064
+ fileName: 'AGENTS.md',
1065
+ content: lines.join('\n'),
1066
+ };
1067
+ }
1068
+ function getMultiTargetCliMcpTools(input) {
1069
+ const { toolName, builtinNames, targets } = input;
1070
+ const tools = [];
1071
+ const contextEndpointProps = {
1072
+ name: { type: 'string', description: 'Context name' },
1073
+ };
1074
+ for (const tgt of targets) {
1075
+ contextEndpointProps[`${tgt.name}_endpoint`] = {
1076
+ type: 'string',
1077
+ description: `${tgt.name} GraphQL endpoint (default: ${tgt.endpoint})`,
1078
+ };
1079
+ }
1080
+ tools.push({
1081
+ name: `${toolName}_${builtinNames.context}_create`,
1082
+ description: 'Create a named API context with per-target endpoint overrides',
1083
+ inputSchema: {
1084
+ type: 'object',
1085
+ properties: contextEndpointProps,
1086
+ required: ['name'],
1087
+ },
1088
+ });
1089
+ tools.push({
1090
+ name: `${toolName}_${builtinNames.context}_list`,
1091
+ description: 'List all configured API contexts',
1092
+ inputSchema: { type: 'object', properties: {} },
1093
+ });
1094
+ tools.push({
1095
+ name: `${toolName}_${builtinNames.context}_use`,
1096
+ description: 'Set the active API context (switches all targets at once)',
1097
+ inputSchema: {
1098
+ type: 'object',
1099
+ properties: {
1100
+ name: { type: 'string', description: 'Context name to activate' },
1101
+ },
1102
+ required: ['name'],
1103
+ },
1104
+ });
1105
+ tools.push({
1106
+ name: `${toolName}_${builtinNames.context}_current`,
1107
+ description: 'Show the currently active API context',
1108
+ inputSchema: { type: 'object', properties: {} },
1109
+ });
1110
+ tools.push({
1111
+ name: `${toolName}_${builtinNames.context}_delete`,
1112
+ description: 'Delete an API context',
1113
+ inputSchema: {
1114
+ type: 'object',
1115
+ properties: {
1116
+ name: { type: 'string', description: 'Context name to delete' },
1117
+ },
1118
+ required: ['name'],
1119
+ },
1120
+ });
1121
+ tools.push({
1122
+ name: `${toolName}_${builtinNames.auth}_set_token`,
1123
+ description: 'Store a bearer token for the current context (shared across all targets)',
1124
+ inputSchema: {
1125
+ type: 'object',
1126
+ properties: {
1127
+ token: { type: 'string', description: 'Bearer token value' },
1128
+ },
1129
+ required: ['token'],
1130
+ },
1131
+ });
1132
+ tools.push({
1133
+ name: `${toolName}_${builtinNames.auth}_status`,
1134
+ description: 'Show authentication status for all contexts',
1135
+ inputSchema: { type: 'object', properties: {} },
1136
+ });
1137
+ tools.push({
1138
+ name: `${toolName}_${builtinNames.auth}_logout`,
1139
+ description: 'Remove credentials for the current context',
1140
+ inputSchema: { type: 'object', properties: {} },
1141
+ });
1142
+ for (const tgt of targets) {
1143
+ for (const table of tgt.tables) {
1144
+ const { singularName } = (0, utils_1.getTableNames)(table);
1145
+ const kebab = (0, komoji_1.toKebabCase)(singularName);
1146
+ const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
1147
+ const scalarFields = (0, utils_1.getScalarFields)(table);
1148
+ const editableFields = (0, docs_utils_1.getEditableFields)(table);
1149
+ const prefix = `${toolName}_${tgt.name}_${kebab}`;
1150
+ tools.push({
1151
+ name: `${prefix}_list`,
1152
+ description: `List all ${table.name} records (${tgt.name} target)`,
1153
+ inputSchema: { type: 'object', properties: {} },
1154
+ });
1155
+ tools.push({
1156
+ name: `${prefix}_get`,
1157
+ description: `Get a single ${table.name} record by ${pk.name} (${tgt.name} target)`,
1158
+ inputSchema: {
1159
+ type: 'object',
1160
+ properties: {
1161
+ [pk.name]: {
1162
+ type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(pk.gqlType),
1163
+ description: `${table.name} ${pk.name}`,
1164
+ },
1165
+ },
1166
+ required: [pk.name],
1167
+ },
1168
+ });
1169
+ const createProps = {};
1170
+ for (const f of editableFields) {
1171
+ createProps[f.name] = {
1172
+ type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(f.type.gqlType),
1173
+ description: `${table.name} ${f.name}`,
1174
+ };
1175
+ }
1176
+ tools.push({
1177
+ name: `${prefix}_create`,
1178
+ description: `Create a new ${table.name} record (${tgt.name} target)`,
1179
+ inputSchema: {
1180
+ type: 'object',
1181
+ properties: createProps,
1182
+ required: editableFields.map((f) => f.name),
1183
+ },
1184
+ });
1185
+ const updateProps = {
1186
+ [pk.name]: {
1187
+ type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(pk.gqlType),
1188
+ description: `${table.name} ${pk.name}`,
1189
+ },
1190
+ };
1191
+ for (const f of editableFields) {
1192
+ updateProps[f.name] = {
1193
+ type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(f.type.gqlType),
1194
+ description: `${table.name} ${f.name}`,
1195
+ };
1196
+ }
1197
+ tools.push({
1198
+ name: `${prefix}_update`,
1199
+ description: `Update an existing ${table.name} record (${tgt.name} target)`,
1200
+ inputSchema: {
1201
+ type: 'object',
1202
+ properties: updateProps,
1203
+ required: [pk.name],
1204
+ },
1205
+ });
1206
+ tools.push({
1207
+ name: `${prefix}_delete`,
1208
+ description: `Delete a ${table.name} record by ${pk.name} (${tgt.name} target)`,
1209
+ inputSchema: {
1210
+ type: 'object',
1211
+ properties: {
1212
+ [pk.name]: {
1213
+ type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(pk.gqlType),
1214
+ description: `${table.name} ${pk.name}`,
1215
+ },
1216
+ },
1217
+ required: [pk.name],
1218
+ },
1219
+ });
1220
+ tools.push({
1221
+ name: `${prefix}_fields`,
1222
+ description: `List available fields for ${table.name} (${tgt.name} target)`,
1223
+ inputSchema: { type: 'object', properties: {} },
1224
+ _meta: {
1225
+ fields: scalarFields.map((f) => ({
1226
+ name: f.name,
1227
+ type: f.type.gqlType,
1228
+ editable: editableFields.some((ef) => ef.name === f.name),
1229
+ primaryKey: f.name === pk.name,
1230
+ })),
1231
+ },
1232
+ });
1233
+ }
1234
+ for (const op of tgt.customOperations) {
1235
+ const kebab = (0, komoji_1.toKebabCase)(op.name);
1236
+ const props = {};
1237
+ const required = [];
1238
+ for (const arg of op.args) {
1239
+ const isRequired = arg.type.kind === 'NON_NULL';
1240
+ const baseType = isRequired && arg.type.ofType ? arg.type.ofType : arg.type;
1241
+ props[arg.name] = {
1242
+ type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(baseType.name ?? 'String'),
1243
+ description: arg.description || arg.name,
1244
+ };
1245
+ if (isRequired) {
1246
+ required.push(arg.name);
1247
+ }
1248
+ }
1249
+ if (tgt.isAuthTarget && op.kind === 'mutation') {
1250
+ props['save_token'] = {
1251
+ type: 'boolean',
1252
+ description: 'Auto-save returned token to credentials',
1253
+ };
1254
+ }
1255
+ tools.push({
1256
+ name: `${toolName}_${tgt.name}_${kebab}`,
1257
+ description: `${op.description || op.name} (${tgt.name} target)`,
1258
+ inputSchema: {
1259
+ type: 'object',
1260
+ properties: props,
1261
+ ...(required.length > 0 ? { required } : {}),
1262
+ },
1263
+ });
1264
+ }
1265
+ }
1266
+ return tools;
1267
+ }
1268
+ function generateMultiTargetSkills(input) {
1269
+ const { toolName, builtinNames, targets } = input;
1270
+ const files = [];
1271
+ const contextUsage = [
1272
+ `${toolName} ${builtinNames.context} create <name>`,
1273
+ `${toolName} ${builtinNames.context} list`,
1274
+ `${toolName} ${builtinNames.context} use <name>`,
1275
+ `${toolName} ${builtinNames.context} current`,
1276
+ `${toolName} ${builtinNames.context} delete <name>`,
1277
+ ];
1278
+ const contextCreateFlags = targets
1279
+ .map((t) => `--${t.name}-endpoint <url>`)
1280
+ .join(' ');
1281
+ files.push({
1282
+ fileName: `skills/${builtinNames.context}.md`,
1283
+ content: (0, docs_utils_1.buildSkillFile)({
1284
+ name: `${toolName}-${builtinNames.context}`,
1285
+ description: `Manage API endpoint contexts for ${toolName} (multi-target: ${targets.map((t) => t.name).join(', ')})`,
1286
+ usage: contextUsage,
1287
+ examples: [
1288
+ {
1289
+ description: 'Create a context for local development (accept all defaults)',
1290
+ code: [
1291
+ `${toolName} ${builtinNames.context} create local`,
1292
+ `${toolName} ${builtinNames.context} use local`,
1293
+ ],
1294
+ },
1295
+ {
1296
+ description: 'Create a production context with custom endpoints',
1297
+ code: [
1298
+ `${toolName} ${builtinNames.context} create production ${contextCreateFlags}`,
1299
+ `${toolName} ${builtinNames.context} use production`,
1300
+ ],
1301
+ },
1302
+ {
1303
+ description: 'List and switch contexts',
1304
+ code: [
1305
+ `${toolName} ${builtinNames.context} list`,
1306
+ `${toolName} ${builtinNames.context} use staging`,
1307
+ ],
1308
+ },
1309
+ ],
1310
+ }),
1311
+ });
1312
+ files.push({
1313
+ fileName: `skills/${builtinNames.auth}.md`,
1314
+ content: (0, docs_utils_1.buildSkillFile)({
1315
+ name: `${toolName}-${builtinNames.auth}`,
1316
+ description: `Manage authentication tokens for ${toolName} (shared across all targets)`,
1317
+ usage: [
1318
+ `${toolName} ${builtinNames.auth} set-token <token>`,
1319
+ `${toolName} ${builtinNames.auth} status`,
1320
+ `${toolName} ${builtinNames.auth} logout`,
1321
+ ],
1322
+ examples: [
1323
+ {
1324
+ description: 'Authenticate with a token',
1325
+ code: [`${toolName} ${builtinNames.auth} set-token eyJhbGciOiJIUzI1NiIs...`],
1326
+ },
1327
+ {
1328
+ description: 'Check auth status',
1329
+ code: [`${toolName} ${builtinNames.auth} status`],
1330
+ },
1331
+ ],
1332
+ }),
1333
+ });
1334
+ for (const tgt of targets) {
1335
+ for (const table of tgt.tables) {
1336
+ const { singularName } = (0, utils_1.getTableNames)(table);
1337
+ const kebab = (0, komoji_1.toKebabCase)(singularName);
1338
+ const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
1339
+ const editableFields = (0, docs_utils_1.getEditableFields)(table);
1340
+ const cmd = `${tgt.name}:${kebab}`;
1341
+ files.push({
1342
+ fileName: `skills/${tgt.name}-${kebab}.md`,
1343
+ content: (0, docs_utils_1.buildSkillFile)({
1344
+ name: `${toolName}-${cmd}`,
1345
+ description: `CRUD operations for ${table.name} records via ${toolName} CLI (${tgt.name} target)`,
1346
+ usage: [
1347
+ `${toolName} ${cmd} list`,
1348
+ `${toolName} ${cmd} get --${pk.name} <value>`,
1349
+ `${toolName} ${cmd} create ${editableFields.map((f) => `--${f.name} <value>`).join(' ')}`,
1350
+ `${toolName} ${cmd} update --${pk.name} <value> ${editableFields.map((f) => `[--${f.name} <value>]`).join(' ')}`,
1351
+ `${toolName} ${cmd} delete --${pk.name} <value>`,
1352
+ ],
1353
+ examples: [
1354
+ {
1355
+ description: `List all ${singularName} records`,
1356
+ code: [`${toolName} ${cmd} list`],
1357
+ },
1358
+ {
1359
+ description: `Create a ${singularName}`,
1360
+ code: [
1361
+ `${toolName} ${cmd} create ${editableFields.map((f) => `--${f.name} "value"`).join(' ')}`,
1362
+ ],
1363
+ },
1364
+ {
1365
+ description: `Get a ${singularName} by ${pk.name}`,
1366
+ code: [`${toolName} ${cmd} get --${pk.name} <value>`],
1367
+ },
1368
+ ],
1369
+ }),
1370
+ });
1371
+ }
1372
+ for (const op of tgt.customOperations) {
1373
+ const kebab = (0, komoji_1.toKebabCase)(op.name);
1374
+ const cmd = `${tgt.name}:${kebab}`;
1375
+ const baseUsage = op.args.length > 0
1376
+ ? `${toolName} ${cmd} ${op.args.map((a) => `--${a.name} <value>`).join(' ')}`
1377
+ : `${toolName} ${cmd}`;
1378
+ const usageLines = [baseUsage];
1379
+ if (tgt.isAuthTarget && op.kind === 'mutation') {
1380
+ usageLines.push(`${baseUsage} --save-token`);
1381
+ }
1382
+ files.push({
1383
+ fileName: `skills/${tgt.name}-${kebab}.md`,
1384
+ content: (0, docs_utils_1.buildSkillFile)({
1385
+ name: `${toolName}-${cmd}`,
1386
+ description: `${op.description || `Execute the ${op.name} ${op.kind}`} (${tgt.name} target)`,
1387
+ usage: usageLines,
1388
+ examples: [
1389
+ {
1390
+ description: `Run ${op.name}`,
1391
+ code: [baseUsage],
1392
+ },
1393
+ ],
1394
+ }),
1395
+ });
1396
+ }
1397
+ }
1398
+ return files;
1399
+ }