aiex-cli 0.0.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 (116) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +118 -0
  3. package/bin/cli.mjs +2 -0
  4. package/dist/cli.d.mts +1 -0
  5. package/dist/cli.mjs +9948 -0
  6. package/dist/core/schema-sqlite/migrate-helper.d.mts +1 -0
  7. package/dist/core/schema-sqlite/migrate-helper.mjs +190 -0
  8. package/dist/doctor-Wic10PLt.mjs +711 -0
  9. package/dist/index.d.mts +281 -0
  10. package/dist/index.mjs +3 -0
  11. package/dist/table-schema.json +220 -0
  12. package/dist/web/assets/abap-Cry0R76c.js +1 -0
  13. package/dist/web/assets/apex-xqbJ58nJ.js +1 -0
  14. package/dist/web/assets/azcli-D7JTNGKs.js +1 -0
  15. package/dist/web/assets/bat-Cuq6hn0K.js +1 -0
  16. package/dist/web/assets/bicep-eTuQjz9F.js +2 -0
  17. package/dist/web/assets/cameligo-DKgCRl36.js +1 -0
  18. package/dist/web/assets/chunk-BEqpzyXh.js +1 -0
  19. package/dist/web/assets/clojure-B_aTBtVh.js +1 -0
  20. package/dist/web/assets/codicon-DCmgc-ay.ttf +0 -0
  21. package/dist/web/assets/coffee-BWAYpIPu.js +1 -0
  22. package/dist/web/assets/cpp-BduBQE8d.js +1 -0
  23. package/dist/web/assets/csharp-CMqOVYKK.js +1 -0
  24. package/dist/web/assets/csp-6cGliXw2.js +1 -0
  25. package/dist/web/assets/css-CHnKqS9Q.js +3 -0
  26. package/dist/web/assets/cssMode-BloHqzZF.js +4 -0
  27. package/dist/web/assets/cypher-DMzZBj2L.js +1 -0
  28. package/dist/web/assets/dart-7hYfJ1Dv.js +1 -0
  29. package/dist/web/assets/dockerfile-BflvjnJW.js +1 -0
  30. package/dist/web/assets/ecl-BEt6xb2p.js +1 -0
  31. package/dist/web/assets/editor-BR-TvLsg.css +1 -0
  32. package/dist/web/assets/editor-DPKWm9GW.css +1 -0
  33. package/dist/web/assets/editor.api-BG499EJF.js +642 -0
  34. package/dist/web/assets/editor.main-BhEWG0_P.js +53 -0
  35. package/dist/web/assets/editor.worker-DwXe4U6w.js +12 -0
  36. package/dist/web/assets/elixir-CnrQCt6o.js +1 -0
  37. package/dist/web/assets/flow9-CfLCoUuB.js +1 -0
  38. package/dist/web/assets/freemarker2-DOHaFATh.js +3 -0
  39. package/dist/web/assets/fsharp-BQqR9uQ6.js +1 -0
  40. package/dist/web/assets/go-C3AlMVwy.js +1 -0
  41. package/dist/web/assets/graphql-O_-hDldf.js +1 -0
  42. package/dist/web/assets/handlebars-BIFWety9.js +1 -0
  43. package/dist/web/assets/hcl-BQQD6Mtj.js +1 -0
  44. package/dist/web/assets/html-YGaqGZNd.js +1 -0
  45. package/dist/web/assets/htmlMode-Bu3PyHjq.js +4 -0
  46. package/dist/web/assets/index-Bi376XVf.css +2 -0
  47. package/dist/web/assets/index-c6KB-9C-.js +3262 -0
  48. package/dist/web/assets/ini-Bf0RDfP_.js +1 -0
  49. package/dist/web/assets/java-nqX2KEDD.js +1 -0
  50. package/dist/web/assets/javascript-N0gZqDK0.js +1 -0
  51. package/dist/web/assets/json.worker-DhD1Scrm.js +51 -0
  52. package/dist/web/assets/jsonMode-z5YscjcG.js +10 -0
  53. package/dist/web/assets/julia-B6P9U5er.js +1 -0
  54. package/dist/web/assets/kotlin-B-LRk09-.js +1 -0
  55. package/dist/web/assets/less-CEaIdW1f.js +2 -0
  56. package/dist/web/assets/lexon-Qv4pvFSW.js +1 -0
  57. package/dist/web/assets/liquid-BHfNNVLs.js +1 -0
  58. package/dist/web/assets/lua-CFpyR7YN.js +1 -0
  59. package/dist/web/assets/m3-CvKhVPQn.js +1 -0
  60. package/dist/web/assets/markdown-qldG3Vc4.js +1 -0
  61. package/dist/web/assets/mdx-Dqu2t0et.js +1 -0
  62. package/dist/web/assets/mips-0D8PRyHq.js +1 -0
  63. package/dist/web/assets/monaco.contribution-ByQ3yI-W.js +2 -0
  64. package/dist/web/assets/msdax-DwZXSC5M.js +1 -0
  65. package/dist/web/assets/mysql-BWq85KY4.js +1 -0
  66. package/dist/web/assets/objective-c-D653JUMG.js +1 -0
  67. package/dist/web/assets/pascal-rWjRDdnR.js +1 -0
  68. package/dist/web/assets/pascaligo-Db8EehaF.js +1 -0
  69. package/dist/web/assets/perl-C68oq8-D.js +1 -0
  70. package/dist/web/assets/pgsql-BXeHe33s.js +1 -0
  71. package/dist/web/assets/php-CDVsAbfl.js +1 -0
  72. package/dist/web/assets/pla-DnryFT0q.js +1 -0
  73. package/dist/web/assets/postiats-CDg_4Ev-.js +1 -0
  74. package/dist/web/assets/powerquery-CWPi8ROz.js +1 -0
  75. package/dist/web/assets/powershell-C5A0QX3-.js +1 -0
  76. package/dist/web/assets/preload-helper-DSXbuxSR.js +1 -0
  77. package/dist/web/assets/primeicons-C6QP2o4f.woff2 +0 -0
  78. package/dist/web/assets/primeicons-DMOk5skT.eot +0 -0
  79. package/dist/web/assets/primeicons-Dr5RGzOO.svg +345 -0
  80. package/dist/web/assets/primeicons-MpK4pl85.ttf +0 -0
  81. package/dist/web/assets/primeicons-WjwUDZjB.woff +0 -0
  82. package/dist/web/assets/protobuf-Cgt-BQbL.js +2 -0
  83. package/dist/web/assets/pug-RPYJC9QB.js +1 -0
  84. package/dist/web/assets/python-icfse9Ji.js +1 -0
  85. package/dist/web/assets/qsharp-BZ3S7fu_.js +1 -0
  86. package/dist/web/assets/r-CN875f1X.js +1 -0
  87. package/dist/web/assets/razor-DwVkryG9.js +1 -0
  88. package/dist/web/assets/redis-BLesvTwR.js +1 -0
  89. package/dist/web/assets/redshift-Byf_0XqD.js +1 -0
  90. package/dist/web/assets/restructuredtext-DYg_6BiZ.js +1 -0
  91. package/dist/web/assets/ruby-C4OkxbC-.js +1 -0
  92. package/dist/web/assets/rust-xAoaEFMh.js +1 -0
  93. package/dist/web/assets/sb-C8dHOW_y.js +1 -0
  94. package/dist/web/assets/scala-Spx0wP1o.js +1 -0
  95. package/dist/web/assets/scheme-D2mZlAUz.js +1 -0
  96. package/dist/web/assets/scss-DDCn3Ylu.js +3 -0
  97. package/dist/web/assets/shell-M6px0EWn.js +1 -0
  98. package/dist/web/assets/solidity-DUWMJi-f.js +1 -0
  99. package/dist/web/assets/sophia-DwJbUG-2.js +1 -0
  100. package/dist/web/assets/sparql-ClQxbRPI.js +1 -0
  101. package/dist/web/assets/sql-BQdjW7Vy.js +1 -0
  102. package/dist/web/assets/st-BpISyZ_v.js +1 -0
  103. package/dist/web/assets/swift-CMbl5gM4.js +1 -0
  104. package/dist/web/assets/systemverilog-jx2Xs7uO.js +1 -0
  105. package/dist/web/assets/tcl-GIGnfs89.js +1 -0
  106. package/dist/web/assets/tsMode-CLrI3bdf.js +11 -0
  107. package/dist/web/assets/twig-Bc0mxc_m.js +1 -0
  108. package/dist/web/assets/typescript-BzuZVF7m.js +1 -0
  109. package/dist/web/assets/typespec-CEioAsEm.js +1 -0
  110. package/dist/web/assets/vb-BPk67J-d.js +1 -0
  111. package/dist/web/assets/wgsl-DOnyt8_J.js +298 -0
  112. package/dist/web/assets/xml-Cr85kdqA.js +1 -0
  113. package/dist/web/assets/yaml-D3RbJnnO.js +1 -0
  114. package/dist/web/index.html +25 -0
  115. package/package.json +86 -0
  116. package/src/core/schema-sqlite/migrate-helper.ts +246 -0
