db4ai 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/dist/chunk-3DWAMVV5.js +305 -0
  2. package/dist/chunk-3DWAMVV5.js.map +1 -0
  3. package/dist/chunk-COTPYBYM.js +618 -0
  4. package/dist/chunk-COTPYBYM.js.map +1 -0
  5. package/dist/chunk-EERD6CDF.js +735 -0
  6. package/dist/chunk-EERD6CDF.js.map +1 -0
  7. package/dist/chunk-FUF4HJTC.js +758 -0
  8. package/dist/chunk-FUF4HJTC.js.map +1 -0
  9. package/dist/chunk-JLL6FH5L.js +16 -0
  10. package/dist/chunk-JLL6FH5L.js.map +1 -0
  11. package/dist/chunk-JXFW6AIT.js +192 -0
  12. package/dist/chunk-JXFW6AIT.js.map +1 -0
  13. package/dist/chunk-XLSYCQPG.js +854 -0
  14. package/dist/chunk-XLSYCQPG.js.map +1 -0
  15. package/dist/chunk-Y5IXAS7F.js +569 -0
  16. package/dist/chunk-Y5IXAS7F.js.map +1 -0
  17. package/dist/cli/bin.d.ts +13 -12
  18. package/dist/cli/bin.js +277 -307
  19. package/dist/cli/bin.js.map +1 -1
  20. package/dist/cli/dashboard/index.d.ts +295 -14
  21. package/dist/cli/dashboard/index.js +60 -15
  22. package/dist/cli/dashboard/index.js.map +1 -1
  23. package/dist/cli/index.d.ts +10 -16
  24. package/dist/cli/index.js +94 -47
  25. package/dist/cli/index.js.map +1 -1
  26. package/dist/cli/runtime/index.d.ts +52 -23
  27. package/dist/cli/runtime/index.js +10 -704
  28. package/dist/cli/runtime/index.js.map +1 -1
  29. package/dist/cli/scanner/index.d.ts +17 -15
  30. package/dist/cli/scanner/index.js +8 -639
  31. package/dist/cli/scanner/index.js.map +1 -1
  32. package/dist/cli/seed/index.d.ts +16 -12
  33. package/dist/cli/seed/index.js +12 -773
  34. package/dist/cli/seed/index.js.map +1 -1
  35. package/dist/cli/sync/index.d.ts +54 -53
  36. package/dist/cli/sync/index.js +23 -704
  37. package/dist/cli/sync/index.js.map +1 -1
  38. package/dist/cli/terminal.d.ts +9 -8
  39. package/dist/cli/terminal.js +6 -209
  40. package/dist/cli/terminal.js.map +1 -1
  41. package/dist/cli/workflow/index.d.ts +18 -10
  42. package/dist/cli/workflow/index.js +6 -307
  43. package/dist/cli/workflow/index.js.map +1 -1
  44. package/dist/handlers.d.ts +10 -9
  45. package/dist/handlers.js +6 -38
  46. package/dist/handlers.js.map +1 -1
  47. package/dist/index.d.ts +120 -118
  48. package/dist/index.js +1963 -3125
  49. package/dist/index.js.map +1 -1
  50. package/package.json +3 -4
  51. package/dist/cli/bin.d.ts.map +0 -1
  52. package/dist/cli/dashboard/App.d.ts +0 -16
  53. package/dist/cli/dashboard/App.d.ts.map +0 -1
  54. package/dist/cli/dashboard/App.js +0 -116
  55. package/dist/cli/dashboard/App.js.map +0 -1
  56. package/dist/cli/dashboard/components/index.d.ts +0 -70
  57. package/dist/cli/dashboard/components/index.d.ts.map +0 -1
  58. package/dist/cli/dashboard/components/index.js +0 -192
  59. package/dist/cli/dashboard/components/index.js.map +0 -1
  60. package/dist/cli/dashboard/hooks/index.d.ts +0 -76
  61. package/dist/cli/dashboard/hooks/index.d.ts.map +0 -1
  62. package/dist/cli/dashboard/hooks/index.js +0 -201
  63. package/dist/cli/dashboard/hooks/index.js.map +0 -1
  64. package/dist/cli/dashboard/index.d.ts.map +0 -1
  65. package/dist/cli/dashboard/types.d.ts +0 -84
  66. package/dist/cli/dashboard/types.d.ts.map +0 -1
  67. package/dist/cli/dashboard/types.js +0 -5
  68. package/dist/cli/dashboard/types.js.map +0 -1
  69. package/dist/cli/dashboard/views/index.d.ts +0 -51
  70. package/dist/cli/dashboard/views/index.d.ts.map +0 -1
  71. package/dist/cli/dashboard/views/index.js +0 -72
  72. package/dist/cli/dashboard/views/index.js.map +0 -1
  73. package/dist/cli/index.d.ts.map +0 -1
  74. package/dist/cli/runtime/index.d.ts.map +0 -1
  75. package/dist/cli/scanner/index.d.ts.map +0 -1
  76. package/dist/cli/seed/index.d.ts.map +0 -1
  77. package/dist/cli/sync/index.d.ts.map +0 -1
  78. package/dist/cli/terminal.d.ts.map +0 -1
  79. package/dist/cli/workflow/index.d.ts.map +0 -1
  80. package/dist/errors.d.ts +0 -43
  81. package/dist/errors.d.ts.map +0 -1
  82. package/dist/errors.js +0 -47
  83. package/dist/errors.js.map +0 -1
  84. package/dist/handlers.d.ts.map +0 -1
  85. package/dist/index.d.ts.map +0 -1
  86. package/dist/types.d.ts +0 -276
  87. package/dist/types.d.ts.map +0 -1
  88. package/dist/types.js +0 -12
  89. package/dist/types.js.map +0 -1
