@constructive-io/graphql-codegen 4.9.0 → 4.12.2

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 (33) hide show
  1. package/core/codegen/cli/arg-mapper.d.ts +1 -1
  2. package/core/codegen/cli/arg-mapper.js +15 -11
  3. package/core/codegen/cli/custom-command-generator.js +4 -3
  4. package/core/codegen/cli/docs-generator.d.ts +6 -5
  5. package/core/codegen/cli/docs-generator.js +167 -64
  6. package/core/codegen/cli/table-command-generator.d.ts +15 -0
  7. package/core/codegen/cli/table-command-generator.js +20 -1
  8. package/core/codegen/docs-utils.d.ts +26 -1
  9. package/core/codegen/docs-utils.js +105 -0
  10. package/core/codegen/orm/input-types-generator.js +112 -14
  11. package/core/codegen/orm/model-generator.js +8 -0
  12. package/core/codegen/orm/select-types.d.ts +4 -2
  13. package/core/codegen/scalars.js +8 -0
  14. package/core/codegen/templates/cli-entry.ts +2 -2
  15. package/core/codegen/templates/cli-utils.ts +28 -0
  16. package/core/codegen/templates/query-builder.ts +28 -5
  17. package/core/codegen/templates/select-types.ts +4 -2
  18. package/core/generate.js +14 -4
  19. package/esm/core/codegen/cli/arg-mapper.d.ts +1 -1
  20. package/esm/core/codegen/cli/arg-mapper.js +15 -11
  21. package/esm/core/codegen/cli/custom-command-generator.js +4 -3
  22. package/esm/core/codegen/cli/docs-generator.d.ts +6 -5
  23. package/esm/core/codegen/cli/docs-generator.js +168 -65
  24. package/esm/core/codegen/cli/table-command-generator.d.ts +15 -0
  25. package/esm/core/codegen/cli/table-command-generator.js +20 -3
  26. package/esm/core/codegen/docs-utils.d.ts +26 -1
  27. package/esm/core/codegen/docs-utils.js +102 -0
  28. package/esm/core/codegen/orm/input-types-generator.js +112 -14
  29. package/esm/core/codegen/orm/model-generator.js +8 -0
  30. package/esm/core/codegen/orm/select-types.d.ts +4 -2
  31. package/esm/core/codegen/scalars.js +8 -0
  32. package/esm/core/generate.js +14 -4
  33. package/package.json +11 -11
@@ -1,8 +1,9 @@
1
1
  import { toKebabCase } from 'komoji';
2
- import { formatArgType, getEditableFields, getReadmeHeader, getReadmeFooter, gqlTypeToJsonSchemaType, buildSkillFile, buildSkillReference, } from '../docs-utils';
2
+ import { flattenArgs, flattenedArgsToFlags, cleanTypeName, getEditableFields, getReadmeHeader, getReadmeFooter, gqlTypeToJsonSchemaType, buildSkillFile, buildSkillReference, } from '../docs-utils';
3
3
  import { getScalarFields, getTableNames, getPrimaryKeyInfo, } from '../utils';
4
+ import { getFieldsWithDefaults } from './table-command-generator';
4
5
  export { resolveDocsConfig } from '../docs-utils';
