aiex-cli 0.0.2-beta.1 → 0.0.2-beta.3

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 (106) hide show
  1. package/dist/cli.mjs +287 -175
  2. package/dist/{doctor-collector-Cbqgwx__.mjs → doctor-collector-CGUF999y.mjs} +1 -1
  3. package/dist/index.mjs +1 -1
  4. package/dist/web/assets/AISettings-BgwAdAIK.js +346 -0
  5. package/dist/web/assets/ExtractRunner-BxI-y6zS.js +1 -0
  6. package/dist/web/assets/{ExtractionViewer-D7tghmR-.js → ExtractionViewer-Dxgbk3y5.js} +1 -1
  7. package/dist/web/assets/{JsonSchemaEditor-DXhYW-Un.js → JsonSchemaEditor-ul3bZNBq.js} +3 -3
  8. package/dist/web/assets/{api-client-CIC2X8_4.js → api-client-BwMoRXRu.js} +1 -1
  9. package/dist/web/assets/{cssMode-CCz1uj8b.js → cssMode-BJcNHjlk.js} +1 -1
  10. package/dist/web/assets/{editor.main-DOue-nGf.js → editor.main-DQNDtAJT.js} +2 -2
  11. package/dist/web/assets/{freemarker2-C87H7V8i.js → freemarker2-S3U7WteK.js} +1 -1
  12. package/dist/web/assets/{handlebars-TLnoktZW.js → handlebars-BrE9AAwL.js} +1 -1
  13. package/dist/web/assets/{html-Rewbtgcp.js → html-C6Vb0qjf.js} +1 -1
  14. package/dist/web/assets/{htmlMode-Cr9y3YUi.js → htmlMode-D6ZrqWr1.js} +1 -1
  15. package/dist/web/assets/{index-CWy8KajQ.js → index-e8dWRIEv.js} +7 -7
  16. package/dist/web/assets/{javascript-BO8DPECx.js → javascript-DB-UTK4i.js} +1 -1
  17. package/dist/web/assets/{jsonMode-B78m_Y1l.js → jsonMode-w2VFiNNs.js} +1 -1
  18. package/dist/web/assets/{liquid-CDp_8YUE.js → liquid-1XTLVrg3.js} +1 -1
  19. package/dist/web/assets/{mdx-CeR1GULE.js → mdx-C4k_4MX5.js} +1 -1
  20. package/dist/web/assets/{monaco.contribution-tCitzj1_.js → monaco.contribution-DrrjJ0Xr.js} +2 -2
  21. package/dist/web/assets/{python-DWmB1hQ6.js → python-DU-NBP37.js} +1 -1
  22. package/dist/web/assets/{razor-BVk762Lq.js → razor-CDS0MJZV.js} +1 -1
  23. package/dist/web/assets/select-Dj2p-fw_.js +439 -0
  24. package/dist/web/assets/{tsMode-Gjs5D1gt.js → tsMode-ClDl0-oy.js} +1 -1
  25. package/dist/web/assets/{typescript-Cw6YtwrM.js → typescript-DVPndl3f.js} +1 -1
  26. package/dist/web/assets/{xml-guZq0YZJ.js → xml-ZTAdiNZS.js} +1 -1
  27. package/dist/web/assets/{yaml-B9TbU-LX.js → yaml-4WO-VI9I.js} +1 -1
  28. package/dist/web/index.html +2 -2
  29. package/package.json +1 -1
  30. package/dist/web/assets/AISettings-Cm8fAfaG.js +0 -205
  31. package/dist/web/assets/ExtractRunner-CzfLlCCf.js +0 -1
  32. package/dist/web/assets/baseinput-B7PU5-38.js +0 -2
  33. package/dist/web/assets/checkbox-CCQwMfLd.js +0 -142
  34. package/dist/web/assets/select-DKPPF403.js +0 -438
  35. /package/dist/web/assets/{DataBrowser-DQwOvooY.js → DataBrowser-CLOlYw5B.js} +0 -0
  36. /package/dist/web/assets/{abap-C3UM4cME.js → abap-CFuyUYKP.js} +0 -0
  37. /package/dist/web/assets/{apex-BQBZvQmN.js → apex-Ctq_xcrv.js} +0 -0
  38. /package/dist/web/assets/{azcli-Dn9Awrok.js → azcli-BBQSVn-C.js} +0 -0
  39. /package/dist/web/assets/{bat-JgEezSDo.js → bat-DbnqAfvr.js} +0 -0
  40. /package/dist/web/assets/{bicep-vcQeC7wE.js → bicep-BtDlIXop.js} +0 -0
  41. /package/dist/web/assets/{cameligo-C0cr0T3L.js → cameligo-BLeJgKTj.js} +0 -0
  42. /package/dist/web/assets/{clojure-Brc1-rbW.js → clojure-aZUQIUKP.js} +0 -0
  43. /package/dist/web/assets/{coffee-BiZYU83a.js → coffee-Secadq9U.js} +0 -0
  44. /package/dist/web/assets/{cpp-ikWHCInz.js → cpp-JicRPTRv.js} +0 -0
  45. /package/dist/web/assets/{csharp-BRWs_LfH.js → csharp-C7NSOZyj.js} +0 -0
  46. /package/dist/web/assets/{csp-CcAumoJw.js → csp-CIje7830.js} +0 -0
  47. /package/dist/web/assets/{css-BZm6paiA.js → css-G0bm1q_M.js} +0 -0
  48. /package/dist/web/assets/{cypher-CDQMONdb.js → cypher-CldD5D0u.js} +0 -0
  49. /package/dist/web/assets/{dart-Ci4SZdF1.js → dart-DIK3l8YT.js} +0 -0
  50. /package/dist/web/assets/{dockerfile-BV0tAr-M.js → dockerfile-czxaGh2L.js} +0 -0
  51. /package/dist/web/assets/{ecl-CP7nM2KN.js → ecl-BqdYhwmw.js} +0 -0
  52. /package/dist/web/assets/{editor.api-BU_q4v8i.js → editor.api-DrogPInQ.js} +0 -0
  53. /package/dist/web/assets/{elixir-GcA6wFiI.js → elixir-m52LePTW.js} +0 -0
  54. /package/dist/web/assets/{flow9-CIb9youF.js → flow9-B5QJ9GvZ.js} +0 -0
  55. /package/dist/web/assets/{fsharp-BVaBE4co.js → fsharp-Bsj2_cCa.js} +0 -0
  56. /package/dist/web/assets/{go-Bbqf306x.js → go-BqOR3oKA.js} +0 -0
  57. /package/dist/web/assets/{graphql-DJPrC4l-.js → graphql-B8qEHPdi.js} +0 -0
  58. /package/dist/web/assets/{hcl-QyfWVWpM.js → hcl-DWuCE4v-.js} +0 -0
  59. /package/dist/web/assets/{ini-CgstZeS8.js → ini-Qq7k0Z4_.js} +0 -0
  60. /package/dist/web/assets/{java-D4AG88ZY.js → java-BYPjirKp.js} +0 -0
  61. /package/dist/web/assets/{julia-CN8U9648.js → julia-BDPeJze-.js} +0 -0
  62. /package/dist/web/assets/{kotlin-gNNgpJhY.js → kotlin-Cn6ib1e9.js} +0 -0
  63. /package/dist/web/assets/{less-C3SY2L8t.js → less-CJaXZ051.js} +0 -0
  64. /package/dist/web/assets/{lexon-CznnqzUX.js → lexon-8Vqfm7H_.js} +0 -0
  65. /package/dist/web/assets/{lua-f3xyJgy5.js → lua-CvR2zKQJ.js} +0 -0
  66. /package/dist/web/assets/{m3-Cl7J89p-.js → m3-B_srJ0-W.js} +0 -0
  67. /package/dist/web/assets/{markdown-Bv2fnzzT.js → markdown-BLHPl-_K.js} +0 -0
  68. /package/dist/web/assets/{mips-D6rXUTWa.js → mips-DVyJ6qEt.js} +0 -0
  69. /package/dist/web/assets/{msdax-Bb1N2x5J.js → msdax-CSgWECQy.js} +0 -0
  70. /package/dist/web/assets/{mysql-DXSr6oD7.js → mysql-DgAobqZA.js} +0 -0
  71. /package/dist/web/assets/{objective-c-CEJiVkDa.js → objective-c-YsnCzZhx.js} +0 -0
  72. /package/dist/web/assets/{pascal-BtkMEIba.js → pascal-DBRbVM1J.js} +0 -0
  73. /package/dist/web/assets/{pascaligo-C7FAwqk7.js → pascaligo-DGMAqea9.js} +0 -0
  74. /package/dist/web/assets/{perl-D9kqkBbN.js → perl-BbO9hyuY.js} +0 -0
  75. /package/dist/web/assets/{pgsql-BjGTBL1W.js → pgsql-C-hxeXjm.js} +0 -0
  76. /package/dist/web/assets/{php-BN0c0noA.js → php-CNUtuIOY.js} +0 -0
  77. /package/dist/web/assets/{pla-B94QTqOt.js → pla-kg11R4PY.js} +0 -0
  78. /package/dist/web/assets/{postiats-DH91dqBs.js → postiats-B1z9yYod.js} +0 -0
  79. /package/dist/web/assets/{powerquery-D7P0oUen.js → powerquery-B7uH8tJZ.js} +0 -0
  80. /package/dist/web/assets/{powershell-CCVHmJax.js → powershell-C4XFI11Z.js} +0 -0
  81. /package/dist/web/assets/{protobuf-BIP7pixC.js → protobuf-BcOV_0Q2.js} +0 -0
  82. /package/dist/web/assets/{pug-DcbLK7HH.js → pug-68xbfbza.js} +0 -0
  83. /package/dist/web/assets/{qsharp-B-VY_WOG.js → qsharp-BrGH6SSV.js} +0 -0
  84. /package/dist/web/assets/{r-DwRtsJsj.js → r--OWX2YhF.js} +0 -0
  85. /package/dist/web/assets/{redis-CaW0tkwu.js → redis-BOXumJdj.js} +0 -0
  86. /package/dist/web/assets/{redshift-3tS8G0ME.js → redshift-8U3qVUZv.js} +0 -0
  87. /package/dist/web/assets/{restructuredtext-_TNyGyK0.js → restructuredtext-D6puF6Gd.js} +0 -0
  88. /package/dist/web/assets/{ruby-A-MwVfO4.js → ruby-g_KUrR8T.js} +0 -0
  89. /package/dist/web/assets/{rust-oemlUIvG.js → rust-Dm8AnzU3.js} +0 -0
  90. /package/dist/web/assets/{sb-BDZuaI3W.js → sb-D_ts6T0n.js} +0 -0
  91. /package/dist/web/assets/{scala-Bfo2loK4.js → scala-C6NOuwmJ.js} +0 -0
  92. /package/dist/web/assets/{scheme-N2eo7rjB.js → scheme-CPooyhAN.js} +0 -0
  93. /package/dist/web/assets/{scss-vjjSCTgN.js → scss-DUEUJROR.js} +0 -0
  94. /package/dist/web/assets/{shell-Bfb9Yq6w.js → shell-kdqtsGKx.js} +0 -0
  95. /package/dist/web/assets/{solidity-C9RbukzG.js → solidity-CnMA-U-d.js} +0 -0
  96. /package/dist/web/assets/{sophia-DWV_MWOg.js → sophia-BKvc9daj.js} +0 -0
  97. /package/dist/web/assets/{sparql-iMXILWhh.js → sparql-Bh3XvRxY.js} +0 -0
  98. /package/dist/web/assets/{sql-CJDj31JM.js → sql-CRPVrMOO.js} +0 -0
  99. /package/dist/web/assets/{st-BG9AQ1OO.js → st-DBvoSKfh.js} +0 -0
  100. /package/dist/web/assets/{swift-B579DvHm.js → swift-B8QEexRZ.js} +0 -0
  101. /package/dist/web/assets/{systemverilog-BNgaF3ZX.js → systemverilog-CBeOTblq.js} +0 -0
  102. /package/dist/web/assets/{tcl-grdtJiUA.js → tcl-DR5kknHN.js} +0 -0
  103. /package/dist/web/assets/{twig-JAsFXBZw.js → twig-5OXXSkT1.js} +0 -0
  104. /package/dist/web/assets/{typespec-D3hIQXEU.js → typespec-cVMWW5z1.js} +0 -0
  105. /package/dist/web/assets/{vb-H38jRcEz.js → vb-DRjqfs-G.js} +0 -0
  106. /package/dist/web/assets/{wgsl-BC5Grc5r.js → wgsl-B5lRvHwm.js} +0 -0
