@constructive-io/graphql-codegen 4.14.3 → 4.15.0

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.
@@ -95,7 +95,7 @@ function generateReadme(tables, customOperations, toolName, registry) {
95
95
  const kebab = (0, komoji_1.toKebabCase)(singularName);
96
96
  const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
97
97
  const scalarFields = (0, utils_1.getScalarFields)(table);
98
- const editableFields = (0, docs_utils_1.getEditableFields)(table);
98
+ const editableFields = (0, docs_utils_1.getEditableFields)(table, registry);
99
99
  lines.push(`### \`${kebab}\``);
100
100
  lines.push('');
101
101
  lines.push(`CRUD operations for ${table.name} records.`);
@@ -128,6 +128,8 @@ function generateReadme(tables, customOperations, toolName, registry) {
128
128
  if (requiredCreate.length === 0 && optionalCreate.length === 0) {
129
129
  lines.push(`**Create fields:** ${editableFields.map((f) => `\`${f.name}\``).join(', ')}`);
130
130
  }
131
+ const specialGroups = (0, docs_utils_1.categorizeSpecialFields)(table, registry);
132
+ lines.push(...(0, docs_utils_1.buildSpecialFieldsMarkdown)(specialGroups));
131
133
  lines.push('');
132
134
  }
133
135
  }
@@ -181,228 +183,42 @@ function generateReadme(tables, customOperations, toolName, registry) {
181
183
  content: lines.join('\n'),
182
184
  };
183
185
  }
184
- function generateAgentsDocs(tables, customOperations, toolName, registry) {
186
+ function generateAgentsDocs(tables, customOperations, toolName, _registry) {
185
187
  const lines = [];
186
- lines.push(`# ${toolName} CLI - Agent Reference`);
188
+ const tableCount = tables.length;
189
+ const customOpCount = customOperations.length;
190
+ lines.push(`# ${toolName} CLI`);
187
191
  lines.push('');
188
192
  lines.push('<!-- @constructive-io/graphql-codegen - DO NOT EDIT -->');
189
- lines.push('> This document is structured for LLM/agent consumption.');
190
193
  lines.push('');
191
- lines.push('## OVERVIEW');
194
+ lines.push('## Stack');
192
195
  lines.push('');
193
- lines.push(`\`${toolName}\` is a CLI tool for interacting with a GraphQL API.`);
194
- lines.push('All commands output JSON to stdout. All commands accept `--help` or `-h` for usage.');
195
- lines.push(`Configuration is stored at \`~/.${toolName}/config/\` via appstash.`);
196
+ lines.push(`- Generated CLI for a GraphQL API (TypeScript)`);
197
+ lines.push(`- ${tableCount} table${tableCount !== 1 ? 's' : ''}${customOpCount > 0 ? `, ${customOpCount} custom operation${customOpCount !== 1 ? 's' : ''}` : ''}`);
198
+ lines.push(`- Config stored at \`~/.${toolName}/config/\` via appstash`);
196
199
  lines.push('');
197
- lines.push('## PREREQUISITES');
198
- lines.push('');
199
- lines.push('Before running any data commands, you must:');
200
- lines.push('');
201
- lines.push(`1. Create a context: \`${toolName} context create <name> --endpoint <url>\``);
202
- lines.push(`2. Activate it: \`${toolName} context use <name>\``);
203
- lines.push(`3. Authenticate: \`${toolName} auth set-token <token>\``);
204
- lines.push('');
205
- lines.push('## TOOLS');
206
- lines.push('');
207
- lines.push('### TOOL: context');
208
- lines.push('');
209
- lines.push('Manage named API endpoint contexts (like kubectl contexts).');
210
- lines.push('');
211
- lines.push('```');
212
- lines.push('SUBCOMMANDS:');
213
- lines.push(` ${toolName} context create <name> --endpoint <url> Create a new context`);
214
- lines.push(` ${toolName} context list List all contexts`);
215
- lines.push(` ${toolName} context use <name> Set active context`);
216
- lines.push(` ${toolName} context current Show active context`);
217
- lines.push(` ${toolName} context delete <name> Delete a context`);
218
- lines.push('');
219
- lines.push('INPUT:');
220
- lines.push(' name: string (required) - Context identifier');
221
- lines.push(' endpoint: string (required for create) - GraphQL endpoint URL');
222
- lines.push('');
223
- lines.push('OUTPUT: JSON');
224
- lines.push(' create: { name, endpoint }');
225
- lines.push(' list: [{ name, endpoint, isCurrent, hasCredentials }]');
226
- lines.push(' use: { name, endpoint }');
227
- lines.push(' current: { name, endpoint }');
228
- lines.push(' delete: { deleted: name }');
229
- lines.push('```');
230
- lines.push('');
231
- lines.push('### TOOL: auth');
232
- lines.push('');
233
- lines.push('Manage authentication tokens per context.');
234
- lines.push('');
235
- lines.push('```');
236
- lines.push('SUBCOMMANDS:');
237
- lines.push(` ${toolName} auth set-token <token> Store bearer token for current context`);
238
- lines.push(` ${toolName} auth status Show auth status for all contexts`);
239
- lines.push(` ${toolName} auth logout Remove credentials for current context`);
240
- lines.push('');
241
- lines.push('INPUT:');
242
- lines.push(' token: string (required for set-token) - Bearer token value');
243
- lines.push('');
244
- lines.push('OUTPUT: JSON');
245
- lines.push(' set-token: { context, status: "authenticated" }');
246
- lines.push(' status: [{ context, authenticated: boolean }]');
247
- lines.push(' logout: { context, status: "logged out" }');
248
- lines.push('```');
249
- lines.push('');
250
- lines.push('### TOOL: config');
251
- lines.push('');
252
- lines.push('Manage per-context key-value configuration variables.');
253
- lines.push('');
254
- lines.push('```');
255
- lines.push('SUBCOMMANDS:');
256
- lines.push(` ${toolName} config get <key> Get a config value`);
257
- lines.push(` ${toolName} config set <key> <value> Set a config value`);
258
- lines.push(` ${toolName} config list List all config values`);
259
- lines.push(` ${toolName} config delete <key> Delete a config value`);
260
- lines.push('');
261
- lines.push('INPUT:');
262
- lines.push(' key: string (required for get/set/delete) - Variable name');
263
- lines.push(' value: string (required for set) - Variable value');
264
- lines.push('');
265
- lines.push('OUTPUT: JSON');
266
- lines.push(' get: { key, value }');
267
- lines.push(' set: { key, value }');
268
- lines.push(' list: { vars: { key: value, ... } }');
269
- lines.push(' delete: { deleted: key }');
270
- lines.push('```');
271
- lines.push('');
272
- for (const table of tables) {
273
- const { singularName } = (0, utils_1.getTableNames)(table);
274
- const kebab = (0, komoji_1.toKebabCase)(singularName);
275
- const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
276
- const scalarFields = (0, utils_1.getScalarFields)(table);
277
- const editableFields = (0, docs_utils_1.getEditableFields)(table);
278
- const defaultFields = (0, table_command_generator_1.getFieldsWithDefaults)(table, registry);
279
- const requiredCreateFields = editableFields.filter((f) => !defaultFields.has(f.name));
280
- const optionalCreateFields = editableFields.filter((f) => defaultFields.has(f.name));
281
- const createFlags = [
282
- ...requiredCreateFields.map((f) => `--${f.name} <value>`),
283
- ...optionalCreateFields.map((f) => `[--${f.name} <value>]`),
284
- ].join(' ');
285
- lines.push(`### TOOL: ${kebab}`);
286
- lines.push('');
287
- lines.push(`CRUD operations for ${table.name} records.`);
288
- lines.push('');
289
- lines.push('```');
290
- lines.push('SUBCOMMANDS:');
291
- lines.push(` ${toolName} ${kebab} list List all records`);
292
- lines.push(` ${toolName} ${kebab} get --${pk.name} <value> Get one record`);
293
- lines.push(` ${toolName} ${kebab} create ${createFlags}`);
294
- lines.push(` ${toolName} ${kebab} update --${pk.name} <value> ${editableFields.map((f) => `[--${f.name} <value>]`).join(' ')}`);
295
- lines.push(` ${toolName} ${kebab} delete --${pk.name} <value> Delete one record`);
296
- lines.push('');
297
- lines.push('INPUT FIELDS:');
298
- for (const f of scalarFields) {
299
- const isPk = f.name === pk.name;
300
- lines.push(` ${f.name}: ${(0, docs_utils_1.cleanTypeName)(f.type.gqlType)}${isPk ? ' (primary key)' : ''}`);
301
- }
302
- lines.push('');
303
- lines.push('EDITABLE FIELDS (for create/update):');
304
- for (const f of editableFields) {
305
- const optLabel = defaultFields.has(f.name) ? ' (optional, has backend default)' : '';
306
- lines.push(` ${f.name}: ${(0, docs_utils_1.cleanTypeName)(f.type.gqlType)}${optLabel}`);
307
- }
308
- lines.push('');
309
- lines.push('OUTPUT: JSON');
310
- lines.push(` list: [{ ${scalarFields.map((f) => f.name).join(', ')} }]`);
311
- lines.push(` get: { ${scalarFields.map((f) => f.name).join(', ')} }`);
312
- lines.push(` create: { ${scalarFields.map((f) => f.name).join(', ')} }`);
313
- lines.push(` update: { ${scalarFields.map((f) => f.name).join(', ')} }`);
314
- lines.push(` delete: { ${pk.name} }`);
315
- lines.push('```');
316
- lines.push('');
317
- }
318
- for (const op of customOperations) {
319
- const kebab = (0, komoji_1.toKebabCase)(op.name);
320
- const flat = (0, docs_utils_1.flattenArgs)(op.args, registry);
321
- lines.push(`### TOOL: ${kebab}`);
322
- lines.push('');
323
- lines.push(op.description || op.name);
324
- lines.push('');
325
- lines.push('```');
326
- lines.push(`TYPE: ${op.kind}`);
327
- if (flat.length > 0) {
328
- const flags = (0, docs_utils_1.flattenedArgsToFlags)(flat);
329
- lines.push(`USAGE: ${toolName} ${kebab} ${flags}`);
330
- lines.push('');
331
- lines.push('INPUT:');
332
- for (const a of flat) {
333
- const reqLabel = a.required ? ' (required)' : '';
334
- lines.push(` ${a.flag}: ${a.type}${reqLabel}`);
335
- }
336
- }
337
- else {
338
- lines.push(`USAGE: ${toolName} ${kebab}`);
339
- lines.push('');
340
- lines.push('INPUT: none');
341
- }
342
- lines.push('');
343
- lines.push('OUTPUT: JSON');
344
- lines.push('```');
345
- lines.push('');
346
- }
347
- lines.push('## WORKFLOWS');
348
- lines.push('');
349
- lines.push('### Initial setup');
200
+ lines.push('## Quick Start');
350
201
  lines.push('');
351
202
  lines.push('```bash');
352
- lines.push(`${toolName} context create dev --endpoint http://localhost:5000/graphql`);
203
+ lines.push(`${toolName} context create dev --endpoint <url>`);
353
204
  lines.push(`${toolName} context use dev`);
354
- lines.push(`${toolName} auth set-token eyJhbGciOiJIUzI1NiIs...`);
205
+ lines.push(`${toolName} auth set-token <token>`);
355
206
  lines.push('```');
356
207
  lines.push('');
357
- if (tables.length > 0) {
358
- const firstTable = tables[0];
359
- const { singularName } = (0, utils_1.getTableNames)(firstTable);
360
- const kebab = (0, komoji_1.toKebabCase)(singularName);
361
- const editableFields = (0, docs_utils_1.getEditableFields)(firstTable);
362
- const pk = (0, utils_1.getPrimaryKeyInfo)(firstTable)[0];
363
- lines.push(`### CRUD workflow (${kebab})`);
364
- lines.push('');
365
- lines.push('```bash');
366
- lines.push(`# List all`);
367
- lines.push(`${toolName} ${kebab} list`);
368
- lines.push('');
369
- lines.push(`# Create`);
370
- lines.push(`${toolName} ${kebab} create ${editableFields.map((f) => `--${f.name} "value"`).join(' ')}`);
371
- lines.push('');
372
- lines.push(`# Get by ${pk.name}`);
373
- lines.push(`${toolName} ${kebab} get --${pk.name} <value>`);
374
- lines.push('');
375
- lines.push(`# Update`);
376
- lines.push(`${toolName} ${kebab} update --${pk.name} <value> --${editableFields[0]?.name || 'field'} "new-value"`);
377
- lines.push('');
378
- lines.push(`# Delete`);
379
- lines.push(`${toolName} ${kebab} delete --${pk.name} <value>`);
380
- lines.push('```');
381
- lines.push('');
382
- }
383
- lines.push('### Piping output');
208
+ lines.push('## Resources');
384
209
  lines.push('');
385
- lines.push('```bash');
386
- lines.push(`# Pretty print`);
387
- lines.push(`${toolName} car list | jq '.'`);
388
- lines.push('');
389
- lines.push(`# Extract field`);
390
- lines.push(`${toolName} car list | jq '.[].id'`);
210
+ lines.push(`- **Full API reference:** [README.md](./README.md) — CRUD docs for all ${tableCount} tables`);
211
+ lines.push('- **Schema types:** [types.ts](./types.ts)');
391
212
  lines.push('');
392
- lines.push(`# Count results`);
393
- lines.push(`${toolName} car list | jq 'length'`);
394
- lines.push('```');
213
+ lines.push('## Conventions');
395
214
  lines.push('');
396
- lines.push('## ERROR HANDLING');
215
+ lines.push('- All commands output JSON to stdout');
216
+ lines.push('- Use `--help` on any command for usage');
217
+ lines.push('- Exit 0 = success, 1 = error');
397
218
  lines.push('');
398
- lines.push('All errors are written to stderr. Exit codes:');
399
- lines.push('- `0`: Success');
400
- lines.push('- `1`: Error (auth failure, not found, validation error, network error)');
219
+ lines.push('## Boundaries');
401
220
  lines.push('');
402
- lines.push('Common errors:');
403
- lines.push('- "No active context": Run `context use <name>` first');
404
- lines.push('- "Not authenticated": Run `auth set-token <token>` first');
405
- lines.push('- "Record not found": The requested ID does not exist');
221
+ lines.push('All files in this directory are generated. Do not edit manually.');
406
222
  lines.push('');
407
223
  return {
408
224
  fileName: 'AGENTS.md',
@@ -520,7 +336,7 @@ function getCliMcpTools(tables, customOperations, toolName, registry) {
520
336
  const kebab = (0, komoji_1.toKebabCase)(singularName);
521
337
  const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
522
338
  const scalarFields = (0, utils_1.getScalarFields)(table);
523
- const editableFields = (0, docs_utils_1.getEditableFields)(table);
339
+ const editableFields = (0, docs_utils_1.getEditableFields)(table, registry);
524
340
  const defaultFields = (0, table_command_generator_1.getFieldsWithDefaults)(table, registry);
525
341
  const requiredCreateFieldNames = editableFields
526
342
  .filter((f) => !defaultFields.has(f.name))
@@ -725,18 +541,23 @@ function generateSkills(tables, customOperations, toolName, targetName, registry
725
541
  const { singularName } = (0, utils_1.getTableNames)(table);
726
542
  const kebab = (0, komoji_1.toKebabCase)(singularName);
727
543
  const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
728
- const editableFields = (0, docs_utils_1.getEditableFields)(table);
544
+ const editableFields = (0, docs_utils_1.getEditableFields)(table, registry);
729
545
  const defaultFields = (0, table_command_generator_1.getFieldsWithDefaults)(table, registry);
730
546
  const createFlags = [
731
547
  ...editableFields.filter((f) => !defaultFields.has(f.name)).map((f) => `--${f.name} <value>`),
732
548
  ...editableFields.filter((f) => defaultFields.has(f.name)).map((f) => `[--${f.name} <value>]`),
733
549
  ].join(' ');
734
550
  referenceNames.push(kebab);
551
+ const skillSpecialGroups = (0, docs_utils_1.categorizeSpecialFields)(table, registry);
552
+ const skillSpecialDesc = skillSpecialGroups.length > 0
553
+ ? `CRUD operations for ${table.name} records via ${toolName} CLI\n\n` +
554
+ skillSpecialGroups.map((g) => `**${g.label}:** ${g.fields.map((f) => `\`${f.name}\``).join(', ')}\n${g.description}`).join('\n\n')
555
+ : `CRUD operations for ${table.name} records via ${toolName} CLI`;
735
556
  files.push({
736
557
  fileName: `${skillName}/references/${kebab}.md`,
737
558
  content: (0, docs_utils_1.buildSkillReference)({
738
559
  title: singularName,
739
- description: `CRUD operations for ${table.name} records via ${toolName} CLI`,
560
+ description: skillSpecialDesc,
740
561
  usage: [
741
562
  `${toolName} ${kebab} list`,
742
563
  `${toolName} ${kebab} get --${pk.name} <value>`,
@@ -994,7 +815,7 @@ function generateMultiTargetReadme(input) {
994
815
  const kebab = (0, komoji_1.toKebabCase)(singularName);
995
816
  const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
996
817
  const scalarFields = (0, utils_1.getScalarFields)(table);
997
- const editableFields = (0, docs_utils_1.getEditableFields)(table);
818
+ const editableFields = (0, docs_utils_1.getEditableFields)(table, registry);
998
819
  const defaultFields = (0, table_command_generator_1.getFieldsWithDefaults)(table, registry);
999
820
  lines.push(`### \`${tgt.name}:${kebab}\``);
1000
821
  lines.push('');
@@ -1027,6 +848,8 @@ function generateMultiTargetReadme(input) {
1027
848
  if (requiredCreate.length === 0 && optionalCreate.length === 0) {
1028
849
  lines.push(`**Create fields:** ${editableFields.map((f) => `\`${f.name}\``).join(', ')}`);
1029
850
  }
851
+ const mtSpecialGroups = (0, docs_utils_1.categorizeSpecialFields)(table, registry);
852
+ lines.push(...(0, docs_utils_1.buildSpecialFieldsMarkdown)(mtSpecialGroups));
1030
853
  lines.push('');
1031
854
  }
1032
855
  for (const op of tgt.customOperations) {
@@ -1088,283 +911,50 @@ function generateMultiTargetReadme(input) {
1088
911
  };
1089
912
  }
1090
913
  function generateMultiTargetAgentsDocs(input) {
1091
- const { toolName, builtinNames, targets, registry } = input;
914
+ const { toolName, builtinNames, targets } = input;
1092
915
  const lines = [];
1093
- lines.push(`# ${toolName} CLI - Agent Reference`);
916
+ const totalTables = targets.reduce((sum, t) => sum + t.tables.length, 0);
917
+ const totalCustomOps = targets.reduce((sum, t) => sum + t.customOperations.length, 0);
918
+ lines.push(`# ${toolName} CLI`);
1094
919
  lines.push('');
1095
920
  lines.push('<!-- @constructive-io/graphql-codegen - DO NOT EDIT -->');
1096
- lines.push('> This document is structured for LLM/agent consumption.');
1097
921
  lines.push('');
1098
- lines.push('## OVERVIEW');
922
+ lines.push('## Stack');
1099
923
  lines.push('');
1100
- lines.push(`\`${toolName}\` is a unified multi-target CLI for interacting with multiple GraphQL APIs.`);
1101
- lines.push('All commands output JSON to stdout. All commands accept `--help` or `-h` for usage.');
1102
- lines.push(`Configuration is stored at \`~/.${toolName}/config/\` via appstash.`);
924
+ lines.push(`- Unified multi-target CLI for GraphQL APIs (TypeScript)`);
925
+ lines.push(`- ${targets.length} target${targets.length !== 1 ? 's' : ''}: ${targets.map((t) => t.name).join(', ')}`);
926
+ lines.push(`- ${totalTables} table${totalTables !== 1 ? 's' : ''}${totalCustomOps > 0 ? `, ${totalCustomOps} custom operation${totalCustomOps !== 1 ? 's' : ''}` : ''}`);
927
+ lines.push(`- Config stored at \`~/.${toolName}/config/\` via appstash`);
1103
928
  lines.push('');
1104
- lines.push('TARGETS:');
1105
- for (const tgt of targets) {
1106
- lines.push(` ${tgt.name}: ${tgt.endpoint}`);
1107
- }
1108
- lines.push('');
1109
- lines.push('COMMAND FORMAT:');
1110
- lines.push(` ${toolName} <target>:<command> <subcommand> [flags] Target-specific commands`);
1111
- lines.push(` ${toolName} ${builtinNames.context} <subcommand> [flags] Context management`);
1112
- lines.push(` ${toolName} ${builtinNames.auth} <subcommand> [flags] Authentication`);
1113
- lines.push(` ${toolName} ${builtinNames.config} <subcommand> [flags] Config key-value store`);
1114
- lines.push('');
1115
- lines.push('## PREREQUISITES');
1116
- lines.push('');
1117
- lines.push('Before running any data commands, you must:');
1118
- lines.push('');
1119
- lines.push(`1. Create a context: \`${toolName} ${builtinNames.context} create <name>\``);
1120
- lines.push(` (prompts for per-target endpoints, defaults baked from config)`);
1121
- lines.push(`2. Activate it: \`${toolName} ${builtinNames.context} use <name>\``);
1122
- lines.push(`3. Authenticate: \`${toolName} ${builtinNames.auth} set-token <token>\``);
1123
- lines.push('');
1124
- lines.push('For local development, create a context accepting all defaults:');
929
+ lines.push('## Quick Start');
1125
930
  lines.push('');
1126
931
  lines.push('```bash');
1127
- lines.push(`${toolName} ${builtinNames.context} create local`);
1128
- lines.push(`${toolName} ${builtinNames.context} use local`);
932
+ lines.push(`${toolName} ${builtinNames.context} create dev`);
933
+ lines.push(`${toolName} ${builtinNames.context} use dev`);
1129
934
  lines.push(`${toolName} ${builtinNames.auth} set-token <token>`);
1130
935
  lines.push('```');
1131
936
  lines.push('');
1132
- lines.push('## TOOLS');
1133
- lines.push('');
1134
- lines.push(`### TOOL: ${builtinNames.context}`);
1135
- lines.push('');
1136
- lines.push('Manage named API endpoint contexts. Each context stores per-target endpoint overrides.');
1137
- lines.push('');
1138
- lines.push('```');
1139
- lines.push('SUBCOMMANDS:');
1140
- lines.push(` ${toolName} ${builtinNames.context} create <name> Create a new context`);
1141
- lines.push(` ${toolName} ${builtinNames.context} list List all contexts`);
1142
- lines.push(` ${toolName} ${builtinNames.context} use <name> Set active context`);
1143
- lines.push(` ${toolName} ${builtinNames.context} current Show active context`);
1144
- lines.push(` ${toolName} ${builtinNames.context} delete <name> Delete a context`);
1145
- lines.push('');
1146
- lines.push('CREATE OPTIONS:');
1147
- for (const tgt of targets) {
1148
- lines.push(` --${tgt.name}-endpoint: string (default: ${tgt.endpoint})`);
1149
- }
1150
- lines.push('');
1151
- lines.push('OUTPUT: JSON');
1152
- lines.push(' create: { name, endpoint, targets }');
1153
- lines.push(' list: [{ name, endpoint, isCurrent, hasCredentials }]');
1154
- lines.push(' use: { name, endpoint }');
1155
- lines.push(' current: { name, endpoint }');
1156
- lines.push(' delete: { deleted: name }');
1157
- lines.push('```');
1158
- lines.push('');
1159
- lines.push(`### TOOL: ${builtinNames.auth}`);
1160
- lines.push('');
1161
- lines.push('Manage authentication tokens per context. One shared token across all targets.');
1162
- lines.push('');
1163
- lines.push('```');
1164
- lines.push('SUBCOMMANDS:');
1165
- lines.push(` ${toolName} ${builtinNames.auth} set-token <token> Store bearer token for current context`);
1166
- lines.push(` ${toolName} ${builtinNames.auth} status Show auth status for all contexts`);
1167
- lines.push(` ${toolName} ${builtinNames.auth} logout Remove credentials for current context`);
1168
- lines.push('');
1169
- lines.push('INPUT:');
1170
- lines.push(' token: string (required for set-token) - Bearer token value');
1171
- lines.push('');
1172
- lines.push('OUTPUT: JSON');
1173
- lines.push(' set-token: { context, status: "authenticated" }');
1174
- lines.push(' status: [{ context, authenticated: boolean }]');
1175
- lines.push(' logout: { context, status: "logged out" }');
1176
- lines.push('```');
1177
- lines.push('');
1178
- lines.push(`### TOOL: ${builtinNames.config}`);
1179
- lines.push('');
1180
- lines.push('Manage per-context key-value configuration variables.');
1181
- lines.push('');
1182
- lines.push('```');
1183
- lines.push('SUBCOMMANDS:');
1184
- lines.push(` ${toolName} ${builtinNames.config} get <key> Get a config value`);
1185
- lines.push(` ${toolName} ${builtinNames.config} set <key> <value> Set a config value`);
1186
- lines.push(` ${toolName} ${builtinNames.config} list List all config values`);
1187
- lines.push(` ${toolName} ${builtinNames.config} delete <key> Delete a config value`);
1188
- lines.push('');
1189
- lines.push('INPUT:');
1190
- lines.push(' key: string (required for get/set/delete) - Variable name');
1191
- lines.push(' value: string (required for set) - Variable value');
1192
- lines.push('');
1193
- lines.push('OUTPUT: JSON');
1194
- lines.push(' get: { key, value }');
1195
- lines.push(' set: { key, value }');
1196
- lines.push(' list: { vars: { key: value, ... } }');
1197
- lines.push(' delete: { deleted: key }');
1198
- lines.push('```');
1199
- lines.push('');
1200
- lines.push('### TOOL: helpers (SDK)');
1201
- lines.push('');
1202
- lines.push('Typed client factories for use in scripts and services (generated helpers.ts).');
1203
- lines.push('Resolves credentials via: appstash store -> env vars -> throw.');
937
+ lines.push('## Command Format');
1204
938
  lines.push('');
1205
939
  lines.push('```');
1206
- lines.push('FACTORIES:');
1207
- for (const tgt of targets) {
1208
- const pascalName = tgt.name.charAt(0).toUpperCase() + tgt.name.slice(1);
1209
- lines.push(` create${pascalName}Client(contextName?) Create a configured ${tgt.name} ORM client`);
1210
- }
1211
- lines.push('');
1212
- lines.push('USAGE:');
1213
- lines.push(` import { create${targets[0] ? targets[0].name.charAt(0).toUpperCase() + targets[0].name.slice(1) : 'Target'}Client } from './helpers';`);
1214
- lines.push(` const client = create${targets[0] ? targets[0].name.charAt(0).toUpperCase() + targets[0].name.slice(1) : 'Target'}Client();`);
1215
- lines.push('');
1216
- lines.push('CREDENTIAL RESOLUTION:');
1217
- lines.push(` 1. appstash store (~/.${toolName}/config/)`);
1218
- const envPrefix = toolName.toUpperCase().replace(/-/g, '_');
1219
- lines.push(` 2. env vars (${envPrefix}_TOKEN, ${envPrefix}_<TARGET>_ENDPOINT)`);
1220
- lines.push(' 3. throws with actionable error message');
1221
- lines.push('```');
1222
- lines.push('');
1223
- for (const tgt of targets) {
1224
- for (const table of tgt.tables) {
1225
- const { singularName } = (0, utils_1.getTableNames)(table);
1226
- const kebab = (0, komoji_1.toKebabCase)(singularName);
1227
- const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
1228
- const scalarFields = (0, utils_1.getScalarFields)(table);
1229
- const editableFields = (0, docs_utils_1.getEditableFields)(table);
1230
- const defaultFields = (0, table_command_generator_1.getFieldsWithDefaults)(table, registry);
1231
- const requiredCreateFields = editableFields.filter((f) => !defaultFields.has(f.name));
1232
- const optionalCreateFields = editableFields.filter((f) => defaultFields.has(f.name));
1233
- const createFlags = [
1234
- ...requiredCreateFields.map((f) => `--${f.name} <value>`),
1235
- ...optionalCreateFields.map((f) => `[--${f.name} <value>]`),
1236
- ].join(' ');
1237
- lines.push(`### TOOL: ${tgt.name}:${kebab}`);
1238
- lines.push('');
1239
- lines.push(`CRUD operations for ${table.name} records (${tgt.name} target).`);
1240
- lines.push('');
1241
- lines.push('```');
1242
- lines.push('SUBCOMMANDS:');
1243
- lines.push(` ${toolName} ${tgt.name}:${kebab} list List all records`);
1244
- lines.push(` ${toolName} ${tgt.name}:${kebab} get --${pk.name} <value> Get one record`);
1245
- lines.push(` ${toolName} ${tgt.name}:${kebab} create ${createFlags}`);
1246
- lines.push(` ${toolName} ${tgt.name}:${kebab} update --${pk.name} <value> ${editableFields.map((f) => `[--${f.name} <value>]`).join(' ')}`);
1247
- lines.push(` ${toolName} ${tgt.name}:${kebab} delete --${pk.name} <value> Delete one record`);
1248
- lines.push('');
1249
- lines.push('INPUT FIELDS:');
1250
- for (const f of scalarFields) {
1251
- const isPk = f.name === pk.name;
1252
- lines.push(` ${f.name}: ${(0, docs_utils_1.cleanTypeName)(f.type.gqlType)}${isPk ? ' (primary key)' : ''}`);
1253
- }
1254
- lines.push('');
1255
- lines.push('EDITABLE FIELDS (for create/update):');
1256
- for (const f of editableFields) {
1257
- const optLabel = defaultFields.has(f.name) ? ' (optional, has backend default)' : '';
1258
- lines.push(` ${f.name}: ${(0, docs_utils_1.cleanTypeName)(f.type.gqlType)}${optLabel}`);
1259
- }
1260
- lines.push('');
1261
- lines.push('OUTPUT: JSON');
1262
- lines.push(` list: [{ ${scalarFields.map((f) => f.name).join(', ')} }]`);
1263
- lines.push(` get: { ${scalarFields.map((f) => f.name).join(', ')} }`);
1264
- lines.push(` create: { ${scalarFields.map((f) => f.name).join(', ')} }`);
1265
- lines.push(` update: { ${scalarFields.map((f) => f.name).join(', ')} }`);
1266
- lines.push(` delete: { ${pk.name} }`);
1267
- lines.push('```');
1268
- lines.push('');
1269
- }
1270
- for (const op of tgt.customOperations) {
1271
- const kebab = (0, komoji_1.toKebabCase)(op.name);
1272
- const flat = (0, docs_utils_1.flattenArgs)(op.args, registry);
1273
- lines.push(`### TOOL: ${tgt.name}:${kebab}`);
1274
- lines.push('');
1275
- lines.push(op.description || op.name);
1276
- lines.push('');
1277
- lines.push('```');
1278
- lines.push(`TYPE: ${op.kind}`);
1279
- if (flat.length > 0) {
1280
- const flags = (0, docs_utils_1.flattenedArgsToFlags)(flat);
1281
- lines.push(`USAGE: ${toolName} ${tgt.name}:${kebab} ${flags}`);
1282
- lines.push('');
1283
- lines.push('INPUT:');
1284
- for (const a of flat) {
1285
- const reqLabel = a.required ? ' (required)' : '';
1286
- lines.push(` ${a.flag}: ${a.type}${reqLabel}`);
1287
- }
1288
- }
1289
- else {
1290
- lines.push(`USAGE: ${toolName} ${tgt.name}:${kebab}`);
1291
- lines.push('');
1292
- lines.push('INPUT: none');
1293
- }
1294
- if (tgt.isAuthTarget && op.kind === 'mutation') {
1295
- lines.push('');
1296
- lines.push('FLAGS:');
1297
- lines.push(' --save-token: boolean - Auto-save returned token to credentials');
1298
- }
1299
- lines.push('');
1300
- lines.push('OUTPUT: JSON');
1301
- lines.push('```');
1302
- lines.push('');
1303
- }
1304
- }
1305
- lines.push('## WORKFLOWS');
1306
- lines.push('');
1307
- lines.push('### Initial setup');
1308
- lines.push('');
1309
- lines.push('```bash');
1310
- lines.push(`${toolName} ${builtinNames.context} create dev`);
1311
- lines.push(`${toolName} ${builtinNames.context} use dev`);
1312
- lines.push(`${toolName} ${builtinNames.auth} set-token eyJhbGciOiJIUzI1NiIs...`);
940
+ lines.push(`${toolName} <target>:<command> <subcommand> [flags]`);
1313
941
  lines.push('```');
1314
942
  lines.push('');
1315
- lines.push('### Switch environment');
943
+ lines.push('## Resources');
1316
944
  lines.push('');
1317
- lines.push('```bash');
1318
- lines.push(`${toolName} ${builtinNames.context} create production \\`);
1319
- for (let i = 0; i < targets.length; i++) {
1320
- const tgt = targets[i];
1321
- const continuation = i < targets.length - 1 ? ' \\' : '';
1322
- lines.push(` --${tgt.name}-endpoint https://${tgt.name}.prod.example.com/graphql${continuation}`);
1323
- }
1324
- lines.push(`${toolName} ${builtinNames.context} use production`);
1325
- lines.push('```');
1326
- lines.push('');
1327
- if (targets.length > 0 && targets[0].tables.length > 0) {
1328
- const tgt = targets[0];
1329
- const table = tgt.tables[0];
1330
- const { singularName } = (0, utils_1.getTableNames)(table);
1331
- const kebab = (0, komoji_1.toKebabCase)(singularName);
1332
- const editableFields = (0, docs_utils_1.getEditableFields)(table);
1333
- const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
1334
- lines.push(`### CRUD workflow (${tgt.name}:${kebab})`);
1335
- lines.push('');
1336
- lines.push('```bash');
1337
- lines.push(`${toolName} ${tgt.name}:${kebab} list`);
1338
- lines.push(`${toolName} ${tgt.name}:${kebab} create ${editableFields.map((f) => `--${f.name} "value"`).join(' ')}`);
1339
- lines.push(`${toolName} ${tgt.name}:${kebab} get --${pk.name} <value>`);
1340
- lines.push(`${toolName} ${tgt.name}:${kebab} update --${pk.name} <value> --${editableFields[0]?.name || 'field'} "new-value"`);
1341
- lines.push(`${toolName} ${tgt.name}:${kebab} delete --${pk.name} <value>`);
1342
- lines.push('```');
1343
- lines.push('');
1344
- }
1345
- lines.push('### Piping output');
945
+ lines.push(`- **Full API reference:** [README.md](./README.md) — CRUD docs for all ${totalTables} tables across ${targets.length} targets`);
946
+ lines.push('- **Schema types:** [types.ts](./types.ts)');
947
+ lines.push('- **SDK helpers:** [helpers.ts](./helpers.ts) typed client factories');
1346
948
  lines.push('');
1347
- lines.push('```bash');
1348
- if (targets.length > 0 && targets[0].tables.length > 0) {
1349
- const tgt = targets[0];
1350
- const kebab = (0, komoji_1.toKebabCase)((0, utils_1.getTableNames)(tgt.tables[0]).singularName);
1351
- lines.push(`${toolName} ${tgt.name}:${kebab} list | jq '.'`);
1352
- lines.push(`${toolName} ${tgt.name}:${kebab} list | jq '.[].id'`);
1353
- lines.push(`${toolName} ${tgt.name}:${kebab} list | jq 'length'`);
1354
- }
1355
- lines.push('```');
949
+ lines.push('## Conventions');
1356
950
  lines.push('');
1357
- lines.push('## ERROR HANDLING');
951
+ lines.push('- All commands output JSON to stdout');
952
+ lines.push('- Use `--help` on any command for usage');
953
+ lines.push('- Exit 0 = success, 1 = error');
1358
954
  lines.push('');
1359
- lines.push('All errors are written to stderr. Exit codes:');
1360
- lines.push('- `0`: Success');
1361
- lines.push('- `1`: Error (auth failure, not found, validation error, network error)');
955
+ lines.push('## Boundaries');
1362
956
  lines.push('');
1363
- lines.push('Common errors:');
1364
- lines.push(`- "No active context": Run \`${builtinNames.context} use <name>\` first`);
1365
- lines.push(`- "Not authenticated": Run \`${builtinNames.auth} set-token <token>\` first`);
1366
- lines.push('- "Unknown target": The target name is not recognized');
1367
- lines.push('- "Record not found": The requested ID does not exist');
957
+ lines.push('All files in this directory are generated. Do not edit manually.');
1368
958
  lines.push('');
1369
959
  return {
1370
960
  fileName: 'AGENTS.md',
@@ -1490,7 +1080,7 @@ function getMultiTargetCliMcpTools(input) {
1490
1080
  const kebab = (0, komoji_1.toKebabCase)(singularName);
1491
1081
  const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
1492
1082
  const scalarFields = (0, utils_1.getScalarFields)(table);
1493
- const editableFields = (0, docs_utils_1.getEditableFields)(table);
1083
+ const editableFields = (0, docs_utils_1.getEditableFields)(table, registry);
1494
1084
  const defaultFields = (0, table_command_generator_1.getFieldsWithDefaults)(table, registry);
1495
1085
  const requiredCreateFieldNames = editableFields
1496
1086
  .filter((f) => !defaultFields.has(f.name))
@@ -1752,7 +1342,7 @@ function generateMultiTargetSkills(input) {
1752
1342
  const { singularName } = (0, utils_1.getTableNames)(table);
1753
1343
  const kebab = (0, komoji_1.toKebabCase)(singularName);
1754
1344
  const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
1755
- const editableFields = (0, docs_utils_1.getEditableFields)(table);
1345
+ const editableFields = (0, docs_utils_1.getEditableFields)(table, registry);
1756
1346
  const defaultFields = (0, table_command_generator_1.getFieldsWithDefaults)(table, registry);
1757
1347
  const createFlags = [
1758
1348
  ...editableFields.filter((f) => !defaultFields.has(f.name)).map((f) => `--${f.name} <value>`),
@@ -1760,11 +1350,16 @@ function generateMultiTargetSkills(input) {
1760
1350
  ].join(' ');
1761
1351
  const cmd = `${tgt.name}:${kebab}`;
1762
1352
  tgtReferenceNames.push(kebab);
1353
+ const mtSkillSpecialGroups = (0, docs_utils_1.categorizeSpecialFields)(table, registry);
1354
+ const mtSkillSpecialDesc = mtSkillSpecialGroups.length > 0
1355
+ ? `CRUD operations for ${table.name} records via ${toolName} CLI (${tgt.name} target)\n\n` +
1356
+ mtSkillSpecialGroups.map((g) => `**${g.label}:** ${g.fields.map((f) => `\`${f.name}\``).join(', ')}\n${g.description}`).join('\n\n')
1357
+ : `CRUD operations for ${table.name} records via ${toolName} CLI (${tgt.name} target)`;
1763
1358
  files.push({
1764
1359
  fileName: `${tgtSkillName}/references/${kebab}.md`,
1765
1360
  content: (0, docs_utils_1.buildSkillReference)({
1766
1361
  title: singularName,
1767
- description: `CRUD operations for ${table.name} records via ${toolName} CLI (${tgt.name} target)`,
1362
+ description: mtSkillSpecialDesc,
1768
1363
  usage: [
1769
1364
  `${toolName} ${cmd} list`,
1770
1365
  `${toolName} ${cmd} get --${pk.name} <value>`,