aiex-cli 0.0.2-beta.2 → 0.0.2-beta.4

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 +295 -218
  2. package/dist/{doctor-collector-BhNgLdrJ.mjs → doctor-collector-DoJqOYMT.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-DoJqOYMT.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import fs from "node:fs/promises";
4
4
  import os from "node:os";
@@ -23,9 +23,10 @@ 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";
27
+ import { Buffer } from "node:buffer";
26
28
  import { execa } from "execa";
27
29
  import { extractText, getDocumentProxy, getMeta } from "unpdf";
28
- import { Buffer } from "node:buffer";
29
30
  import { execFile } from "node:child_process";
30
31
  import { promisify } from "node:util";
31
32
  import { serve } from "@hono/node-server";
@@ -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,208 @@ 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
+ const dataSourceId = firstDataSourceId(database);
13627
+ 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.");
13628
+ const dataSource = await notion.dataSources.retrieve({ data_source_id: dataSourceId });
13629
+ 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.");
13630
+ return {
13631
+ databaseId: database.id ?? id,
13632
+ dataSourceId: dataSource.id ?? dataSourceId,
13633
+ properties: dataSource.properties,
13634
+ parent: { data_source_id: dataSource.id ?? dataSourceId }
13635
+ };
13636
+ }
13637
+ async function inspectNotionDatabase(input) {
13638
+ if (!input.token.trim()) throw new Error("Notion integration token is required.");
13639
+ const id = parseNotionDatabaseId(input.databaseId);
13640
+ if (!id) throw new Error("Notion database or data source URL/ID is required.");
13641
+ const resolved = await resolveNotionDataSource(new Client({ auth: input.token }), id);
13642
+ const databaseProperties = resolved.properties;
13643
+ const titleProperty = findTitleProperty(databaseProperties) ?? void 0;
13644
+ return {
13645
+ databaseId: resolved.databaseId,
13646
+ dataSourceId: resolved.dataSourceId,
13647
+ titleProperty,
13648
+ properties: Object.entries(databaseProperties).map(([name$1, property]) => ({
13649
+ name: name$1,
13650
+ type: property?.type ?? "unknown"
13651
+ })).sort((a, b) => a.name.localeCompare(b.name)),
13652
+ suggestedFieldMap: suggestFieldMap(input.schemaFields, databaseProperties)
13653
+ };
13654
+ }
13655
+ function validateNotionConfig(config) {
13656
+ if (!config?.enabled) return "Notion export is not enabled. Configure Notion settings first.";
13657
+ if (!config.token.trim()) return "Notion integration token is required.";
13658
+ return null;
13659
+ }
13660
+ async function writeNotionPage(config, schemaName, data) {
13661
+ const configError = validateNotionConfig(config);
13662
+ if (configError) throw new Error(configError);
13663
+ const notionConfig = config;
13664
+ const schemaConfig = notionConfig.schemas[schemaName];
13665
+ if (!schemaConfig) throw new Error(`Notion database is not configured for schema "${schemaName}".`);
13666
+ if (!schemaConfig.databaseId.trim()) throw new Error(`Notion database ID is required for schema "${schemaName}".`);
13667
+ const notion = new Client({ auth: notionConfig.token });
13668
+ const resolved = await resolveNotionDataSource(notion, schemaConfig.databaseId);
13669
+ const databaseProperties = resolved.properties;
13670
+ const fieldMap = schemaConfig.fieldMap ?? {};
13671
+ const properties = {};
13672
+ for (const [sourceField, sourceValue] of Object.entries(data)) {
13673
+ const notionPropertyName = fieldMap[sourceField] ?? sourceField;
13674
+ const notionProperty = databaseProperties[notionPropertyName];
13675
+ if (!notionProperty) continue;
13676
+ const propertyValue = buildPropertyValue(notionProperty.type, sourceValue);
13677
+ if (propertyValue) properties[notionPropertyName] = propertyValue;
13678
+ }
13679
+ const titleProperty = findTitleProperty(databaseProperties, schemaConfig.titleProperty);
13680
+ if (titleProperty && !properties[titleProperty]) properties[titleProperty] = buildPropertyValue("title", schemaName);
13681
+ if (Object.keys(properties).length === 0) throw new Error("No extracted fields matched Notion database properties.");
13682
+ return {
13683
+ pageId: (await notion.pages.create({
13684
+ parent: resolved.parent,
13685
+ properties
13686
+ })).id,
13687
+ databaseId: resolved.databaseId,
13688
+ dataSourceId: resolved.dataSourceId
13689
+ };
13690
+ }
13691
+
13490
13692
  //#endregion
13491
13693
  //#region src/core/pdf-converter/external.ts