package/dist/cli.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { S as version, T as formatDoctorDiagnosticsJson, _ as createConfig, a as parseJsonSchema, b as name, c as getDefaultAIConfig, d as DEFAULT_MARKITDOWN_CONFIG, f as DEFAULT_MINERU_CONFIG, g as AIConfigSchema, h as PLACEHOLDER_TEXT, i as JsonSchemaDefinitionSchema, l as readAIConfig, m as PLACEHOLDER_SCHEMA, n as createMigrationConfig, o as toSnakeCase, p as DEFAULT_PROMPT_CONFIG, s as generateDrizzleSchema, t as collectDoctorDiagnostics, u as writeAIConfig, v as seedConfig, w as doctorDiagnosticsTableRows, x as package_default, y as description } from "./doctor-collector-Cbqgwx__.mjs";
1
+ import { S as version, T as formatDoctorDiagnosticsJson, _ as createConfig, a as parseJsonSchema, b as name, c as getDefaultAIConfig, d as DEFAULT_MARKITDOWN_CONFIG, f as DEFAULT_MINERU_CONFIG, g as AIConfigSchema, h as PLACEHOLDER_TEXT, i as JsonSchemaDefinitionSchema, l as readAIConfig, m as PLACEHOLDER_SCHEMA, n as createMigrationConfig, o as toSnakeCase, p as DEFAULT_PROMPT_CONFIG, s as generateDrizzleSchema, t as collectDoctorDiagnostics, u as writeAIConfig, v as seedConfig, w as doctorDiagnosticsTableRows, x as package_default, y as description } from "./doctor-collector-CGUF999y.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import fs from "node:fs/promises";
4
4
  import os from "node:os";