@@ -0,0 +1,569 @@
1
+ // cli/scanner/index.ts
2
+ import { readdir, readFile, stat, access } from "fs/promises";
3
+ import { join, relative } from "path";
4
+ import { parse } from "@babel/parser";
5
+ import traverse from "@babel/traverse";
6
+ import matter from "gray-matter";
7
+ import { minimatch } from "minimatch";
8
+ var DEFAULT_EXCLUDE = ["node_modules/**", "dist/**", "**/*.test.ts", "**/*.spec.ts", "tests/**", "__tests__/**"];
9
+ function validateSchemaFile(schema) {
10
+ return typeof schema.path === "string" && schema.path.length > 0 && typeof schema.relativePath === "string" && schema.relativePath.length > 0 && typeof schema.exportName === "string" && schema.exportName.length > 0 && Array.isArray(schema.types);
11
+ }
12
+ function validateSeedFile(seed) {
13
+ return typeof seed.path === "string" && seed.path.length > 0 && typeof seed.relativePath === "string" && seed.relativePath.length > 0 && (seed.format === "ts" || seed.format === "mdx");
14
+ }
15
+ function validateWorkflowFile(workflow) {
16
+ return typeof workflow.path === "string" && workflow.path.length > 0 && typeof workflow.relativePath === "string" && workflow.relativePath.length > 0;
17
+ }
18
+ function matchesPatterns(filePath, patterns) {
19
+ const positivePatterns = patterns.filter((p) => !p.startsWith("!"));
20
+ const negativePatterns = patterns.filter((p) => p.startsWith("!")).map((p) => p.slice(1));
21
+ const matchesPositive = positivePatterns.length === 0 || positivePatterns.some((p) => minimatch(filePath, p, { dot: true }));
22
+ const matchesNegative = negativePatterns.some((p) => minimatch(filePath, p, { dot: true }));
23
+ return matchesPositive && !matchesNegative;
24
+ }
25
+ function shouldIncludeFile(relativePath, include, exclude) {
26
+ if (include && include.length > 0) {
27
+ if (!matchesPatterns(relativePath, include)) {
28
+ return false;
29
+ }
30
+ }
31
+ const excludePatterns = exclude || DEFAULT_EXCLUDE;
32
+ if (excludePatterns.some((p) => minimatch(relativePath, p, { dot: true }))) {
33
+ return false;
34
+ }
35
+ return true;
36
+ }
37
+ async function* walkDirectory(dir, root) {
38
+ const entries = await readdir(dir, { withFileTypes: true });
39
+ for (const entry of entries) {
40
+ const fullPath = join(dir, entry.name);
41
+ const relativePath = relative(root, fullPath);
42
+ if (entry.isDirectory()) {
43
+ if (entry.name === "node_modules" || entry.name.startsWith(".")) {
44
+ continue;
45
+ }
46
+ yield* walkDirectory(fullPath, root);
47
+ } else if (entry.isFile()) {
48
+ yield { path: fullPath, relativePath };
49
+ }
50
+ }
51
+ }
52
+ function parseTypeScript(content) {
53
+ try {
54
+ return {
55
+ ast: parse(content, {
56
+ sourceType: "module",
57
+ plugins: ["typescript", "jsx"]
58
+ })
59
+ };
60
+ } catch (err) {
61
+ return {
62
+ ast: null,
63
+ error: err instanceof Error ? err.message : String(err)
64
+ };
65
+ }
66
+ }
67
+ function extractValue(node) {
68
+ if (!node) return void 0;
69
+ switch (node.type) {
70
+ case "StringLiteral":
71
+ return node.value;
72
+ case "NumericLiteral":
73
+ return node.value;
74
+ case "BooleanLiteral":
75
+ return node.value;
76
+ case "NullLiteral":
77
+ return null;
78
+ case "ArrayExpression":
79
+ return node.elements.map((el) => extractValue(el));
80
+ case "ObjectExpression":
81
+ return extractObjectValue(node);
82
+ case "TemplateLiteral":
83
+ if (node.expressions.length === 0 && node.quasis.length === 1) {
84
+ return node.quasis[0].value.cooked;
85
+ }
86
+ return void 0;
87
+ default:
88
+ return void 0;
89
+ }
90
+ }
91
+ function extractObjectValue(node) {
92
+ const result = {};
93
+ for (const prop of node.properties) {
94
+ if (prop.type === "ObjectProperty") {
95
+ const key = prop.key.type === "Identifier" ? prop.key.name : prop.key.type === "StringLiteral" ? prop.key.value : null;
96
+ if (key) {
97
+ result[key] = extractValue(prop.value);
98
+ }
99
+ } else if (prop.type === "SpreadElement") {
100
+ continue;
101
+ }
102
+ }
103
+ return result;
104
+ }
105
+ function getImportsFromMdxai(ast) {
106
+ const imports = /* @__PURE__ */ new Map();
107
+ traverse(ast, {
108
+ ImportDeclaration(path) {
109
+ const source = path.node.source.value;
110
+ if (source !== "mdxai") return;
111
+ for (const specifier of path.node.specifiers) {
112
+ if (specifier.type === "ImportSpecifier") {
113
+ const importedName = specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value;
114
+ imports.set(specifier.local.name, {
115
+ localName: specifier.local.name,
116
+ importedName,
117
+ source
118
+ });
119
+ } else if (specifier.type === "ImportNamespaceSpecifier") {
120
+ imports.set(specifier.local.name, {
121
+ localName: specifier.local.name,
122
+ importedName: "*",
123
+ source
124
+ });
125
+ }
126
+ }
127
+ }
128
+ });
129
+ return imports;
130
+ }
131
+ function isDBCall(callee, dbLocalName, namespaceImport) {
132
+ if (callee.type === "Identifier" && callee.name === "DB") {
133
+ return dbLocalName === "DB" || dbLocalName === null;
134
+ }
135
+ if (callee.type === "Identifier" && callee.name === dbLocalName) {
136
+ return true;
137
+ }
138
+ if (callee.type === "MemberExpression" && callee.object.type === "Identifier" && callee.object.name === namespaceImport && callee.property.type === "Identifier" && callee.property.name === "DB") {
139
+ return true;
140
+ }
141
+ return false;
142
+ }
143
+ function findDBExports(content, ast, imports, rejectNonMdxaiImports) {
144
+ const results = [];
145
+ const dbVariables = /* @__PURE__ */ new Map();
146
+ let dbLocalName = null;
147
+ let namespaceImport = null;
148
+ let hasNonMdxaiDBImport = false;
149
+ for (const [localName, info] of imports) {
150
+ if (info.importedName === "DB") {
151
+ dbLocalName = localName;
152
+ } else if (info.importedName === "*") {
153
+ namespaceImport = localName;
154
+ }
155
+ }
156
+ traverse(ast, {
157
+ // Check for DB import from non-mdxai packages
158
+ ImportDeclaration(path) {
159
+ const source = path.node.source.value;
160
+ if (source !== "mdxai") {
161
+ for (const specifier of path.node.specifiers) {
162
+ if (specifier.type === "ImportSpecifier") {
163
+ const importedName = specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value;
164
+ if (importedName === "DB") {
165
+ hasNonMdxaiDBImport = true;
166
+ }
167
+ }
168
+ }
169
+ }
170
+ },
171
+ // Handle: export default DB({...})
172
+ ExportDefaultDeclaration(path) {
173
+ if (rejectNonMdxaiImports && hasNonMdxaiDBImport) return;
174
+ const declaration = path.node.declaration;
175
+ if (declaration && declaration.type === "CallExpression") {
176
+ const callee = declaration.callee;
177
+ if (isDBCall(callee, dbLocalName, namespaceImport) && declaration.arguments.length > 0) {
178
+ const arg = declaration.arguments[0];
179
+ if (arg.type === "ObjectExpression") {
180
+ const config = extractObjectValue(arg);
181
+ const types = extractTypesFromConfig(config);
182
+ results.push({
183
+ exportName: "default",
184
+ config,
185
+ types
186
+ });
187
+ }
188
+ }
189
+ }
190
+ },
191
+ // Handle: export const schema = DB({...})
192
+ ExportNamedDeclaration(path) {
193
+ if (rejectNonMdxaiImports && hasNonMdxaiDBImport) return;
194
+ const declaration = path.node.declaration;
195
+ if (declaration && declaration.type === "VariableDeclaration") {
196
+ for (const decl of declaration.declarations) {
197
+ if (decl.id.type === "Identifier" && decl.init && decl.init.type === "CallExpression") {
198
+ const callee = decl.init.callee;
199
+ if (isDBCall(callee, dbLocalName, namespaceImport) && decl.init.arguments.length > 0) {
200
+ const arg = decl.init.arguments[0];
201
+ if (arg.type === "ObjectExpression") {
202
+ const config = extractObjectValue(arg);
203
+ const types = extractTypesFromConfig(config);
204
+ results.push({
205
+ exportName: decl.id.name,
206
+ config,
207
+ types
208
+ });
209
+ }
210
+ }
211
+ }
212
+ }
213
+ }
214
+ if (path.node.specifiers) {
215
+ for (const specifier of path.node.specifiers) {
216
+ if (specifier.type === "ExportSpecifier") {
217
+ const localName = specifier.local.name;
218
+ if (dbVariables.has(localName)) {
219
+ const info = dbVariables.get(localName);
220
+ const exportedName = specifier.exported.type === "Identifier" ? specifier.exported.name : specifier.exported.value;
221
+ results.push({
222
+ ...info,
223
+ exportName: exportedName
224
+ });
225
+ }
226
+ }
227
+ }
228
+ }
229
+ },
230
+ // Track variable declarations that might be exported later
231
+ VariableDeclarator(path) {
232
+ if (rejectNonMdxaiImports && hasNonMdxaiDBImport) return;
233
+ if (path.node.id.type === "Identifier" && path.node.init && path.node.init.type === "CallExpression") {
234
+ const callee = path.node.init.callee;
235
+ if (isDBCall(callee, dbLocalName, namespaceImport) && path.node.init.arguments.length > 0) {
236
+ const arg = path.node.init.arguments[0];
237
+ if (arg.type === "ObjectExpression") {
238
+ const config = extractObjectValue(arg);
239
+ const types = extractTypesFromConfig(config);
240
+ dbVariables.set(path.node.id.name, {
241
+ exportName: path.node.id.name,
242
+ config,
243
+ types
244
+ });
245
+ }
246
+ }
247
+ }
248
+ }
249
+ });
250
+ if (rejectNonMdxaiImports && hasNonMdxaiDBImport) {
251
+ return [];
252
+ }
253
+ return results;
254
+ }
255
+ function extractTypesFromConfig(config) {
256
+ const types = [];
257
+ for (const key of Object.keys(config)) {
258
+ if (!key.startsWith("$")) {
259
+ types.push(key);
260
+ }
261
+ }
262
+ return types;
263
+ }
264
+ function extractNamespace(config) {
265
+ const id = config["$id"];
266
+ if (typeof id === "string") {
267
+ if (id.includes("/")) {
268
+ const parts = id.split("/");
269
+ return parts[parts.length - 1];
270
+ }
271
+ return id;
272
+ }
273
+ const context = config["$context"];
274
+ if (typeof context === "string") {
275
+ return context;
276
+ }
277
+ return void 0;
278
+ }
279
+ async function parseSchemaFile(filePath, relativePath, content, rejectNonMdxaiImports) {
280
+ const parseResult = parseTypeScript(content);
281
+ if (!parseResult.ast) {
282
+ return { schemas: null, error: parseResult.error };
283
+ }
284
+ const imports = getImportsFromMdxai(parseResult.ast);
285
+ const dbExports = findDBExports(content, parseResult.ast, imports, rejectNonMdxaiImports);
286
+ if (dbExports.length === 0) return { schemas: null };
287
+ return {
288
+ schemas: dbExports.map((dbExport) => ({
289
+ path: filePath,
290
+ relativePath,
291
+ namespace: extractNamespace(dbExport.config),
292
+ types: dbExport.types,
293
+ exportName: dbExport.exportName
294
+ }))
295
+ };
296
+ }
297
+ function findSeedOrGenerateExports(ast) {
298
+ let config = null;
299
+ traverse(ast, {
300
+ ExportDefaultDeclaration(path) {
301
+ const declaration = path.node.declaration;
302
+ if (declaration && declaration.type === "CallExpression") {
303
+ const callee = declaration.callee;
304
+ if (callee.type === "Identifier" && (callee.name === "Seed" || callee.name === "Generate")) {
305
+ if (declaration.arguments.length > 0) {
306
+ const arg = declaration.arguments[0];
307
+ if (arg.type === "ObjectExpression") {
308
+ config = extractObjectValue(arg);
309
+ if (callee.name === "Generate" && config && !config.prompt) {
310
+ }
311
+ }
312
+ }
313
+ }
314
+ }
315
+ }
316
+ });
317
+ return config;
318
+ }
319
+ async function parseSeedTsFile(filePath, relativePath, content) {
320
+ const parseResult = parseTypeScript(content);
321
+ if (!parseResult.ast) {
322
+ return { seed: null, error: parseResult.error };
323
+ }
324
+ const config = findSeedOrGenerateExports(parseResult.ast);
325
+ if (!config) return { seed: null };
326
+ return {
327
+ seed: {
328
+ path: filePath,
329
+ relativePath,
330
+ format: "ts",
331
+ targetType: config.type,
332
+ config
333
+ }
334
+ };
335
+ }
336
+ async function parseSeedMdxFile(filePath, relativePath, content) {
337
+ try {
338
+ const { data: frontmatter, content: mdxContent } = matter(content);
339
+ const prompt = mdxContent.trim() || void 0;
340
+ const config = {
341
+ ...frontmatter,
342
+ prompt: prompt || frontmatter.prompt
343
+ };
344
+ return {
345
+ path: filePath,
346
+ relativePath,
347
+ format: "mdx",
348
+ targetType: frontmatter.type,
349
+ config
350
+ };
351
+ } catch {
352
+ return null;
353
+ }
354
+ }
355
+ function findWorkflowExport(ast) {
356
+ let config = null;
357
+ traverse(ast, {
358
+ ExportDefaultDeclaration(path) {
359
+ const declaration = path.node.declaration;
360
+ if (declaration && declaration.type === "CallExpression") {
361
+ const callee = declaration.callee;
362
+ if (callee.type === "Identifier" && callee.name === "Workflow") {
363
+ if (declaration.arguments.length > 0) {
364
+ const arg = declaration.arguments[0];
365
+ if (arg.type === "ObjectExpression") {
366
+ config = extractObjectValue(arg);
367
+ }
368
+ }
369
+ }
370
+ }
371
+ }
372
+ });
373
+ return config;
374
+ }
375
+ async function parseWorkflowFile(filePath, relativePath, content) {
376
+ const parseResult = parseTypeScript(content);
377
+ if (!parseResult.ast) {
378
+ return { workflow: null, error: parseResult.error };
379
+ }
380
+ const config = findWorkflowExport(parseResult.ast);
381
+ if (!config) return { workflow: null };
382
+ return {
383
+ workflow: {
384
+ path: filePath,
385
+ relativePath,
386
+ name: config.name,
387
+ trigger: config.trigger,
388
+ config
389
+ }
390
+ };
391
+ }
392
+ async function loadProjectConfig(root) {
393
+ const configFiles = ["db4.config.ts", "db4.config.js"];
394
+ for (const configFile of configFiles) {
395
+ const configPath = join(root, configFile);
396
+ try {
397
+ await access(configPath);
398
+ const content = await readFile(configPath, "utf-8");
399
+ if (configFile.endsWith(".ts")) {
400
+ return parseTsConfig(content);
401
+ } else {
402
+ return parseJsConfig(content);
403
+ }
404
+ } catch {
405
+ continue;
406
+ }
407
+ }
408
+ return void 0;
409
+ }
410
+ function parseTsConfig(content) {
411
+ const parseResult = parseTypeScript(content);
412
+ if (!parseResult.ast) return void 0;
413
+ let config;
414
+ traverse(parseResult.ast, {
415
+ ExportDefaultDeclaration(path) {
416
+ const declaration = path.node.declaration;
417
+ if (declaration && declaration.type === "ObjectExpression") {
418
+ config = extractObjectValue(declaration);
419
+ }
420
+ }
421
+ });
422
+ return config;
423
+ }
424
+ function parseJsConfig(content) {
425
+ const parseResult = parseTypeScript(content);
426
+ if (!parseResult.ast) return void 0;
427
+ let config;
428
+ traverse(parseResult.ast, {
429
+ AssignmentExpression(path) {
430
+ const left = path.node.left;
431
+ const right = path.node.right;
432
+ if (left.type === "MemberExpression" && left.object.type === "Identifier" && left.object.name === "module" && left.property.type === "Identifier" && left.property.name === "exports" && right.type === "ObjectExpression") {
433
+ config = extractObjectValue(right);
434
+ }
435
+ }
436
+ });
437
+ return config;
438
+ }
439
+ function createScanner(scannerConfig) {
440
+ const { root } = scannerConfig;
441
+ const fileCache = /* @__PURE__ */ new Map();
442
+ async function scan(options = {}) {
443
+ const startTime = performance.now();
444
+ try {
445
+ const rootStat = await stat(root);
446
+ if (!rootStat.isDirectory()) {
447
+ throw new Error(`Not a directory: ${root}`);
448
+ }
449
+ } catch (err) {
450
+ throw new Error(`Cannot access directory: ${root}`);
451
+ }
452
+ const schemas = [];
453
+ const seeds = [];
454
+ const workflows = [];
455
+ const errors = [];
456
+ const projectConfig = await loadProjectConfig(root);
457
+ const includePatterns = scannerConfig.include || projectConfig?.scan?.include;
458
+ const excludePatterns = scannerConfig.exclude || projectConfig?.scan?.exclude;
459
+ for await (const { path: filePath, relativePath } of walkDirectory(root, root)) {
460
+ const ext = filePath.slice(filePath.lastIndexOf("."));
461
+ if (ext !== ".ts" && ext !== ".mdx") {
462
+ continue;
463
+ }
464
+ if (!shouldIncludeFile(relativePath, includePatterns, excludePatterns)) {
465
+ continue;
466
+ }
467
+ try {
468
+ const fileStat = await stat(filePath);
469
+ const mtime = fileStat.mtimeMs;
470
+ const cached = fileCache.get(filePath);
471
+ if (cached && cached.mtime === mtime) {
472
+ if (relativePath.endsWith(".seed.ts") && cached.seedResult) {
473
+ if (cached.seedResult.seed) seeds.push(cached.seedResult.seed);
474
+ if (cached.seedResult.error) errors.push({ path: filePath, error: cached.seedResult.error });
475
+ } else if (relativePath.endsWith(".seed.mdx") && cached.mdxSeed !== void 0) {
476
+ if (cached.mdxSeed) seeds.push(cached.mdxSeed);
477
+ } else if (relativePath.endsWith(".workflow.ts") && cached.workflowResult) {
478
+ if (cached.workflowResult.workflow) workflows.push(cached.workflowResult.workflow);
479
+ if (cached.workflowResult.error) errors.push({ path: filePath, error: cached.workflowResult.error });
480
+ } else if (cached.schemaResult) {
481
+ if (cached.schemaResult.schemas) schemas.push(...cached.schemaResult.schemas);
482
+ if (cached.schemaResult.error) errors.push({ path: filePath, error: cached.schemaResult.error });
483
+ }
484
+ continue;
485
+ }
486
+ const content = await readFile(filePath, "utf-8");
487
+ if (!content.trim()) {
488
+ continue;
489
+ }
490
+ const cacheEntry = { mtime, content };
491
+ if (relativePath.endsWith(".seed.ts")) {
492
+ const result2 = await parseSeedTsFile(filePath, relativePath, content);
493
+ cacheEntry.seedResult = result2;
494
+ if (result2.error) {
495
+ errors.push({ path: filePath, error: result2.error });
496
+ } else if (result2.seed && validateSeedFile(result2.seed)) {
497
+ seeds.push(result2.seed);
498
+ }
499
+ } else if (relativePath.endsWith(".seed.mdx")) {
500
+ const seedFile = await parseSeedMdxFile(filePath, relativePath, content);
501
+ cacheEntry.mdxSeed = seedFile;
502
+ if (seedFile && validateSeedFile(seedFile)) {
503
+ seeds.push(seedFile);
504
+ }
505
+ } else if (relativePath.endsWith(".workflow.ts")) {
506
+ const result2 = await parseWorkflowFile(filePath, relativePath, content);
507
+ cacheEntry.workflowResult = result2;
508
+ if (result2.error) {
509
+ errors.push({ path: filePath, error: result2.error });
510
+ } else if (result2.workflow && validateWorkflowFile(result2.workflow)) {
511
+ workflows.push(result2.workflow);
512
+ }
513
+ } else if (ext === ".ts") {
514
+ const result2 = await parseSchemaFile(filePath, relativePath, content, true);
515
+ cacheEntry.schemaResult = result2;
516
+ if (result2.error) {
517
+ errors.push({ path: filePath, error: result2.error });
518
+ } else if (result2.schemas) {
519
+ const validSchemas = result2.schemas.filter(validateSchemaFile);
520
+ schemas.push(...validSchemas);
521
+ }
522
+ }
523
+ fileCache.set(filePath, cacheEntry);
524
+ } catch (err) {
525
+ errors.push({
526
+ path: filePath,
527
+ error: err instanceof Error ? err.message : String(err)
528
+ });
529
+ }
530
+ }
531
+ const duration = performance.now() - startTime;
532
+ const result = {
533
+ root,
534
+ schemas,
535
+ seeds,
536
+ workflows,
537
+ duration
538
+ };
539
+ if (projectConfig) {
540
+ result.config = projectConfig;
541
+ }
542
+ if (errors.length > 0) {
543
+ result.errors = errors;
544
+ }
545
+ return result;
546
+ }
547
+ function watch(callback) {
548
+ let isWatching = true;
549
+ scan().then((result) => {
550
+ if (isWatching) {
551
+ callback(result);
552
+ }
553
+ }).catch(() => {
554
+ });
555
+ return () => {
556
+ isWatching = false;
557
+ };
558
+ }
559
+ return {
560
+ scan,
561
+ watch
562
+ };
563
+ }
564
+
565
+ export {
566
+ minimatch,
567
+ createScanner
568
+ };
569
+ //# sourceMappingURL=chunk-Y5IXAS7F.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../cli/scanner/index.ts"],"sourcesContent":["/**\n * Module 13: Project Scanner\n *\n * Scans project files to find schemas, seeds, and workflows.\n */\n\nimport { readdir, readFile, stat, access } from 'fs/promises'\nimport { join, relative, basename } from 'path'\nimport { parse } from '@babel/parser'\nimport traverse from '@babel/traverse'\nimport type { Expression, ObjectExpression, SpreadElement } from '@babel/types'\nimport matter from 'gray-matter'\nimport { minimatch } from 'minimatch'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ScannerConfig {\n root: string\n include?: string[]\n exclude?: string[]\n}\n\nexport interface ProjectConfig {\n namespace?: string\n ai?: {\n model?: string\n temperature?: number\n maxTokens?: number\n }\n scan?: {\n include?: string[]\n exclude?: string[]\n }\n}\n\nexport interface SchemaFile {\n path: string\n relativePath: string\n namespace?: string\n types: string[]\n exportName: string\n}\n\nexport interface SeedConfig {\n type?: string\n count?: number\n source?: string\n items?: unknown[]\n prompt?: string\n constraints?: Record<string, unknown>\n tags?: string[]\n title?: string\n author?: string\n metadata?: Record<string, unknown>\n [key: string]: unknown\n}\n\nexport interface SeedFile {\n path: string\n relativePath: string\n format: 'ts' | 'mdx'\n targetType?: string\n config?: SeedConfig\n}\n\nexport interface WorkflowConfig {\n name?: string\n trigger?: string | { schedule: string }\n steps?: unknown[]\n input?: Record<string, unknown>\n}\n\nexport interface WorkflowFile {\n path: string\n relativePath: string\n name?: string\n trigger?: string | { schedule: string }\n config?: WorkflowConfig\n}\n\nexport interface ScanError {\n path: string\n error: string\n}\n\nexport interface ScanResult {\n root: string\n schemas: SchemaFile[]\n seeds: SeedFile[]\n workflows: WorkflowFile[]\n config?: ProjectConfig\n errors?: ScanError[]\n duration: number\n}\n\nexport interface ScanOptions {\n incremental?: boolean\n}\n\nexport interface Scanner {\n scan(options?: ScanOptions): Promise<ScanResult>\n watch(callback: (result: ScanResult) => void): () => void\n}\n\n// ============================================================================\n// Default patterns\n// ============================================================================\n\nconst DEFAULT_EXCLUDE = ['node_modules/**', 'dist/**', '**/*.test.ts', '**/*.spec.ts', 'tests/**', '__tests__/**']\n\n// ============================================================================\n// Validation utilities\n// ============================================================================\n\n/**\n * Validates a SchemaFile to ensure it has required fields\n */\nfunction validateSchemaFile(schema: SchemaFile): boolean {\n return (\n typeof schema.path === 'string' &&\n schema.path.length > 0 &&\n typeof schema.relativePath === 'string' &&\n schema.relativePath.length > 0 &&\n typeof schema.exportName === 'string' &&\n schema.exportName.length > 0 &&\n Array.isArray(schema.types)\n )\n}\n\n/**\n * Validates a SeedFile to ensure it has required fields\n */\nfunction validateSeedFile(seed: SeedFile): boolean {\n return (\n typeof seed.path === 'string' &&\n seed.path.length > 0 &&\n typeof seed.relativePath === 'string' &&\n seed.relativePath.length > 0 &&\n (seed.format === 'ts' || seed.format === 'mdx')\n )\n}\n\n/**\n * Validates a WorkflowFile to ensure it has required fields\n */\nfunction validateWorkflowFile(workflow: WorkflowFile): boolean {\n return (\n typeof workflow.path === 'string' &&\n workflow.path.length > 0 &&\n typeof workflow.relativePath === 'string' &&\n workflow.relativePath.length > 0\n )\n}\n\n// ============================================================================\n// Glob matching utilities\n// ============================================================================\n\nfunction matchesPatterns(filePath: string, patterns: string[]): boolean {\n // Separate positive and negative patterns\n const positivePatterns = patterns.filter((p) => !p.startsWith('!'))\n const negativePatterns = patterns.filter((p) => p.startsWith('!')).map((p) => p.slice(1))\n\n // Must match at least one positive pattern (or have no positive patterns)\n const matchesPositive = positivePatterns.length === 0 || positivePatterns.some((p) => minimatch(filePath, p, { dot: true }))\n\n // Must not match any negative pattern\n const matchesNegative = negativePatterns.some((p) => minimatch(filePath, p, { dot: true }))\n\n return matchesPositive && !matchesNegative\n}\n\nfunction shouldIncludeFile(relativePath: string, include?: string[], exclude?: string[]): boolean {\n // Check include patterns if provided\n if (include && include.length > 0) {\n if (!matchesPatterns(relativePath, include)) {\n return false\n }\n }\n\n // Check exclude patterns\n const excludePatterns = exclude || DEFAULT_EXCLUDE\n if (excludePatterns.some((p) => minimatch(relativePath, p, { dot: true }))) {\n return false\n }\n\n return true\n}\n\n// ============================================================================\n// File scanning\n// ============================================================================\n\nasync function* walkDirectory(dir: string, root: string): AsyncGenerator<{ path: string; relativePath: string }> {\n const entries = await readdir(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name)\n const relativePath = relative(root, fullPath)\n\n if (entry.isDirectory()) {\n // Skip node_modules and hidden directories by default\n if (entry.name === 'node_modules' || entry.name.startsWith('.')) {\n continue\n }\n yield* walkDirectory(fullPath, root)\n } else if (entry.isFile()) {\n yield { path: fullPath, relativePath }\n }\n }\n}\n\n// ============================================================================\n// AST Parsing utilities\n// ============================================================================\n\ninterface ParseResult {\n ast: ReturnType<typeof parse> | null\n error?: string\n}\n\nfunction parseTypeScript(content: string): ParseResult {\n try {\n return {\n ast: parse(content, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n }),\n }\n } catch (err) {\n return {\n ast: null,\n error: err instanceof Error ? err.message : String(err),\n }\n }\n}\n\n/**\n * Extract a simple value from an AST node (strings, numbers, booleans, arrays, objects)\n */\nfunction extractValue(node: Expression | SpreadElement | null | undefined): unknown {\n if (!node) return undefined\n\n switch (node.type) {\n case 'StringLiteral':\n return node.value\n case 'NumericLiteral':\n return node.value\n case 'BooleanLiteral':\n return node.value\n case 'NullLiteral':\n return null\n case 'ArrayExpression':\n return node.elements.map((el: Expression | SpreadElement | null) => extractValue(el as Expression))\n case 'ObjectExpression':\n return extractObjectValue(node)\n case 'TemplateLiteral':\n // Simple case: no expressions\n if (node.expressions.length === 0 && node.quasis.length === 1) {\n return node.quasis[0].value.cooked\n }\n return undefined\n default:\n return undefined\n }\n}\n\nfunction extractObjectValue(node: ObjectExpression): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n\n for (const prop of node.properties) {\n if (prop.type === 'ObjectProperty') {\n const key = prop.key.type === 'Identifier' ? prop.key.name : prop.key.type === 'StringLiteral' ? prop.key.value : null\n\n if (key) {\n result[key] = extractValue(prop.value as Expression)\n }\n } else if (prop.type === 'SpreadElement') {\n // Can't statically analyze spreads\n continue\n }\n }\n\n return result\n}\n\n/**\n * Check if an import is from 'mdxai' package\n */\ninterface ImportInfo {\n localName: string\n importedName: string\n source: string\n}\n\nfunction getImportsFromMdxai(ast: ReturnType<typeof parse>): Map<string, ImportInfo> {\n const imports = new Map<string, ImportInfo>()\n\n traverse(ast, {\n ImportDeclaration(path) {\n const source = path.node.source.value\n if (source !== 'mdxai') return\n\n for (const specifier of path.node.specifiers) {\n if (specifier.type === 'ImportSpecifier') {\n const importedName = specifier.imported.type === 'Identifier' ? specifier.imported.name : specifier.imported.value\n imports.set(specifier.local.name, {\n localName: specifier.local.name,\n importedName,\n source,\n })\n } else if (specifier.type === 'ImportNamespaceSpecifier') {\n // import * as mdxai from 'mdxai'\n imports.set(specifier.local.name, {\n localName: specifier.local.name,\n importedName: '*',\n source,\n })\n }\n }\n },\n })\n\n return imports\n}\n\n// ============================================================================\n// Schema file parsing\n// ============================================================================\n\ninterface DBCallInfo {\n exportName: string\n config: Record<string, unknown>\n types: string[]\n}\n\nfunction isDBCall(callee: Expression, dbLocalName: string | null, namespaceImport: string | null): boolean {\n // Direct DB() call\n if (callee.type === 'Identifier' && callee.name === 'DB') {\n return dbLocalName === 'DB' || dbLocalName === null // Allow bare DB() if no import check needed\n }\n // Aliased import: Database() where DB was imported as Database\n if (callee.type === 'Identifier' && callee.name === dbLocalName) {\n return true\n }\n // Namespace import: mdxai.DB()\n if (callee.type === 'MemberExpression' && callee.object.type === 'Identifier' && callee.object.name === namespaceImport && callee.property.type === 'Identifier' && callee.property.name === 'DB') {\n return true\n }\n return false\n}\n\nfunction findDBExports(content: string, ast: ReturnType<typeof parse>, imports: Map<string, ImportInfo>, rejectNonMdxaiImports: boolean): DBCallInfo[] {\n const results: DBCallInfo[] = []\n\n // Track which variable declarations contain DB() calls\n const dbVariables = new Map<string, DBCallInfo>()\n\n // Find the local name for DB (could be aliased)\n let dbLocalName: string | null = null\n let namespaceImport: string | null = null\n let hasNonMdxaiDBImport = false\n\n for (const [localName, info] of imports) {\n if (info.importedName === 'DB') {\n dbLocalName = localName\n } else if (info.importedName === '*') {\n namespaceImport = localName\n }\n }\n\n // Single optimized traversal - handles imports and exports in one pass\n traverse(ast, {\n // Check for DB import from non-mdxai packages\n ImportDeclaration(path) {\n const source = path.node.source.value\n if (source !== 'mdxai') {\n for (const specifier of path.node.specifiers) {\n if (specifier.type === 'ImportSpecifier') {\n const importedName = specifier.imported.type === 'Identifier' ? specifier.imported.name : specifier.imported.value\n if (importedName === 'DB') {\n hasNonMdxaiDBImport = true\n }\n }\n }\n }\n },\n\n // Handle: export default DB({...})\n ExportDefaultDeclaration(path) {\n // Skip if we detected a non-mdxai DB import\n if (rejectNonMdxaiImports && hasNonMdxaiDBImport) return\n\n const declaration = path.node.declaration\n if (declaration && declaration.type === 'CallExpression') {\n const callee = declaration.callee as Expression\n\n if (isDBCall(callee, dbLocalName, namespaceImport) && declaration.arguments.length > 0) {\n const arg = declaration.arguments[0]\n if (arg.type === 'ObjectExpression') {\n const config = extractObjectValue(arg) as Record<string, unknown>\n const types = extractTypesFromConfig(config)\n results.push({\n exportName: 'default',\n config,\n types,\n })\n }\n }\n }\n },\n\n // Handle: export const schema = DB({...})\n ExportNamedDeclaration(path) {\n // Skip if we detected a non-mdxai DB import\n if (rejectNonMdxaiImports && hasNonMdxaiDBImport) return\n\n const declaration = path.node.declaration\n if (declaration && declaration.type === 'VariableDeclaration') {\n for (const decl of declaration.declarations) {\n if (decl.id.type === 'Identifier' && decl.init && decl.init.type === 'CallExpression') {\n const callee = decl.init.callee as Expression\n\n if (isDBCall(callee, dbLocalName, namespaceImport) && decl.init.arguments.length > 0) {\n const arg = decl.init.arguments[0]\n if (arg.type === 'ObjectExpression') {\n const config = extractObjectValue(arg) as Record<string, unknown>\n const types = extractTypesFromConfig(config)\n results.push({\n exportName: decl.id.name,\n config,\n types,\n })\n }\n }\n }\n }\n }\n\n // Handle: export { schema }\n if (path.node.specifiers) {\n for (const specifier of path.node.specifiers) {\n if (specifier.type === 'ExportSpecifier') {\n const localName = specifier.local.name\n if (dbVariables.has(localName)) {\n const info = dbVariables.get(localName)!\n const exportedName = specifier.exported.type === 'Identifier' ? specifier.exported.name : specifier.exported.value\n results.push({\n ...info,\n exportName: exportedName,\n })\n }\n }\n }\n }\n },\n\n // Track variable declarations that might be exported later\n VariableDeclarator(path) {\n // Skip if we detected a non-mdxai DB import\n if (rejectNonMdxaiImports && hasNonMdxaiDBImport) return\n\n if (path.node.id.type === 'Identifier' && path.node.init && path.node.init.type === 'CallExpression') {\n const callee = path.node.init.callee as Expression\n\n if (isDBCall(callee, dbLocalName, namespaceImport) && path.node.init.arguments.length > 0) {\n const arg = path.node.init.arguments[0]\n if (arg.type === 'ObjectExpression') {\n const config = extractObjectValue(arg) as Record<string, unknown>\n const types = extractTypesFromConfig(config)\n dbVariables.set(path.node.id.name, {\n exportName: path.node.id.name,\n config,\n types,\n })\n }\n }\n }\n },\n })\n\n // If we detected a non-mdxai DB import, return empty results\n if (rejectNonMdxaiImports && hasNonMdxaiDBImport) {\n return []\n }\n\n return results\n}\n\nfunction extractTypesFromConfig(config: Record<string, unknown>): string[] {\n const types: string[] = []\n for (const key of Object.keys(config)) {\n // Skip special keys that start with $\n if (!key.startsWith('$')) {\n types.push(key)\n }\n }\n return types\n}\n\nfunction extractNamespace(config: Record<string, unknown>): string | undefined {\n // Try $id first\n const id = config['$id']\n if (typeof id === 'string') {\n // Handle URLs like 'https://db.sb/my-namespace'\n if (id.includes('/')) {\n const parts = id.split('/')\n return parts[parts.length - 1]\n }\n return id\n }\n\n // Try $context\n const context = config['$context']\n if (typeof context === 'string') {\n return context\n }\n\n return undefined\n}\n\ninterface SchemaParseResult {\n schemas: SchemaFile[] | null\n error?: string\n}\n\nasync function parseSchemaFile(filePath: string, relativePath: string, content: string, rejectNonMdxaiImports: boolean): Promise<SchemaParseResult> {\n const parseResult = parseTypeScript(content)\n if (!parseResult.ast) {\n return { schemas: null, error: parseResult.error }\n }\n\n const imports = getImportsFromMdxai(parseResult.ast)\n const dbExports = findDBExports(content, parseResult.ast, imports, rejectNonMdxaiImports)\n\n if (dbExports.length === 0) return { schemas: null }\n\n return {\n schemas: dbExports.map((dbExport) => ({\n path: filePath,\n relativePath,\n namespace: extractNamespace(dbExport.config),\n types: dbExport.types,\n exportName: dbExport.exportName,\n })),\n }\n}\n\n// ============================================================================\n// Seed file parsing\n// ============================================================================\n\nfunction findSeedOrGenerateExports(ast: ReturnType<typeof parse>): SeedConfig | null {\n let config: SeedConfig | null = null\n\n traverse(ast, {\n ExportDefaultDeclaration(path) {\n const declaration = path.node.declaration\n if (declaration && declaration.type === 'CallExpression') {\n const callee = declaration.callee\n\n // Check for Seed(...) or Generate(...)\n if (callee.type === 'Identifier' && (callee.name === 'Seed' || callee.name === 'Generate')) {\n if (declaration.arguments.length > 0) {\n const arg = declaration.arguments[0]\n if (arg.type === 'ObjectExpression') {\n config = extractObjectValue(arg) as SeedConfig\n // For Generate(), also capture the function name as a hint\n if (callee.name === 'Generate' && config && !config.prompt) {\n // Generate typically has a prompt, keep type from config\n }\n }\n }\n }\n }\n },\n })\n\n return config\n}\n\ninterface SeedParseResult {\n seed: SeedFile | null\n error?: string\n}\n\nasync function parseSeedTsFile(filePath: string, relativePath: string, content: string): Promise<SeedParseResult> {\n const parseResult = parseTypeScript(content)\n if (!parseResult.ast) {\n return { seed: null, error: parseResult.error }\n }\n\n const config = findSeedOrGenerateExports(parseResult.ast)\n if (!config) return { seed: null }\n\n return {\n seed: {\n path: filePath,\n relativePath,\n format: 'ts',\n targetType: config.type,\n config,\n },\n }\n}\n\nasync function parseSeedMdxFile(filePath: string, relativePath: string, content: string): Promise<SeedFile | null> {\n try {\n const { data: frontmatter, content: mdxContent } = matter(content)\n\n // Extract prompt from MDX content (strip frontmatter)\n const prompt = mdxContent.trim() || undefined\n\n const config: SeedConfig = {\n ...frontmatter,\n prompt: (prompt || frontmatter.prompt) as string | undefined,\n }\n\n return {\n path: filePath,\n relativePath,\n format: 'mdx',\n targetType: frontmatter.type as string | undefined,\n config,\n }\n } catch {\n return null\n }\n}\n\n// ============================================================================\n// Workflow file parsing\n// ============================================================================\n\nfunction findWorkflowExport(ast: ReturnType<typeof parse>): WorkflowConfig | null {\n let config: WorkflowConfig | null = null\n\n traverse(ast, {\n ExportDefaultDeclaration(path) {\n const declaration = path.node.declaration\n if (declaration && declaration.type === 'CallExpression') {\n const callee = declaration.callee\n\n // Check for Workflow(...)\n if (callee.type === 'Identifier' && callee.name === 'Workflow') {\n if (declaration.arguments.length > 0) {\n const arg = declaration.arguments[0]\n if (arg.type === 'ObjectExpression') {\n config = extractObjectValue(arg) as WorkflowConfig\n }\n }\n }\n }\n },\n })\n\n return config\n}\n\ninterface WorkflowParseResult {\n workflow: WorkflowFile | null\n error?: string\n}\n\nasync function parseWorkflowFile(filePath: string, relativePath: string, content: string): Promise<WorkflowParseResult> {\n const parseResult = parseTypeScript(content)\n if (!parseResult.ast) {\n return { workflow: null, error: parseResult.error }\n }\n\n const config = findWorkflowExport(parseResult.ast)\n if (!config) return { workflow: null }\n\n return {\n workflow: {\n path: filePath,\n relativePath,\n name: config.name,\n trigger: config.trigger,\n config,\n },\n }\n}\n\n// ============================================================================\n// Config file loading\n// ============================================================================\n\nasync function loadProjectConfig(root: string): Promise<ProjectConfig | undefined> {\n // Try .ts first, then .js\n const configFiles = ['db4.config.ts', 'db4.config.js']\n\n for (const configFile of configFiles) {\n const configPath = join(root, configFile)\n try {\n await access(configPath)\n const content = await readFile(configPath, 'utf-8')\n\n // Parse the config file\n if (configFile.endsWith('.ts')) {\n return parseTsConfig(content)\n } else {\n return parseJsConfig(content)\n }\n } catch {\n // File doesn't exist or can't be read\n continue\n }\n }\n\n return undefined\n}\n\nfunction parseTsConfig(content: string): ProjectConfig | undefined {\n const parseResult = parseTypeScript(content)\n if (!parseResult.ast) return undefined\n\n let config: ProjectConfig | undefined\n\n traverse(parseResult.ast, {\n ExportDefaultDeclaration(path) {\n const declaration = path.node.declaration\n if (declaration && declaration.type === 'ObjectExpression') {\n config = extractObjectValue(declaration) as ProjectConfig\n }\n },\n })\n\n return config\n}\n\nfunction parseJsConfig(content: string): ProjectConfig | undefined {\n // Handle CommonJS: module.exports = { ... }\n const parseResult = parseTypeScript(content)\n if (!parseResult.ast) return undefined\n\n let config: ProjectConfig | undefined\n\n traverse(parseResult.ast, {\n AssignmentExpression(path) {\n const left = path.node.left\n const right = path.node.right\n\n // Check for module.exports = { ... }\n if (left.type === 'MemberExpression' && left.object.type === 'Identifier' && left.object.name === 'module' && left.property.type === 'Identifier' && left.property.name === 'exports' && right.type === 'ObjectExpression') {\n config = extractObjectValue(right) as ProjectConfig\n }\n },\n })\n\n return config\n}\n\n// ============================================================================\n// Main Scanner\n// ============================================================================\n\n// ============================================================================\n// File Cache for Watch Mode\n// ============================================================================\n\ninterface CacheEntry {\n mtime: number\n content: string\n schemaResult?: SchemaParseResult\n seedResult?: SeedParseResult\n workflowResult?: WorkflowParseResult\n mdxSeed?: SeedFile | null\n}\n\nexport function createScanner(scannerConfig: ScannerConfig): Scanner {\n const { root } = scannerConfig\n\n // Cache for incremental scanning - stores parsed results keyed by file path\n const fileCache = new Map<string, CacheEntry>()\n\n async function scan(options: ScanOptions = {}): Promise<ScanResult> {\n const startTime = performance.now()\n\n // Verify root directory exists\n try {\n const rootStat = await stat(root)\n if (!rootStat.isDirectory()) {\n throw new Error(`Not a directory: ${root}`)\n }\n } catch (err) {\n throw new Error(`Cannot access directory: ${root}`)\n }\n\n const schemas: SchemaFile[] = []\n const seeds: SeedFile[] = []\n const workflows: WorkflowFile[] = []\n const errors: ScanError[] = []\n\n // Load project config first (it may override include/exclude patterns)\n const projectConfig = await loadProjectConfig(root)\n\n // Determine effective include/exclude patterns\n const includePatterns = scannerConfig.include || projectConfig?.scan?.include\n const excludePatterns = scannerConfig.exclude || projectConfig?.scan?.exclude\n\n // Walk the directory\n for await (const { path: filePath, relativePath } of walkDirectory(root, root)) {\n // Check file extension\n const ext = filePath.slice(filePath.lastIndexOf('.'))\n if (ext !== '.ts' && ext !== '.mdx') {\n continue\n }\n\n // Apply include/exclude filters\n if (!shouldIncludeFile(relativePath, includePatterns, excludePatterns)) {\n continue\n }\n\n try {\n // Get file modification time for cache check\n const fileStat = await stat(filePath)\n const mtime = fileStat.mtimeMs\n\n // Check cache - use cached result if file hasn't changed\n const cached = fileCache.get(filePath)\n if (cached && cached.mtime === mtime) {\n // Use cached results\n if (relativePath.endsWith('.seed.ts') && cached.seedResult) {\n if (cached.seedResult.seed) seeds.push(cached.seedResult.seed)\n if (cached.seedResult.error) errors.push({ path: filePath, error: cached.seedResult.error })\n } else if (relativePath.endsWith('.seed.mdx') && cached.mdxSeed !== undefined) {\n if (cached.mdxSeed) seeds.push(cached.mdxSeed)\n } else if (relativePath.endsWith('.workflow.ts') && cached.workflowResult) {\n if (cached.workflowResult.workflow) workflows.push(cached.workflowResult.workflow)\n if (cached.workflowResult.error) errors.push({ path: filePath, error: cached.workflowResult.error })\n } else if (cached.schemaResult) {\n if (cached.schemaResult.schemas) schemas.push(...cached.schemaResult.schemas)\n if (cached.schemaResult.error) errors.push({ path: filePath, error: cached.schemaResult.error })\n }\n continue\n }\n\n const content = await readFile(filePath, 'utf-8')\n\n // Skip empty files\n if (!content.trim()) {\n continue\n }\n\n // Create cache entry\n const cacheEntry: CacheEntry = { mtime, content }\n\n // Determine file type and parse accordingly\n if (relativePath.endsWith('.seed.ts')) {\n const result = await parseSeedTsFile(filePath, relativePath, content)\n cacheEntry.seedResult = result\n if (result.error) {\n errors.push({ path: filePath, error: result.error })\n } else if (result.seed && validateSeedFile(result.seed)) {\n seeds.push(result.seed)\n }\n } else if (relativePath.endsWith('.seed.mdx')) {\n const seedFile = await parseSeedMdxFile(filePath, relativePath, content)\n cacheEntry.mdxSeed = seedFile\n if (seedFile && validateSeedFile(seedFile)) {\n seeds.push(seedFile)\n }\n } else if (relativePath.endsWith('.workflow.ts')) {\n const result = await parseWorkflowFile(filePath, relativePath, content)\n cacheEntry.workflowResult = result\n if (result.error) {\n errors.push({ path: filePath, error: result.error })\n } else if (result.workflow && validateWorkflowFile(result.workflow)) {\n workflows.push(result.workflow)\n }\n } else if (ext === '.ts') {\n // All other .ts files (including .schema.ts, .db.ts) - check for DB() exports\n const result = await parseSchemaFile(filePath, relativePath, content, true)\n cacheEntry.schemaResult = result\n if (result.error) {\n errors.push({ path: filePath, error: result.error })\n } else if (result.schemas) {\n // Validate each schema before adding\n const validSchemas = result.schemas.filter(validateSchemaFile)\n schemas.push(...validSchemas)\n }\n }\n\n // Store in cache\n fileCache.set(filePath, cacheEntry)\n } catch (err) {\n errors.push({\n path: filePath,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n const duration = performance.now() - startTime\n\n const result: ScanResult = {\n root,\n schemas,\n seeds,\n workflows,\n duration,\n }\n\n if (projectConfig) {\n result.config = projectConfig\n }\n\n if (errors.length > 0) {\n result.errors = errors\n }\n\n return result\n }\n\n function watch(callback: (result: ScanResult) => void): () => void {\n // For now, just return a no-op unsubscribe function\n // A full implementation would use fs.watch or chokidar\n let isWatching = true\n\n // Do an initial scan (catch errors to avoid unhandled rejections)\n scan()\n .then((result) => {\n if (isWatching) {\n callback(result)\n }\n })\n .catch(() => {\n // Ignore errors if we've already unsubscribed\n })\n\n return () => {\n isWatching = false\n }\n }\n\n return {\n scan,\n watch,\n }\n}\n\n// Re-export minimatch for tests that might need it\nexport { minimatch }\n"],"mappings":"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","names":["result"]}