5
- export function generateReadme(tables, customOperations, toolName) {
6
+ export function generateReadme(tables, customOperations, toolName, registry) {
6
7
  const lines = [];
7
8
  lines.push(...getReadmeHeader(`${toolName} CLI`));
8
9
  lines.push('## Setup');
@@ -86,10 +87,21 @@ export function generateReadme(tables, customOperations, toolName) {
86
87
  lines.push('| Field | Type |');
87
88
  lines.push('|-------|------|');
88
89
  for (const f of scalarFields) {
89
- lines.push(`| \`${f.name}\` | ${f.type.gqlType} |`);
90
+ lines.push(`| \`${f.name}\` | ${cleanTypeName(f.type.gqlType)} |`);
90
91
  }
91
92
  lines.push('');
92
- lines.push(`**Create fields:** ${editableFields.map((f) => `\`${f.name}\``).join(', ')}`);
93
+ const defaultFields = getFieldsWithDefaults(table, registry);
94
+ const requiredCreate = editableFields.filter((f) => !defaultFields.has(f.name));
95
+ const optionalCreate = editableFields.filter((f) => defaultFields.has(f.name));
96
+ if (requiredCreate.length > 0) {
97
+ lines.push(`**Required create fields:** ${requiredCreate.map((f) => `\`${f.name}\``).join(', ')}`);
98
+ }
99
+ if (optionalCreate.length > 0) {
100
+ lines.push(`**Optional create fields (backend defaults):** ${optionalCreate.map((f) => `\`${f.name}\``).join(', ')}`);
101
+ }
102
+ if (requiredCreate.length === 0 && optionalCreate.length === 0) {
103
+ lines.push(`**Create fields:** ${editableFields.map((f) => `\`${f.name}\``).join(', ')}`);
104
+ }
93
105
  lines.push('');
94
106
  }
95
107
  }
@@ -98,18 +110,20 @@ export function generateReadme(tables, customOperations, toolName) {
98
110
  lines.push('');
99
111
  for (const op of customOperations) {
100
112
  const kebab = toKebabCase(op.name);
113
+ const flat = flattenArgs(op.args, registry);
101
114
  lines.push(`### \`${kebab}\``);
102
115
  lines.push('');
103
116
  lines.push(op.description || op.name);
104
117
  lines.push('');
105
118
  lines.push(`- **Type:** ${op.kind}`);
106
- if (op.args.length > 0) {
119
+ if (flat.length > 0) {
107
120
  lines.push('- **Arguments:**');
108
121
  lines.push('');
109
122
  lines.push(' | Argument | Type |');
110
123
  lines.push(' |----------|------|');
111
- for (const arg of op.args) {
112
- lines.push(` | \`${arg.name}\` | ${formatArgType(arg)} |`);
124
+ for (const a of flat) {
125
+ const reqLabel = a.required ? ' (required)' : '';
126
+ lines.push(` | \`--${a.flag}\` | ${a.type}${reqLabel} |`);
113
127
  }
114
128
  }
115
129
  else {
@@ -127,13 +141,21 @@ export function generateReadme(tables, customOperations, toolName) {
127
141
  lines.push(`${toolName} car get --id <uuid> | jq '.'`);
128
142
  lines.push('```');
129
143
  lines.push('');
144
+ lines.push('## Non-Interactive Mode');
145
+ lines.push('');
146
+ lines.push('Use `--no-tty` to skip all interactive prompts (useful for scripts and CI):');
147
+ lines.push('');
148
+ lines.push('```bash');
149
+ lines.push(`${toolName} --no-tty car create --name "Sedan" --year 2024`);
150
+ lines.push('```');
151
+ lines.push('');
130
152
  lines.push(...getReadmeFooter());
131
153
  return {
132
154
  fileName: 'README.md',
133
155
  content: lines.join('\n'),
134
156
  };
135
157
  }
136
- export function generateAgentsDocs(tables, customOperations, toolName) {
158
+ export function generateAgentsDocs(tables, customOperations, toolName, registry) {
137
159
  const lines = [];
138
160
  lines.push(`# ${toolName} CLI - Agent Reference`);
139
161
  lines.push('');
@@ -205,6 +227,13 @@ export function generateAgentsDocs(tables, customOperations, toolName) {
205
227
  const pk = getPrimaryKeyInfo(table)[0];
206
228
  const scalarFields = getScalarFields(table);
207
229
  const editableFields = getEditableFields(table);
230
+ const defaultFields = getFieldsWithDefaults(table, registry);
231
+ const requiredCreateFields = editableFields.filter((f) => !defaultFields.has(f.name));
232
+ const optionalCreateFields = editableFields.filter((f) => defaultFields.has(f.name));
233
+ const createFlags = [
234
+ ...requiredCreateFields.map((f) => `--${f.name} <value>`),
235
+ ...optionalCreateFields.map((f) => `[--${f.name} <value>]`),
236
+ ].join(' ');
208
237
  lines.push(`### TOOL: ${kebab}`);
209
238
  lines.push('');
210
239
  lines.push(`CRUD operations for ${table.name} records.`);
@@ -213,19 +242,20 @@ export function generateAgentsDocs(tables, customOperations, toolName) {
213
242
  lines.push('SUBCOMMANDS:');
214
243
  lines.push(` ${toolName} ${kebab} list List all records`);
215
244
  lines.push(` ${toolName} ${kebab} get --${pk.name} <value> Get one record`);
216
- lines.push(` ${toolName} ${kebab} create ${editableFields.map((f) => `--${f.name} <value>`).join(' ')}`);
245
+ lines.push(` ${toolName} ${kebab} create ${createFlags}`);
217
246
  lines.push(` ${toolName} ${kebab} update --${pk.name} <value> ${editableFields.map((f) => `[--${f.name} <value>]`).join(' ')}`);
218
247
  lines.push(` ${toolName} ${kebab} delete --${pk.name} <value> Delete one record`);
219
248
  lines.push('');
220
249
  lines.push('INPUT FIELDS:');
221
250
  for (const f of scalarFields) {
222
251
  const isPk = f.name === pk.name;
223
- lines.push(` ${f.name}: ${f.type.gqlType}${isPk ? ' (primary key)' : ''}`);
252
+ lines.push(` ${f.name}: ${cleanTypeName(f.type.gqlType)}${isPk ? ' (primary key)' : ''}`);
224
253
  }
225
254
  lines.push('');
226
255
  lines.push('EDITABLE FIELDS (for create/update):');
227
256
  for (const f of editableFields) {
228
- lines.push(` ${f.name}: ${f.type.gqlType}`);
257
+ const optLabel = defaultFields.has(f.name) ? ' (optional, has backend default)' : '';
258
+ lines.push(` ${f.name}: ${cleanTypeName(f.type.gqlType)}${optLabel}`);
229
259
  }
230
260
  lines.push('');
231
261
  lines.push('OUTPUT: JSON');
@@ -239,19 +269,21 @@ export function generateAgentsDocs(tables, customOperations, toolName) {
239
269
  }
240
270
  for (const op of customOperations) {
241
271
  const kebab = toKebabCase(op.name);
272
+ const flat = flattenArgs(op.args, registry);
242
273
  lines.push(`### TOOL: ${kebab}`);
243
274
  lines.push('');
244
275
  lines.push(op.description || op.name);
245
276
  lines.push('');
246
277
  lines.push('```');
247
278
  lines.push(`TYPE: ${op.kind}`);
248
- if (op.args.length > 0) {
249
- const flags = op.args.map((a) => `--${a.name} <value>`).join(' ');
279
+ if (flat.length > 0) {
280
+ const flags = flattenedArgsToFlags(flat);
250
281
  lines.push(`USAGE: ${toolName} ${kebab} ${flags}`);
251
282
  lines.push('');
252
283
  lines.push('INPUT:');
253
- for (const arg of op.args) {
254
- lines.push(` ${arg.name}: ${formatArgType(arg)}`);
284
+ for (const a of flat) {
285
+ const reqLabel = a.required ? ' (required)' : '';
286
+ lines.push(` ${a.flag}: ${a.type}${reqLabel}`);
255
287
  }
256
288
  }
257
289
  else {
@@ -329,7 +361,7 @@ export function generateAgentsDocs(tables, customOperations, toolName) {
329
361
  content: lines.join('\n'),
330
362
  };
331
363
  }
332
- export function getCliMcpTools(tables, customOperations, toolName) {
364
+ export function getCliMcpTools(tables, customOperations, toolName, registry) {
333
365
  const tools = [];
334
366
  tools.push({
335
367
  name: `${toolName}_context_create`,
@@ -402,6 +434,10 @@ export function getCliMcpTools(tables, customOperations, toolName) {
402
434
  const pk = getPrimaryKeyInfo(table)[0];
403
435
  const scalarFields = getScalarFields(table);
404
436
  const editableFields = getEditableFields(table);
437
+ const defaultFields = getFieldsWithDefaults(table, registry);
438
+ const requiredCreateFieldNames = editableFields
439
+ .filter((f) => !defaultFields.has(f.name))
440
+ .map((f) => f.name);
405
441
  tools.push({
406
442
  name: `${toolName}_${kebab}_list`,
407
443
  description: `List all ${table.name} records`,
@@ -424,7 +460,7 @@ export function getCliMcpTools(tables, customOperations, toolName) {
424
460
  const createProps = {};
425
461
  for (const f of editableFields) {
426
462
  createProps[f.name] = {
427
- type: gqlTypeToJsonSchemaType(f.type.gqlType),
463
+ type: gqlTypeToJsonSchemaType(cleanTypeName(f.type.gqlType)),
428
464
  description: `${table.name} ${f.name}`,
429
465
  };
430
466
  }
@@ -434,7 +470,7 @@ export function getCliMcpTools(tables, customOperations, toolName) {
434
470
  inputSchema: {
435
471
  type: 'object',
436
472
  properties: createProps,
437
- required: editableFields.map((f) => f.name),
473
+ ...(requiredCreateFieldNames.length > 0 ? { required: requiredCreateFieldNames } : {}),
438
474
  },
439
475
  });
440
476
  const updateProps = {
@@ -445,7 +481,7 @@ export function getCliMcpTools(tables, customOperations, toolName) {
445
481
  };
446
482
  for (const f of editableFields) {
447
483
  updateProps[f.name] = {
448
- type: gqlTypeToJsonSchemaType(f.type.gqlType),
484
+ type: gqlTypeToJsonSchemaType(cleanTypeName(f.type.gqlType)),
449
485
  description: `${table.name} ${f.name}`,
450
486
  };
451
487
  }
@@ -479,7 +515,7 @@ export function getCliMcpTools(tables, customOperations, toolName) {
479
515
  _meta: {
480
516
  fields: scalarFields.map((f) => ({
481
517
  name: f.name,
482
- type: f.type.gqlType,
518
+ type: cleanTypeName(f.type.gqlType),
483
519
  editable: editableFields.some((ef) => ef.name === f.name),
484
520
  primaryKey: f.name === pk.name,
485
521
  })),
@@ -488,17 +524,16 @@ export function getCliMcpTools(tables, customOperations, toolName) {
488
524
  }
489
525
  for (const op of customOperations) {
490
526
  const kebab = toKebabCase(op.name);
527
+ const flat = flattenArgs(op.args, registry);
491
528
  const props = {};
492
529
  const required = [];
493
- for (const arg of op.args) {
494
- const isRequired = arg.type.kind === 'NON_NULL';
495
- const baseType = isRequired && arg.type.ofType ? arg.type.ofType : arg.type;
496
- props[arg.name] = {
497
- type: gqlTypeToJsonSchemaType(baseType.name ?? 'String'),
498
- description: arg.description || arg.name,
530
+ for (const a of flat) {
531
+ props[a.flag] = {
532
+ type: gqlTypeToJsonSchemaType(a.type),
533
+ description: a.description || a.flag,
499
534
  };
500
- if (isRequired) {
501
- required.push(arg.name);
535
+ if (a.required) {
536
+ required.push(a.flag);
502
537
  }
503
538
  }
504
539
  tools.push({
@@ -513,7 +548,7 @@ export function getCliMcpTools(tables, customOperations, toolName) {
513
548
  }
514
549
  return tools;
515
550
  }
516
- export function generateSkills(tables, customOperations, toolName, targetName) {
551
+ export function generateSkills(tables, customOperations, toolName, targetName, registry) {
517
552
  const files = [];
518
553
  const skillName = `cli-${targetName}`;
519
554
  const referenceNames = [];
@@ -576,6 +611,11 @@ export function generateSkills(tables, customOperations, toolName, targetName) {
576
611
  const kebab = toKebabCase(singularName);
577
612
  const pk = getPrimaryKeyInfo(table)[0];
578
613
  const editableFields = getEditableFields(table);
614
+ const defaultFields = getFieldsWithDefaults(table, registry);
615
+ const createFlags = [
616
+ ...editableFields.filter((f) => !defaultFields.has(f.name)).map((f) => `--${f.name} <value>`),
617
+ ...editableFields.filter((f) => defaultFields.has(f.name)).map((f) => `[--${f.name} <value>]`),
618
+ ].join(' ');
579
619
  referenceNames.push(kebab);
580
620
  files.push({
581
621
  fileName: `${skillName}/references/${kebab}.md`,
@@ -585,7 +625,7 @@ export function generateSkills(tables, customOperations, toolName, targetName) {
585
625
  usage: [
586
626
  `${toolName} ${kebab} list`,
587
627
  `${toolName} ${kebab} get --${pk.name} <value>`,
588
- `${toolName} ${kebab} create ${editableFields.map((f) => `--${f.name} <value>`).join(' ')}`,
628
+ `${toolName} ${kebab} create ${createFlags}`,
589
629
  `${toolName} ${kebab} update --${pk.name} <value> ${editableFields.map((f) => `[--${f.name} <value>]`).join(' ')}`,
590
630
  `${toolName} ${kebab} delete --${pk.name} <value>`,
591
631
  ],
@@ -597,7 +637,7 @@ export function generateSkills(tables, customOperations, toolName, targetName) {
597
637
  {
598
638
  description: `Create a ${singularName}`,
599
639
  code: [
600
- `${toolName} ${kebab} create ${editableFields.map((f) => `--${f.name} "value"`).join(' ')}`,
640
+ `${toolName} ${kebab} create ${createFlags}`,
601
641
  ],
602
642
  },
603
643
  {
@@ -611,8 +651,9 @@ export function generateSkills(tables, customOperations, toolName, targetName) {
611
651
  // Custom operation references
612
652
  for (const op of customOperations) {
613
653
  const kebab = toKebabCase(op.name);
614
- const usage = op.args.length > 0
615
- ? `${toolName} ${kebab} ${op.args.map((a) => `--${a.name} <value>`).join(' ')}`
654
+ const flat = flattenArgs(op.args, registry);
655
+ const usage = flat.length > 0
656
+ ? `${toolName} ${kebab} ${flattenedArgsToFlags(flat)}`
616
657
  : `${toolName} ${kebab}`;
617
658
  referenceNames.push(kebab);
618
659
  files.push({
@@ -649,6 +690,9 @@ export function generateSkills(tables, customOperations, toolName, targetName) {
649
690
  `${toolName} ${tableKebabs[0] || 'model'} list`,
650
691
  `${toolName} ${tableKebabs[0] || 'model'} get --id <value>`,
651
692
  `${toolName} ${tableKebabs[0] || 'model'} create --<field> <value>`,
693
+ '',
694
+ `# Non-interactive mode (skip all prompts, use flags only)`,
695
+ `${toolName} --no-tty ${tableKebabs[0] || 'model'} list`,
652
696
  ],
653
697
  examples: [
654
698
  {
@@ -660,13 +704,19 @@ export function generateSkills(tables, customOperations, toolName, targetName) {
660
704
  `${toolName} ${tableKebabs[0] || 'model'} list`,
661
705
  ],
662
706
  },
707
+ {
708
+ description: 'Non-interactive mode (for scripts and CI)',
709
+ code: [
710
+ `${toolName} --no-tty ${tableKebabs[0] || 'model'} create --<field> <value>`,
711
+ ],
712
+ },
663
713
  ],
664
714
  }, referenceNames),
665
715
  });
666
716
  return files;
667
717
  }
668
718
  export function generateMultiTargetReadme(input) {
669
- const { toolName, builtinNames, targets } = input;
719
+ const { toolName, builtinNames, targets, registry } = input;
670
720
  const lines = [];
671
721
  lines.push(...getReadmeHeader(`${toolName} CLI`));
672
722
  lines.push('## Setup');
@@ -791,6 +841,7 @@ export function generateMultiTargetReadme(input) {
791
841
  const pk = getPrimaryKeyInfo(table)[0];
792
842
  const scalarFields = getScalarFields(table);
793
843
  const editableFields = getEditableFields(table);
844
+ const defaultFields = getFieldsWithDefaults(table, registry);
794
845
  lines.push(`### \`${tgt.name}:${kebab}\``);
795
846
  lines.push('');
796
847
  lines.push(`CRUD operations for ${table.name} records.`);
@@ -808,26 +859,38 @@ export function generateMultiTargetReadme(input) {
808
859
  lines.push('| Field | Type |');
809
860
  lines.push('|-------|------|');
810
861
  for (const f of scalarFields) {
811
- lines.push(`| \`${f.name}\` | ${f.type.gqlType} |`);
862
+ lines.push(`| \`${f.name}\` | ${cleanTypeName(f.type.gqlType)} |`);
812
863
  }
813
864
  lines.push('');
814
- lines.push(`**Create fields:** ${editableFields.map((f) => `\`${f.name}\``).join(', ')}`);
865
+ const requiredCreate = editableFields.filter((f) => !defaultFields.has(f.name));
866
+ const optionalCreate = editableFields.filter((f) => defaultFields.has(f.name));
867
+ if (requiredCreate.length > 0) {
868
+ lines.push(`**Required create fields:** ${requiredCreate.map((f) => `\`${f.name}\``).join(', ')}`);
869
+ }
870
+ if (optionalCreate.length > 0) {
871
+ lines.push(`**Optional create fields (backend defaults):** ${optionalCreate.map((f) => `\`${f.name}\``).join(', ')}`);
872
+ }
873
+ if (requiredCreate.length === 0 && optionalCreate.length === 0) {
874
+ lines.push(`**Create fields:** ${editableFields.map((f) => `\`${f.name}\``).join(', ')}`);
875
+ }
815
876
  lines.push('');
816
877
  }
817
878
  for (const op of tgt.customOperations) {
818
879
  const kebab = toKebabCase(op.name);
880
+ const flat = flattenArgs(op.args, registry);
819
881
  lines.push(`### \`${tgt.name}:${kebab}\``);
820
882
  lines.push('');
821
883
  lines.push(op.description || op.name);
822
884
  lines.push('');
823
885
  lines.push(`- **Type:** ${op.kind}`);
824
- if (op.args.length > 0) {
886
+ if (flat.length > 0) {
825
887
  lines.push('- **Arguments:**');
826
888
  lines.push('');
827
889
  lines.push(' | Argument | Type |');
828
890
  lines.push(' |----------|------|');
829
- for (const arg of op.args) {
830
- lines.push(` | \`${arg.name}\` | ${formatArgType(arg)} |`);
891
+ for (const a of flat) {
892
+ const reqLabel = a.required ? ' (required)' : '';
893
+ lines.push(` | \`--${a.flag}\` | ${a.type}${reqLabel} |`);
831
894
  }
832
895
  }
833
896
  else {
@@ -852,6 +915,18 @@ export function generateMultiTargetReadme(input) {
852
915
  }
853
916
  lines.push('```');
854
917
  lines.push('');
918
+ lines.push('## Non-Interactive Mode');
919
+ lines.push('');
920
+ lines.push('Use `--no-tty` to skip all interactive prompts (useful for scripts and CI):');
921
+ lines.push('');
922
+ lines.push('```bash');
923
+ if (targets.length > 0 && targets[0].tables.length > 0) {
924
+ const tgt = targets[0];
925
+ const kebab = toKebabCase(getTableNames(tgt.tables[0]).singularName);
926
+ lines.push(`${toolName} --no-tty ${tgt.name}:${kebab} create --name "Example"`);
927
+ }
928
+ lines.push('```');
929
+ lines.push('');
855
930
  lines.push(...getReadmeFooter());
856
931
  return {
857
932
  fileName: 'README.md',
@@ -859,7 +934,7 @@ export function generateMultiTargetReadme(input) {
859
934
  };
860
935
  }
861
936
  export function generateMultiTargetAgentsDocs(input) {
862
- const { toolName, builtinNames, targets } = input;
937
+ const { toolName, builtinNames, targets, registry } = input;
863
938
  const lines = [];
864
939
  lines.push(`# ${toolName} CLI - Agent Reference`);
865
940
  lines.push('');
@@ -952,6 +1027,13 @@ export function generateMultiTargetAgentsDocs(input) {
952
1027
  const pk = getPrimaryKeyInfo(table)[0];
953
1028
  const scalarFields = getScalarFields(table);
954
1029
  const editableFields = getEditableFields(table);
1030
+ const defaultFields = getFieldsWithDefaults(table, registry);
1031
+ const requiredCreateFields = editableFields.filter((f) => !defaultFields.has(f.name));
1032
+ const optionalCreateFields = editableFields.filter((f) => defaultFields.has(f.name));
1033
+ const createFlags = [
1034
+ ...requiredCreateFields.map((f) => `--${f.name} <value>`),
1035
+ ...optionalCreateFields.map((f) => `[--${f.name} <value>]`),
1036
+ ].join(' ');
955
1037
  lines.push(`### TOOL: ${tgt.name}:${kebab}`);
956
1038
  lines.push('');
957
1039
  lines.push(`CRUD operations for ${table.name} records (${tgt.name} target).`);
@@ -960,19 +1042,20 @@ export function generateMultiTargetAgentsDocs(input) {
960
1042
  lines.push('SUBCOMMANDS:');
961
1043
  lines.push(` ${toolName} ${tgt.name}:${kebab} list List all records`);
962
1044
  lines.push(` ${toolName} ${tgt.name}:${kebab} get --${pk.name} <value> Get one record`);
963
- lines.push(` ${toolName} ${tgt.name}:${kebab} create ${editableFields.map((f) => `--${f.name} <value>`).join(' ')}`);
1045
+ lines.push(` ${toolName} ${tgt.name}:${kebab} create ${createFlags}`);
964
1046
  lines.push(` ${toolName} ${tgt.name}:${kebab} update --${pk.name} <value> ${editableFields.map((f) => `[--${f.name} <value>]`).join(' ')}`);
965
1047
  lines.push(` ${toolName} ${tgt.name}:${kebab} delete --${pk.name} <value> Delete one record`);
966
1048
  lines.push('');
967
1049
  lines.push('INPUT FIELDS:');
968
1050
  for (const f of scalarFields) {
969
1051
  const isPk = f.name === pk.name;
970
- lines.push(` ${f.name}: ${f.type.gqlType}${isPk ? ' (primary key)' : ''}`);
1052
+ lines.push(` ${f.name}: ${cleanTypeName(f.type.gqlType)}${isPk ? ' (primary key)' : ''}`);
971
1053
  }
972
1054
  lines.push('');
973
1055
  lines.push('EDITABLE FIELDS (for create/update):');
974
1056
  for (const f of editableFields) {
975
- lines.push(` ${f.name}: ${f.type.gqlType}`);
1057
+ const optLabel = defaultFields.has(f.name) ? ' (optional, has backend default)' : '';
1058
+ lines.push(` ${f.name}: ${cleanTypeName(f.type.gqlType)}${optLabel}`);
976
1059
  }
977
1060
  lines.push('');
978
1061
  lines.push('OUTPUT: JSON');
@@ -986,19 +1069,21 @@ export function generateMultiTargetAgentsDocs(input) {
986
1069
  }
987
1070
  for (const op of tgt.customOperations) {
988
1071
  const kebab = toKebabCase(op.name);
1072
+ const flat = flattenArgs(op.args, registry);
989
1073
  lines.push(`### TOOL: ${tgt.name}:${kebab}`);
990
1074
  lines.push('');
991
1075
  lines.push(op.description || op.name);
992
1076
  lines.push('');
993
1077
  lines.push('```');
994
1078
  lines.push(`TYPE: ${op.kind}`);
995
- if (op.args.length > 0) {
996
- const flags = op.args.map((a) => `--${a.name} <value>`).join(' ');
1079
+ if (flat.length > 0) {
1080
+ const flags = flattenedArgsToFlags(flat);
997
1081
  lines.push(`USAGE: ${toolName} ${tgt.name}:${kebab} ${flags}`);
998
1082
  lines.push('');
999
1083
  lines.push('INPUT:');
1000
- for (const arg of op.args) {
1001
- lines.push(` ${arg.name}: ${formatArgType(arg)}`);
1084
+ for (const a of flat) {
1085
+ const reqLabel = a.required ? ' (required)' : '';
1086
+ lines.push(` ${a.flag}: ${a.type}${reqLabel}`);
1002
1087
  }
1003
1088
  }
1004
1089
  else {
@@ -1087,7 +1172,7 @@ export function generateMultiTargetAgentsDocs(input) {
1087
1172
  };
1088
1173
  }
1089
1174
  export function getMultiTargetCliMcpTools(input) {
1090
- const { toolName, builtinNames, targets } = input;
1175
+ const { toolName, builtinNames, targets, registry } = input;
1091
1176
  const tools = [];
1092
1177
  const contextEndpointProps = {
1093
1178
  name: { type: 'string', description: 'Context name' },
@@ -1167,6 +1252,10 @@ export function getMultiTargetCliMcpTools(input) {
1167
1252
  const pk = getPrimaryKeyInfo(table)[0];
1168
1253
  const scalarFields = getScalarFields(table);
1169
1254
  const editableFields = getEditableFields(table);
1255
+ const defaultFields = getFieldsWithDefaults(table, registry);
1256
+ const requiredCreateFieldNames = editableFields
1257
+ .filter((f) => !defaultFields.has(f.name))
1258
+ .map((f) => f.name);
1170
1259
  const prefix = `${toolName}_${tgt.name}_${kebab}`;
1171
1260
  tools.push({
1172
1261
  name: `${prefix}_list`,
@@ -1190,7 +1279,7 @@ export function getMultiTargetCliMcpTools(input) {
1190
1279
  const createProps = {};
1191
1280
  for (const f of editableFields) {
1192
1281
  createProps[f.name] = {
1193
- type: gqlTypeToJsonSchemaType(f.type.gqlType),
1282
+ type: gqlTypeToJsonSchemaType(cleanTypeName(f.type.gqlType)),
1194
1283
  description: `${table.name} ${f.name}`,
1195
1284
  };
1196
1285
  }
@@ -1200,7 +1289,7 @@ export function getMultiTargetCliMcpTools(input) {
1200
1289
  inputSchema: {
1201
1290
  type: 'object',
1202
1291
  properties: createProps,
1203
- required: editableFields.map((f) => f.name),
1292
+ ...(requiredCreateFieldNames.length > 0 ? { required: requiredCreateFieldNames } : {}),
1204
1293
  },
1205
1294
  });
1206
1295
  const updateProps = {
@@ -1211,7 +1300,7 @@ export function getMultiTargetCliMcpTools(input) {
1211
1300
  };
1212
1301
  for (const f of editableFields) {
1213
1302
  updateProps[f.name] = {
1214
- type: gqlTypeToJsonSchemaType(f.type.gqlType),
1303
+ type: gqlTypeToJsonSchemaType(cleanTypeName(f.type.gqlType)),
1215
1304
  description: `${table.name} ${f.name}`,
1216
1305
  };
1217
1306
  }
@@ -1245,7 +1334,7 @@ export function getMultiTargetCliMcpTools(input) {
1245
1334
  _meta: {
1246
1335
  fields: scalarFields.map((f) => ({
1247
1336
  name: f.name,
1248
- type: f.type.gqlType,
1337
+ type: cleanTypeName(f.type.gqlType),
1249
1338
  editable: editableFields.some((ef) => ef.name === f.name),
1250
1339
  primaryKey: f.name === pk.name,
1251
1340
  })),
@@ -1254,17 +1343,16 @@ export function getMultiTargetCliMcpTools(input) {
1254
1343
  }
1255
1344
  for (const op of tgt.customOperations) {
1256
1345
  const kebab = toKebabCase(op.name);
1346
+ const flat = flattenArgs(op.args, registry);
1257
1347
  const props = {};
1258
1348
  const required = [];
1259
- for (const arg of op.args) {
1260
- const isRequired = arg.type.kind === 'NON_NULL';
1261
- const baseType = isRequired && arg.type.ofType ? arg.type.ofType : arg.type;
1262
- props[arg.name] = {
1263
- type: gqlTypeToJsonSchemaType(baseType.name ?? 'String'),
1264
- description: arg.description || arg.name,
1349
+ for (const a of flat) {
1350
+ props[a.flag] = {
1351
+ type: gqlTypeToJsonSchemaType(a.type),
1352
+ description: a.description || a.flag,
1265
1353
  };
1266
- if (isRequired) {
1267
- required.push(arg.name);
1354
+ if (a.required) {
1355
+ required.push(a.flag);
1268
1356
  }
1269
1357
  }
1270
1358
  if (tgt.isAuthTarget && op.kind === 'mutation') {
@@ -1287,7 +1375,7 @@ export function getMultiTargetCliMcpTools(input) {
1287
1375
  return tools;
1288
1376
  }
1289
1377
  export function generateMultiTargetSkills(input) {
1290
- const { toolName, builtinNames, targets } = input;
1378
+ const { toolName, builtinNames, targets, registry } = input;
1291
1379
  const files = [];
1292
1380
  // Generate one skill per target, plus a shared cli-common skill for context/auth
1293
1381
  const commonSkillName = 'cli-common';
@@ -1387,6 +1475,11 @@ export function generateMultiTargetSkills(input) {
1387
1475
  const kebab = toKebabCase(singularName);
1388
1476
  const pk = getPrimaryKeyInfo(table)[0];
1389
1477
  const editableFields = getEditableFields(table);
1478
+ const defaultFields = getFieldsWithDefaults(table, registry);
1479
+ const createFlags = [
1480
+ ...editableFields.filter((f) => !defaultFields.has(f.name)).map((f) => `--${f.name} <value>`),
1481
+ ...editableFields.filter((f) => defaultFields.has(f.name)).map((f) => `[--${f.name} <value>]`),
1482
+ ].join(' ');
1390
1483
  const cmd = `${tgt.name}:${kebab}`;
1391
1484
  tgtReferenceNames.push(kebab);
1392
1485
  files.push({
@@ -1397,7 +1490,7 @@ export function generateMultiTargetSkills(input) {
1397
1490
  usage: [
1398
1491
  `${toolName} ${cmd} list`,
1399
1492
  `${toolName} ${cmd} get --${pk.name} <value>`,
1400
- `${toolName} ${cmd} create ${editableFields.map((f) => `--${f.name} <value>`).join(' ')}`,
1493
+ `${toolName} ${cmd} create ${createFlags}`,
1401
1494
  `${toolName} ${cmd} update --${pk.name} <value> ${editableFields.map((f) => `[--${f.name} <value>]`).join(' ')}`,
1402
1495
  `${toolName} ${cmd} delete --${pk.name} <value>`,
1403
1496
  ],
@@ -1409,7 +1502,7 @@ export function generateMultiTargetSkills(input) {
1409
1502
  {
1410
1503
  description: `Create a ${singularName}`,
1411
1504
  code: [
1412
- `${toolName} ${cmd} create ${editableFields.map((f) => `--${f.name} "value"`).join(' ')}`,
1505
+ `${toolName} ${cmd} create ${createFlags}`,
1413
1506
  ],
1414
1507
  },
1415
1508
  ],
@@ -1419,8 +1512,9 @@ export function generateMultiTargetSkills(input) {
1419
1512
  for (const op of tgt.customOperations) {
1420
1513
  const kebab = toKebabCase(op.name);
1421
1514
  const cmd = `${tgt.name}:${kebab}`;
1422
- const baseUsage = op.args.length > 0
1423
- ? `${toolName} ${cmd} ${op.args.map((a) => `--${a.name} <value>`).join(' ')}`
1515
+ const flat = flattenArgs(op.args, registry);
1516
+ const baseUsage = flat.length > 0
1517
+ ? `${toolName} ${cmd} ${flattenedArgsToFlags(flat)}`
1424
1518
  : `${toolName} ${cmd}`;
1425
1519
  const usageLines = [baseUsage];
1426
1520
  if (tgt.isAuthTarget && op.kind === 'mutation') {
@@ -1456,12 +1550,21 @@ export function generateMultiTargetSkills(input) {
1456
1550
  `${toolName} ${tgt.name}:${firstKebab} list`,
1457
1551
  `${toolName} ${tgt.name}:${firstKebab} get --id <value>`,
1458
1552
  `${toolName} ${tgt.name}:${firstKebab} create --<field> <value>`,
1553
+ '',
1554
+ `# Non-interactive mode (skip all prompts, use flags only)`,
1555
+ `${toolName} --no-tty ${tgt.name}:${firstKebab} list`,
1459
1556
  ],
1460
1557
  examples: [
1461
1558
  {
1462
1559
  description: `Query ${tgt.name} records`,
1463
1560
  code: [`${toolName} ${tgt.name}:${firstKebab} list`],
1464
1561
  },
1562
+ {
1563
+ description: 'Non-interactive mode (for scripts and CI)',
1564
+ code: [
1565
+ `${toolName} --no-tty ${tgt.name}:${firstKebab} create --<field> <value>`,
1566
+ ],
1567
+ },
1465
1568
  ],
1466
1569
  }, tgtReferenceNames),
1467
1570
  });
@@ -1,5 +1,20 @@
1
1
  import type { CleanTable, TypeRegistry } from '../../../types/schema';
2
2
  import type { GeneratedFile } from './executor-generator';
3
+ /**
4
+ * Get the set of field names that have defaults in the create input type.
5
+ * Looks up the CreateXInput -> inner input type (e.g. DatabaseInput) in the
6
+ * TypeRegistry and checks each field's defaultValue from introspection.
7
+ */
8
+ /**
9
+ * Resolve the inner input type from a CreateXInput or UpdateXInput type.
10
+ * The CreateXInput has an inner field (e.g. "database" of type DatabaseInput)
11
+ * that contains the actual field definitions.
12
+ */
13
+ export declare function resolveInnerInputType(inputTypeName: string, typeRegistry: TypeRegistry): {
14
+ name: string;
15
+ fields: Set<string>;
16
+ } | null;
17
+ export declare function getFieldsWithDefaults(table: CleanTable, typeRegistry?: TypeRegistry): Set<string>;
3
18
  export interface TableCommandOptions {
4
19
  targetName?: string;
5
20
  executorImportPath?: string;