@@ -23,6 +23,7 @@ import { jsonrepair } from "jsonrepair";
23
23
  import fs$1 from "node:fs";
24
24
  import Database from "better-sqlite3";
25
25
  import { glob, globSync } from "tinyglobby";
26
+ import { Client, extractNotionId } from "@notionhq/client";
26
27
  import { execa } from "execa";
27
28
  import { extractText, getDocumentProxy, getMeta } from "unpdf";
28
29
  import { Buffer } from "node:buffer";
@@ -33,7 +34,6 @@ import open from "open";
33
34
  import { serveStatic } from "@hono/node-server/serve-static";
34
35
  import { Hono } from "hono";
35
36
  import { cors } from "hono/cors";
36
- import { Client } from "@notionhq/client";
37
37
  import { zValidator } from "@hono/zod-validator";
38
38
  import { Kysely, SqliteDialect, sql } from "kysely";
39
39
 
@@ -13487,6 +13487,213 @@ async function deleteExtractionAuditRecord(aiexDir, id) {
13487
13487
  return true;
13488
13488
  }
13489
13489
 
13490
+ //#endregion
13491
+ //#region src/core/notion-sink.ts
13492
+ const RICH_TEXT_LIMIT = 2e3;
13493
+ const UUID_RE = /^[0-9a-f]{32}$/i;
13494
+ const HYPHENATED_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
13495
+ function truncateText(value) {
13496
+ return value.length > RICH_TEXT_LIMIT ? value.slice(0, RICH_TEXT_LIMIT) : value;
13497
+ }
13498
+ function stringifyValue(value) {
13499
+ if (value === null || value === void 0) return "";
13500
+ if (typeof value === "string") return value;
13501
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
13502
+ return JSON.stringify(value);
13503
+ }
13504
+ function asNumber(value) {
13505
+ if (typeof value === "number" && Number.isFinite(value)) return value;
13506
+ if (typeof value === "string" && value.trim()) {
13507
+ const parsed = Number(value);
13508
+ return Number.isFinite(parsed) ? parsed : null;
13509
+ }
13510
+ return null;
13511
+ }
13512
+ function asBoolean(value) {
13513
+ if (typeof value === "boolean") return value;
13514
+ if (typeof value === "number") return value !== 0;
13515
+ if (typeof value === "string") {
13516
+ const normalized = value.trim().toLowerCase();
13517
+ return [
13518
+ "true",
13519
+ "yes",
13520
+ "1",
13521
+ "y"
13522
+ ].includes(normalized);
13523
+ }
13524
+ return !!value;
13525
+ }
13526
+ function asDateStart(value) {
13527
+ if (value instanceof Date && !Number.isNaN(value.getTime())) return value.toISOString();
13528
+ if (typeof value === "number" && Number.isFinite(value)) {
13529
+ const date = new Date(value);
13530
+ return Number.isNaN(date.getTime()) ? null : date.toISOString();
13531
+ }
13532
+ if (typeof value === "string" && value.trim()) {
13533
+ const ms = Date.parse(value);
13534
+ if (Number.isNaN(ms)) return null;
13535
+ return new Date(ms).toISOString();
13536
+ }
13537
+ return null;
13538
+ }
13539
+ function asStringArray(value) {
13540
+ if (Array.isArray(value)) return value.map((item) => stringifyValue(item).trim()).filter(Boolean);
13541
+ const text$1 = stringifyValue(value).trim();
13542
+ return text$1 ? [text$1] : [];
13543
+ }
13544
+ function buildPropertyValue(type, value) {
13545
+ const text$1 = truncateText(stringifyValue(value));
13546
+ switch (type) {
13547
+ case "title": return { title: text$1 ? [{ text: { content: text$1 } }] : [] };
13548
+ case "rich_text": return { rich_text: text$1 ? [{ text: { content: text$1 } }] : [] };
13549
+ case "number": return { number: asNumber(value) };
13550
+ case "checkbox": return { checkbox: asBoolean(value) };
13551
+ case "date": {
13552
+ const start = asDateStart(value);
13553
+ return { date: start ? { start } : null };
13554
+ }
13555
+ case "select": {
13556
+ const name$1 = stringifyValue(value).trim();
13557
+ return { select: name$1 ? { name: name$1 } : null };
13558
+ }
13559
+ case "multi_select": return { multi_select: asStringArray(value).map((name$1) => ({ name: name$1 })) };
13560
+ case "url": return { url: text$1 || null };
13561
+ case "email": return { email: text$1 || null };
13562
+ case "phone_number": return { phone_number: text$1 || null };
13563
+ default: return null;
13564
+ }
13565
+ }
13566
+ function findTitleProperty(properties, preferred) {
13567
+ if (preferred && properties[preferred]?.type === "title") return preferred;
13568
+ return Object.entries(properties).find(([, property]) => property?.type === "title")?.[0] ?? null;
13569
+ }
13570
+ function hyphenateDatabaseId(value) {
13571
+ const id = value.replace(/-/g, "");
13572
+ if (!UUID_RE.test(id)) return value;
13573
+ return `${id.slice(0, 8)}-${id.slice(8, 12)}-${id.slice(12, 16)}-${id.slice(16, 20)}-${id.slice(20)}`;
13574
+ }
13575
+ function parseNotionDatabaseId(value) {
13576
+ const input = value.trim();
13577
+ if (!input) return "";
13578
+ const extracted = extractNotionId(input);
13579
+ if (extracted) return extracted;
13580
+ if (HYPHENATED_UUID_RE.test(input)) return input;
13581
+ if (UUID_RE.test(input)) return hyphenateDatabaseId(input);
13582
+ return input;
13583
+ }
13584
+ function normalizeFieldName(value) {
13585
+ return value.normalize("NFKC").toLowerCase().replace(/[^\p{Letter}\p{Number}]+/gu, "");
13586
+ }
13587
+ function buildMatchKeys(field) {
13588
+ return [
13589
+ field.name,
13590
+ field.title,
13591
+ field.description
13592
+ ].filter((value) => !!value?.trim()).map(normalizeFieldName).filter(Boolean);
13593
+ }
13594
+ function suggestFieldMap(schemaFields, databaseProperties) {
13595
+ const propertyByKey = /* @__PURE__ */ new Map();
13596
+ for (const propertyName of Object.keys(databaseProperties)) propertyByKey.set(normalizeFieldName(propertyName), propertyName);
13597
+ const fieldMap = {};
13598
+ for (const field of schemaFields) for (const key of buildMatchKeys(field)) {
13599
+ const propertyName = propertyByKey.get(key);
13600
+ if (propertyName) {
13601
+ fieldMap[field.name] = propertyName;
13602
+ break;
13603
+ }
13604
+ }
13605
+ return fieldMap;
13606
+ }
13607
+ function hasProperties(value) {
13608
+ return !!value && typeof value === "object" && !!value.properties && typeof value.properties === "object";
13609
+ }
13610
+ function firstDataSourceId(database) {
13611
+ return (Array.isArray(database?.data_sources) ? database.data_sources : []).find((source) => typeof source?.id === "string" && source.id.trim())?.id;
13612
+ }
13613
+ async function resolveNotionDataSource(notion, inputId) {
13614
+ const id = parseNotionDatabaseId(inputId);
13615
+ if (!id) throw new Error("Notion database or data source URL/ID is required.");
13616
+ try {
13617
+ const dataSource$1 = await notion.dataSources.retrieve({ data_source_id: id });
13618
+ if (hasProperties(dataSource$1)) return {
13619
+ databaseId: typeof dataSource$1.parent?.database_id === "string" ? dataSource$1.parent.database_id : id,
13620
+ dataSourceId: dataSource$1.id ?? id,
13621
+ properties: dataSource$1.properties,
13622
+ parent: { data_source_id: dataSource$1.id ?? id }
13623
+ };
13624
+ } catch {}
13625
+ const database = await notion.databases.retrieve({ database_id: id });
13626
+ if (hasProperties(database)) return {
13627
+ databaseId: database.id ?? id,
13628
+ properties: database.properties,
13629
+ parent: { database_id: database.id ?? id }
13630
+ };
13631
+ const dataSourceId = firstDataSourceId(database);
13632
+ if (!dataSourceId) throw new Error("No data source found for this Notion database. Copy the data source link from Notion, or share the source database with the integration.");
13633
+ const dataSource = await notion.dataSources.retrieve({ data_source_id: dataSourceId });
13634
+ if (!hasProperties(dataSource)) throw new Error("Notion data source did not return properties. Make sure it is shared with the integration and is not a linked data source.");
13635
+ return {
13636
+ databaseId: database.id ?? id,
13637
+ dataSourceId: dataSource.id ?? dataSourceId,
13638
+ properties: dataSource.properties,
13639
+ parent: { data_source_id: dataSource.id ?? dataSourceId }
13640
+ };
13641
+ }
13642
+ async function inspectNotionDatabase(input) {
13643
+ if (!input.token.trim()) throw new Error("Notion integration token is required.");
13644
+ const id = parseNotionDatabaseId(input.databaseId);
13645
+ if (!id) throw new Error("Notion database or data source URL/ID is required.");
13646
+ const resolved = await resolveNotionDataSource(new Client({ auth: input.token }), id);
13647
+ const databaseProperties = resolved.properties;
13648
+ const titleProperty = findTitleProperty(databaseProperties) ?? void 0;
13649
+ return {
13650
+ databaseId: resolved.databaseId,
13651
+ dataSourceId: resolved.dataSourceId,
13652
+ titleProperty,
13653
+ properties: Object.entries(databaseProperties).map(([name$1, property]) => ({
13654
+ name: name$1,
13655
+ type: property?.type ?? "unknown"
13656
+ })).sort((a, b) => a.name.localeCompare(b.name)),
13657
+ suggestedFieldMap: suggestFieldMap(input.schemaFields, databaseProperties)
13658
+ };
13659
+ }
13660
+ function validateNotionConfig(config) {
13661
+ if (!config?.enabled) return "Notion export is not enabled. Configure Notion settings first.";
13662
+ if (!config.token.trim()) return "Notion integration token is required.";
13663
+ return null;
13664
+ }
13665
+ async function writeNotionPage(config, schemaName, data) {
13666
+ const configError = validateNotionConfig(config);
13667
+ if (configError) throw new Error(configError);
13668
+ const notionConfig = config;
13669
+ const schemaConfig = notionConfig.schemas[schemaName];
13670
+ if (!schemaConfig) throw new Error(`Notion database is not configured for schema "${schemaName}".`);
13671
+ if (!schemaConfig.databaseId.trim()) throw new Error(`Notion database ID is required for schema "${schemaName}".`);
13672
+ const notion = new Client({ auth: notionConfig.token });
13673
+ const resolved = await resolveNotionDataSource(notion, schemaConfig.databaseId);
13674
+ const databaseProperties = resolved.properties;
13675
+ const fieldMap = schemaConfig.fieldMap ?? {};
13676
+ const properties = {};
13677
+ for (const [sourceField, sourceValue] of Object.entries(data)) {
13678
+ const notionPropertyName = fieldMap[sourceField] ?? sourceField;
13679
+ const notionProperty = databaseProperties[notionPropertyName];
13680
+ if (!notionProperty) continue;
13681
+ const propertyValue = buildPropertyValue(notionProperty.type, sourceValue);
13682
+ if (propertyValue) properties[notionPropertyName] = propertyValue;
13683
+ }
13684
+ const titleProperty = findTitleProperty(databaseProperties, schemaConfig.titleProperty);
13685
+ if (titleProperty && !properties[titleProperty]) properties[titleProperty] = buildPropertyValue("title", Object.entries(data).find(([, value]) => typeof value === "string" && value.trim())?.[1] ?? schemaName);
13686
+ if (Object.keys(properties).length === 0) throw new Error("No extracted fields matched Notion database properties.");
13687
+ return {
13688
+ pageId: (await notion.pages.create({
13689
+ parent: resolved.parent,
13690
+ properties
13691
+ })).id,
13692
+ databaseId: resolved.databaseId,
13693
+ dataSourceId: resolved.dataSourceId
13694
+ };
13695
+ }
13696
+
13490
13697
  //#endregion
