aiex-cli 0.0.1-beta.9 → 0.0.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 (123) hide show
  1. package/README.md +32 -25
  2. package/dist/cli.mjs +912 -567
  3. package/dist/{completions-ygS1okck.mjs → completions-C3rmTwXZ.mjs} +2 -2
  4. package/dist/core/schema-sqlite/migrate-helper.mjs +35 -37
  5. package/dist/{doctor-BiU1lDp-.mjs → doctor-collector-CykRm0fC.mjs} +282 -223
  6. package/dist/index.d.mts +15 -15
  7. package/dist/index.mjs +1 -1
  8. package/dist/table-schema.json +4 -0
  9. package/dist/web/assets/AISettings-CI6Lgx0p.js +339 -0
  10. package/dist/web/assets/DataBrowser-CwcTG80-.js +6 -0
  11. package/dist/web/assets/ExtractionViewer-CsdK1kKK.js +1 -0
  12. package/dist/web/assets/JsonSchemaEditor-D477lV5a.js +570 -0
  13. package/dist/web/assets/api-client-D2Y_-4JM.js +1 -0
  14. package/dist/web/assets/button-Cdgr9Igy.js +927 -0
  15. package/dist/web/assets/{cssMode-DAbG0CMn.js → cssMode-CPThwItX.js} +1 -1
  16. package/dist/web/assets/dialog-CUkPLPNP.js +109 -0
  17. package/dist/web/assets/dist-9yHVMqQ0.js +1 -0
  18. package/dist/web/assets/{editor.main-BqhfoHxy.js → editor.main-BnOkwRFv.js} +2 -2
  19. package/dist/web/assets/{freemarker2-B9_5ct2b.js → freemarker2-DWDTYVJR.js} +1 -1
  20. package/dist/web/assets/{handlebars-TY59WcoQ.js → handlebars-D4DzjGQ7.js} +1 -1
  21. package/dist/web/assets/{html-CLULsh27.js → html-DnzhKSoD.js} +1 -1
  22. package/dist/web/assets/{htmlMode-BvG7RNbU.js → htmlMode-CR7UKfEH.js} +1 -1
  23. package/dist/web/assets/index-C9N8oWt4.css +2 -0
  24. package/dist/web/assets/{index-CKUXTDYj.js → index-DVDVw-GK.js} +38 -38
  25. package/dist/web/assets/{javascript-DHrLp6gu.js → javascript-D2srszZ8.js} +1 -1
  26. package/dist/web/assets/{jsonMode-DBDhdzl1.js → jsonMode-B4jaPYEr.js} +1 -1
  27. package/dist/web/assets/{liquid-tGeb-nqF.js → liquid-CIT2Wl_l.js} +1 -1
  28. package/dist/web/assets/{mdx-Cmdz78VU.js → mdx-CWLaEOFy.js} +1 -1
  29. package/dist/web/assets/{monaco.contribution-CroYPUF5.js → monaco.contribution-DDv5ldfS.js} +2 -2
  30. package/dist/web/assets/object-utils-I4gWdSnS.js +1 -0
  31. package/dist/web/assets/{python-Dmfz4iDE.js → python-6CGfpCNq.js} +1 -1
  32. package/dist/web/assets/{razor-BJicZHJs.js → razor-DEMMh3TD.js} +1 -1
  33. package/dist/web/assets/runtime-dom.esm-bundler-ei_N7Xjw.js +1 -0
  34. package/dist/web/assets/select-BGex2SPs.js +439 -0
  35. package/dist/web/assets/{tsMode-DYqTyE66.js → tsMode-Cm1NtjPs.js} +1 -1
  36. package/dist/web/assets/{typescript-DLnTe9Hf.js → typescript-BM9aPEFg.js} +1 -1
  37. package/dist/web/assets/{xml-BIYqLORk.js → xml-CoSbvcg5.js} +1 -1
  38. package/dist/web/assets/{yaml-BjmulkMX.js → yaml-56GOgy8k.js} +1 -1
  39. package/dist/web/index.html +10 -8
  40. package/package.json +16 -1
  41. package/src/core/schema-sqlite/migrate-helper.ts +32 -46
  42. package/dist/web/assets/AISettings-DOzonIux.js +0 -334
  43. package/dist/web/assets/DataBrowser-rznfVRaV.js +0 -3
  44. package/dist/web/assets/JsonSchemaEditor-C9iyQs7N.js +0 -929
  45. package/dist/web/assets/api-client-Dsg4WOM9.js +0 -1
  46. package/dist/web/assets/button-kTMweGMc.js +0 -927
  47. package/dist/web/assets/dialog-CWuu7WjI.js +0 -108
  48. package/dist/web/assets/index-DDFnprdM.css +0 -2
  49. package/dist/web/assets/lib-C30cIFrm.js +0 -1
  50. package/dist/web/assets/overlayeventbus-AtOpmI6n.js +0 -80
  51. package/dist/web/assets/table-schema-mJrrf9qw.js +0 -2
  52. /package/dist/web/assets/{abap-DrZwwXZX.js → abap-Bgec7Keq.js} +0 -0
  53. /package/dist/web/assets/{apex-CrCz0btt.js → apex-VBlPwEoQ.js} +0 -0
  54. /package/dist/web/assets/{azcli-BapzKHay.js → azcli-DKqrEFBx.js} +0 -0
  55. /package/dist/web/assets/{bat-C_NRAiA1.js → bat-DdgQWy_0.js} +0 -0
  56. /package/dist/web/assets/{bicep-C7pp2CNk.js → bicep-CRMM43EB.js} +0 -0
  57. /package/dist/web/assets/{cameligo-BhhK9vxZ.js → cameligo-UatALtML.js} +0 -0
  58. /package/dist/web/assets/{clojure-D0ujmUyE.js → clojure-D8JU08RA.js} +0 -0
  59. /package/dist/web/assets/{coffee-DHEl7Jbb.js → coffee-C56wu358.js} +0 -0
  60. /package/dist/web/assets/{cpp-Iil-3nzZ.js → cpp-CyZLvhJG.js} +0 -0
  61. /package/dist/web/assets/{csharp-Dh0Ee7SY.js → csharp-BJl3ixva.js} +0 -0
  62. /package/dist/web/assets/{csp-mwzjw0JL.js → csp-CxEKxmO-.js} +0 -0
  63. /package/dist/web/assets/{css-COIa8ZTR.js → css-B0t_muXd.js} +0 -0
  64. /package/dist/web/assets/{cypher-GVc17FC4.js → cypher-D1hqiMFD.js} +0 -0
  65. /package/dist/web/assets/{dart-phiCaE7_.js → dart-Bz550Pyv.js} +0 -0
  66. /package/dist/web/assets/{dockerfile-BMaDhdim.js → dockerfile-CIXgVAuA.js} +0 -0
  67. /package/dist/web/assets/{ecl-Cj47kvqp.js → ecl-D9qbvZoA.js} +0 -0
  68. /package/dist/web/assets/{editor.api-DLXGyrN1.js → editor.api-C8BHpRhn.js} +0 -0
  69. /package/dist/web/assets/{elixir-DBbstcE1.js → elixir-b2M38fAy.js} +0 -0
  70. /package/dist/web/assets/{flow9-ChHb1adO.js → flow9-Dq1UYMkt.js} +0 -0
  71. /package/dist/web/assets/{fsharp-CMk2OIJN.js → fsharp-BaeLhgfq.js} +0 -0
  72. /package/dist/web/assets/{go-BrMkuJg0.js → go-Bd-NFKIC.js} +0 -0
  73. /package/dist/web/assets/{graphql-PSR1UKGv.js → graphql-DZVerJfy.js} +0 -0
  74. /package/dist/web/assets/{hcl-DAQrbDOW.js → hcl-CAVzrZfH.js} +0 -0
  75. /package/dist/web/assets/{ini-0TG5BxW0.js → ini-CyXdX58t.js} +0 -0
  76. /package/dist/web/assets/{java-rgorz17v.js → java-B5pNgvhy.js} +0 -0
  77. /package/dist/web/assets/{julia-C8VMdHm8.js → julia-XRhmV3AN.js} +0 -0
  78. /package/dist/web/assets/{kotlin-CllWo3gX.js → kotlin-DOd3J5vr.js} +0 -0
  79. /package/dist/web/assets/{less-Cgca25AP.js → less-veZSnyw6.js} +0 -0
  80. /package/dist/web/assets/{lexon-D0GHdBaw.js → lexon-QWGkuK0H.js} +0 -0
  81. /package/dist/web/assets/{lua-DmRsNG-P.js → lua-CYGpjuO5.js} +0 -0
  82. /package/dist/web/assets/{m3-BgL5dNKT.js → m3-yNnrZkdc.js} +0 -0
  83. /package/dist/web/assets/{markdown-BuJfycGS.js → markdown-BCSWEPSX.js} +0 -0
  84. /package/dist/web/assets/{mips-C9m_93PR.js → mips-OpYmcC30.js} +0 -0
  85. /package/dist/web/assets/{msdax-CpFHC9OI.js → msdax-2oxoTO9Z.js} +0 -0
  86. /package/dist/web/assets/{mysql-qFvltsqN.js → mysql-5KlC-K_9.js} +0 -0
  87. /package/dist/web/assets/{objective-c-Bnmr858J.js → objective-c-CcDCgtLx.js} +0 -0
  88. /package/dist/web/assets/{pascal-WP0_D5AO.js → pascal-BZGsbaEV.js} +0 -0
  89. /package/dist/web/assets/{pascaligo-Blom4Rij.js → pascaligo-DtD5qU3G.js} +0 -0
  90. /package/dist/web/assets/{perl-B-vk8g64.js → perl-C1jNNS3E.js} +0 -0
  91. /package/dist/web/assets/{pgsql-Cgvz6v67.js → pgsql-CT0fhiZa.js} +0 -0
  92. /package/dist/web/assets/{php-8a3Lrw9m.js → php-D6DrXoPM.js} +0 -0
  93. /package/dist/web/assets/{pla-DuFqEZ8V.js → pla-b3-HN2pF.js} +0 -0
  94. /package/dist/web/assets/{postiats-DkLtSgkp.js → postiats-Bin2ApVS.js} +0 -0
  95. /package/dist/web/assets/{powerquery-BJ1aNepW.js → powerquery-7ASnn-ZG.js} +0 -0
  96. /package/dist/web/assets/{powershell-rE98k687.js → powershell-t4p7sU1H.js} +0 -0
  97. /package/dist/web/assets/{preload-helper-DWTEM3RW.js → preload-helper-Dd-HcVz_.js} +0 -0
  98. /package/dist/web/assets/{protobuf-CUheFacr.js → protobuf-BUGeWa_j.js} +0 -0
  99. /package/dist/web/assets/{pug-LDcAMD8w.js → pug-BuKcgC9s.js} +0 -0
  100. /package/dist/web/assets/{qsharp-IHfqKOfK.js → qsharp-DxLLX8mo.js} +0 -0
  101. /package/dist/web/assets/{r-D-QApv87.js → r-DMlFgn7A.js} +0 -0
  102. /package/dist/web/assets/{redis-SXdDyWR9.js → redis-cXItkC5u.js} +0 -0
  103. /package/dist/web/assets/{redshift-Y6lsCryn.js → redshift-BZVbW7HE.js} +0 -0
  104. /package/dist/web/assets/{restructuredtext-edObr9a8.js → restructuredtext-BzjxwS8h.js} +0 -0
  105. /package/dist/web/assets/{ruby-CNnUfF-8.js → ruby-C5nyLV4l.js} +0 -0
  106. /package/dist/web/assets/{rust-IHUZWzBr.js → rust-BcmMsHdf.js} +0 -0
  107. /package/dist/web/assets/{sb-DrUvY44N.js → sb-Dnb1iy6B.js} +0 -0
  108. /package/dist/web/assets/{scala-B4hbXGLM.js → scala-anMIFYpA.js} +0 -0
  109. /package/dist/web/assets/{scheme-BGrd12j3.js → scheme-BItQTe08.js} +0 -0
  110. /package/dist/web/assets/{scss-x5G1ES4U.js → scss-BOv51BJ5.js} +0 -0
  111. /package/dist/web/assets/{shell-DOehe2Y8.js → shell-BsRYRTNN.js} +0 -0
  112. /package/dist/web/assets/{solidity-BeRvcwWV.js → solidity-BtuLgGDx.js} +0 -0
  113. /package/dist/web/assets/{sophia-DZbkUNjy.js → sophia-B0Vkc5MF.js} +0 -0
  114. /package/dist/web/assets/{sparql-B7_oi5-h.js → sparql-B7lvkZQM.js} +0 -0
  115. /package/dist/web/assets/{sql-CTlsFWVE.js → sql-DvP5MpA3.js} +0 -0
  116. /package/dist/web/assets/{st-DJVEJdPE.js → st-GVUeyB3U.js} +0 -0
  117. /package/dist/web/assets/{swift-CwhT3fYa.js → swift-DSPIoCjm.js} +0 -0
  118. /package/dist/web/assets/{systemverilog-BQN63pkN.js → systemverilog-Icj2-k23.js} +0 -0
  119. /package/dist/web/assets/{tcl-DqwfpskA.js → tcl-Cd8KQcm-.js} +0 -0
  120. /package/dist/web/assets/{twig-BiyenUgc.js → twig-CBHmt8z3.js} +0 -0
  121. /package/dist/web/assets/{typespec-CWOJribt.js → typespec-Ckc037mq.js} +0 -0
  122. /package/dist/web/assets/{vb-Cq5F87m3.js → vb-B97GW9Wb.js} +0 -0
  123. /package/dist/web/assets/{wgsl-BAvW2lVr.js → wgsl-DIKmb3YH.js} +0 -0