@@ -0,0 +1,711 @@
1
+ import path from "node:path";
2
+ import process from "node:process";
3
+ import { z } from "zod";
4
+ import fs from "node:fs/promises";
5
+ import os from "node:os";
6
+ import Conf from "conf";
7
+
8
+ //#region src/core/doctor.ts
9
+ function buildDoctorDiagnostics(input) {
10
+ return {
11
+ cli: {
12
+ name: input.pkg.name,
13
+ version: input.pkg.version,
14
+ executable: input.executable
15
+ },
16
+ runtime: {
17
+ node: input.node,
18
+ platform: input.platform,
19
+ arch: input.arch,
20
+ shell: input.shell,
21
+ packageManager: input.packageManager
22
+ },
23
+ system: {
24
+ os: `${input.osType} ${input.osRelease}`,
25
+ cwd: input.cwd
26
+ },
27
+ config: {
28
+ path: input.configPath,
29
+ keys: [...input.configStoreKeys].sort()
30
+ },
31
+ project: { ...input.project }
32
+ };
33
+ }
34
+ function formatDoctorDiagnosticsJson(d) {
35
+ return `${JSON.stringify(d, null, 2)}\n`;
36
+ }
37
+ function doctorDiagnosticsTableRows(d) {
38
+ const rows = [
39
+ ["node", d.runtime.node],
40
+ ["platform", d.runtime.platform],
41
+ ["arch", d.runtime.arch],
42
+ ["shell", d.runtime.shell],
43
+ ["packageManager", d.runtime.packageManager],
44
+ ["os", d.system.os],
45
+ ["cwd", d.system.cwd],
46
+ ["config", d.config.path],
47
+ ["configKeys", d.config.keys.join(", ")]
48
+ ];
49
+ const p = d.project;
50
+ rows.push(["aiexDir", p.aiexDir]);
51
+ rows.push(["dirExists", String(p.dirExists)]);
52
+ rows.push(["schemaFiles", `${p.schemaCount} (${p.schemaFiles.join(", ") || "none"})`]);
53
+ rows.push(["aiConfig", String(p.aiConfig)]);
54
+ rows.push(["aiApiKeySet", String(p.aiApiKeySet)]);
55
+ rows.push(["aiModels", p.aiModelCount ? p.aiModels.join(", ") : "none"]);
56
+ rows.push(["aiProvider", p.aiProvider ?? "none"]);
57
+ rows.push(["aiConnectionOk", p.aiConnectionOk === null ? "not tested" : String(p.aiConnectionOk)]);
58
+ rows.push(["hasDatabase", String(p.hasDatabase)]);
59
+ rows.push(["migrations", String(p.migrationCount)]);
60
+ for (const err of p.errors) rows.push(["error", err]);
61
+ return rows;
62
+ }
63
+
64
+ //#endregion
65
+ //#region src/core/schema-sqlite/generator.ts
66
+ function generateColumnDefinition(column) {
67
+ if (column.isPrimary && column.isAutoIncrement) return ` ${column.name}: integer().primaryKey({ autoIncrement: true })`;
68
+ let def = ` ${column.name}: ${column.drizzleType}`;
69
+ if (column.isPrimary) def += ".primaryKey()";
70
+ if (!column.isNullable && !column.isPrimary) def += ".notNull()";
71
+ if (column.isUnique && !column.isPrimary) def += ".unique()";
72
+ if (column.defaultValue !== void 0) def += `.default(${column.defaultValue})`;
73
+ if (column.isForeignKey && column.foreignKeyRef) def += `.references(() => ${column.foreignKeyRef.table}.${column.foreignKeyRef.column})`;
74
+ return def;
75
+ }
76
+ function generateTableDefinition(table) {
77
+ const columns = table.columns.map(generateColumnDefinition);
78
+ return `export const ${table.name} = sqliteTable('${table.name}', {\n${columns.join(",\n")}\n})`;
79
+ }
80
+ function generateRelationDefinitions(relations, reverseRelations) {
81
+ if (relations.length === 0 && reverseRelations.length === 0) return "";
82
+ const definitions = [];
83
+ const childByTable = /* @__PURE__ */ new Map();
84
+ for (const rel of relations) {
85
+ const list = childByTable.get(rel.fromTable) ?? [];
86
+ list.push(rel);
87
+ childByTable.set(rel.fromTable, list);
88
+ }
89
+ const parentByTable = /* @__PURE__ */ new Map();
90
+ for (const rel of reverseRelations) {
91
+ const list = parentByTable.get(rel.fromTable) ?? [];
92
+ list.push(rel);
93
+ parentByTable.set(rel.fromTable, list);
94
+ }
95
+ const allTableNames = new Set([...childByTable.keys(), ...parentByTable.keys()]);
96
+ for (const tableName of allTableNames) {
97
+ const childRels = childByTable.get(tableName) ?? [];
98
+ const parentRels = parentByTable.get(tableName) ?? [];
99
+ const needsOne = childRels.length > 0 || parentRels.some((r) => r.type === "has-one");
100
+ const needsMany = parentRels.some((r) => r.type === "has-many");
101
+ const imports = [];
102
+ if (needsOne) imports.push("one");
103
+ if (needsMany) imports.push("many");
104
+ const importStr = imports.join(", ");
105
+ const relDefs = [];
106
+ for (const rel of childRels) relDefs.push(` ${rel.name}: one(${rel.toTable}, {\n fields: [${rel.fromColumn}],\n references: [id],\n })`);
107
+ for (const rel of parentRels) if (rel.type === "has-many") relDefs.push(` ${rel.name}: many(${rel.toTable})`);
108
+ else relDefs.push(` ${rel.name}: one(${rel.toTable})`);
109
+ definitions.push(`export const ${tableName}Relations = relations(${tableName}, ({ ${importStr} }) => ({\n${relDefs.join(",\n")}\n}))`);
110
+ }
111
+ return definitions.join("\n\n");
112
+ }
113
+ function generateDrizzleSchema(result) {
114
+ const imports = `import { sqliteTable, text, integer, real } from 'drizzle-orm/sqlite-core'\nimport { relations } from 'drizzle-orm'`;
115
+ const tableDefs = result.tables.map(generateTableDefinition).join("\n\n");
116
+ const relationDefs = generateRelationDefinitions(result.relations, result.reverseRelations);
117
+ const parts = [
118
+ imports,
119
+ "",
120
+ tableDefs
121
+ ];
122
+ if (relationDefs) parts.push("", relationDefs);
123
+ parts.push("");
124
+ return parts.join("\n");
125
+ }
126
+
127
+ //#endregion
128
+ //#region src/core/schema-sqlite/parser.ts
129
+ function toSnakeCase(str) {
130
+ return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
131
+ }
132
+ function mapPropertyToColumn(name$1, property, isRequired) {
133
+ const snakeName = toSnakeCase(name$1);
134
+ let drizzleType;
135
+ const isPrimary = property.primary ?? false;
136
+ const isAutoIncrement = property.autoIncrement ?? false;
137
+ switch (property.type) {
138
+ case "string": {
139
+ const format = property.format;
140
+ if (format === "date-time" || property.drizzle?.mode === "timestamp") drizzleType = `integer({ mode: 'timestamp' })`;
141
+ else if (format === "json" || property.drizzle?.mode === "json") drizzleType = `text({ mode: 'json' })`;
142
+ else drizzleType = "text()";
143
+ break;
144
+ }
145
+ case "integer": {
146
+ const mode = property.drizzle?.mode;
147
+ if (mode === "boolean") drizzleType = `integer({ mode: 'boolean' })`;
148
+ else if (mode === "timestamp" || mode === "timestamp_ms") drizzleType = `integer({ mode: '${mode}' })`;
149
+ else if (mode === "bigint") drizzleType = `integer({ mode: 'bigint' })`;
150
+ else drizzleType = "integer()";
151
+ break;
152
+ }
153
+ case "number":
154
+ drizzleType = "real()";
155
+ break;
156
+ case "boolean":
157
+ drizzleType = `integer({ mode: 'boolean' })`;
158
+ break;
159
+ case "object":
160
+ case "array":
161
+ drizzleType = `text({ mode: 'json' })`;
162
+ break;
163
+ case "null":
164
+ drizzleType = "text()";
165
+ break;
166
+ default: drizzleType = "text()";
167
+ }
168
+ return {
169
+ name: snakeName,
170
+ drizzleType,
171
+ isPrimary,
172
+ isAutoIncrement,
173
+ isNullable: !isRequired && !isPrimary,
174
+ isUnique: property.unique ?? false,
175
+ defaultValue: property.default !== void 0 ? JSON.stringify(property.default) : void 0,
176
+ isForeignKey: property.foreignKey !== void 0,
177
+ foreignKeyRef: property.foreignKey ?? void 0
178
+ };
179
+ }
180
+ function parseObjectToTable(schema, _warnings) {
181
+ const tableName = schema.table.name;
182
+ const columns = [];
183
+ const requiredFields = new Set(schema.required ?? []);
184
+ const autoColumns = /* @__PURE__ */ new Set();
185
+ if (schema.table.timestamps) {
186
+ autoColumns.add("created_at");
187
+ autoColumns.add("updated_at");
188
+ }
189
+ if (schema.table.softDelete) autoColumns.add("deleted_at");
190
+ for (const [propName, prop] of Object.entries(schema.properties)) {
191
+ if (prop.nested?.enabled && (prop.type === "object" || prop.type === "array")) continue;
192
+ if (prop.type === "array" && prop.items?.nested?.enabled) continue;
193
+ const snakeName = toSnakeCase(propName);
194
+ if (autoColumns.has(snakeName)) continue;
195
+ const column = mapPropertyToColumn(propName, prop, requiredFields.has(propName));
196
+ columns.push(column);
197
+ }
198
+ if (schema.table.timestamps) {
199
+ columns.push({
200
+ name: "created_at",
201
+ drizzleType: `integer({ mode: 'timestamp' })`,
202
+ isPrimary: false,
203
+ isAutoIncrement: false,
204
+ isNullable: false,
205
+ isUnique: false,
206
+ defaultValue: void 0
207
+ });
208
+ columns.push({
209
+ name: "updated_at",
210
+ drizzleType: `integer({ mode: 'timestamp' })`,
211
+ isPrimary: false,
212
+ isAutoIncrement: false,
213
+ isNullable: false,
214
+ isUnique: false,
215
+ defaultValue: void 0
216
+ });
217
+ }
218
+ if (schema.table.softDelete) columns.push({
219
+ name: "deleted_at",
220
+ drizzleType: `integer({ mode: 'timestamp' })`,
221
+ isPrimary: false,
222
+ isAutoIncrement: false,
223
+ isNullable: true,
224
+ isUnique: false,
225
+ defaultValue: void 0
226
+ });
227
+ return {
228
+ name: tableName,
229
+ columns
230
+ };
231
+ }
232
+ function parseNestedObject(propName, property, parentTableName, warnings) {
233
+ const nestedTableName = `${parentTableName}_${toSnakeCase(propName)}`;
234
+ const columns = [];
235
+ const relationType = property.nested?.relation === "has-many" ? "has-many" : "has-one";
236
+ columns.push({
237
+ name: "id",
238
+ drizzleType: "integer()",
239
+ isPrimary: true,
240
+ isAutoIncrement: true,
241
+ isNullable: false,
242
+ isUnique: false,
243
+ defaultValue: void 0
244
+ });
245
+ columns.push({
246
+ name: `${parentTableName}_id`,
247
+ drizzleType: "integer()",
248
+ isPrimary: false,
249
+ isAutoIncrement: false,
250
+ isNullable: false,
251
+ isUnique: false,
252
+ defaultValue: void 0,
253
+ isForeignKey: true,
254
+ foreignKeyRef: {
255
+ table: parentTableName,
256
+ column: "id"
257
+ }
258
+ });
259
+ if (property.type === "object" && property.properties) for (const [childName, childProp] of Object.entries(property.properties)) {
260
+ if (childProp.nested?.enabled) {
261
+ warnings.push(`Nested property "${childName}" inside "${nestedTableName}" is skipped — only one level of nesting is supported. Remove nested.enabled or use drizzle.mode: 'json' instead.`);
262
+ continue;
263
+ }
264
+ const column = mapPropertyToColumn(childName, childProp, false);
265
+ columns.push(column);
266
+ }
267
+ const relation = {
268
+ fromTable: nestedTableName,
269
+ fromColumn: `${parentTableName}_id`,
270
+ toTable: parentTableName,
271
+ toColumn: "id",
272
+ name: parentTableName
273
+ };
274
+ const reverseRelation = {
275
+ type: relationType,
276
+ fromTable: parentTableName,
277
+ toTable: nestedTableName,
278
+ name: toSnakeCase(propName)
279
+ };
280
+ return {
281
+ table: {
282
+ name: nestedTableName,
283
+ columns
284
+ },
285
+ relation,
286
+ reverseRelation
287
+ };
288
+ }
289
+ function parseJsonSchema(schema) {
290
+ const tables = [];
291
+ const relations = [];
292
+ const reverseRelations = [];
293
+ const warnings = [];
294
+ const mainTable = parseObjectToTable(schema, warnings);
295
+ tables.push(mainTable);
296
+ for (const [propName, prop] of Object.entries(schema.properties)) if (prop.type === "object" && prop.nested?.enabled) {
297
+ const nested = parseNestedObject(propName, prop, mainTable.name, warnings);
298
+ tables.push(nested.table);
299
+ relations.push(nested.relation);
300
+ reverseRelations.push(nested.reverseRelation);
301
+ } else if (prop.type === "array" && prop.items?.nested?.enabled && prop.items?.type === "object" && prop.items.properties) {
302
+ const nested = parseNestedObject(propName, prop.items, mainTable.name, warnings);
303
+ tables.push(nested.table);
304
+ relations.push(nested.relation);
305
+ reverseRelations.push(nested.reverseRelation);
306
+ }
307
+ return {
308
+ tables,
309
+ relations,
310
+ reverseRelations,
311
+ warnings
312
+ };
313
+ }
314
+
315
+ //#endregion
316
+ //#region src/core/schema-sqlite/schemas.ts
317
+ const DrizzleModeSchema = z.enum([
318
+ "json",
319
+ "timestamp",
320
+ "timestamp_ms",
321
+ "boolean",
322
+ "bigint"
323
+ ]);
324
+ const DrizzleExtensionSchema = z.object({
325
+ mode: DrizzleModeSchema.optional(),
326
+ customType: z.string().optional()
327
+ }).optional();
328
+ const NestedConfigSchema = z.object({
329
+ enabled: z.literal(true),
330
+ relation: z.enum(["has-one", "has-many"])
331
+ });
332
+ const ForeignKeyRefSchema = z.object({
333
+ table: z.string().min(1),
334
+ column: z.string().min(1)
335
+ });
336
+ const JsonSchemaPropertySchema = z.lazy(() => z.object({
337
+ type: z.enum([
338
+ "string",
339
+ "integer",
340
+ "number",
341
+ "boolean",
342
+ "object",
343
+ "array",
344
+ "null"
345
+ ]),
346
+ format: z.string().optional(),
347
+ primary: z.boolean().optional(),
348
+ autoIncrement: z.boolean().optional(),
349
+ unique: z.boolean().optional(),
350
+ default: z.unknown().optional(),
351
+ maxLength: z.number().int().positive().optional(),
352
+ minLength: z.number().int().nonnegative().optional(),
353
+ minimum: z.number().optional(),
354
+ maximum: z.number().optional(),
355
+ drizzle: DrizzleExtensionSchema,
356
+ nested: NestedConfigSchema.optional(),
357
+ foreignKey: ForeignKeyRefSchema.optional(),
358
+ properties: z.record(z.string(), JsonSchemaPropertySchema).optional(),
359
+ items: JsonSchemaPropertySchema.optional(),
360
+ required: z.array(z.string()).optional()
361
+ }));
362
+ const TableConfigSchema = z.object({
363
+ name: z.string().min(1).regex(/^[a-z][a-z0-9_]*$/, "Table name must be snake_case (lowercase letters, digits, underscores)"),
364
+ timestamps: z.boolean().optional(),
365
+ softDelete: z.boolean().optional()
366
+ });
367
+ const JsonSchemaDefinitionSchema = z.object({
368
+ $schema: z.string().optional(),
369
+ title: z.string().min(1),
370
+ description: z.string().optional(),
371
+ type: z.literal("object"),
372
+ table: TableConfigSchema,
373
+ properties: z.record(z.string(), JsonSchemaPropertySchema),
374
+ required: z.array(z.string()).optional()
375
+ }).refine((schema) => Object.keys(schema.properties).length >= 1, {
376
+ message: "At least one property is required",
377
+ path: ["properties"]
378
+ }).refine((schema) => !schema.required || schema.required.every((r) => r in schema.properties), {
379
+ message: "All required fields must be defined in properties",
380
+ path: ["required"]
381
+ }).refine((schema) => {
382
+ return !Object.values(schema.properties).some((p) => p.primary) || Object.values(schema.properties).filter((p) => p.primary).length === 1;
383
+ }, {
384
+ message: "Only one primary key is allowed per table",
385
+ path: ["properties"]
386
+ });
387
+
388
+ //#endregion
389
+ //#region src/core/schema-sqlite/migrator.ts
390
+ function createMigrationConfig(cwd) {
391
+ return {
392
+ schemaPath: `${cwd}/.aiex/schema`,
393
+ drizzleSchemaPath: `${cwd}/.aiex/drizzle/schema.ts`,
394
+ migrationsPath: `${cwd}/.aiex/migrations`,
395
+ databasePath: `${cwd}/.aiex/database.db`,
396
+ drizzleConfigPath: `${cwd}/.aiex/drizzle.config.ts`
397
+ };
398
+ }
399
+ function generateDrizzleConfig() {
400
+ return `export default {
401
+ dialect: 'sqlite',
402
+ schema: './.aiex/drizzle/schema.ts',
403
+ out: './.aiex/migrations',
404
+ dbCredentials: {
405
+ url: './.aiex/database.db',
406
+ },
407
+ }
408
+ `;
409
+ }
410
+
411
+ //#endregion
412
+ //#region package.json
413
+ var name = "aiex-cli";
414
+ var version = "0.0.0";
415
+ var description = "JSON Schema → SQLite with AI-powered data extraction";
416
+ var package_default = {
417
+ name,
418
+ type: "module",
419
+ version,
420
+ description,
421
+ author: "OSpoon <zxin088@gmail.com>",
422
+ license: "MIT",
423
+ homepage: "https://github.com/OSpoon/aiex-cli#readme",
424
+ repository: {
425
+ "type": "git",
426
+ "url": "git+https://github.com/OSpoon/aiex-cli.git"
427
+ },
428
+ bugs: "https://github.com/OSpoon/aiex-cli/issues",
429
+ keywords: [
430
+ "json-schema",
431
+ "sqlite",
432
+ "drizzle",
433
+ "orm",
434
+ "ai-extraction",
435
+ "cli",
436
+ "database-migration",
437
+ "schema-editor",
438
+ "code-generation",
439
+ "structured-output"
440
+ ],
441
+ sideEffects: false,
442
+ exports: {
443
+ ".": "./dist/index.mjs",
444
+ "./cli": "./dist/cli.mjs",
445
+ "./core/schema-sqlite/migrate-helper": "./dist/core/schema-sqlite/migrate-helper.mjs",
446
+ "./package.json": "./package.json"
447
+ },
448
+ main: "./dist/index.mjs",
449
+ module: "./dist/index.mjs",
450
+ types: "./dist/index.d.mts",
451
+ bin: { "aiex": "./bin/cli.mjs" },
452
+ files: [
453
+ "bin",
454
+ "dist",
455
+ "src/core/schema-sqlite/migrate-helper.ts"
456
+ ],
457
+ scripts: {
458
+ "build": "tsdown && pnpm --filter aiex-web build",
459
+ "dev": "tsdown --watch",
460
+ "start": "tsx src/index.ts",
461
+ "test": "vitest",
462
+ "typecheck": "tsc",
463
+ "lint": "eslint .",
464
+ "prepublishOnly": "cp ../../README.md . && pnpm run build",
465
+ "postpublish": "rm -f README.md"
466
+ },
467
+ dependencies: {
468
+ "@ai-sdk/openai-compatible": "catalog:",
469
+ "@clack/prompts": "catalog:",
470
+ "@hono/node-server": "catalog:",
471
+ "ai": "catalog:",
472
+ "better-sqlite3": "catalog:",
473
+ "citty": "catalog:",
474
+ "cli-table3": "catalog:",
475
+ "conf": "catalog:",
476
+ "consola": "catalog:",
477
+ "date-fns": "catalog:",
478
+ "drizzle-kit": "catalog:cli",
479
+ "drizzle-orm": "catalog:",
480
+ "es-toolkit": "catalog:",
481
+ "esbuild": "catalog:",
482
+ "hono": "catalog:",
483
+ "picocolors": "catalog:",
484
+ "tsx": "catalog:cli",
485
+ "update-notifier": "catalog:",
486
+ "zod": "catalog:"
487
+ },
488
+ devDependencies: {
489
+ "@antfu/eslint-config": "catalog:cli",
490
+ "@antfu/ni": "catalog:cli",
491
+ "@types/better-sqlite3": "catalog:types",
492
+ "@types/node": "catalog:types",
493
+ "@types/update-notifier": "catalog:",
494
+ "eslint": "catalog:cli",
495
+ "publint": "catalog:cli",
496
+ "tsdown": "catalog:cli",
497
+ "tsnapi": "catalog:testing",
498
+ "typescript": "catalog:cli",
499
+ "vitest": "catalog:testing"
500
+ }
501
+ };
502
+
503
+ //#endregion
504
+ //#region src/config.ts
505
+ function createConfig() {
506
+ return new Conf({
507
+ cwd: process.env.CLI_CONFIG_DIR,
508
+ projectName: process.env.CLI_CONFIG_PROJECT_NAME || name
509
+ });
510
+ }
511
+ function seedConfig(config = createConfig()) {
512
+ if (!config.has("name")) config.set("name", name);
513
+ if (!config.has("version")) config.set("version", version);
514
+ }
515
+
516
+ //#endregion
517
+ //#region src/core/ai-extraction/schemas.ts
518
+ const ModelCapabilitiesSchema = z.object({
519
+ vision: z.boolean(),
520
+ structuredOutput: z.boolean()
521
+ });
522
+ const AIModelConfigSchema = z.object({
523
+ name: z.string().min(1),
524
+ capabilities: ModelCapabilitiesSchema
525
+ });
526
+ const AIProviderConfigSchema = z.object({
527
+ baseURL: z.string().min(1),
528
+ apiKey: z.string(),
529
+ models: z.array(AIModelConfigSchema).min(1)
530
+ });
531
+ const PromptConfigSchema = z.object({
532
+ systemTemplate: z.string().min(1),
533
+ userTemplate: z.string().min(1)
534
+ });
535
+ const ExtractionConfigSchema = z.object({ outputDir: z.string().min(1) });
536
+ const AIConfigSchema = z.object({
537
+ provider: AIProviderConfigSchema,
538
+ prompt: PromptConfigSchema,
539
+ extraction: ExtractionConfigSchema
540
+ });
541
+
542
+ //#endregion
543
+ //#region src/core/ai-extraction/types.ts
544
+ const PLACEHOLDER_SCHEMA = "{schema}";
545
+ const PLACEHOLDER_TEXT = "{text}";
546
+ const DEFAULT_MODELS = [{
547
+ name: "qwen-plus",
548
+ capabilities: {
549
+ vision: false,
550
+ structuredOutput: true
551
+ }
552
+ }, {
553
+ name: "qwen-vl-plus",
554
+ capabilities: {
555
+ vision: true,
556
+ structuredOutput: true
557
+ }
558
+ }];
559
+ const DEFAULT_PROVIDER_CONFIG = {
560
+ baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
561
+ apiKey: "",
562
+ models: [...DEFAULT_MODELS]
563
+ };
564
+ const DEFAULT_PROMPT_CONFIG = {
565
+ systemTemplate: `You are a professional data extraction assistant. Your task is to extract structured data from text based on the data structure definition provided below.
566
+
567
+ {schema}
568
+
569
+ Extraction requirements:
570
+ 1. Extract strictly according to the field names and types defined in the structure
571
+ 2. If the text lacks information for a field, set that field to null
572
+ 3. Do not add fields that do not exist in the structure definition
573
+ 4. Maintain data accuracy and completeness`,
574
+ userTemplate: `Please extract data from the following text:
575
+ {text}`
576
+ };
577
+ const DEFAULT_EXTRACTION_CONFIG = { outputDir: ".aiex/extracted" };
578
+ const DEFAULT_AI_CONFIG = {
579
+ provider: DEFAULT_PROVIDER_CONFIG,
580
+ prompt: DEFAULT_PROMPT_CONFIG,
581
+ extraction: DEFAULT_EXTRACTION_CONFIG
582
+ };
583
+
584
+ //#endregion
585
+ //#region src/core/ai-extraction/config.ts
586
+ const CONFIG_FILE_NAME = "ai-config.json";
587
+ const GITIGNORE_FILE = ".gitignore";
588
+ async function readAIConfig(aiexDir) {
589
+ const configPath = path.join(aiexDir, CONFIG_FILE_NAME);
590
+ try {
591
+ const content = await fs.readFile(configPath, "utf-8");
592
+ const parsed = JSON.parse(content);
593
+ return AIConfigSchema.parse(parsed);
594
+ } catch {
595
+ return null;
596
+ }
597
+ }
598
+ async function writeAIConfig(aiexDir, config) {
599
+ const configPath = path.join(aiexDir, CONFIG_FILE_NAME);
600
+ await fs.mkdir(aiexDir, { recursive: true });
601
+ await fs.writeFile(configPath, `${JSON.stringify(config, null, 2)}\n`);
602
+ await addToGitignore(aiexDir, CONFIG_FILE_NAME);
603
+ }
604
+ function getDefaultAIConfig() {
605
+ return { ...DEFAULT_AI_CONFIG };
606
+ }
607
+ function maskApiKey(apiKey) {
608
+ if (apiKey.length <= 4) return "****";
609
+ return `sk-***${apiKey.slice(-4)}`;
610
+ }
611
+ async function addToGitignore(aiexDir, fileName) {
612
+ const projectRoot = path.dirname(aiexDir);
613
+ const gitignorePath = path.join(projectRoot, GITIGNORE_FILE);
614
+ try {
615
+ const content = await fs.readFile(gitignorePath, "utf-8");
616
+ if (content.split("\n").some((line) => line.trim() === fileName || line.includes(".aiex/"))) return;
617
+ const newContent = content.endsWith("\n") ? `${content}${fileName}\n` : `${content}\n${fileName}\n`;
618
+ await fs.writeFile(gitignorePath, newContent);
619
+ } catch {
620
+ await fs.writeFile(gitignorePath, `${fileName}\n`);
621
+ }
622
+ }
623
+
624
+ //#endregion
625
+ //#region src/doctor.ts
626
+ const V1_SUFFIX_RE = /\/v1\/?$/;
627
+ async function checkConnection(baseURL) {
628
+ try {
629
+ const base = baseURL.replace(V1_SUFFIX_RE, "");
630
+ return (await fetch(`${base}/v1/models`, { signal: AbortSignal.timeout(5e3) })).ok;
631
+ } catch {
632
+ return false;
633
+ }
634
+ }
635
+ async function collectDoctorDiagnostics(options = {}) {
636
+ const config = options.config ?? createConfig();
637
+ const cwd = process.cwd();
638
+ const errors = [];
639
+ const migConfig = createMigrationConfig(cwd);
640
+ const aiexDir = path.dirname(migConfig.schemaPath);
641
+ const dirExists = await fs.stat(aiexDir).then((s) => s.isDirectory()).catch(() => false);
642
+ let schemaFiles = [];
643
+ if (dirExists) try {
644
+ const schemaDir = migConfig.schemaPath;
645
+ schemaFiles = (await fs.readdir(schemaDir).catch(() => [])).filter((f) => f.endsWith(".json")).sort();
646
+ } catch {
647
+ errors.push("Could not read schema directory");
648
+ }
649
+ let aiConfig = false;
650
+ let aiApiKeySet = false;
651
+ let aiModelCount = 0;
652
+ let aiModels = [];
653
+ let aiProvider = null;
654
+ let aiConnectionOk = null;
655
+ if (dirExists) {
656
+ const cfg = await readAIConfig(aiexDir);
657
+ if (cfg) {
658
+ aiConfig = true;
659
+ aiApiKeySet = Boolean(cfg.provider.apiKey);
660
+ aiModelCount = cfg.provider.models?.length ?? 0;
661
+ aiModels = cfg.provider.models?.map((m) => m.name) ?? [];
662
+ aiProvider = cfg.provider.baseURL;
663
+ aiConnectionOk = await checkConnection(cfg.provider.baseURL);
664
+ }
665
+ }
666
+ let dbExists = false;
667
+ if (dirExists) try {
668
+ dbExists = (await fs.stat(migConfig.databasePath)).isFile();
669
+ } catch {
670
+ dbExists = false;
671
+ }
672
+ let migrationCount = 0;
673
+ if (dirExists) try {
674
+ migrationCount = (await fs.readdir(migConfig.migrationsPath).catch(() => [])).filter((f) => f.endsWith(".sql")).length;
675
+ } catch {}
676
+ return buildDoctorDiagnostics({
677
+ pkg: {
678
+ name,
679
+ version
680
+ },
681
+ executable: process.argv[1] ?? "unknown",
682
+ node: process.version,
683
+ platform: process.platform,
684
+ arch: process.arch,
685
+ shell: process.env.SHELL ?? process.env.ComSpec ?? "unknown",
686
+ packageManager: process.env.npm_config_user_agent?.split(" ")[0] || "unknown",
687
+ osType: os.type(),
688
+ osRelease: os.release(),
689
+ cwd,
690
+ configPath: config.path,
691
+ configStoreKeys: Object.keys(config.store),
692
+ project: {
693
+ aiexDir,
694
+ dirExists,
695
+ schemaCount: schemaFiles.length,
696
+ schemaFiles,
697
+ aiConfig,
698
+ aiApiKeySet,
699
+ aiModelCount,
700
+ aiModels,
701
+ aiProvider,
702
+ aiConnectionOk,
703
+ hasDatabase: dbExists,
704
+ migrationCount,
705
+ errors
706
+ }
707
+ });
708
+ }
709
+
710
+ //#endregion
711
+ export { formatDoctorDiagnosticsJson as C, doctorDiagnosticsTableRows as S, generateDrizzleConfig as _, writeAIConfig as a, generateDrizzleSchema as b, PLACEHOLDER_TEXT as c, seedConfig as d, description as f, createMigrationConfig as g, version as h, readAIConfig as i, AIConfigSchema as l, package_default as m, getDefaultAIConfig as n, DEFAULT_PROMPT_CONFIG as o, name as p, maskApiKey as r, PLACEHOLDER_SCHEMA as s, collectDoctorDiagnostics as t, createConfig as u, JsonSchemaDefinitionSchema as v, buildDoctorDiagnostics as x, parseJsonSchema as y };