@constructive-io/graphql-codegen 4.25.0 → 4.27.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.
Files changed (41) hide show
  1. package/core/codegen/cli/command-map-generator.js +9 -9
  2. package/core/codegen/cli/custom-command-generator.js +2 -2
  3. package/core/codegen/cli/docs-generator.js +23 -31
  4. package/core/codegen/cli/index.d.ts +3 -1
  5. package/core/codegen/cli/index.js +16 -1
  6. package/core/codegen/cli/table-command-generator.d.ts +2 -0
  7. package/core/codegen/cli/table-command-generator.js +251 -37
  8. package/core/codegen/cli/utils-generator.d.ts +8 -0
  9. package/core/codegen/cli/utils-generator.js +14 -0
  10. package/core/codegen/docs-utils.d.ts +17 -0
  11. package/core/codegen/docs-utils.js +137 -3
  12. package/core/codegen/hooks-docs-generator.js +3 -3
  13. package/core/codegen/index.js +1 -1
  14. package/core/codegen/orm/docs-generator.js +3 -3
  15. package/core/codegen/orm/index.js +1 -1
  16. package/core/codegen/orm/input-types-generator.js +1 -1
  17. package/core/codegen/orm/model-generator.js +1 -1
  18. package/core/codegen/queries.js +1 -1
  19. package/core/codegen/templates/cli-utils.ts +11 -11
  20. package/core/codegen/templates/embedder.ts +175 -0
  21. package/core/generate.js +2 -0
  22. package/esm/core/codegen/cli/command-map-generator.js +1 -1
  23. package/esm/core/codegen/cli/custom-command-generator.js +1 -1
  24. package/esm/core/codegen/cli/docs-generator.js +7 -15
  25. package/esm/core/codegen/cli/index.d.ts +3 -1
  26. package/esm/core/codegen/cli/index.js +16 -2
  27. package/esm/core/codegen/cli/table-command-generator.d.ts +2 -0
  28. package/esm/core/codegen/cli/table-command-generator.js +251 -37
  29. package/esm/core/codegen/cli/utils-generator.d.ts +8 -0
  30. package/esm/core/codegen/cli/utils-generator.js +13 -0
  31. package/esm/core/codegen/docs-utils.d.ts +17 -0
  32. package/esm/core/codegen/docs-utils.js +135 -3
  33. package/esm/core/codegen/hooks-docs-generator.js +1 -1
  34. package/esm/core/codegen/index.js +1 -1
  35. package/esm/core/codegen/orm/docs-generator.js +1 -1
  36. package/esm/core/codegen/orm/index.js +1 -1
  37. package/esm/core/codegen/orm/input-types-generator.js +1 -1
  38. package/esm/core/codegen/orm/model-generator.js +1 -1
  39. package/esm/core/codegen/queries.js +1 -1
  40. package/esm/core/generate.js +2 -0
  41. package/package.json +15 -16
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateHooksReadme = generateHooksReadme;
4
4
  exports.generateHooksAgentsDocs = generateHooksAgentsDocs;
5
5
  exports.generateHooksSkills = generateHooksSkills;
6
- const komoji_1 = require("komoji");
6
+ const inflekt_1 = require("inflekt");
7
7
  const docs_utils_1 = require("./docs-utils");
8
8
  const utils_1 = require("./utils");