13491
13698
  //#region src/core/pdf-converter/external.ts
13492
13699
  function applyTemplate(value, context) {
@@ -13681,6 +13888,17 @@ const SUPPORTED_EXTENSIONS = new Set([
13681
13888
  const PDF_EXT_RE = /\.pdf$/i;
13682
13889
  const JSON_EXT_RE$1 = /\.json$/;
13683
13890
  const SUPPORTED_FILE_PATTERN = `*.{${[...SUPPORTED_EXTENSIONS].join(",")}}`;
13891
+ async function syncResultToNotion(aiConfig, schemaName, data) {
13892
+ if (!data || typeof data !== "object" || Array.isArray(data)) throw new Error("Extraction result is not an object and cannot be written to Notion.");
13893
+ const page = await writeNotionPage(aiConfig.notion, schemaName, data);
13894
+ return [{
13895
+ databaseId: page.databaseId,
13896
+ pageId: page.pageId
13897
+ }];
13898
+ }
13899
+ function shouldSyncNotion(aiConfig, schemaName) {
13900
+ return !!aiConfig.notion?.enabled && !!aiConfig.notion.schemas?.[schemaName]?.databaseId?.trim();
13901
+ }
13684
13902
  async function ensureDatabaseReady(dbPath, schema) {
13685
13903
  try {
13686
13904
  await fs.access(dbPath);
@@ -13872,11 +14090,28 @@ async function processOneFile(aiexDir, config, aiConfig, schemaName, filePath, m
13872
14090
  insert: options?.insert
13873
14091
  });
13874
14092
  if (r.success) {
14093
+ let notionPages;
14094
+ if (shouldSyncNotion(aiConfig, schemaName)) try {
14095
+ notionPages = await syncResultToNotion(aiConfig, schemaName, r.data);
14096
+ consola.success(`Synced to Notion: ${notionPages.length} page(s)`);
14097
+ } catch (error) {
14098
+ await updateExtractionAuditRecord(aiexDir, audit.id, {
14099
+ status: "failed",
14100
+ outputPath: r.outputPath,
14101
+ outputName: r.outputPath ? path.basename(r.outputPath) : void 0,
14102
+ tablesInserted: r.tablesInserted,
14103
+ tokensUsed: r.tokensUsed,
14104
+ error: error instanceof Error ? error.message : String(error)
14105
+ });
14106
+ consola.error(`Notion sync failed: ${error instanceof Error ? error.message : String(error)}`);
14107
+ return false;
14108
+ }
13875
14109
  await updateExtractionAuditRecord(aiexDir, audit.id, {
13876
14110
  status: "succeeded",
13877
14111
  outputPath: r.outputPath,
13878
14112
  outputName: r.outputPath ? path.basename(r.outputPath) : void 0,
13879
14113
  tablesInserted: r.tablesInserted,
14114
+ notionPages,
13880
14115
  tokensUsed: r.tokensUsed
13881
14116
  });
13882
14117
  consola.success(`Processed: ${path.basename(filePath)}`);
@@ -13984,11 +14219,33 @@ async function runAuditedSingleExtraction(input) {
13984
14219
  });
13985
14220
  return false;
13986
14221
  }
14222
+ let notionPages;
14223
+ if (input.aiConfig.notion?.enabled && input.aiConfig.notion.schemas?.[input.schemaName]?.databaseId?.trim()) try {
14224
+ if (!result.data || typeof result.data !== "object" || Array.isArray(result.data)) throw new Error("Extraction result is not an object and cannot be written to Notion.");
14225
+ const page = await writeNotionPage(input.aiConfig.notion, input.schemaName, result.data);
14226
+ notionPages = [{
14227
+ databaseId: page.databaseId,
14228
+ pageId: page.pageId
14229
+ }];
14230
+ consola.success(`Synced to Notion: ${notionPages.length} page(s)`);
14231
+ } catch (error) {
14232
+ await updateExtractionAuditRecord(input.aiexDir, audit.id, {
14233
+ status: "failed",
14234
+ outputPath: result.outputPath,
14235
+ outputName: result.outputPath ? path.basename(result.outputPath) : void 0,
14236
+ tablesInserted: result.tablesInserted,
14237
+ tokensUsed: result.tokensUsed,
14238
+ error: error instanceof Error ? error.message : String(error)
14239
+ });
14240
+ consola.error(`Notion sync failed: ${error instanceof Error ? error.message : String(error)}`);
14241
+ return false;
14242
+ }
13987
14243
  await updateExtractionAuditRecord(input.aiexDir, audit.id, {
13988
14244
  status: "succeeded",
13989
14245
  outputPath: result.outputPath,
13990
14246
  outputName: result.outputPath ? path.basename(result.outputPath) : void 0,
13991
14247
  tablesInserted: result.tablesInserted,
14248
+ notionPages,
13992
14249
  tokensUsed: result.tokensUsed
13993
14250
  });
13994
14251
  return true;
@@ -14300,7 +14557,18 @@ async function runInteractive(aiexDir, config, aiConfig, modelOverride) {
14300
14557
  cancel("Cancelled");
14301
14558
  return false;
14302
14559
  }
14303
- return (await extractSingle(aiexDir, config, aiConfig, schemaName, textContent, void 0, modelOverride)).success;
14560
+ return runAuditedSingleExtraction({
14561
+ aiexDir,
14562
+ config,
14563
+ aiConfig,
14564
+ schemaName,
14565
+ text: textContent,
14566
+ source: {
14567
+ type: "text",
14568
+ text: textContent
14569
+ },
14570
+ modelOverride
14571
+ });
14304
14572
  } else if (inputSource === "file") {
14305
14573
  const filePathStr = await text({
14306
14574
  message: "Enter file path:",
@@ -14315,7 +14583,20 @@ async function runInteractive(aiexDir, config, aiConfig, modelOverride) {
14315
14583
  const fp = filePathStr;
14316
14584
  try {
14317
14585
  const input = await readExtractFileInput(fp, aiConfig);
14318
- return (await extractSingle(aiexDir, config, aiConfig, schemaName, input.text, input.filePath, modelOverride)).success;
14586
+ return runAuditedSingleExtraction({
14587
+ aiexDir,
14588
+ config,
14589
+ aiConfig,
14590
+ schemaName,
14591
+ text: input.text,
14592
+ filePath: input.filePath,
14593
+ source: {
14594
+ type: "file",
14595
+ filePath: fp,
14596
+ fileName: path.basename(fp)
14597
+ },
14598
+ modelOverride
14599
+ });
14319
14600
  } catch (e) {
14320
14601
  consola.error(`Cannot read file: ${fp} — ${e instanceof Error ? e.message : String(e)}`);
14321
14602
  return false;
@@ -14521,173 +14802,6 @@ const schemaCommand = defineCommand({
14521
14802
  }
14522
14803
  });
14523
14804
 
14524
- //#endregion
14525
- //#region src/core/notion-sink.ts
14526
- const RICH_TEXT_LIMIT = 2e3;
14527
- const UUID_RE = /^[0-9a-f]{32}$/i;
14528
- const HYPHENATED_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
14529
- const UUID_IN_TEXT_RE = /[0-9a-f]{32}/i;
14530
- function truncateText(value) {
14531
- return value.length > RICH_TEXT_LIMIT ? value.slice(0, RICH_TEXT_LIMIT) : value;
14532
- }
14533
- function stringifyValue(value) {
14534
- if (value === null || value === void 0) return "";
14535
- if (typeof value === "string") return value;
14536
- if (typeof value === "number" || typeof value === "boolean") return String(value);
14537
- return JSON.stringify(value);
14538
- }
14539
- function asNumber(value) {
14540
- if (typeof value === "number" && Number.isFinite(value)) return value;
14541
- if (typeof value === "string" && value.trim()) {
14542
- const parsed = Number(value);
14543
- return Number.isFinite(parsed) ? parsed : null;
14544
- }
14545
- return null;
14546
- }
14547
- function asBoolean(value) {
14548
- if (typeof value === "boolean") return value;
14549
- if (typeof value === "number") return value !== 0;
14550
- if (typeof value === "string") {
14551
- const normalized = value.trim().toLowerCase();
14552
- return [
14553
- "true",
14554
- "yes",
14555
- "1",
14556
- "y"
14557
- ].includes(normalized);
14558
- }
14559
- return !!value;
14560
- }
14561
- function asDateStart(value) {
14562
- if (value instanceof Date && !Number.isNaN(value.getTime())) return value.toISOString();
14563
- if (typeof value === "number" && Number.isFinite(value)) {
14564
- const date = new Date(value);
14565
- return Number.isNaN(date.getTime()) ? null : date.toISOString();
14566
- }
14567
- if (typeof value === "string" && value.trim()) {
14568
- const ms = Date.parse(value);
14569
- if (Number.isNaN(ms)) return null;
14570
- return new Date(ms).toISOString();
14571
- }
14572
- return null;
14573
- }
14574
- function asStringArray(value) {
14575
- if (Array.isArray(value)) return value.map((item) => stringifyValue(item).trim()).filter(Boolean);
14576
- const text$1 = stringifyValue(value).trim();
14577
- return text$1 ? [text$1] : [];
14578
- }
14579
- function buildPropertyValue(type, value) {
14580
- const text$1 = truncateText(stringifyValue(value));
14581
- switch (type) {
14582
- case "title": return { title: text$1 ? [{ text: { content: text$1 } }] : [] };
14583
- case "rich_text": return { rich_text: text$1 ? [{ text: { content: text$1 } }] : [] };
14584
- case "number": return { number: asNumber(value) };
14585
- case "checkbox": return { checkbox: asBoolean(value) };
14586
- case "date": {
14587
- const start = asDateStart(value);
14588
- return { date: start ? { start } : null };
14589
- }
14590
- case "select": {
14591
- const name$1 = stringifyValue(value).trim();
14592
- return { select: name$1 ? { name: name$1 } : null };
14593
- }
14594
- case "multi_select": return { multi_select: asStringArray(value).map((name$1) => ({ name: name$1 })) };
14595
- case "url": return { url: text$1 || null };
14596
- case "email": return { email: text$1 || null };
14597
- case "phone_number": return { phone_number: text$1 || null };
14598
- default: return null;
14599
- }
14600
- }
14601
- function findTitleProperty(properties, preferred) {
14602
- if (preferred && properties[preferred]?.type === "title") return preferred;
14603
- return Object.entries(properties).find(([, property]) => property?.type === "title")?.[0] ?? null;
14604
- }
14605
- function hyphenateDatabaseId(value) {
14606
- const id = value.replace(/-/g, "");
14607
- if (!UUID_RE.test(id)) return value;
14608
- return `${id.slice(0, 8)}-${id.slice(8, 12)}-${id.slice(12, 16)}-${id.slice(16, 20)}-${id.slice(20)}`;
14609
- }
14610
- function parseNotionDatabaseId(value) {
14611
- const input = value.trim();
14612
- if (!input) return "";
14613
- if (HYPHENATED_UUID_RE.test(input)) return input;
14614
- if (UUID_RE.test(input)) return hyphenateDatabaseId(input);
14615
- const match = input.replace(/-/g, "").match(UUID_IN_TEXT_RE);
14616
- return match ? hyphenateDatabaseId(match[0]) : input;
14617
- }
14618
- function normalizeFieldName(value) {
14619
- return value.normalize("NFKC").toLowerCase().replace(/[^\p{Letter}\p{Number}]+/gu, "");
14620
- }
14621
- function buildMatchKeys(field) {
14622
- return [
14623
- field.name,
14624
- field.title,
14625
- field.description
14626
- ].filter((value) => !!value?.trim()).map(normalizeFieldName).filter(Boolean);
14627
- }
14628
- function suggestFieldMap(schemaFields, databaseProperties) {
14629
- const propertyByKey = /* @__PURE__ */ new Map();
14630
- for (const propertyName of Object.keys(databaseProperties)) propertyByKey.set(normalizeFieldName(propertyName), propertyName);
14631
- const fieldMap = {};
14632
- for (const field of schemaFields) for (const key of buildMatchKeys(field)) {
14633
- const propertyName = propertyByKey.get(key);
14634
- if (propertyName) {
14635
- fieldMap[field.name] = propertyName;
14636
- break;
14637
- }
14638
- }
14639
- return fieldMap;
14640
- }
14641
- async function inspectNotionDatabase(input) {
14642
- if (!input.token.trim()) throw new Error("Notion integration token is required.");
14643
- const databaseId = parseNotionDatabaseId(input.databaseId);
14644
- if (!databaseId) throw new Error("Notion database URL or ID is required.");
14645
- const databaseProperties = (await new Client({ auth: input.token }).databases.retrieve({ database_id: databaseId })).properties;
14646
- return {
14647
- databaseId,
14648
- titleProperty: findTitleProperty(databaseProperties) ?? void 0,
14649
- properties: Object.entries(databaseProperties).map(([name$1, property]) => ({
14650
- name: name$1,
14651
- type: property?.type ?? "unknown"
14652
- })).sort((a, b) => a.name.localeCompare(b.name)),
14653
- suggestedFieldMap: suggestFieldMap(input.schemaFields, databaseProperties)
14654
- };
14655
- }
14656
- function validateNotionConfig(config) {
14657
- if (!config?.enabled) return "Notion export is not enabled. Configure Notion settings first.";
14658
- if (!config.token.trim()) return "Notion integration token is required.";
14659
- return null;
14660
- }
14661
- async function writeNotionPage(config, schemaName, data) {
14662
- const configError = validateNotionConfig(config);
14663
- if (configError) throw new Error(configError);
14664
- const notionConfig = config;
14665
- const schemaConfig = notionConfig.schemas[schemaName];
14666
- if (!schemaConfig) throw new Error(`Notion database is not configured for schema "${schemaName}".`);
14667
- if (!schemaConfig.databaseId.trim()) throw new Error(`Notion database ID is required for schema "${schemaName}".`);
14668
- const notion = new Client({ auth: notionConfig.token });
14669
- const databaseProperties = (await notion.databases.retrieve({ database_id: schemaConfig.databaseId })).properties;
14670
- const fieldMap = schemaConfig.fieldMap ?? {};
14671
- const properties = {};
14672
- for (const [sourceField, sourceValue] of Object.entries(data)) {
14673
- const notionPropertyName = fieldMap[sourceField] ?? sourceField;
14674
- const notionProperty = databaseProperties[notionPropertyName];
14675
- if (!notionProperty) continue;
14676
- const propertyValue = buildPropertyValue(notionProperty.type, sourceValue);
14677
- if (propertyValue) properties[notionPropertyName] = propertyValue;
14678
- }
14679
- const titleProperty = findTitleProperty(databaseProperties, schemaConfig.titleProperty);
14680
- if (titleProperty && !properties[titleProperty]) properties[titleProperty] = buildPropertyValue("title", Object.entries(data).find(([, value]) => typeof value === "string" && value.trim())?.[1] ?? schemaName);
14681
- if (Object.keys(properties).length === 0) throw new Error("No extracted fields matched Notion database properties.");
14682
- return {
14683
- pageId: (await notion.pages.create({
14684
- parent: { database_id: schemaConfig.databaseId },
14685
- properties
14686
- })).id,
14687
- databaseId: schemaConfig.databaseId
14688
- };
14689
- }
14690
-
14691
14805
  //#endregion
14692
14806
  //#region src/server/routes/ai.ts
14693
14807
  const JSON_EXT_RE = /\.json$/i;
@@ -15073,7 +15187,7 @@ async function executeAuditedExtraction(input) {
15073
15187
  });
15074
15188
  }
15075
15189
  const notionPages = [];
15076
- if (input.syncNotion) try {
15190
+ if (aiConfig.notion?.enabled && aiConfig.notion.schemas?.[input.schemaName]?.databaseId?.trim()) try {
15077
15191
  if (!result.data || typeof result.data !== "object" || Array.isArray(result.data)) throw new Error("Extraction result is not an object and cannot be written to Notion.");
15078
15192
  notionPages.push(await writeNotionPage(aiConfig.notion, input.schemaName, result.data));
15079
15193
  } catch (error) {
@@ -15128,7 +15242,6 @@ function extractRoutes(config) {
15128
15242
  const schemaName = getFormString(body.schema);
15129
15243
  const text$1 = getFormString(body.text);
15130
15244
  const modelName = getFormString(body.model);
15131
- const syncNotion = getFormString(body.notion) === "true";
15132
15245
  const file = getFormFile(body.file);
15133
15246
  if (!schemaName) return c.json({
15134
15247
  success: false,
@@ -15169,8 +15282,7 @@ function extractRoutes(config) {
15169
15282
  schemaName,
15170
15283
  text: text$1,
15171
15284
  filePath,
15172
- modelName,
15173
- syncNotion
15285
+ modelName
15174
15286
  });
15175
15287
  } catch (error) {
15176
15288
  return c.json({
@@ -65,7 +65,7 @@ function doctorDiagnosticsTableRows(d) {
65
65
  //#endregion
66
66
  //#region package.json
67
67
  var name = "aiex-cli";
68
- var version = "0.0.2-beta.1";
68
+ var version = "0.0.2-beta.3";
69
69
  var description = "JSON Schema → SQLite with AI-powered data extraction";
70
70
  var package_default = {
71
71
  name,
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { C as buildDoctorDiagnostics, T as formatDoctorDiagnosticsJson, a as parseJsonSchema, i as JsonSchemaDefinitionSchema, n as createMigrationConfig, r as generateDrizzleConfig, s as generateDrizzleSchema, t as collectDoctorDiagnostics, w as doctorDiagnosticsTableRows } from "./doctor-collector-Cbqgwx__.mjs";
1
+ import { C as buildDoctorDiagnostics, T as formatDoctorDiagnosticsJson, a as parseJsonSchema, i as JsonSchemaDefinitionSchema, n as createMigrationConfig, r as generateDrizzleConfig, s as generateDrizzleSchema, t as collectDoctorDiagnostics, w as doctorDiagnosticsTableRows } from "./doctor-collector-CGUF999y.mjs";
2
2
 
3
3
  export { JsonSchemaDefinitionSchema, buildDoctorDiagnostics, collectDoctorDiagnostics, createMigrationConfig, doctorDiagnosticsTableRows, formatDoctorDiagnosticsJson, generateDrizzleConfig, generateDrizzleSchema, parseJsonSchema };