@@ -1,5 +1,6 @@
1
1
  import path from "node:path";
2
2
  import process from "node:process";
3
+ import { readFileSync } from "jsonfile";
3
4
  import fs from "node:fs";
4
5
 
5
6
  //#region src/core/completions.ts
@@ -27,8 +28,7 @@ function getFileCompletions(pattern) {
27
28
  }
28
29
  function getJsonModelNames(configPath) {
29
30
  try {
30
- const content = fs.readFileSync(configPath, "utf-8");
31
- const config = JSON.parse(content);
31
+ const config = readFileSync(configPath);
32
32
  if (config.provider?.models) return config.provider.models.map((m) => m.name);
33
33
  } catch {}
34
34
  return [];
@@ -1,10 +1,12 @@
1
1
  import { createRequire } from "node:module";
2
+ import fs from "node:fs/promises";
2
3
  import path from "node:path";
3
4
  import process from "node:process";
5
+ import { readFile, writeFile } from "jsonfile";
4
6
  import { fileURLToPath } from "node:url";
5
- import fs from "node:fs/promises";
6
7
  import Database from "better-sqlite3";
7
8
  import * as esbuild from "esbuild";
9
+ import lockfile from "proper-lockfile";
8
10
 
9
11
  //#region src/core/schema-sqlite/migration-name.ts
10
12
  function sanitizeMigrationName(name) {
@@ -62,11 +64,10 @@ async function loadSchemaExports(schemaPath) {
62
64
  async function loadPrevSnapshot(migrationsPath) {
63
65
  const metaPath = path.join(migrationsPath, "meta", "_journal.json");
64
66
  try {
65
- const journal = JSON.parse(await fs.readFile(metaPath, "utf-8"));
67
+ const journal = await readFile(metaPath);
66
68
  if (!journal.entries?.length) return null;
67
69
  const latestEntry = journal.entries[journal.entries.length - 1];
68
- const snapshotPath = path.join(migrationsPath, "meta", `${latestEntry.tag}_snapshot.json`);
69
- return JSON.parse(await fs.readFile(snapshotPath, "utf-8"));
70
+ return await readFile(path.join(migrationsPath, "meta", `${latestEntry.tag}_snapshot.json`));
70
71
  } catch {
71
72
  return null;
72
73
  }
@@ -77,7 +78,7 @@ async function saveSnapshot(migrationsPath, snapshot, migrationName) {
77
78
  const journalPath = path.join(metaPath, "_journal.json");
78
79
  let journal;
79
80
  try {
80
- journal = JSON.parse(await fs.readFile(journalPath, "utf-8"));
81
+ journal = await readFile(journalPath);
81
82
  } catch {
82
83
  journal = {
83
84
  version: "6",
@@ -88,8 +89,10 @@ async function saveSnapshot(migrationsPath, snapshot, migrationName) {
88
89
  const idx = journal.entries.length + 1;
89
90
  const suffix = sanitizeMigrationName(migrationName) || snapshot.id.replace(/-/g, "_").substring(0, 8);
90
91
  const tag = `${String(idx).padStart(4, "0")}_${suffix}`;
91
- const snapshotPath = path.join(metaPath, `${tag}_snapshot.json`);
92
- await fs.writeFile(snapshotPath, JSON.stringify(snapshot, null, 2));
92
+ await writeFile(path.join(metaPath, `${tag}_snapshot.json`), snapshot, {
93
+ spaces: 2,
94
+ EOL: "\n"
95
+ });
93
96
  journal.entries.push({
94
97
  idx,
95
98
  version: snapshot.id,
@@ -97,7 +100,10 @@ async function saveSnapshot(migrationsPath, snapshot, migrationName) {
97
100
  tag,
98
101
  breakpoints: true
99
102
  });
100
- await fs.writeFile(journalPath, JSON.stringify(journal, null, 2));
103
+ await writeFile(journalPath, journal, {
104
+ spaces: 2,
105
+ EOL: "\n"
106
+ });
101
107
  return tag;
102
108
  }
103
109
  async function saveMigrationFile(migrationsPath, tag, sqlStatements) {
@@ -119,35 +125,22 @@ function applyMigrationWithTransaction(dbPath, sqlStatements) {
119
125
  }
120
126
  }
121
127
  const LOCK_FILE = ".migrate.lock";
122
- async function acquireLock(aiexDir) {
123
- const lockPath = path.join(aiexDir, LOCK_FILE);
128
+ async function acquireMigrationLock(aiexDir) {
124
129
  await fs.mkdir(aiexDir, { recursive: true });
125
130
  try {
126
- const fd = await fs.open(lockPath, "wx");
127
- await fd.write(`${process.pid}\n${Date.now()}`);
128
- await fd.close();
129
- } catch (e) {
130
- if (e.code === "EEXIST") try {
131
- const [pidStr, timestampStr] = (await fs.readFile(lockPath, "utf-8")).split("\n");
132
- const lockPid = Number.parseInt(pidStr, 10);
133
- const lockTime = Number.parseInt(timestampStr, 10);
134
- const lockAge = Date.now() - lockTime;
135
- if (lockAge > 3e5) {
136
- await fs.unlink(lockPath);
137
- return acquireLock(aiexDir);
138
- }
139
- throw new Error(`Migration is already running (PID ${lockPid}, started ${Math.round(lockAge / 1e3)}s ago). Wait for it to complete or remove ${lockPath} if stale.`);
140
- } catch {
141
- await fs.unlink(lockPath).catch(() => {});
142
- return acquireLock(aiexDir);
143
- }
144
- throw e;
131
+ return await lockfile.lock(aiexDir, {
132
+ lockfilePath: path.join(aiexDir, LOCK_FILE),
133
+ realpath: false,
134
+ stale: 3e5,
135
+ update: 1e4,
136
+ retries: 0
137
+ });
138
+ } catch (error) {
139
+ const lockPath = path.join(aiexDir, LOCK_FILE);
140
+ const message = error instanceof Error ? error.message : String(error);
141
+ throw new Error(`Migration is already running or the lock could not be acquired. Wait for it to complete or remove ${lockPath} if stale. ${message}`);
145
142
  }
146
143
  }
147
- async function releaseLock(aiexDir) {
148
- const lockPath = path.join(aiexDir, LOCK_FILE);
149
- await fs.unlink(lockPath).catch(() => {});
150
- }
151
144
  async function main() {
152
145
  const args = process.argv.slice(2);
153
146
  const schemaPath = args[0];
@@ -159,11 +152,16 @@ async function main() {
159
152
  process.exit(1);
160
153
  }
161
154
  try {
162
- const aiexDir = path.dirname(path.dirname(migrationsPath));
163
- await acquireLock(aiexDir);
155
+ const releaseLock = await acquireMigrationLock(path.dirname(path.dirname(migrationsPath)));
164
156
  try {
165
157
  const exports = await loadSchemaExports(schemaPath);
166
- const prevSnapshot = await loadPrevSnapshot(migrationsPath);
158
+ let dbMissing = false;
159
+ try {
160
+ await fs.access(dbPath);
161
+ } catch {
162
+ dbMissing = true;
163
+ }
164
+ const prevSnapshot = dbMissing ? null : await loadPrevSnapshot(migrationsPath);
167
165
  const currentSnapshot = await generateSQLiteDrizzleJson(exports, prevSnapshot?.id);
168
166
  const sqlStatements = await generateSQLiteMigration(prevSnapshot || EMPTY_SNAPSHOT, currentSnapshot);
169
167
  if (sqlStatements.length === 0) {
@@ -182,7 +180,7 @@ async function main() {
182
180
  tag
183
181
  }));
184
182
  } finally {
185
- await releaseLock(aiexDir);
183
+ await releaseLock();
186
184
  }
187
185
  } catch (error) {
188
186
  const message = error instanceof Error ? error.message : String(error);
@@ -1,9 +1,10 @@
1
- import path from "node:path";
2
- import process from "node:process";
3
- import { z } from "zod";
4
1
  import fs from "node:fs/promises";
5
2
  import os from "node:os";
3
+ import path from "node:path";
4
+ import process from "node:process";
6
5
  import Conf from "conf";
6
+ import { readFile, writeFile } from "jsonfile";
7
+ import { z } from "zod";
7
8
 
8
9
  //#region src/core/doctor.ts
9
10
  function buildDoctorDiagnostics(input) {
@@ -61,6 +62,281 @@ function doctorDiagnosticsTableRows(d) {
61
62
  return rows;
62
63
  }
63
64
 
65
+ //#endregion
66
+ //#region package.json
67
+ var name = "aiex-cli";
68
+ var version = "0.0.1";
69
+ var description = "JSON Schema → SQLite with AI-powered data extraction";
70
+ var package_default = {
71
+ name,
72
+ type: "module",
73
+ version,
74
+ description,
75
+ author: "OSpoon <zxin088@gmail.com>",
76
+ license: "MIT",
77
+ homepage: "https://github.com/OSpoon/aiex-cli#readme",
78
+ repository: {
79
+ "type": "git",
80
+ "url": "git+https://github.com/OSpoon/aiex-cli.git"
81
+ },
82
+ bugs: "https://github.com/OSpoon/aiex-cli/issues",
83
+ keywords: [
84
+ "json-schema",
85
+ "sqlite",
86
+ "drizzle",
87
+ "orm",
88
+ "ai-extraction",
89
+ "cli",
90
+ "database-migration",
91
+ "schema-editor",
92
+ "code-generation",
93
+ "structured-output"
94
+ ],
95
+ sideEffects: false,
96
+ exports: {
97
+ ".": "./dist/index.mjs",
98
+ "./cli": "./dist/cli.mjs",
99
+ "./core/schema-sqlite/migrate-helper": "./dist/core/schema-sqlite/migrate-helper.mjs",
100
+ "./package.json": "./package.json"
101
+ },
102
+ main: "./dist/index.mjs",
103
+ module: "./dist/index.mjs",
104
+ types: "./dist/index.d.mts",
105
+ bin: { "aiex": "./bin/cli.mjs" },
106
+ files: [
107
+ "bin",
108
+ "dist",
109
+ "src/core/schema-sqlite/migrate-helper.ts",
110
+ "src/core/schema-sqlite/migration-name.ts"
111
+ ],
112
+ scripts: {
113
+ "build": "tsdown && pnpm --filter aiex-web build",
114
+ "dev": "tsdown --watch",
115
+ "start": "tsx src/index.ts",
116
+ "test": "vitest",
117
+ "coverage": "vitest --coverage",
118
+ "typecheck": "tsc",
119
+ "lint": "eslint .",
120
+ "prepack": "cp ../../README.md .",
121
+ "postpack": "rm -f README.md",
122
+ "prepublishOnly": "pnpm run build"
123
+ },
124
+ dependencies: {
125
+ "@ai-sdk/openai-compatible": "catalog:",
126
+ "@clack/prompts": "catalog:",
127
+ "@hono/node-server": "catalog:",
128
+ "@hono/zod-validator": "catalog:",
129
+ "@langfuse/otel": "catalog:",
130
+ "@opentelemetry/sdk-trace-node": "catalog:",
131
+ "ai": "catalog:",
132
+ "better-sqlite3": "catalog:",
133
+ "citty": "catalog:",
134
+ "cli-table3": "catalog:",
135
+ "conf": "catalog:",
136
+ "consola": "catalog:",
137
+ "date-fns": "catalog:",
138
+ "drizzle-kit": "catalog:cli",
139
+ "drizzle-orm": "catalog:",
140
+ "es-toolkit": "catalog:",
141
+ "esbuild": "catalog:",
142
+ "execa": "catalog:",
143
+ "hono": "catalog:",
144
+ "jsonfile": "catalog:",
145
+ "jsonrepair": "catalog:",
146
+ "kysely": "catalog:",
147
+ "mime": "catalog:",
148
+ "open": "catalog:",
149
+ "p-retry": "catalog:",
150
+ "picocolors": "catalog:",
151
+ "proper-lockfile": "catalog:",
152
+ "tinyglobby": "catalog:",
153
+ "tsx": "catalog:cli",
154
+ "unpdf": "catalog:",
155
+ "update-notifier": "catalog:",
156
+ "zod": "catalog:"
157
+ },
158
+ devDependencies: {
159
+ "@antfu/eslint-config": "catalog:cli",
160
+ "@antfu/ni": "catalog:cli",
161
+ "@types/better-sqlite3": "catalog:types",
162
+ "@types/jsonfile": "catalog:",
163
+ "@types/node": "catalog:types",
164
+ "@types/proper-lockfile": "catalog:",
165
+ "@types/update-notifier": "catalog:",
166
+ "@vitest/coverage-v8": "catalog:testing",
167
+ "eslint": "catalog:cli",
168
+ "publint": "catalog:cli",
169
+ "tsdown": "catalog:cli",
170
+ "tsnapi": "catalog:testing",
171
+ "typescript": "catalog:cli",
172
+ "vitest": "catalog:testing"
173
+ }
174
+ };
175
+
176
+ //#endregion
177
+ //#region src/config.ts
178
+ function createConfig() {
179
+ return new Conf({
180
+ cwd: process.env.CLI_CONFIG_DIR,
181
+ projectName: process.env.CLI_CONFIG_PROJECT_NAME || name
182
+ });
183
+ }
184
+ function seedConfig(config = createConfig()) {
185
+ if (!config.has("name")) config.set("name", name);
186
+ if (!config.has("version")) config.set("version", version);
187
+ }
188
+
189
+ //#endregion
190
+ //#region src/core/ai-extraction/schemas.ts
191
+ const ModelCapabilitiesSchema = z.object({
192
+ vision: z.boolean(),
193
+ structuredOutput: z.boolean(),
194
+ maxTokens: z.number().int().positive().optional(),
195
+ maxOutputTokens: z.number().int().positive().optional()
196
+ });
197
+ const AIModelConfigSchema = z.object({
198
+ name: z.string().min(1),
199
+ capabilities: ModelCapabilitiesSchema
200
+ });
201
+ const AIProviderConfigSchema = z.object({
202
+ baseURL: z.string().min(1),
203
+ apiKey: z.string(),
204
+ models: z.array(AIModelConfigSchema).min(1),
205
+ timeout: z.number().int().positive().default(300).optional()
206
+ });
207
+ const PromptConfigSchema = z.object({
208
+ systemTemplate: z.string().min(1),
209
+ userTemplate: z.string().min(1)
210
+ });
211
+ const ExtractionConfigSchema = z.object({ outputDir: z.string().min(1) });
212
+ const ExternalPdfConverterConfigSchema = z.object({
213
+ command: z.string().min(1),
214
+ args: z.array(z.string()),
215
+ outputFile: z.string().min(1).optional(),
216
+ timeout: z.number().int().positive().default(600).optional(),
217
+ fallbackToUnpdf: z.boolean().optional(),
218
+ keepOutput: z.boolean().optional()
219
+ });
220
+ const PdfConfigSchema = z.object({
221
+ converter: z.enum([
222
+ "unpdf",
223
+ "mineru",
224
+ "external"
225
+ ]),
226
+ mineru: ExternalPdfConverterConfigSchema.optional(),
227
+ external: ExternalPdfConverterConfigSchema.optional()
228
+ });
229
+ const LangfuseConfigSchema = z.object({
230
+ publicKey: z.string(),
231
+ secretKey: z.string(),
232
+ host: z.string().optional()
233
+ });
234
+ const AIConfigSchema = z.object({
235
+ provider: AIProviderConfigSchema,
236
+ prompt: PromptConfigSchema,
237
+ extraction: ExtractionConfigSchema,
238
+ pdf: PdfConfigSchema.optional(),
239
+ langfuse: LangfuseConfigSchema.optional()
240
+ });
241
+
242
+ //#endregion
243
+ //#region src/core/ai-extraction/types.ts
244
+ const PLACEHOLDER_SCHEMA = "{schema}";
245
+ const PLACEHOLDER_TEXT = "{text}";
246
+ const DEFAULT_MODELS = [{
247
+ name: "qwen-plus",
248
+ capabilities: {
249
+ vision: false,
250
+ structuredOutput: true
251
+ }
252
+ }, {
253
+ name: "qwen-vl-plus",
254
+ capabilities: {
255
+ vision: true,
256
+ structuredOutput: true
257
+ }
258
+ }];
259
+ const DEFAULT_PROVIDER_CONFIG = {
260
+ baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
261
+ apiKey: "",
262
+ models: [...DEFAULT_MODELS],
263
+ timeout: 300
264
+ };
265
+ const DEFAULT_PROMPT_CONFIG = {
266
+ systemTemplate: `You are a professional data extraction assistant. Your task is to extract structured data from text and return a JSON object based on the data structure definition provided below.
267
+
268
+ {schema}
269
+
270
+ Extraction requirements:
271
+ 1. Extract strictly according to the field names and types defined in the structure
272
+ 2. If the text lacks information for a field, set that field to null
273
+ 3. Do not add fields that do not exist in the structure definition
274
+ 4. Maintain data accuracy and completeness`,
275
+ userTemplate: `Please extract data from the following text:
276
+ {text}`
277
+ };
278
+ const DEFAULT_EXTRACTION_CONFIG = { outputDir: ".aiex/extracted" };
279
+ const DEFAULT_MINERU_CONFIG = {
280
+ command: "mineru",
281
+ args: [
282
+ "-p",
283
+ "{input}",
284
+ "-o",
285
+ "{outputDir}"
286
+ ],
287
+ timeout: 600,
288
+ fallbackToUnpdf: true,
289
+ keepOutput: true
290
+ };
291
+ const DEFAULT_PDF_CONFIG = {
292
+ converter: "unpdf",
293
+ mineru: DEFAULT_MINERU_CONFIG
294
+ };
295
+ const DEFAULT_AI_CONFIG = {
296
+ provider: DEFAULT_PROVIDER_CONFIG,
297
+ prompt: DEFAULT_PROMPT_CONFIG,
298
+ extraction: DEFAULT_EXTRACTION_CONFIG,
299
+ pdf: DEFAULT_PDF_CONFIG
300
+ };
301
+
302
+ //#endregion
303
+ //#region src/core/ai-extraction/config.ts
304
+ const CONFIG_FILE_NAME = "ai-config.json";
305
+ const GITIGNORE_FILE = ".gitignore";
306
+ async function readAIConfig(aiexDir) {
307
+ const configPath = path.join(aiexDir, CONFIG_FILE_NAME);
308
+ try {
309
+ const parsed = await readFile(configPath);
310
+ return AIConfigSchema.parse(parsed);
311
+ } catch {
312
+ return null;
313
+ }
314
+ }
315
+ async function writeAIConfig(aiexDir, config) {
316
+ const configPath = path.join(aiexDir, CONFIG_FILE_NAME);
317
+ await fs.mkdir(aiexDir, { recursive: true });
318
+ await writeFile(configPath, config, {
319
+ spaces: 2,
320
+ EOL: "\n"
321
+ });
322
+ await addToGitignore(aiexDir, CONFIG_FILE_NAME);
323
+ }
324
+ function getDefaultAIConfig() {
325
+ return structuredClone(DEFAULT_AI_CONFIG);
326
+ }
327
+ async function addToGitignore(aiexDir, fileName) {
328
+ const projectRoot = path.dirname(aiexDir);
329
+ const gitignorePath = path.join(projectRoot, GITIGNORE_FILE);
330
+ try {
331
+ const content = await fs.readFile(gitignorePath, "utf-8");
332
+ if (content.split("\n").some((line) => line.trim() === fileName || line.includes(".aiex/"))) return;
333
+ const newContent = content.endsWith("\n") ? `${content}${fileName}\n` : `${content}\n${fileName}\n`;
334
+ await fs.writeFile(gitignorePath, newContent);
335
+ } catch {
336
+ await fs.writeFile(gitignorePath, `${fileName}\n`);
337
+ }
338
+ }
339
+
64
340
  //#endregion
65
341
  //#region src/core/schema-sqlite/generator.ts
66
342
  function generateColumnDefinition(column) {
@@ -334,6 +610,7 @@ const ForeignKeyRefSchema = z.object({
334
610
  column: z.string().min(1)
335
611
  });
336
612
  const JsonSchemaPropertySchema = z.lazy(() => z.object({
613
+ description: z.string().optional(),
337
614
  type: z.enum([
338
615
  "string",
339
616
  "integer",
@@ -409,225 +686,7 @@ function generateDrizzleConfig() {
409
686
  }
410
687
 
411
688
  //#endregion
412
- //#region package.json
413
- var name = "aiex-cli";
414
- var version = "0.0.1-beta.9";
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
- "src/core/schema-sqlite/migration-name.ts"
457
- ],
458
- scripts: {
459
- "build": "tsdown && pnpm --filter aiex-web build",
460
- "dev": "tsdown --watch",
461
- "start": "tsx src/index.ts",
462
- "test": "vitest",
463
- "coverage": "vitest --coverage",
464
- "typecheck": "tsc",
465
- "lint": "eslint .",
466
- "prepublishOnly": "cp ../../README.md . && pnpm run build",
467
- "postpublish": "rm -f README.md"
468
- },
469
- dependencies: {
470
- "@ai-sdk/openai-compatible": "catalog:",
471
- "@clack/prompts": "catalog:",
472
- "@hono/node-server": "catalog:",
473
- "ai": "catalog:",
474
- "better-sqlite3": "catalog:",
475
- "citty": "catalog:",
476
- "cli-table3": "catalog:",
477
- "conf": "catalog:",
478
- "consola": "catalog:",
479
- "date-fns": "catalog:",
480
- "drizzle-kit": "catalog:cli",
481
- "drizzle-orm": "catalog:",
482
- "es-toolkit": "catalog:",
483
- "esbuild": "catalog:",
484
- "hono": "catalog:",
485
- "picocolors": "catalog:",
486
- "tsx": "catalog:cli",
487
- "update-notifier": "catalog:",
488
- "zod": "catalog:"
489
- },
490
- devDependencies: {
491
- "@antfu/eslint-config": "catalog:cli",
492
- "@antfu/ni": "catalog:cli",
493
- "@types/better-sqlite3": "catalog:types",
494
- "@types/node": "catalog:types",
495
- "@types/update-notifier": "catalog:",
496
- "@vitest/coverage-v8": "catalog:testing",
497
- "eslint": "catalog:cli",
498
- "publint": "catalog:cli",
499
- "tsdown": "catalog:cli",
500
- "tsnapi": "catalog:testing",
501
- "typescript": "catalog:cli",
502
- "vitest": "catalog:testing"
503
- }
504
- };
505
-
506
- //#endregion
507
- //#region src/config.ts
508
- function createConfig() {
509
- return new Conf({
510
- cwd: process.env.CLI_CONFIG_DIR,
511
- projectName: process.env.CLI_CONFIG_PROJECT_NAME || name
512
- });
513
- }
514
- function seedConfig(config = createConfig()) {
515
- if (!config.has("name")) config.set("name", name);
516
- if (!config.has("version")) config.set("version", version);
517
- }
518
-
519
- //#endregion
520
- //#region src/core/ai-extraction/schemas.ts
521
- const ModelCapabilitiesSchema = z.object({
522
- vision: z.boolean(),
523
- structuredOutput: z.boolean(),
524
- maxTokens: z.number().int().positive().optional(),
525
- maxOutputTokens: z.number().int().positive().optional()
526
- });
527
- const AIModelConfigSchema = z.object({
528
- name: z.string().min(1),
529
- capabilities: ModelCapabilitiesSchema
530
- });
531
- const AIProviderConfigSchema = z.object({
532
- baseURL: z.string().min(1),
533
- apiKey: z.string(),
534
- models: z.array(AIModelConfigSchema).min(1)
535
- });
536
- const PromptConfigSchema = z.object({
537
- systemTemplate: z.string().min(1),
538
- userTemplate: z.string().min(1)
539
- });
540
- const ExtractionConfigSchema = z.object({ outputDir: z.string().min(1) });
541
- const AIConfigSchema = z.object({
542
- provider: AIProviderConfigSchema,
543
- prompt: PromptConfigSchema,
544
- extraction: ExtractionConfigSchema
545
- });
546
-
547
- //#endregion
548
- //#region src/core/ai-extraction/types.ts
549
- const PLACEHOLDER_SCHEMA = "{schema}";
550
- const PLACEHOLDER_TEXT = "{text}";
551
- const DEFAULT_MODELS = [{
552
- name: "qwen-plus",
553
- capabilities: {
554
- vision: false,
555
- structuredOutput: true
556
- }
557
- }, {
558
- name: "qwen-vl-plus",
559
- capabilities: {
560
- vision: true,
561
- structuredOutput: true
562
- }
563
- }];
564
- const DEFAULT_PROVIDER_CONFIG = {
565
- baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
566
- apiKey: "",
567
- models: [...DEFAULT_MODELS]
568
- };
569
- const DEFAULT_PROMPT_CONFIG = {
570
- systemTemplate: `You are a professional data extraction assistant. Your task is to extract structured data from text and return a JSON object based on the data structure definition provided below.
571
-
572
- {schema}
573
-
574
- Extraction requirements:
575
- 1. Extract strictly according to the field names and types defined in the structure
576
- 2. If the text lacks information for a field, set that field to null
577
- 3. Do not add fields that do not exist in the structure definition
578
- 4. Maintain data accuracy and completeness`,
579
- userTemplate: `Please extract data from the following text:
580
- {text}`
581
- };
582
- const DEFAULT_EXTRACTION_CONFIG = { outputDir: ".aiex/extracted" };
583
- const DEFAULT_AI_CONFIG = {
584
- provider: DEFAULT_PROVIDER_CONFIG,
585
- prompt: DEFAULT_PROMPT_CONFIG,
586
- extraction: DEFAULT_EXTRACTION_CONFIG
587
- };
588
-
589
- //#endregion
590
- //#region src/core/ai-extraction/config.ts
591
- const CONFIG_FILE_NAME = "ai-config.json";
592
- const GITIGNORE_FILE = ".gitignore";
593
- async function readAIConfig(aiexDir) {
594
- const configPath = path.join(aiexDir, CONFIG_FILE_NAME);
595
- try {
596
- const content = await fs.readFile(configPath, "utf-8");
597
- const parsed = JSON.parse(content);
598
- return AIConfigSchema.parse(parsed);
599
- } catch {
600
- return null;
601
- }
602
- }
603
- async function writeAIConfig(aiexDir, config) {
604
- const configPath = path.join(aiexDir, CONFIG_FILE_NAME);
605
- await fs.mkdir(aiexDir, { recursive: true });
606
- await fs.writeFile(configPath, `${JSON.stringify(config, null, 2)}\n`);
607
- await addToGitignore(aiexDir, CONFIG_FILE_NAME);
608
- }
609
- function getDefaultAIConfig() {
610
- return { ...DEFAULT_AI_CONFIG };
611
- }
612
- function maskApiKey(apiKey) {
613
- if (apiKey.length <= 4) return "****";
614
- return `sk-***${apiKey.slice(-4)}`;
615
- }
616
- async function addToGitignore(aiexDir, fileName) {
617
- const projectRoot = path.dirname(aiexDir);
618
- const gitignorePath = path.join(projectRoot, GITIGNORE_FILE);
619
- try {
620
- const content = await fs.readFile(gitignorePath, "utf-8");
621
- if (content.split("\n").some((line) => line.trim() === fileName || line.includes(".aiex/"))) return;
622
- const newContent = content.endsWith("\n") ? `${content}${fileName}\n` : `${content}\n${fileName}\n`;
623
- await fs.writeFile(gitignorePath, newContent);
624
- } catch {
625
- await fs.writeFile(gitignorePath, `${fileName}\n`);
626
- }
627
- }
628
-
629
- //#endregion
630
- //#region src/doctor.ts
689
+ //#region src/core/doctor-collector.ts
631
690
  const V1_SUFFIX_RE = /\/v1\/?$/;
632
691
  async function checkConnection(baseURL) {
633
692
  try {
@@ -713,4 +772,4 @@ async function collectDoctorDiagnostics(options = {}) {
713
772
  }
714
773
 
715
774
  //#endregion
716
- export { doctorDiagnosticsTableRows as C, buildDoctorDiagnostics as S, generateDrizzleConfig as _, writeAIConfig as a, toSnakeCase 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, formatDoctorDiagnosticsJson as w, generateDrizzleSchema as x, parseJsonSchema as y };
775
+ export { doctorDiagnosticsTableRows as C, buildDoctorDiagnostics as S, seedConfig as _, parseJsonSchema as a, package_default as b, getDefaultAIConfig as c, DEFAULT_MINERU_CONFIG as d, DEFAULT_PROMPT_CONFIG as f, createConfig as g, AIConfigSchema as h, JsonSchemaDefinitionSchema as i, readAIConfig as l, PLACEHOLDER_TEXT as m, createMigrationConfig as n, toSnakeCase as o, PLACEHOLDER_SCHEMA as p, generateDrizzleConfig as r, generateDrizzleSchema as s, collectDoctorDiagnostics as t, writeAIConfig as u, description as v, formatDoctorDiagnosticsJson as w, version as x, name as y };