aiex-cli 0.0.2-beta.2 → 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 -215
  2. package/dist/{doctor-collector-BhNgLdrJ.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-FPVIOydC.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-DU-jBPOf.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-BhNgLdrJ.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, extractNotionId } 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,213 +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
- function truncateText(value) {
14530
- return value.length > RICH_TEXT_LIMIT ? value.slice(0, RICH_TEXT_LIMIT) : value;
14531
- }
14532
- function stringifyValue(value) {
14533
- if (value === null || value === void 0) return "";
14534
- if (typeof value === "string") return value;
14535
- if (typeof value === "number" || typeof value === "boolean") return String(value);
14536
- return JSON.stringify(value);
14537
- }
14538
- function asNumber(value) {
14539
- if (typeof value === "number" && Number.isFinite(value)) return value;
14540
- if (typeof value === "string" && value.trim()) {
14541
- const parsed = Number(value);
14542
- return Number.isFinite(parsed) ? parsed : null;
14543
- }
14544
- return null;
14545
- }
14546
- function asBoolean(value) {
14547
- if (typeof value === "boolean") return value;
14548
- if (typeof value === "number") return value !== 0;
14549
- if (typeof value === "string") {
14550
- const normalized = value.trim().toLowerCase();
14551
- return [
14552
- "true",
14553
- "yes",
14554
- "1",
14555
- "y"
14556
- ].includes(normalized);
14557
- }
14558
- return !!value;
14559
- }
14560
- function asDateStart(value) {
14561
- if (value instanceof Date && !Number.isNaN(value.getTime())) return value.toISOString();
14562
- if (typeof value === "number" && Number.isFinite(value)) {
14563
- const date = new Date(value);
14564
- return Number.isNaN(date.getTime()) ? null : date.toISOString();
14565
- }
14566
- if (typeof value === "string" && value.trim()) {
14567
- const ms = Date.parse(value);
14568
- if (Number.isNaN(ms)) return null;
14569
- return new Date(ms).toISOString();
14570
- }
14571
- return null;
14572
- }
14573
- function asStringArray(value) {
14574
- if (Array.isArray(value)) return value.map((item) => stringifyValue(item).trim()).filter(Boolean);
14575
- const text$1 = stringifyValue(value).trim();
14576
- return text$1 ? [text$1] : [];
14577
- }
14578
- function buildPropertyValue(type, value) {
14579
- const text$1 = truncateText(stringifyValue(value));
14580
- switch (type) {
14581
- case "title": return { title: text$1 ? [{ text: { content: text$1 } }] : [] };
14582
- case "rich_text": return { rich_text: text$1 ? [{ text: { content: text$1 } }] : [] };
14583
- case "number": return { number: asNumber(value) };
14584
- case "checkbox": return { checkbox: asBoolean(value) };
14585
- case "date": {
14586
- const start = asDateStart(value);
14587
- return { date: start ? { start } : null };
14588
- }
14589
- case "select": {
14590
- const name$1 = stringifyValue(value).trim();
14591
- return { select: name$1 ? { name: name$1 } : null };
14592
- }
14593
- case "multi_select": return { multi_select: asStringArray(value).map((name$1) => ({ name: name$1 })) };
14594
- case "url": return { url: text$1 || null };
14595
- case "email": return { email: text$1 || null };
14596
- case "phone_number": return { phone_number: text$1 || null };
14597
- default: return null;
14598
- }
14599
- }
14600
- function findTitleProperty(properties, preferred) {
14601
- if (preferred && properties[preferred]?.type === "title") return preferred;
14602
- return Object.entries(properties).find(([, property]) => property?.type === "title")?.[0] ?? null;
14603
- }
14604
- function hyphenateDatabaseId(value) {
14605
- const id = value.replace(/-/g, "");
14606
- if (!UUID_RE.test(id)) return value;
14607
- return `${id.slice(0, 8)}-${id.slice(8, 12)}-${id.slice(12, 16)}-${id.slice(16, 20)}-${id.slice(20)}`;
14608
- }
14609
- function parseNotionDatabaseId(value) {
14610
- const input = value.trim();
14611
- if (!input) return "";
14612
- const extracted = extractNotionId(input);
14613
- if (extracted) return extracted;
14614
- if (HYPHENATED_UUID_RE.test(input)) return input;
14615
- if (UUID_RE.test(input)) return hyphenateDatabaseId(input);
14616
- return 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
- function hasProperties(value) {
14642
- return !!value && typeof value === "object" && !!value.properties && typeof value.properties === "object";
14643
- }
14644
- function firstDataSourceId(database) {
14645
- return (Array.isArray(database?.data_sources) ? database.data_sources : []).find((source) => typeof source?.id === "string" && source.id.trim())?.id;
14646
- }
14647
- async function resolveNotionDataSource(notion, inputId) {
14648
- const id = parseNotionDatabaseId(inputId);
14649
- if (!id) throw new Error("Notion database or data source URL/ID is required.");
14650
- try {
14651
- const dataSource$1 = await notion.dataSources.retrieve({ data_source_id: id });
14652
- if (hasProperties(dataSource$1)) return {
14653
- databaseId: typeof dataSource$1.parent?.database_id === "string" ? dataSource$1.parent.database_id : id,
14654
- dataSourceId: dataSource$1.id ?? id,
14655
- properties: dataSource$1.properties,
14656
- parent: { data_source_id: dataSource$1.id ?? id }
14657
- };
14658
- } catch {}
14659
- const database = await notion.databases.retrieve({ database_id: id });
14660
- if (hasProperties(database)) return {
14661
- databaseId: database.id ?? id,
14662
- properties: database.properties,
14663
- parent: { database_id: database.id ?? id }
14664
- };
14665
- const dataSourceId = firstDataSourceId(database);
14666
- 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.");
14667
- const dataSource = await notion.dataSources.retrieve({ data_source_id: dataSourceId });
14668
- 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.");
14669
- return {
14670
- databaseId: database.id ?? id,
14671
- dataSourceId: dataSource.id ?? dataSourceId,
14672
- properties: dataSource.properties,
14673
- parent: { data_source_id: dataSource.id ?? dataSourceId }
14674
- };
14675
- }
14676
- async function inspectNotionDatabase(input) {
14677
- if (!input.token.trim()) throw new Error("Notion integration token is required.");
14678
- const id = parseNotionDatabaseId(input.databaseId);
14679
- if (!id) throw new Error("Notion database or data source URL/ID is required.");
14680
- const resolved = await resolveNotionDataSource(new Client({ auth: input.token }), id);
14681
- const databaseProperties = resolved.properties;
14682
- const titleProperty = findTitleProperty(databaseProperties) ?? void 0;
14683
- return {
14684
- databaseId: resolved.databaseId,
14685
- dataSourceId: resolved.dataSourceId,
14686
- titleProperty,
14687
- properties: Object.entries(databaseProperties).map(([name$1, property]) => ({
14688
- name: name$1,
14689
- type: property?.type ?? "unknown"
14690
- })).sort((a, b) => a.name.localeCompare(b.name)),
14691
- suggestedFieldMap: suggestFieldMap(input.schemaFields, databaseProperties)
14692
- };
14693
- }
14694
- function validateNotionConfig(config) {
14695
- if (!config?.enabled) return "Notion export is not enabled. Configure Notion settings first.";
14696
- if (!config.token.trim()) return "Notion integration token is required.";
14697
- return null;
14698
- }
14699
- async function writeNotionPage(config, schemaName, data) {
14700
- const configError = validateNotionConfig(config);
14701
- if (configError) throw new Error(configError);
14702
- const notionConfig = config;
14703
- const schemaConfig = notionConfig.schemas[schemaName];
14704
- if (!schemaConfig) throw new Error(`Notion database is not configured for schema "${schemaName}".`);
14705
- if (!schemaConfig.databaseId.trim()) throw new Error(`Notion database ID is required for schema "${schemaName}".`);
14706
- const notion = new Client({ auth: notionConfig.token });
14707
- const resolved = await resolveNotionDataSource(notion, schemaConfig.databaseId);
14708
- const databaseProperties = resolved.properties;
14709
- const fieldMap = schemaConfig.fieldMap ?? {};
14710
- const properties = {};
14711
- for (const [sourceField, sourceValue] of Object.entries(data)) {
14712
- const notionPropertyName = fieldMap[sourceField] ?? sourceField;
14713
- const notionProperty = databaseProperties[notionPropertyName];
14714
- if (!notionProperty) continue;
14715
- const propertyValue = buildPropertyValue(notionProperty.type, sourceValue);
14716
- if (propertyValue) properties[notionPropertyName] = propertyValue;
14717
- }
14718
- const titleProperty = findTitleProperty(databaseProperties, schemaConfig.titleProperty);
14719
- if (titleProperty && !properties[titleProperty]) properties[titleProperty] = buildPropertyValue("title", Object.entries(data).find(([, value]) => typeof value === "string" && value.trim())?.[1] ?? schemaName);
14720
- if (Object.keys(properties).length === 0) throw new Error("No extracted fields matched Notion database properties.");
14721
- return {
14722
- pageId: (await notion.pages.create({
14723
- parent: resolved.parent,
14724
- properties
14725
- })).id,
14726
- databaseId: resolved.databaseId,
14727
- dataSourceId: resolved.dataSourceId
14728
- };
14729
- }
14730
-
14731
14805
  //#endregion
14732
14806
  //#region src/server/routes/ai.ts
14733
14807
  const JSON_EXT_RE = /\.json$/i;
@@ -15113,7 +15187,7 @@ async function executeAuditedExtraction(input) {
15113
15187
  });
15114
15188
  }
15115
15189
  const notionPages = [];
15116
- if (input.syncNotion) try {
15190
+ if (aiConfig.notion?.enabled && aiConfig.notion.schemas?.[input.schemaName]?.databaseId?.trim()) try {
15117
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.");
15118
15192
  notionPages.push(await writeNotionPage(aiConfig.notion, input.schemaName, result.data));
15119
15193
  } catch (error) {
@@ -15168,7 +15242,6 @@ function extractRoutes(config) {
15168
15242
  const schemaName = getFormString(body.schema);
15169
15243
  const text$1 = getFormString(body.text);
15170
15244
  const modelName = getFormString(body.model);
15171
- const syncNotion = getFormString(body.notion) === "true";
15172
15245
  const file = getFormFile(body.file);
15173
15246
  if (!schemaName) return c.json({
15174
15247
  success: false,
@@ -15209,8 +15282,7 @@ function extractRoutes(config) {
15209
15282
  schemaName,
15210
15283
  text: text$1,
15211
15284
  filePath,
15212
- modelName,
15213
- syncNotion
15285
+ modelName
15214
15286
  });
15215
15287
  } catch (error) {
15216
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.2";
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-BhNgLdrJ.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 };