9
9
  function getCustomHookName(op) {
@@ -178,7 +178,7 @@ function generateHooksSkills(tables, customOperations, targetName, registry) {
178
178
  const selectFields = scalarFields
179
179
  .map((f) => `${f.name}: true`)
180
180
  .join(', ');
181
- const refName = (0, komoji_1.toKebabCase)(singularName);
181
+ const refName = (0, inflekt_1.toKebabCase)(singularName);
182
182
  referenceNames.push(refName);
183
183
  files.push({
184
184
  fileName: `${skillName}/references/${refName}.md`,
@@ -229,7 +229,7 @@ function generateHooksSkills(tables, customOperations, targetName, registry) {
229
229
  const callArgs = op.args.length > 0
230
230
  ? `{ ${op.args.map((a) => `${a.name}: ${(0, docs_utils_1.argPlaceholder)(a, registry)}`).join(', ')} }`
231
231
  : '';
232
- const refName = (0, komoji_1.toKebabCase)(op.name);
232
+ const refName = (0, inflekt_1.toKebabCase)(op.name);
233
233
  referenceNames.push(refName);
234
234
  files.push({
235
235
  fileName: `${skillName}/references/${refName}.md`,
@@ -97,7 +97,7 @@ function generate(options) {
97
97
  hasInvalidation = true;
98
98
  }
99
99
  // Condition types (PostGraphile simple equality filters)
100
- const conditionEnabled = config.codegen?.condition !== false;
100
+ const conditionEnabled = config.codegen?.condition === true;
101
101
  // 4. Generate table-based query hooks (queries/*.ts)
102
102
  const queryHooks = (0, queries_1.generateAllQueryHooks)(tables, {
103
103
  reactQueryEnabled,
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateOrmReadme = generateOrmReadme;
4
4
  exports.generateOrmAgentsDocs = generateOrmAgentsDocs;
5
5
  exports.generateOrmSkills = generateOrmSkills;
6
- const komoji_1 = require("komoji");
6
+ const inflekt_1 = require("inflekt");
7
7
  const docs_utils_1 = require("../docs-utils");
8
8
  const utils_1 = require("../utils");
9
9
  function generateOrmReadme(tables, customOperations, registry) {
@@ -169,7 +169,7 @@ function generateOrmSkills(tables, customOperations, targetName, registry) {
169
169
  const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
170
170
  const editableFields = (0, docs_utils_1.getEditableFields)(table);
171
171
  const modelName = (0, utils_1.lcFirst)(singularName);
172
- const refName = (0, komoji_1.toKebabCase)(singularName);
172
+ const refName = (0, inflekt_1.toKebabCase)(singularName);
173
173
  referenceNames.push(refName);
174
174
  const ormSkillSpecialGroups = (0, docs_utils_1.categorizeSpecialFields)(table);
175
175
  const ormSkillBaseDesc = table.description || `ORM operations for ${table.name} records`;
@@ -218,7 +218,7 @@ function generateOrmSkills(tables, customOperations, targetName, registry) {
218
218
  const callArgs = op.args.length > 0
219
219
  ? `{ ${op.args.map((a) => `${a.name}: ${(0, docs_utils_1.argPlaceholder)(a, registry)}`).join(', ')} }`
220
220
  : '';
221
- const refName = (0, komoji_1.toKebabCase)(op.name);
221
+ const refName = (0, inflekt_1.toKebabCase)(op.name);
222
222
  referenceNames.push(refName);
223
223
  files.push({
224
224
  fileName: `${skillName}/references/${refName}.md`,
@@ -13,7 +13,7 @@ const model_generator_1 = require("./model-generator");
13
13
  function generateOrm(options) {
14
14
  const { tables, customOperations, sharedTypesPath } = options;
15
15
  const commentsEnabled = options.config.codegen?.comments !== false;
16
- const conditionEnabled = options.config.codegen?.condition !== false;
16
+ const conditionEnabled = options.config.codegen?.condition === true;
17
17
  const files = [];
18
18
  // Use shared types when a sharedTypesPath is provided (unified output mode)
19
19
  const useSharedTypes = !!sharedTypesPath;
@@ -1420,7 +1420,7 @@ function collectConditionExtraInputTypes(tables, typeRegistry) {
1420
1420
  * Generate comprehensive input-types.ts file using Babel AST
1421
1421
  */
1422
1422
  function generateInputTypesFile(typeRegistry, usedInputTypes, tables, usedPayloadTypes, comments = true, options) {
1423
- const conditionEnabled = options?.condition !== false;
1423
+ const conditionEnabled = options?.condition === true;
1424
1424
  const statements = [];
1425
1425
  const tablesList = tables ?? [];
1426
1426
  const hasTables = tablesList.length > 0;
@@ -104,7 +104,7 @@ function strictSelectGuard(selectTypeName) {
104
104
  ]));
105
105
  }
106
106
  function generateModelFile(table, _useSharedTypes, options, allTables) {
107
- const conditionEnabled = options?.condition !== false;
107
+ const conditionEnabled = options?.condition === true;
108
108
  const { typeName, singularName, pluralName } = (0, utils_1.getTableNames)(table);
109
109
  const modelName = `${typeName}Model`;
110
110
  const baseFileName = (0, utils_1.lcFirst)(typeName);
@@ -49,7 +49,7 @@ const babel_ast_1 = require("./babel-ast");
49
49
  const hooks_ast_1 = require("./hooks-ast");
50
50
  const utils_1 = require("./utils");
51
51
  function generateListQueryHook(table, options = {}) {
52
- const { reactQueryEnabled = true, useCentralizedKeys = true, hasRelationships = false, condition: conditionEnabled = true, } = options;
52
+ const { reactQueryEnabled = true, useCentralizedKeys = true, hasRelationships = false, condition: conditionEnabled = false, } = options;
53
53
  const { typeName, pluralName, singularName } = (0, utils_1.getTableNames)(table);
54
54
  const hookName = (0, utils_1.getListQueryHookName)(table);
55
55
  const queryName = (0, utils_1.getAllRowsQueryName)(table);
@@ -229,16 +229,16 @@ export function parseOrderByFlag(
229
229
  }
230
230
 
231
231
  /**
232
- * Parse --fields flag into a select object, falling back to a default.
233
- * e.g. --fields id,name → { id: true, name: true }
232
+ * Parse --select flag into a select object, falling back to a default.
233
+ * e.g. --select id,name → { id: true, name: true }
234
234
  */
235
235
  export function parseSelectFlag(
236
236
  argv: Record<string, unknown>,
237
237
  defaultSelect: Record<string, unknown>,
238
238
  ): Record<string, unknown> {
239
- const fields = argv.fields;
240
- return typeof fields === 'string'
241
- ? buildSelectFromPaths(fields)
239
+ const raw = argv.select;
240
+ return typeof raw === 'string'
241
+ ? buildSelectFromPaths(raw)
242
242
  : defaultSelect;
243
243
  }
244
244
 
@@ -252,11 +252,11 @@ export function parseSelectFlag(
252
252
  * const findManyArgs = parseFindManyArgs(argv, { id: true, name: true });
253
253
  * const result = await client.user.findMany(findManyArgs).execute();
254
254
  */
255
- export function parseFindManyArgs(
255
+ export function parseFindManyArgs<T = Record<string, unknown>>(
256
256
  argv: Record<string, unknown>,
257
257
  defaultSelect: Record<string, unknown>,
258
258
  extraWhere?: Record<string, unknown>,
259
- ): Record<string, unknown> {
259
+ ): T {
260
260
  const limit = parseIntFlag(argv, 'limit');
261
261
  const last = parseIntFlag(argv, 'last');
262
262
  const offset = parseIntFlag(argv, 'offset');
@@ -280,7 +280,7 @@ export function parseFindManyArgs(
280
280
  ...(where !== undefined ? { where } : {}),
281
281
  ...(condition !== undefined ? { condition } : {}),
282
282
  ...(orderBy !== undefined ? { orderBy } : {}),
283
- };
283
+ } as unknown as T;
284
284
  }
285
285
 
286
286
  /**
@@ -288,10 +288,10 @@ export function parseFindManyArgs(
288
288
  * Like parseFindManyArgs but only includes select, where, and condition
289
289
  * (no pagination flags — findFirst returns the first matching record).
290
290
  */
291
- export function parseFindFirstArgs(
291
+ export function parseFindFirstArgs<T = Record<string, unknown>>(
292
292
  argv: Record<string, unknown>,
293
293
  defaultSelect: Record<string, unknown>,
294
- ): Record<string, unknown> {
294
+ ): T {
295
295
  const select = parseSelectFlag(argv, defaultSelect);
296
296
  const parsed = unflattenDotNotation(argv);
297
297
  const where = parsed.where;
@@ -301,7 +301,7 @@ export function parseFindFirstArgs(
301
301
  select,
302
302
  ...(where !== undefined ? { where } : {}),
303
303
  ...(condition !== undefined ? { condition } : {}),
304
- };
304
+ } as unknown as T;
305
305
  }
306
306
 
307
307
  export function buildSelectFromPaths(
@@ -0,0 +1,175 @@
1
+ /**
2
+ * CLI Embedder — pluggable text-to-vector embedding for CLI commands
3
+ *
4
+ * This is RUNTIME code that gets copied to generated output.
5
+ * Provides a pluggable system for registering embedding functions so that
6
+ * CLI commands can convert text queries into vector arrays for pgvector
7
+ * similarity search (list/search) and create/update vector fields inline.
8
+ *
9
+ * Configuration via appstash config or environment variables:
10
+ * embedder.provider = 'ollama' | 'custom'
11
+ * embedder.model = 'nomic-embed-text' (default)
12
+ * embedder.baseUrl = 'http://localhost:11434' (Ollama endpoint)
13
+ *
14
+ * Uses @agentic-kit/ollama for the built-in Ollama provider.
15
+ *
16
+ * NOTE: This file is read at codegen time and written to output.
17
+ * Any changes here will affect all generated CLI embedder modules.
18
+ */
19
+
20
+ import OllamaClient from '@agentic-kit/ollama';
21
+
22
+ // ─── Types ───────────────────────────────────────────────────────────────────
23
+
24
+ export type EmbedderFunction = (text: string) => Promise<number[]>;
25
+
26
+ export interface EmbedderConfig {
27
+ /** Provider name: 'ollama' or 'custom' */
28
+ provider: string;
29
+ /** Model identifier (e.g. 'nomic-embed-text') */
30
+ model?: string;
31
+ /** Base URL for the provider (e.g. 'http://localhost:11434' for Ollama) */
32
+ baseUrl?: string;
33
+ }
34
+
35
+ // ─── Built-in Ollama Provider ────────────────────────────────────────────────
36
+
37
+ function createOllamaEmbedder(
38
+ baseUrl: string = 'http://localhost:11434',
39
+ model: string = 'nomic-embed-text',
40
+ ): EmbedderFunction {
41
+ const client = new OllamaClient(baseUrl);
42
+ return async (text: string): Promise<number[]> => {
43
+ return client.generateEmbedding(text, model);
44
+ };
45
+ }
46
+
47
+ // ─── Embedder Resolution ─────────────────────────────────────────────────────
48
+
49
+ /**
50
+ * Resolve an embedder function from environment variables or appstash config.
51
+ *
52
+ * Resolution order:
53
+ * 1. EMBEDDER_PROVIDER env var (+ EMBEDDER_MODEL, EMBEDDER_BASE_URL)
54
+ * 2. appstash config keys: embedder.provider, embedder.model, embedder.baseUrl
55
+ * 3. null (no embedder configured)
56
+ *
57
+ * @param store - Optional appstash config store for reading persisted config
58
+ * @returns An EmbedderFunction or null if no embedder is configured
59
+ */
60
+ export function resolveEmbedder(
61
+ store?: { getVar: (key: string) => string | undefined },
62
+ ): EmbedderFunction | null {
63
+ // 1. Check environment variables first
64
+ const envProvider = process.env.EMBEDDER_PROVIDER;
65
+ if (envProvider) {
66
+ return buildEmbedder({
67
+ provider: envProvider,
68
+ model: process.env.EMBEDDER_MODEL,
69
+ baseUrl: process.env.EMBEDDER_BASE_URL,
70
+ });
71
+ }
72
+
73
+ // 2. Check appstash config
74
+ if (store) {
75
+ const configProvider = store.getVar('embedder.provider');
76
+ if (configProvider) {
77
+ return buildEmbedder({
78
+ provider: configProvider,
79
+ model: store.getVar('embedder.model'),
80
+ baseUrl: store.getVar('embedder.baseUrl'),
81
+ });
82
+ }
83
+ }
84
+
85
+ // 3. No embedder configured
86
+ return null;
87
+ }
88
+
89
+ /**
90
+ * Build an embedder function from a config object.
91
+ */
92
+ function buildEmbedder(config: EmbedderConfig): EmbedderFunction | null {
93
+ switch (config.provider) {
94
+ case 'ollama':
95
+ return createOllamaEmbedder(config.baseUrl, config.model);
96
+ default:
97
+ console.error(
98
+ `Unknown embedder provider: '${config.provider}'. Supported: ollama`,
99
+ );
100
+ return null;
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Auto-embed text values in vector where-clause fields.
106
+ *
107
+ * When --auto-embed is passed, any vector field in the where clause that
108
+ * contains a text string (instead of a float array) will be converted to
109
+ * an embedding vector using the configured embedder.
110
+ *
111
+ * @param where - The where clause object (mutated in place)
112
+ * @param vectorFieldNames - Names of vector embedding fields (e.g. ['vectorEmbedding'])
113
+ * @param embedder - The resolved embedder function
114
+ * @returns The modified where clause
115
+ */
116
+ export async function autoEmbedWhere(
117
+ where: Record<string, unknown>,
118
+ vectorFieldNames: string[],
119
+ embedder: EmbedderFunction,
120
+ ): Promise<Record<string, unknown>> {
121
+ for (const fieldName of vectorFieldNames) {
122
+ const fieldValue = where[fieldName];
123
+ if (fieldValue && typeof fieldValue === 'object') {
124
+ const input = fieldValue as Record<string, unknown>;
125
+ // If 'vector' is a string, embed it
126
+ if (typeof input.vector === 'string') {
127
+ const text = input.vector;
128
+ const embedding = await embedder(text);
129
+ input.vector = embedding;
130
+ }
131
+ } else if (typeof fieldValue === 'string') {
132
+ // Shorthand: --where.vectorEmbedding "text" with --auto-embed
133
+ // becomes { vector: [embedded], metric: 'COSINE' }
134
+ const embedding = await embedder(fieldValue);
135
+ where[fieldName] = { vector: embedding };
136
+ }
137
+ }
138
+ return where;
139
+ }
140
+
141
+ /**
142
+ * Auto-embed text values in mutation input data (create/update).
143
+ *
144
+ * When --auto-embed is passed on create or update, any vector field in
145
+ * the input data that contains a text string will be converted to an
146
+ * embedding vector using the configured embedder.
147
+ *
148
+ * Usage:
149
+ * csdk article create --input.embedding "Machine learning concepts" --auto-embed
150
+ * csdk article update --id xxx --input.embedding "Updated description" --auto-embed
151
+ *
152
+ * This is a CLI-only convenience — in production, database triggers or
153
+ * a job queue should handle embedding generation.
154
+ *
155
+ * @param data - The mutation input data object (mutated in place)
156
+ * @param vectorFieldNames - Names of vector embedding fields (e.g. ['embedding'])
157
+ * @param embedder - The resolved embedder function
158
+ * @returns The modified data object with text values replaced by vectors
159
+ */
160
+ export async function autoEmbedInput(
161
+ data: Record<string, unknown>,
162
+ vectorFieldNames: string[],
163
+ embedder: EmbedderFunction,
164
+ ): Promise<Record<string, unknown>> {
165
+ for (const fieldName of vectorFieldNames) {
166
+ const fieldValue = data[fieldName];
167
+ if (typeof fieldValue === 'string') {
168
+ // Text string → embed to vector array
169
+ const embedding = await embedder(fieldValue);
170
+ data[fieldName] = embedding;
171
+ }
172
+ // If it's already an array (pre-computed vector), leave it as-is
173
+ }
174
+ return data;
175
+ }
package/core/generate.js CHANGED
@@ -587,12 +587,14 @@ async function generateMulti(options) {
587
587
  const firstTargetConfig = configs[names[0]];
588
588
  const multiNodeHttpAdapter = firstTargetConfig?.nodeHttpAdapter === true ||
589
589
  (firstTargetConfig?.nodeHttpAdapter !== false);
590
+ const multiConditionEnabled = firstTargetConfig?.codegen?.condition === true;
590
591
  const { files } = (0, cli_1.generateMultiTargetCli)({
591
592
  toolName,
592
593
  builtinNames: cliConfig.builtinNames,
593
594
  targets: cliTargets,
594
595
  nodeHttpAdapter: multiNodeHttpAdapter,
595
596
  entryPoint: cliConfig.entryPoint,
597
+ condition: multiConditionEnabled,
596
598
  });
597
599
  const cliFilesToWrite = files.map((file) => ({
598
600
  path: node_path_1.default.posix.join('cli', file.fileName),
@@ -1,5 +1,5 @@
1
1
  import * as t from '@babel/types';
2
- import { toKebabCase } from 'komoji';
2
+ import { toKebabCase } from 'inflekt';
3
3
  import { generateCode } from '../babel-ast';
4
4
  import { getGeneratedFileHeader, getTableNames } from '../utils';
5
5
  function createImportDeclaration(moduleSpecifier, defaultImportName) {
@@ -1,5 +1,5 @@
1
1
  import * as t from '@babel/types';
2
- import { toKebabCase } from 'komoji';
2
+ import { toKebabCase } from 'inflekt';
3
3
  import { generateCode } from '../babel-ast';
4
4
  import { getGeneratedFileHeader, ucFirst } from '../utils';
5
5
  import { buildQuestionsArray } from './arg-mapper';
@@ -1,5 +1,5 @@
1
- import { toKebabCase } from 'komoji';
2
- import { flattenArgs, flattenedArgsToFlags, cleanTypeName, getEditableFields, categorizeSpecialFields, buildSpecialFieldsMarkdown, getReadmeHeader, getReadmeFooter, buildSkillFile, buildSkillReference, } from '../docs-utils';
1
+ import { toKebabCase } from 'inflekt';
2
+ import { flattenArgs, flattenedArgsToFlags, cleanTypeName, getEditableFields, categorizeSpecialFields, buildSpecialFieldsMarkdown, buildSearchExamples, buildSearchExamplesMarkdown, getReadmeHeader, getReadmeFooter, buildSkillFile, buildSkillReference, } from '../docs-utils';
3
3
  import { getScalarFields, getTableNames, getPrimaryKeyInfo, } from '../utils';
4
4
  import { getFieldsWithDefaults } from './table-command-generator';
5
5
  export { resolveDocsConfig } from '../docs-utils';
@@ -124,6 +124,7 @@ export function generateReadme(tables, customOperations, toolName, registry) {
124
124
  }
125
125
  const specialGroups = categorizeSpecialFields(table, registry);
126
126
  lines.push(...buildSpecialFieldsMarkdown(specialGroups));
127
+ lines.push(...buildSearchExamplesMarkdown(specialGroups, toolName, kebab));
127
128
  lines.push('');
128
129
  }
129
130
  }
@@ -358,18 +359,13 @@ export function generateSkills(tables, customOperations, toolName, targetName, r
358
359
  },
359
360
  {
360
361
  description: `List ${singularName} records with field selection`,
361
- code: [`${toolName} ${kebab} list --fields id,${pk.name}`],
362
+ code: [`${toolName} ${kebab} list --select id,${pk.name}`],
362
363
  },
363
364
  {
364
365
  description: `List ${singularName} records with filtering and ordering`,
365
366
  code: [`${toolName} ${kebab} list --where.${pk.name}.equalTo <value> --orderBy ${pk.name.replace(/([A-Z])/g, '_$1').toUpperCase()}_ASC`],
366
367
  },
367
- ...(skillSpecialGroups.some((g) => g.category === 'search' || g.category === 'embedding')
368
- ? [{
369
- description: `Search ${singularName} records`,
370
- code: [`${toolName} ${kebab} search "query text" --limit 10 --fields id,searchScore`],
371
- }]
372
- : []),
368
+ ...buildSearchExamples(skillSpecialGroups, toolName, kebab),
373
369
  {
374
370
  description: `Create a ${singularName}`,
375
371
  code: [
@@ -656,6 +652,7 @@ export function generateMultiTargetReadme(input) {
656
652
  }
657
653
  const mtSpecialGroups = categorizeSpecialFields(table, registry);
658
654
  lines.push(...buildSpecialFieldsMarkdown(mtSpecialGroups));
655
+ lines.push(...buildSearchExamplesMarkdown(mtSpecialGroups, toolName, `${tgt.name}:${kebab}`));
659
656
  lines.push('');
660
657
  }
661
658
  for (const op of tgt.customOperations) {
@@ -958,12 +955,7 @@ export function generateMultiTargetSkills(input) {
958
955
  description: `List ${singularName} records with filtering and ordering`,
959
956
  code: [`${toolName} ${cmd} list --where.${pk.name}.equalTo <value> --orderBy ${pk.name.replace(/([A-Z])/g, '_$1').toUpperCase()}_ASC`],
960
957
  },
961
- ...(mtSkillSpecialGroups.some((g) => g.category === 'search' || g.category === 'embedding')
962
- ? [{
963
- description: `Search ${singularName} records`,
964
- code: [`${toolName} ${cmd} search "query text" --limit 10 --fields id,searchScore`],
965
- }]
966
- : []),
958
+ ...buildSearchExamples(mtSkillSpecialGroups, toolName, cmd),
967
959
  {
968
960
  description: `Create a ${singularName}`,
969
961
  code: [
@@ -43,6 +43,8 @@ export interface GenerateMultiTargetCliOptions {
43
43
  nodeHttpAdapter?: boolean;
44
44
  /** Generate a runnable index.ts entry point */
45
45
  entryPoint?: boolean;
46
+ /** Whether PostGraphile condition types are enabled (default: true) */
47
+ condition?: boolean;
46
48
  }
47
49
  export declare function resolveBuiltinNames(targetNames: string[], userOverrides?: BuiltinNames): {
48
50
  auth: string;
@@ -62,5 +64,5 @@ export { generateReadme, generateAgentsDocs, generateSkills, generateMultiTarget
62
64
  export type { MultiTargetDocsInput } from './docs-generator';
63
65
  export { resolveDocsConfig } from '../docs-utils';
64
66
  export type { GeneratedDocFile } from '../docs-utils';
65
- export { generateUtilsFile, generateEntryPointFile } from './utils-generator';
67
+ export { generateUtilsFile, generateEntryPointFile, generateEmbedderFile } from './utils-generator';
66
68
  export type { GeneratedFile, MultiTargetExecutorInput } from './executor-generator';
@@ -5,7 +5,7 @@ import { generateExecutorFile, generateMultiTargetExecutorFile } from './executo
5
5
  import { generateHelpersFile } from './helpers-generator';
6
6
  import { generateAuthCommand, generateAuthCommandWithName, generateContextCommand, generateMultiTargetContextCommand, } from './infra-generator';
7
7
  import { generateTableCommand } from './table-command-generator';
8
- import { generateUtilsFile, generateNodeFetchFile, generateEntryPointFile } from './utils-generator';
8
+ import { generateUtilsFile, generateNodeFetchFile, generateEntryPointFile, generateEmbedderFile } from './utils-generator';
9
9
  export function generateCli(options) {
10
10
  const { tables, customOperations, config } = options;
11
11
  const files = [];
@@ -21,6 +21,11 @@ export function generateCli(options) {
21
21
  files.push(executorFile);
22
22
  const utilsFile = generateUtilsFile();
23
23
  files.push(utilsFile);
24
+ // Generate embedder module if any table has vector embedding fields
25
+ const hasAnyEmbeddings = tables.some((t) => t.fields.some((f) => f.type.gqlType === 'Vector' || f.type.gqlType === '[Float]'));
26
+ if (hasAnyEmbeddings) {
27
+ files.push(generateEmbedderFile());
28
+ }
24
29
  // Generate node HTTP adapter if configured (for *.localhost subdomain routing)
25
30
  if (useNodeHttpAdapter) {
26
31
  files.push(generateNodeFetchFile());
@@ -29,9 +34,11 @@ export function generateCli(options) {
29
34
  files.push(contextFile);
30
35
  const authFile = generateAuthCommand(toolName);
31
36
  files.push(authFile);
37
+ const conditionEnabled = config.codegen?.condition === true;
32
38
  for (const table of tables) {
33
39
  const tableFile = generateTableCommand(table, {
34
40
  typeRegistry: options.typeRegistry,
41
+ condition: conditionEnabled,
35
42
  });
36
43
  files.push(tableFile);
37
44
  }
@@ -78,6 +85,7 @@ export function resolveBuiltinNames(targetNames, userOverrides) {
78
85
  }
79
86
  export function generateMultiTargetCli(options) {
80
87
  const { toolName, targets } = options;
88
+ const conditionEnabled = options.condition === true;
81
89
  const files = [];
82
90
  const targetNames = targets.map((t) => t.name);
83
91
  const builtinNames = resolveBuiltinNames(targetNames, options.builtinNames);
@@ -92,6 +100,11 @@ export function generateMultiTargetCli(options) {
92
100
  files.push(executorFile);
93
101
  const utilsFile = generateUtilsFile();
94
102
  files.push(utilsFile);
103
+ // Generate embedder module if any target has tables with vector embedding fields
104
+ const hasAnyMtEmbeddings = targets.some((tgt) => tgt.tables.some((t) => t.fields.some((f) => f.type.gqlType === 'Vector' || f.type.gqlType === '[Float]')));
105
+ if (hasAnyMtEmbeddings) {
106
+ files.push(generateEmbedderFile());
107
+ }
95
108
  // Generate node HTTP adapter if configured (for *.localhost subdomain routing)
96
109
  if (options.nodeHttpAdapter) {
97
110
  files.push(generateNodeFetchFile());
@@ -122,6 +135,7 @@ export function generateMultiTargetCli(options) {
122
135
  targetName: target.name,
123
136
  executorImportPath: '../../executor',
124
137
  typeRegistry: target.typeRegistry,
138
+ condition: conditionEnabled,
125
139
  });
126
140
  files.push(tableFile);
127
141
  }
@@ -173,4 +187,4 @@ export { generateHelpersFile } from './helpers-generator';
173
187
  export { generateContextCommand, generateAuthCommand, generateMultiTargetContextCommand, generateAuthCommandWithName, } from './infra-generator';
174
188
  export { generateReadme, generateAgentsDocs, generateSkills, generateMultiTargetReadme, generateMultiTargetAgentsDocs, generateMultiTargetSkills, } from './docs-generator';
175
189
  export { resolveDocsConfig } from '../docs-utils';
176
- export { generateUtilsFile, generateEntryPointFile } from './utils-generator';
190
+ export { generateUtilsFile, generateEntryPointFile, generateEmbedderFile } from './utils-generator';
@@ -6,5 +6,7 @@ export interface TableCommandOptions {
6
6
  executorImportPath?: string;
7
7
  /** TypeRegistry from introspection, used to check field defaults */
8
8
  typeRegistry?: TypeRegistry;
9
+ /** Whether PostGraphile condition types are enabled (default: true) */
10
+ condition?: boolean;
9
11
  }
10
12
  export declare function generateTableCommand(table: Table, options?: TableCommandOptions): GeneratedFile;