13492
13694
  function applyTemplate(value, context) {
@@ -13527,7 +13729,7 @@ function formatCommandError(error, command$1) {
13527
13729
  }
13528
13730
  async function countPdfPages(input) {
13529
13731
  try {
13530
- return (await getDocumentProxy(input)).numPages;
13732
+ return (await getDocumentProxy(Buffer.isBuffer(input) ? new Uint8Array(input) : input)).numPages;
13531
13733
  } catch {
13532
13734
  return 0;
13533
13735
  }
@@ -13681,6 +13883,17 @@ const SUPPORTED_EXTENSIONS = new Set([
13681
13883
  const PDF_EXT_RE = /\.pdf$/i;
13682
13884
  const JSON_EXT_RE$1 = /\.json$/;
13683
13885
  const SUPPORTED_FILE_PATTERN = `*.{${[...SUPPORTED_EXTENSIONS].join(",")}}`;
13886
+ async function syncResultToNotion(aiConfig, schemaName, data) {
13887
+ if (!data || typeof data !== "object" || Array.isArray(data)) throw new Error("Extraction result is not an object and cannot be written to Notion.");
13888
+ const page = await writeNotionPage(aiConfig.notion, schemaName, data);
13889
+ return [{
13890
+ databaseId: page.databaseId,
13891
+ pageId: page.pageId
13892
+ }];
13893
+ }
13894
+ function shouldSyncNotion(aiConfig, schemaName) {
13895
+ return !!aiConfig.notion?.enabled && !!aiConfig.notion.schemas?.[schemaName]?.databaseId?.trim();
13896
+ }
13684
13897
  async function ensureDatabaseReady(dbPath, schema) {
13685
13898
  try {
13686
13899
  await fs.access(dbPath);
@@ -13872,11 +14085,28 @@ async function processOneFile(aiexDir, config, aiConfig, schemaName, filePath, m
13872
14085
  insert: options?.insert
13873
14086
  });
13874
14087
  if (r.success) {
14088
+ let notionPages;
14089
+ if (shouldSyncNotion(aiConfig, schemaName)) try {
14090
+ notionPages = await syncResultToNotion(aiConfig, schemaName, r.data);
14091
+ consola.success(`Synced to Notion: ${notionPages.length} page(s)`);
14092
+ } catch (error) {
14093
+ await updateExtractionAuditRecord(aiexDir, audit.id, {
14094
+ status: "failed",
14095
+ outputPath: r.outputPath,
14096
+ outputName: r.outputPath ? path.basename(r.outputPath) : void 0,
14097
+ tablesInserted: r.tablesInserted,
14098
+ tokensUsed: r.tokensUsed,
14099
+ error: error instanceof Error ? error.message : String(error)
14100
+ });
14101
+ consola.error(`Notion sync failed: ${error instanceof Error ? error.message : String(error)}`);
14102
+ return false;
14103
+ }
13875
14104
  await updateExtractionAuditRecord(aiexDir, audit.id, {
13876
14105
  status: "succeeded",
13877
14106
  outputPath: r.outputPath,
13878
14107
  outputName: r.outputPath ? path.basename(r.outputPath) : void 0,
13879
14108
  tablesInserted: r.tablesInserted,
14109
+ notionPages,
13880
14110
  tokensUsed: r.tokensUsed
13881
14111
  });
13882
14112
  consola.success(`Processed: ${path.basename(filePath)}`);
@@ -13941,6 +14171,15 @@ function getIdArg(args) {
13941
14171
  const positional = args._;
13942
14172
  return Array.isArray(positional) && typeof positional[0] === "string" ? positional[0] : "";
13943
14173
  }
14174
+ function isExtractSubCommand(rawArgs) {
14175
+ if (!Array.isArray(rawArgs)) return false;
14176
+ return rawArgs.some((arg) => typeof arg === "string" && [
14177
+ "history",
14178
+ "show",
14179
+ "retry",
14180
+ "rm"
14181
+ ].includes(arg));
14182
+ }
13944
14183
  function formatSource(source) {
13945
14184
  return source.type === "file" ? source.fileName || "file" : "text";
13946
14185
  }
@@ -13984,11 +14223,33 @@ async function runAuditedSingleExtraction(input) {
13984
14223
  });
13985
14224
  return false;
13986
14225
  }
14226
+ let notionPages;
14227
+ if (input.aiConfig.notion?.enabled && input.aiConfig.notion.schemas?.[input.schemaName]?.databaseId?.trim()) try {
14228
+ 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.");
14229
+ const page = await writeNotionPage(input.aiConfig.notion, input.schemaName, result.data);
14230
+ notionPages = [{
14231
+ databaseId: page.databaseId,
14232
+ pageId: page.pageId
14233
+ }];
14234
+ consola.success(`Synced to Notion: ${notionPages.length} page(s)`);
14235
+ } catch (error) {
14236
+ await updateExtractionAuditRecord(input.aiexDir, audit.id, {
14237
+ status: "failed",
14238
+ outputPath: result.outputPath,
14239
+ outputName: result.outputPath ? path.basename(result.outputPath) : void 0,
14240
+ tablesInserted: result.tablesInserted,
14241
+ tokensUsed: result.tokensUsed,
14242
+ error: error instanceof Error ? error.message : String(error)
14243
+ });
14244
+ consola.error(`Notion sync failed: ${error instanceof Error ? error.message : String(error)}`);
14245
+ return false;
14246
+ }
13987
14247
  await updateExtractionAuditRecord(input.aiexDir, audit.id, {
13988
14248
  status: "succeeded",
13989
14249
  outputPath: result.outputPath,
13990
14250
  outputName: result.outputPath ? path.basename(result.outputPath) : void 0,
13991
14251
  tablesInserted: result.tablesInserted,
14252
+ notionPages,
13992
14253
  tokensUsed: result.tokensUsed
13993
14254
  });
13994
14255
  return true;
@@ -14166,7 +14427,8 @@ const extractCommand = defineCommand({
14166
14427
  default: false
14167
14428
  }
14168
14429
  },
14169
- async run({ args }) {
14430
+ async run({ args, rawArgs }) {
14431
+ if (isExtractSubCommand(rawArgs)) return;
14170
14432
  intro(pc.inverse(" aiex extract "));
14171
14433
  const config = createMigrationConfig(process.cwd());
14172
14434
  const aiexDir = path.dirname(config.schemaPath);
@@ -14300,7 +14562,18 @@ async function runInteractive(aiexDir, config, aiConfig, modelOverride) {
14300
14562
  cancel("Cancelled");
14301
14563
  return false;
14302
14564
  }
14303
- return (await extractSingle(aiexDir, config, aiConfig, schemaName, textContent, void 0, modelOverride)).success;
14565
+ return runAuditedSingleExtraction({
14566
+ aiexDir,
14567
+ config,
14568
+ aiConfig,
14569
+ schemaName,
14570
+ text: textContent,
14571
+ source: {
14572
+ type: "text",
14573
+ text: textContent
14574
+ },
14575
+ modelOverride
14576
+ });
14304
14577
  } else if (inputSource === "file") {
14305
14578
  const filePathStr = await text({
14306
14579
  message: "Enter file path:",
@@ -14315,7 +14588,20 @@ async function runInteractive(aiexDir, config, aiConfig, modelOverride) {
14315
14588
  const fp = filePathStr;
14316
14589
  try {
14317
14590
  const input = await readExtractFileInput(fp, aiConfig);
14318
- return (await extractSingle(aiexDir, config, aiConfig, schemaName, input.text, input.filePath, modelOverride)).success;
14591
+ return runAuditedSingleExtraction({
14592
+ aiexDir,
14593
+ config,
14594
+ aiConfig,
14595
+ schemaName,
14596
+ text: input.text,
14597
+ filePath: input.filePath,
14598
+ source: {
14599
+ type: "file",
14600
+ filePath: fp,
14601
+ fileName: path.basename(fp)
14602
+ },
14603
+ modelOverride
14604
+ });
14319
14605
  } catch (e) {
14320
14606
  consola.error(`Cannot read file: ${fp} — ${e instanceof Error ? e.message : String(e)}`);
14321
14607
  return false;
@@ -14521,213 +14807,6 @@ const schemaCommand = defineCommand({
14521
14807
  }
14522
14808
  });
14523
14809
 
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
14810
  //#endregion
14732
14811
  //#region src/server/routes/ai.ts
14733
14812
  const JSON_EXT_RE = /\.json$/i;
@@ -15113,7 +15192,7 @@ async function executeAuditedExtraction(input) {
15113
15192
  });
15114
15193
  }
15115
15194
  const notionPages = [];
15116
- if (input.syncNotion) try {
15195
+ if (aiConfig.notion?.enabled && aiConfig.notion.schemas?.[input.schemaName]?.databaseId?.trim()) try {
15117
15196
  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
15197
  notionPages.push(await writeNotionPage(aiConfig.notion, input.schemaName, result.data));
15119
15198
  } catch (error) {
@@ -15168,7 +15247,6 @@ function extractRoutes(config) {
15168
15247
  const schemaName = getFormString(body.schema);
15169
15248
  const text$1 = getFormString(body.text);
15170
15249
  const modelName = getFormString(body.model);
15171
- const syncNotion = getFormString(body.notion) === "true";
15172
15250
  const file = getFormFile(body.file);
15173
15251
  if (!schemaName) return c.json({
15174
15252
  success: false,
@@ -15209,8 +15287,7 @@ function extractRoutes(config) {
15209
15287
  schemaName,
15210
15288
  text: text$1,
15211
15289
  filePath,
15212
- modelName,
15213
- syncNotion
15290
+ modelName
15214
15291
  });
15215
15292
  } catch (error) {
15216
15293
  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.4";
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-DoJqOYMT.mjs";
2
2
 
3
3
  export { JsonSchemaDefinitionSchema, buildDoctorDiagnostics, collectDoctorDiagnostics, createMigrationConfig, doctorDiagnosticsTableRows, formatDoctorDiagnosticsJson, generateDrizzleConfig, generateDrizzleSchema, parseJsonSchema };