aiex-cli 0.0.1-beta.5 → 0.0.1-beta.6
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.
- package/README.md +2 -2
- package/dist/cli.mjs +198 -311
- package/dist/core/schema-sqlite/migrate-helper.mjs +14 -5
- package/dist/{doctor-Cd_N16iC.mjs → doctor-BTfByg-I.mjs} +2 -2
- package/dist/index.mjs +1 -1
- package/dist/web/assets/AISettings-D_AFhorO.js +334 -0
- package/dist/web/assets/DataBrowser-DZT0kGQE.css +1 -0
- package/dist/web/assets/DataBrowser-rznfVRaV.js +3 -0
- package/dist/web/assets/JsonSchemaEditor-C9iyQs7N.js +929 -0
- package/dist/web/assets/api-client-Dsg4WOM9.js +1 -0
- package/dist/web/assets/button-kTMweGMc.js +927 -0
- package/dist/web/assets/chunk-DtRyYLXJ.js +1 -0
- package/dist/web/assets/{cssMode-BloHqzZF.js → cssMode-DAbG0CMn.js} +1 -1
- package/dist/web/assets/dialog-CWuu7WjI.js +108 -0
- package/dist/web/assets/{editor.api-BG499EJF.js → editor.api-DLXGyrN1.js} +1 -1
- package/dist/web/assets/{editor.main-BhEWG0_P.js → editor.main-BqhfoHxy.js} +2 -2
- package/dist/web/assets/{freemarker2-DOHaFATh.js → freemarker2-B9_5ct2b.js} +1 -1
- package/dist/web/assets/{handlebars-BIFWety9.js → handlebars-TY59WcoQ.js} +1 -1
- package/dist/web/assets/{html-YGaqGZNd.js → html-CLULsh27.js} +1 -1
- package/dist/web/assets/{htmlMode-Bu3PyHjq.js → htmlMode-BvG7RNbU.js} +1 -1
- package/dist/web/assets/index-BRvFRL-3.js +882 -0
- package/dist/web/assets/index-DDFnprdM.css +2 -0
- package/dist/web/assets/{javascript-N0gZqDK0.js → javascript-DHrLp6gu.js} +1 -1
- package/dist/web/assets/{jsonMode-z5YscjcG.js → jsonMode-DBDhdzl1.js} +1 -1
- package/dist/web/assets/lib-C30cIFrm.js +1 -0
- package/dist/web/assets/{liquid-BHfNNVLs.js → liquid-tGeb-nqF.js} +1 -1
- package/dist/web/assets/{mdx-Dqu2t0et.js → mdx-Cmdz78VU.js} +1 -1
- package/dist/web/assets/{monaco.contribution-ByQ3yI-W.js → monaco.contribution-CroYPUF5.js} +2 -2
- package/dist/web/assets/overlayeventbus-AtOpmI6n.js +80 -0
- package/dist/web/assets/{python-icfse9Ji.js → python-Dmfz4iDE.js} +1 -1
- package/dist/web/assets/{razor-DwVkryG9.js → razor-BJicZHJs.js} +1 -1
- package/dist/web/assets/table-schema-mJrrf9qw.js +2 -0
- package/dist/web/assets/{tsMode-CLrI3bdf.js → tsMode-DYqTyE66.js} +1 -1
- package/dist/web/assets/{typescript-BzuZVF7m.js → typescript-DLnTe9Hf.js} +1 -1
- package/dist/web/assets/{xml-Cr85kdqA.js → xml-BIYqLORk.js} +1 -1
- package/dist/web/assets/{yaml-D3RbJnnO.js → yaml-BjmulkMX.js} +1 -1
- package/dist/web/index.html +8 -4
- package/package.json +1 -1
- package/src/core/schema-sqlite/migrate-helper.ts +9 -4
- package/dist/web/assets/chunk-BEqpzyXh.js +0 -1
- package/dist/web/assets/index-DTABZIZZ.css +0 -2
- package/dist/web/assets/index-DVc9DeYI.js +0 -3266
- /package/dist/web/assets/{abap-Cry0R76c.js → abap-DrZwwXZX.js} +0 -0
- /package/dist/web/assets/{apex-xqbJ58nJ.js → apex-CrCz0btt.js} +0 -0
- /package/dist/web/assets/{azcli-D7JTNGKs.js → azcli-BapzKHay.js} +0 -0
- /package/dist/web/assets/{bat-Cuq6hn0K.js → bat-C_NRAiA1.js} +0 -0
- /package/dist/web/assets/{bicep-eTuQjz9F.js → bicep-C7pp2CNk.js} +0 -0
- /package/dist/web/assets/{cameligo-DKgCRl36.js → cameligo-BhhK9vxZ.js} +0 -0
- /package/dist/web/assets/{clojure-B_aTBtVh.js → clojure-D0ujmUyE.js} +0 -0
- /package/dist/web/assets/{coffee-BWAYpIPu.js → coffee-DHEl7Jbb.js} +0 -0
- /package/dist/web/assets/{cpp-BduBQE8d.js → cpp-Iil-3nzZ.js} +0 -0
- /package/dist/web/assets/{csharp-CMqOVYKK.js → csharp-Dh0Ee7SY.js} +0 -0
- /package/dist/web/assets/{csp-6cGliXw2.js → csp-mwzjw0JL.js} +0 -0
- /package/dist/web/assets/{css-CHnKqS9Q.js → css-COIa8ZTR.js} +0 -0
- /package/dist/web/assets/{cypher-DMzZBj2L.js → cypher-GVc17FC4.js} +0 -0
- /package/dist/web/assets/{dart-7hYfJ1Dv.js → dart-phiCaE7_.js} +0 -0
- /package/dist/web/assets/{dockerfile-BflvjnJW.js → dockerfile-BMaDhdim.js} +0 -0
- /package/dist/web/assets/{ecl-BEt6xb2p.js → ecl-Cj47kvqp.js} +0 -0
- /package/dist/web/assets/{elixir-CnrQCt6o.js → elixir-DBbstcE1.js} +0 -0
- /package/dist/web/assets/{flow9-CfLCoUuB.js → flow9-ChHb1adO.js} +0 -0
- /package/dist/web/assets/{fsharp-BQqR9uQ6.js → fsharp-CMk2OIJN.js} +0 -0
- /package/dist/web/assets/{go-C3AlMVwy.js → go-BrMkuJg0.js} +0 -0
- /package/dist/web/assets/{graphql-O_-hDldf.js → graphql-PSR1UKGv.js} +0 -0
- /package/dist/web/assets/{hcl-BQQD6Mtj.js → hcl-DAQrbDOW.js} +0 -0
- /package/dist/web/assets/{ini-Bf0RDfP_.js → ini-0TG5BxW0.js} +0 -0
- /package/dist/web/assets/{java-nqX2KEDD.js → java-rgorz17v.js} +0 -0
- /package/dist/web/assets/{julia-B6P9U5er.js → julia-C8VMdHm8.js} +0 -0
- /package/dist/web/assets/{kotlin-B-LRk09-.js → kotlin-CllWo3gX.js} +0 -0
- /package/dist/web/assets/{less-CEaIdW1f.js → less-Cgca25AP.js} +0 -0
- /package/dist/web/assets/{lexon-Qv4pvFSW.js → lexon-D0GHdBaw.js} +0 -0
- /package/dist/web/assets/{lua-CFpyR7YN.js → lua-DmRsNG-P.js} +0 -0
- /package/dist/web/assets/{m3-CvKhVPQn.js → m3-BgL5dNKT.js} +0 -0
- /package/dist/web/assets/{markdown-qldG3Vc4.js → markdown-BuJfycGS.js} +0 -0
- /package/dist/web/assets/{mips-0D8PRyHq.js → mips-C9m_93PR.js} +0 -0
- /package/dist/web/assets/{msdax-DwZXSC5M.js → msdax-CpFHC9OI.js} +0 -0
- /package/dist/web/assets/{mysql-BWq85KY4.js → mysql-qFvltsqN.js} +0 -0
- /package/dist/web/assets/{objective-c-D653JUMG.js → objective-c-Bnmr858J.js} +0 -0
- /package/dist/web/assets/{pascal-rWjRDdnR.js → pascal-WP0_D5AO.js} +0 -0
- /package/dist/web/assets/{pascaligo-Db8EehaF.js → pascaligo-Blom4Rij.js} +0 -0
- /package/dist/web/assets/{perl-C68oq8-D.js → perl-B-vk8g64.js} +0 -0
- /package/dist/web/assets/{pgsql-BXeHe33s.js → pgsql-Cgvz6v67.js} +0 -0
- /package/dist/web/assets/{php-CDVsAbfl.js → php-8a3Lrw9m.js} +0 -0
- /package/dist/web/assets/{pla-DnryFT0q.js → pla-DuFqEZ8V.js} +0 -0
- /package/dist/web/assets/{postiats-CDg_4Ev-.js → postiats-DkLtSgkp.js} +0 -0
- /package/dist/web/assets/{powerquery-CWPi8ROz.js → powerquery-BJ1aNepW.js} +0 -0
- /package/dist/web/assets/{powershell-C5A0QX3-.js → powershell-rE98k687.js} +0 -0
- /package/dist/web/assets/{preload-helper-DSXbuxSR.js → preload-helper-DWTEM3RW.js} +0 -0
- /package/dist/web/assets/{protobuf-Cgt-BQbL.js → protobuf-CUheFacr.js} +0 -0
- /package/dist/web/assets/{pug-RPYJC9QB.js → pug-LDcAMD8w.js} +0 -0
- /package/dist/web/assets/{qsharp-BZ3S7fu_.js → qsharp-IHfqKOfK.js} +0 -0
- /package/dist/web/assets/{r-CN875f1X.js → r-D-QApv87.js} +0 -0
- /package/dist/web/assets/{redis-BLesvTwR.js → redis-SXdDyWR9.js} +0 -0
- /package/dist/web/assets/{redshift-Byf_0XqD.js → redshift-Y6lsCryn.js} +0 -0
- /package/dist/web/assets/{restructuredtext-DYg_6BiZ.js → restructuredtext-edObr9a8.js} +0 -0
- /package/dist/web/assets/{ruby-C4OkxbC-.js → ruby-CNnUfF-8.js} +0 -0
- /package/dist/web/assets/{rust-xAoaEFMh.js → rust-IHUZWzBr.js} +0 -0
- /package/dist/web/assets/{sb-C8dHOW_y.js → sb-DrUvY44N.js} +0 -0
- /package/dist/web/assets/{scala-Spx0wP1o.js → scala-B4hbXGLM.js} +0 -0
- /package/dist/web/assets/{scheme-D2mZlAUz.js → scheme-BGrd12j3.js} +0 -0
- /package/dist/web/assets/{scss-DDCn3Ylu.js → scss-x5G1ES4U.js} +0 -0
- /package/dist/web/assets/{shell-M6px0EWn.js → shell-DOehe2Y8.js} +0 -0
- /package/dist/web/assets/{solidity-DUWMJi-f.js → solidity-BeRvcwWV.js} +0 -0
- /package/dist/web/assets/{sophia-DwJbUG-2.js → sophia-DZbkUNjy.js} +0 -0
- /package/dist/web/assets/{sparql-ClQxbRPI.js → sparql-B7_oi5-h.js} +0 -0
- /package/dist/web/assets/{sql-BQdjW7Vy.js → sql-CTlsFWVE.js} +0 -0
- /package/dist/web/assets/{st-BpISyZ_v.js → st-DJVEJdPE.js} +0 -0
- /package/dist/web/assets/{swift-CMbl5gM4.js → swift-CwhT3fYa.js} +0 -0
- /package/dist/web/assets/{systemverilog-jx2Xs7uO.js → systemverilog-BQN63pkN.js} +0 -0
- /package/dist/web/assets/{tcl-GIGnfs89.js → tcl-DqwfpskA.js} +0 -0
- /package/dist/web/assets/{twig-Bc0mxc_m.js → twig-BiyenUgc.js} +0 -0
- /package/dist/web/assets/{typespec-CEioAsEm.js → typespec-CWOJribt.js} +0 -0
- /package/dist/web/assets/{vb-BPk67J-d.js → vb-Cq5F87m3.js} +0 -0
- /package/dist/web/assets/{wgsl-DOnyt8_J.js → wgsl-BAvW2lVr.js} +0 -0
package/dist/cli.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as doctorDiagnosticsTableRows, a as writeAIConfig, b as toSnakeCase, c as PLACEHOLDER_TEXT, d as seedConfig, f as description
|
|
1
|
+
import { C as doctorDiagnosticsTableRows, a as writeAIConfig, b as toSnakeCase, c as PLACEHOLDER_TEXT, d as seedConfig, f as description, g as createMigrationConfig, h as version, i as readAIConfig, l as AIConfigSchema, m as package_default, n as getDefaultAIConfig, o as DEFAULT_PROMPT_CONFIG, p as name, r as maskApiKey, s as PLACEHOLDER_SCHEMA, t as collectDoctorDiagnostics, u as createConfig, v as JsonSchemaDefinitionSchema, w as formatDoctorDiagnosticsJson, x as generateDrizzleSchema, y as parseJsonSchema } from "./doctor-BTfByg-I.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import process from "node:process";
|
|
@@ -12702,248 +12702,6 @@ function lookupModelCapabilities(modelName) {
|
|
|
12702
12702
|
return null;
|
|
12703
12703
|
}
|
|
12704
12704
|
|
|
12705
|
-
//#endregion
|
|
12706
|
-
//#region schemas/table-schema.json
|
|
12707
|
-
var $id = "https://raw.githubusercontent.com/OSpoon/aiex-cli/main/app/cli/schemas/table-schema.json";
|
|
12708
|
-
var table_schema_default = {
|
|
12709
|
-
$schema: "http://json-schema.org/draft-07/schema#",
|
|
12710
|
-
$id,
|
|
12711
|
-
title: "aiex Table Schema",
|
|
12712
|
-
description: "Defines a database table and its columns for aiex-cli schema-to-SQLite migration.",
|
|
12713
|
-
type: "object",
|
|
12714
|
-
required: [
|
|
12715
|
-
"title",
|
|
12716
|
-
"type",
|
|
12717
|
-
"table",
|
|
12718
|
-
"properties"
|
|
12719
|
-
],
|
|
12720
|
-
additionalProperties: false,
|
|
12721
|
-
properties: {
|
|
12722
|
-
"$schema": {
|
|
12723
|
-
"type": "string",
|
|
12724
|
-
"description": "Pointer to this schema file for IDE validation.",
|
|
12725
|
-
"format": "uri",
|
|
12726
|
-
"default": "https://raw.githubusercontent.com/OSpoon/aiex-cli/main/app/cli/schemas/table-schema.json"
|
|
12727
|
-
},
|
|
12728
|
-
"title": {
|
|
12729
|
-
"type": "string",
|
|
12730
|
-
"minLength": 1,
|
|
12731
|
-
"description": "Human-readable table title (e.g. 'User', 'OrderItem')."
|
|
12732
|
-
},
|
|
12733
|
-
"description": {
|
|
12734
|
-
"type": "string",
|
|
12735
|
-
"description": "Optional table description."
|
|
12736
|
-
},
|
|
12737
|
-
"type": {
|
|
12738
|
-
"type": "string",
|
|
12739
|
-
"const": "object",
|
|
12740
|
-
"description": "Must be 'object' — each file defines one table."
|
|
12741
|
-
},
|
|
12742
|
-
"table": {
|
|
12743
|
-
"$ref": "#/$defs/tableConfig",
|
|
12744
|
-
"description": "Table-level configuration."
|
|
12745
|
-
},
|
|
12746
|
-
"properties": {
|
|
12747
|
-
"$ref": "#/$defs/properties",
|
|
12748
|
-
"description": "Column definitions keyed by property name (camelCase)."
|
|
12749
|
-
},
|
|
12750
|
-
"required": {
|
|
12751
|
-
"type": "array",
|
|
12752
|
-
"items": { "type": "string" },
|
|
12753
|
-
"description": "List of property names that are NOT NULL.",
|
|
12754
|
-
"default": []
|
|
12755
|
-
}
|
|
12756
|
-
},
|
|
12757
|
-
$defs: {
|
|
12758
|
-
"tableConfig": {
|
|
12759
|
-
"type": "object",
|
|
12760
|
-
"required": ["name"],
|
|
12761
|
-
"additionalProperties": false,
|
|
12762
|
-
"properties": {
|
|
12763
|
-
"name": {
|
|
12764
|
-
"type": "string",
|
|
12765
|
-
"minLength": 1,
|
|
12766
|
-
"pattern": "^[a-z][a-z0-9_]*$",
|
|
12767
|
-
"description": "SQLite table name in snake_case (lowercase letters, digits, underscores).",
|
|
12768
|
-
"examples": [
|
|
12769
|
-
"users",
|
|
12770
|
-
"order_items",
|
|
12771
|
-
"blog_posts"
|
|
12772
|
-
]
|
|
12773
|
-
},
|
|
12774
|
-
"timestamps": {
|
|
12775
|
-
"type": "boolean",
|
|
12776
|
-
"default": false,
|
|
12777
|
-
"description": "Automatically add created_at and updated_at TIMESTAMP columns."
|
|
12778
|
-
},
|
|
12779
|
-
"softDelete": {
|
|
12780
|
-
"type": "boolean",
|
|
12781
|
-
"default": false,
|
|
12782
|
-
"description": "Automatically add deleted_at nullable TIMESTAMP column."
|
|
12783
|
-
}
|
|
12784
|
-
}
|
|
12785
|
-
},
|
|
12786
|
-
"properties": {
|
|
12787
|
-
"type": "object",
|
|
12788
|
-
"minProperties": 1,
|
|
12789
|
-
"additionalProperties": { "$ref": "#/$defs/property" },
|
|
12790
|
-
"description": "Column definitions. Keys are camelCase property names."
|
|
12791
|
-
},
|
|
12792
|
-
"property": {
|
|
12793
|
-
"type": "object",
|
|
12794
|
-
"required": ["type"],
|
|
12795
|
-
"additionalProperties": false,
|
|
12796
|
-
"properties": {
|
|
12797
|
-
"type": {
|
|
12798
|
-
"$ref": "#/$defs/columnType",
|
|
12799
|
-
"description": "Column data type."
|
|
12800
|
-
},
|
|
12801
|
-
"format": {
|
|
12802
|
-
"$ref": "#/$defs/formatType",
|
|
12803
|
-
"description": "Semantic format hint that influences the SQLite column type."
|
|
12804
|
-
},
|
|
12805
|
-
"primary": {
|
|
12806
|
-
"type": "boolean",
|
|
12807
|
-
"default": false,
|
|
12808
|
-
"description": "Mark this column as PRIMARY KEY. Only one per table."
|
|
12809
|
-
},
|
|
12810
|
-
"autoIncrement": {
|
|
12811
|
-
"type": "boolean",
|
|
12812
|
-
"default": false,
|
|
12813
|
-
"description": "AUTO_INCREMENT for integer primary keys."
|
|
12814
|
-
},
|
|
12815
|
-
"unique": {
|
|
12816
|
-
"type": "boolean",
|
|
12817
|
-
"default": false,
|
|
12818
|
-
"description": "Add UNIQUE constraint."
|
|
12819
|
-
},
|
|
12820
|
-
"default": { "description": "Default value for the column. Type should match the column type." },
|
|
12821
|
-
"minLength": {
|
|
12822
|
-
"type": "integer",
|
|
12823
|
-
"minimum": 0,
|
|
12824
|
-
"description": "Minimum string length (validation only, not a DB constraint)."
|
|
12825
|
-
},
|
|
12826
|
-
"maxLength": {
|
|
12827
|
-
"type": "integer",
|
|
12828
|
-
"minimum": 1,
|
|
12829
|
-
"description": "Maximum string length (validation only, not a DB constraint)."
|
|
12830
|
-
},
|
|
12831
|
-
"minimum": {
|
|
12832
|
-
"type": "number",
|
|
12833
|
-
"description": "Minimum numeric value (validation only, not a DB constraint)."
|
|
12834
|
-
},
|
|
12835
|
-
"maximum": {
|
|
12836
|
-
"type": "number",
|
|
12837
|
-
"description": "Maximum numeric value (validation only, not a DB constraint)."
|
|
12838
|
-
},
|
|
12839
|
-
"drizzle": {
|
|
12840
|
-
"$ref": "#/$defs/drizzleConfig",
|
|
12841
|
-
"description": "Drizzle ORM specific overrides."
|
|
12842
|
-
},
|
|
12843
|
-
"nested": {
|
|
12844
|
-
"$ref": "#/$defs/nestedConfig",
|
|
12845
|
-
"description": "Create a separate related table instead of embedding as JSON."
|
|
12846
|
-
},
|
|
12847
|
-
"foreignKey": {
|
|
12848
|
-
"$ref": "#/$defs/foreignKeyRef",
|
|
12849
|
-
"description": "Foreign key reference to another table."
|
|
12850
|
-
},
|
|
12851
|
-
"properties": {
|
|
12852
|
-
"$ref": "#/$defs/properties",
|
|
12853
|
-
"description": "Sub-properties when type is 'object'. Ignored unless nested.enabled or drizzle.mode='json'."
|
|
12854
|
-
},
|
|
12855
|
-
"items": {
|
|
12856
|
-
"$ref": "#/$defs/property",
|
|
12857
|
-
"description": "Item schema when type is 'array'. Ignored unless items.nested.enabled."
|
|
12858
|
-
},
|
|
12859
|
-
"required": {
|
|
12860
|
-
"type": "array",
|
|
12861
|
-
"items": { "type": "string" },
|
|
12862
|
-
"description": "Required sub-properties for nested objects."
|
|
12863
|
-
}
|
|
12864
|
-
}
|
|
12865
|
-
},
|
|
12866
|
-
"columnType": {
|
|
12867
|
-
"type": "string",
|
|
12868
|
-
"enum": [
|
|
12869
|
-
"string",
|
|
12870
|
-
"integer",
|
|
12871
|
-
"number",
|
|
12872
|
-
"boolean",
|
|
12873
|
-
"object",
|
|
12874
|
-
"array",
|
|
12875
|
-
"null"
|
|
12876
|
-
],
|
|
12877
|
-
"description": "Data type. Maps to SQLite as: string→TEXT, integer→INTEGER, number→REAL, boolean→INTEGER(boolean), object→TEXT(json), array→TEXT(json), null→TEXT."
|
|
12878
|
-
},
|
|
12879
|
-
"formatType": {
|
|
12880
|
-
"type": "string",
|
|
12881
|
-
"enum": [
|
|
12882
|
-
"date-time",
|
|
12883
|
-
"email",
|
|
12884
|
-
"uri",
|
|
12885
|
-
"json"
|
|
12886
|
-
],
|
|
12887
|
-
"description": "Format hints: 'date-time' → INTEGER(timestamp), 'json' → TEXT(json), 'email'/'uri' → TEXT (no special mapping)."
|
|
12888
|
-
},
|
|
12889
|
-
"drizzleConfig": {
|
|
12890
|
-
"type": "object",
|
|
12891
|
-
"additionalProperties": false,
|
|
12892
|
-
"properties": {
|
|
12893
|
-
"mode": {
|
|
12894
|
-
"type": "string",
|
|
12895
|
-
"enum": [
|
|
12896
|
-
"json",
|
|
12897
|
-
"timestamp",
|
|
12898
|
-
"timestamp_ms",
|
|
12899
|
-
"boolean",
|
|
12900
|
-
"bigint"
|
|
12901
|
-
],
|
|
12902
|
-
"description": "Override Drizzle column mode. 'json' stores as TEXT(json), 'timestamp'/'timestamp_ms' as INTEGER, 'boolean' as INTEGER(boolean), 'bigint' as INTEGER(bigint)."
|
|
12903
|
-
},
|
|
12904
|
-
"customType": {
|
|
12905
|
-
"type": "string",
|
|
12906
|
-
"description": "Custom Drizzle type name (reserved for future use)."
|
|
12907
|
-
}
|
|
12908
|
-
}
|
|
12909
|
-
},
|
|
12910
|
-
"nestedConfig": {
|
|
12911
|
-
"type": "object",
|
|
12912
|
-
"required": ["enabled", "relation"],
|
|
12913
|
-
"additionalProperties": false,
|
|
12914
|
-
"properties": {
|
|
12915
|
-
"enabled": {
|
|
12916
|
-
"type": "boolean",
|
|
12917
|
-
"const": true,
|
|
12918
|
-
"description": "Must be true to activate nested table creation."
|
|
12919
|
-
},
|
|
12920
|
-
"relation": {
|
|
12921
|
-
"type": "string",
|
|
12922
|
-
"enum": ["has-one", "has-many"],
|
|
12923
|
-
"description": "'has-one' → one() relation, 'has-many' → many() relation. Only one level of nesting is supported."
|
|
12924
|
-
}
|
|
12925
|
-
}
|
|
12926
|
-
},
|
|
12927
|
-
"foreignKeyRef": {
|
|
12928
|
-
"type": "object",
|
|
12929
|
-
"required": ["table", "column"],
|
|
12930
|
-
"additionalProperties": false,
|
|
12931
|
-
"properties": {
|
|
12932
|
-
"table": {
|
|
12933
|
-
"type": "string",
|
|
12934
|
-
"minLength": 1,
|
|
12935
|
-
"description": "Target table name (snake_case)."
|
|
12936
|
-
},
|
|
12937
|
-
"column": {
|
|
12938
|
-
"type": "string",
|
|
12939
|
-
"minLength": 1,
|
|
12940
|
-
"description": "Target column name in the referenced table."
|
|
12941
|
-
}
|
|
12942
|
-
}
|
|
12943
|
-
}
|
|
12944
|
-
}
|
|
12945
|
-
};
|
|
12946
|
-
|
|
12947
12705
|
//#endregion
|
|
12948
12706
|
//#region src/core/ai-extraction/json-utils.ts
|
|
12949
12707
|
function stripFences(text) {
|
|
@@ -13132,6 +12890,100 @@ async function readFilePart(filePath) {
|
|
|
13132
12890
|
mimeType: mime
|
|
13133
12891
|
};
|
|
13134
12892
|
}
|
|
12893
|
+
function nullableType(type) {
|
|
12894
|
+
return type === "null" ? ["null"] : [type, "null"];
|
|
12895
|
+
}
|
|
12896
|
+
function propertyToExtractionSchema(property) {
|
|
12897
|
+
if (property.type === "array") return {
|
|
12898
|
+
type: nullableType("array"),
|
|
12899
|
+
items: property.items ? propertyToExtractionSchema(property.items) : {}
|
|
12900
|
+
};
|
|
12901
|
+
if (property.type === "object") {
|
|
12902
|
+
const childProperties = property.properties ? Object.fromEntries(Object.entries(property.properties).map(([name$1, prop]) => [name$1, propertyToExtractionSchema(prop)])) : void 0;
|
|
12903
|
+
return {
|
|
12904
|
+
type: nullableType("object"),
|
|
12905
|
+
...childProperties ? {
|
|
12906
|
+
properties: childProperties,
|
|
12907
|
+
required: Object.keys(childProperties),
|
|
12908
|
+
additionalProperties: false
|
|
12909
|
+
} : { additionalProperties: true }
|
|
12910
|
+
};
|
|
12911
|
+
}
|
|
12912
|
+
return { type: nullableType(property.type) };
|
|
12913
|
+
}
|
|
12914
|
+
function isRecord(value) {
|
|
12915
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12916
|
+
}
|
|
12917
|
+
function schemaToExtractionOutputSchema(schema) {
|
|
12918
|
+
const properties = Object.fromEntries(Object.entries(schema.properties).filter(([, prop]) => !(prop.primary && prop.autoIncrement)).map(([name$1, prop]) => [name$1, propertyToExtractionSchema(prop)]));
|
|
12919
|
+
return {
|
|
12920
|
+
type: "object",
|
|
12921
|
+
additionalProperties: false,
|
|
12922
|
+
properties,
|
|
12923
|
+
required: Object.keys(properties)
|
|
12924
|
+
};
|
|
12925
|
+
}
|
|
12926
|
+
function validatePropertyValue(path$1, property, value, issues) {
|
|
12927
|
+
if (value === null) return;
|
|
12928
|
+
switch (property.type) {
|
|
12929
|
+
case "string":
|
|
12930
|
+
if (typeof value !== "string") issues.push(`${path$1}: expected string or null`);
|
|
12931
|
+
return;
|
|
12932
|
+
case "integer":
|
|
12933
|
+
if (!Number.isInteger(value)) issues.push(`${path$1}: expected integer or null`);
|
|
12934
|
+
return;
|
|
12935
|
+
case "number":
|
|
12936
|
+
if (typeof value !== "number" || Number.isNaN(value)) issues.push(`${path$1}: expected number or null`);
|
|
12937
|
+
return;
|
|
12938
|
+
case "boolean":
|
|
12939
|
+
if (typeof value !== "boolean") issues.push(`${path$1}: expected boolean or null`);
|
|
12940
|
+
return;
|
|
12941
|
+
case "array":
|
|
12942
|
+
if (!Array.isArray(value)) {
|
|
12943
|
+
issues.push(`${path$1}: expected array or null`);
|
|
12944
|
+
return;
|
|
12945
|
+
}
|
|
12946
|
+
if (property.items) {
|
|
12947
|
+
const itemProperty = property.items;
|
|
12948
|
+
value.forEach((item, index) => validatePropertyValue(`${path$1}[${index}]`, itemProperty, item, issues));
|
|
12949
|
+
}
|
|
12950
|
+
return;
|
|
12951
|
+
case "object":
|
|
12952
|
+
if (!isRecord(value)) {
|
|
12953
|
+
issues.push(`${path$1}: expected object or null`);
|
|
12954
|
+
return;
|
|
12955
|
+
}
|
|
12956
|
+
if (property.properties) validateProperties(path$1, property.properties, value, issues);
|
|
12957
|
+
return;
|
|
12958
|
+
case "null": issues.push(`${path$1}: expected null`);
|
|
12959
|
+
}
|
|
12960
|
+
}
|
|
12961
|
+
function validateProperties(basePath, properties, data, issues) {
|
|
12962
|
+
const expected = Object.entries(properties).filter(([, prop]) => !(prop.primary && prop.autoIncrement));
|
|
12963
|
+
const expectedKeys = new Set(expected.map(([name$1]) => name$1));
|
|
12964
|
+
for (const key of Object.keys(data)) if (!expectedKeys.has(key)) issues.push(`${basePath}.${key}: unexpected field`);
|
|
12965
|
+
for (const [name$1, prop] of expected) {
|
|
12966
|
+
const path$1 = `${basePath}.${name$1}`;
|
|
12967
|
+
if (!(name$1 in data)) {
|
|
12968
|
+
issues.push(`${path$1}: missing field`);
|
|
12969
|
+
continue;
|
|
12970
|
+
}
|
|
12971
|
+
validatePropertyValue(path$1, prop, data[name$1], issues);
|
|
12972
|
+
}
|
|
12973
|
+
}
|
|
12974
|
+
function validateExtractedData(schema, data) {
|
|
12975
|
+
if (!isRecord(data)) return {
|
|
12976
|
+
success: false,
|
|
12977
|
+
error: "Extracted data must be a JSON object."
|
|
12978
|
+
};
|
|
12979
|
+
const issues = [];
|
|
12980
|
+
validateProperties("$", schema.properties, data, issues);
|
|
12981
|
+
if (issues.length > 0) return {
|
|
12982
|
+
success: false,
|
|
12983
|
+
error: `Extracted data does not match schema:\n${issues.map((issue) => ` - ${issue}`).join("\n")}`
|
|
12984
|
+
};
|
|
12985
|
+
return { success: true };
|
|
12986
|
+
}
|
|
13135
12987
|
async function loadPromptSnapshot(aiexDir, tableName) {
|
|
13136
12988
|
const snapshotPath = path.join(aiexDir, "extracted", `${tableName}.prompt.md`);
|
|
13137
12989
|
try {
|
|
@@ -13173,15 +13025,16 @@ async function extractStructuredData(input) {
|
|
|
13173
13025
|
let system;
|
|
13174
13026
|
let user;
|
|
13175
13027
|
const snapshot = await loadPromptSnapshot(aiexDir, schema.table.name);
|
|
13028
|
+
const promptText = file ? PLACEHOLDER_TEXT : text;
|
|
13176
13029
|
if (snapshot) {
|
|
13177
13030
|
system = snapshot.system;
|
|
13178
|
-
user = snapshot.user.replaceAll(PLACEHOLDER_TEXT,
|
|
13031
|
+
user = snapshot.user.replaceAll(PLACEHOLDER_TEXT, promptText);
|
|
13179
13032
|
} else {
|
|
13180
|
-
const generated = generateExtractionPrompt(schema,
|
|
13033
|
+
const generated = generateExtractionPrompt(schema, promptText, config.prompt ?? DEFAULT_PROMPT_CONFIG);
|
|
13181
13034
|
system = generated.system;
|
|
13182
13035
|
user = generated.user;
|
|
13183
13036
|
}
|
|
13184
|
-
const outputSchema = jsonSchema(
|
|
13037
|
+
const outputSchema = jsonSchema(schemaToExtractionOutputSchema(schema));
|
|
13185
13038
|
let result;
|
|
13186
13039
|
if (useFileContent) {
|
|
13187
13040
|
const filePart = await readFilePart(file);
|
|
@@ -13225,6 +13078,11 @@ async function extractStructuredData(input) {
|
|
|
13225
13078
|
let data;
|
|
13226
13079
|
if (useStructuredOutput) data = result.output;
|
|
13227
13080
|
else data = safeParseJSON(result.text);
|
|
13081
|
+
const validation = validateExtractedData(schema, data);
|
|
13082
|
+
if (!validation.success) return {
|
|
13083
|
+
success: false,
|
|
13084
|
+
error: validation.error
|
|
13085
|
+
};
|
|
13228
13086
|
const outputDir = path.resolve(aiexDir, config.extraction.outputDir.replace(".aiex/", ""));
|
|
13229
13087
|
await fs.mkdir(outputDir, { recursive: true });
|
|
13230
13088
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
@@ -13409,6 +13267,12 @@ const IMAGE_EXTENSIONS = new Set([
|
|
|
13409
13267
|
"bmp",
|
|
13410
13268
|
"svg"
|
|
13411
13269
|
]);
|
|
13270
|
+
const FILE_PART_EXTENSIONS = new Set([...IMAGE_EXTENSIONS, "pdf"]);
|
|
13271
|
+
function fail$1(message) {
|
|
13272
|
+
if (message) consola.error(message);
|
|
13273
|
+
outro("Failed!");
|
|
13274
|
+
process.exitCode = 1;
|
|
13275
|
+
}
|
|
13412
13276
|
async function ensureDatabaseReady(dbPath, schema) {
|
|
13413
13277
|
try {
|
|
13414
13278
|
await fs.access(dbPath);
|
|
@@ -13467,29 +13331,24 @@ const extractCommand = defineCommand({
|
|
|
13467
13331
|
const config = createMigrationConfig(process.cwd());
|
|
13468
13332
|
const aiexDir = path.dirname(config.schemaPath);
|
|
13469
13333
|
if (!args.text && !args.file) {
|
|
13470
|
-
|
|
13471
|
-
outro("Failed!");
|
|
13334
|
+
fail$1("Please provide text (-t) or a file (-f) to extract from");
|
|
13472
13335
|
return;
|
|
13473
13336
|
}
|
|
13474
13337
|
if (args.text && args.file) {
|
|
13475
|
-
|
|
13476
|
-
outro("Failed!");
|
|
13338
|
+
fail$1("-t and -f cannot be used together");
|
|
13477
13339
|
return;
|
|
13478
13340
|
}
|
|
13479
13341
|
const aiConfig = await readAIConfig(aiexDir);
|
|
13480
13342
|
if (!aiConfig) {
|
|
13481
|
-
|
|
13482
|
-
outro("Failed!");
|
|
13343
|
+
fail$1("AI configuration not found. Please configure AI settings in the Web interface first");
|
|
13483
13344
|
return;
|
|
13484
13345
|
}
|
|
13485
13346
|
if (!aiConfig.provider.apiKey) {
|
|
13486
|
-
|
|
13487
|
-
outro("Failed!");
|
|
13347
|
+
fail$1("API Key not configured. Please configure AI settings in the Web interface first");
|
|
13488
13348
|
return;
|
|
13489
13349
|
}
|
|
13490
13350
|
if (!aiConfig.provider.models?.length) {
|
|
13491
|
-
|
|
13492
|
-
outro("Failed!");
|
|
13351
|
+
fail$1("No models configured. Please add at least one model in AI Settings");
|
|
13493
13352
|
return;
|
|
13494
13353
|
}
|
|
13495
13354
|
let modelOverride;
|
|
@@ -13497,8 +13356,7 @@ const extractCommand = defineCommand({
|
|
|
13497
13356
|
const matched = aiConfig.provider.models.find((m) => m.name === args.model);
|
|
13498
13357
|
if (!matched) {
|
|
13499
13358
|
const available = aiConfig.provider.models.map((m) => m.name).join(", ");
|
|
13500
|
-
|
|
13501
|
-
outro("Failed!");
|
|
13359
|
+
fail$1(`Model "${args.model}" not found in configuration. Available models: ${available}`);
|
|
13502
13360
|
return;
|
|
13503
13361
|
}
|
|
13504
13362
|
modelOverride = matched;
|
|
@@ -13507,12 +13365,11 @@ const extractCommand = defineCommand({
|
|
|
13507
13365
|
let filePath;
|
|
13508
13366
|
if (args.file) {
|
|
13509
13367
|
const ext = path.extname(args.file).toLowerCase().replace(".", "");
|
|
13510
|
-
if (
|
|
13368
|
+
if (FILE_PART_EXTENSIONS.has(ext)) filePath = args.file;
|
|
13511
13369
|
else try {
|
|
13512
13370
|
text = await fs.readFile(args.file, "utf-8");
|
|
13513
13371
|
} catch {
|
|
13514
|
-
|
|
13515
|
-
outro("Failed!");
|
|
13372
|
+
fail$1(`Cannot read file: ${args.file}`);
|
|
13516
13373
|
return;
|
|
13517
13374
|
}
|
|
13518
13375
|
} else if (args.text) text = args.text;
|
|
@@ -13523,18 +13380,17 @@ const extractCommand = defineCommand({
|
|
|
13523
13380
|
const content = await fs.readFile(schemaPath, "utf-8");
|
|
13524
13381
|
schema = JSON.parse(content);
|
|
13525
13382
|
} catch {
|
|
13526
|
-
|
|
13527
|
-
outro("Failed!");
|
|
13383
|
+
fail$1(`Cannot read schema file: ${schemaName}.json`);
|
|
13528
13384
|
return;
|
|
13529
13385
|
}
|
|
13530
13386
|
try {
|
|
13531
|
-
JsonSchemaDefinitionSchema.parse(schema);
|
|
13387
|
+
schema = JsonSchemaDefinitionSchema.parse(schema);
|
|
13532
13388
|
} catch (e) {
|
|
13533
13389
|
if (e instanceof ZodError) {
|
|
13534
13390
|
consola.error(`Schema validation failed: ${schemaName}.json`);
|
|
13535
13391
|
for (const issue of e.issues) consola.error(` - ${issue.path.join(".")}: ${issue.message}`);
|
|
13536
13392
|
}
|
|
13537
|
-
|
|
13393
|
+
fail$1();
|
|
13538
13394
|
return;
|
|
13539
13395
|
}
|
|
13540
13396
|
const s = spinner();
|
|
@@ -13549,8 +13405,7 @@ const extractCommand = defineCommand({
|
|
|
13549
13405
|
});
|
|
13550
13406
|
if (!result.success) {
|
|
13551
13407
|
s.stop("Extraction failed");
|
|
13552
|
-
|
|
13553
|
-
outro("Failed!");
|
|
13408
|
+
fail$1(result.error || "Unknown error");
|
|
13554
13409
|
return;
|
|
13555
13410
|
}
|
|
13556
13411
|
s.stop("Extraction complete");
|
|
@@ -13562,8 +13417,7 @@ const extractCommand = defineCommand({
|
|
|
13562
13417
|
const dbError = await ensureDatabaseReady(config.databasePath, schema);
|
|
13563
13418
|
if (dbError) {
|
|
13564
13419
|
s2.stop("Database not ready");
|
|
13565
|
-
|
|
13566
|
-
outro("Failed!");
|
|
13420
|
+
fail$1(dbError);
|
|
13567
13421
|
return;
|
|
13568
13422
|
}
|
|
13569
13423
|
try {
|
|
@@ -13573,8 +13427,7 @@ const extractCommand = defineCommand({
|
|
|
13573
13427
|
if (insertResult.success) s2.stop(`Inserted into ${insertResult.tablesInserted.length} table(s)`);
|
|
13574
13428
|
else {
|
|
13575
13429
|
s2.stop("Database insert failed");
|
|
13576
|
-
|
|
13577
|
-
outro("Failed!");
|
|
13430
|
+
fail$1(insertResult.error || "Unknown error");
|
|
13578
13431
|
return;
|
|
13579
13432
|
}
|
|
13580
13433
|
} finally {
|
|
@@ -13582,8 +13435,7 @@ const extractCommand = defineCommand({
|
|
|
13582
13435
|
}
|
|
13583
13436
|
} catch (e) {
|
|
13584
13437
|
s2.stop("Database insert failed");
|
|
13585
|
-
|
|
13586
|
-
outro("Failed!");
|
|
13438
|
+
fail$1(e instanceof Error ? e.message : String(e));
|
|
13587
13439
|
return;
|
|
13588
13440
|
}
|
|
13589
13441
|
}
|
|
@@ -13591,9 +13443,27 @@ const extractCommand = defineCommand({
|
|
|
13591
13443
|
}
|
|
13592
13444
|
});
|
|
13593
13445
|
|
|
13446
|
+
//#endregion
|
|
13447
|
+
//#region schemas/table-schema.json
|
|
13448
|
+
var $id = "https://raw.githubusercontent.com/OSpoon/aiex-cli/main/app/cli/schemas/table-schema.json";
|
|
13449
|
+
|
|
13594
13450
|
//#endregion
|
|
13595
13451
|
//#region src/commands/schema.ts
|
|
13596
13452
|
const execFileAsync$1 = promisify(execFile);
|
|
13453
|
+
function fail(message) {
|
|
13454
|
+
if (message) consola.error(message);
|
|
13455
|
+
outro("Failed!");
|
|
13456
|
+
process.exitCode = 1;
|
|
13457
|
+
}
|
|
13458
|
+
async function writeJsonIfAbsent(filePath, data) {
|
|
13459
|
+
try {
|
|
13460
|
+
await fs.writeFile(filePath, `${JSON.stringify(data, null, 2)}\n`, { flag: "wx" });
|
|
13461
|
+
return "created";
|
|
13462
|
+
} catch (error) {
|
|
13463
|
+
if (error.code === "EEXIST") return "skipped";
|
|
13464
|
+
throw error;
|
|
13465
|
+
}
|
|
13466
|
+
}
|
|
13597
13467
|
async function generateFromFiles(schemaFiles, config) {
|
|
13598
13468
|
const result = parseAllSchemas(await Promise.all(schemaFiles.map(async (filePath) => {
|
|
13599
13469
|
return {
|
|
@@ -13611,17 +13481,18 @@ async function generateFromFiles(schemaFiles, config) {
|
|
|
13611
13481
|
consola.success(`Generated ${pc.cyan(".aiex/drizzle/schema.ts")} from ${schemaFiles.length} schema file(s)`);
|
|
13612
13482
|
return true;
|
|
13613
13483
|
}
|
|
13614
|
-
async function migrate(config) {
|
|
13484
|
+
async function migrate(config, migrationName) {
|
|
13615
13485
|
const helperPath = resolveHelperPath();
|
|
13616
|
-
const
|
|
13486
|
+
const helperArgs = [
|
|
13487
|
+
resolveTsxPath(),
|
|
13488
|
+
helperPath,
|
|
13489
|
+
config.drizzleSchemaPath,
|
|
13490
|
+
config.migrationsPath,
|
|
13491
|
+
config.databasePath
|
|
13492
|
+
];
|
|
13493
|
+
if (migrationName) helperArgs.push(migrationName);
|
|
13617
13494
|
try {
|
|
13618
|
-
const { stdout } = await execFileAsync$1(process.execPath,
|
|
13619
|
-
tsxPath,
|
|
13620
|
-
helperPath,
|
|
13621
|
-
config.drizzleSchemaPath,
|
|
13622
|
-
config.migrationsPath,
|
|
13623
|
-
config.databasePath
|
|
13624
|
-
], { cwd: process.cwd() });
|
|
13495
|
+
const { stdout } = await execFileAsync$1(process.execPath, helperArgs, { cwd: process.cwd() });
|
|
13625
13496
|
const result = JSON.parse(stdout.trim());
|
|
13626
13497
|
if (!result.success) {
|
|
13627
13498
|
consola.error("Failed to generate migration");
|
|
@@ -13862,9 +13733,11 @@ const schemaCommand = defineCommand({
|
|
|
13862
13733
|
"authorId"
|
|
13863
13734
|
]
|
|
13864
13735
|
};
|
|
13865
|
-
await
|
|
13866
|
-
await
|
|
13736
|
+
const userStatus = await writeJsonIfAbsent(path.join(config.schemaPath, "user.json"), userSchema);
|
|
13737
|
+
const postStatus = await writeJsonIfAbsent(path.join(config.schemaPath, "post.json"), postSchema);
|
|
13867
13738
|
consola.success(`Initialized ${pc.cyan(".aiex/")} with example schemas`);
|
|
13739
|
+
if (userStatus === "skipped") consola.warn(`${pc.cyan(".aiex/schema/user.json")} already exists, skipped`);
|
|
13740
|
+
if (postStatus === "skipped") consola.warn(`${pc.cyan(".aiex/schema/post.json")} already exists, skipped`);
|
|
13868
13741
|
consola.info("Example includes: User (with preferences has-one), Post (with comments has-many)");
|
|
13869
13742
|
outro("Run: aiex schema");
|
|
13870
13743
|
return;
|
|
@@ -13877,9 +13750,8 @@ const schemaCommand = defineCommand({
|
|
|
13877
13750
|
schemaFiles = [];
|
|
13878
13751
|
}
|
|
13879
13752
|
if (schemaFiles.length === 0) {
|
|
13880
|
-
consola.error(`No schema files found in ${pc.cyan(".aiex/schema/")}`);
|
|
13881
13753
|
consola.info("Use --init to initialize with an example schema");
|
|
13882
|
-
|
|
13754
|
+
fail(`No schema files found in ${pc.cyan(".aiex/schema/")}`);
|
|
13883
13755
|
return;
|
|
13884
13756
|
}
|
|
13885
13757
|
const s1 = spinner();
|
|
@@ -13887,7 +13759,7 @@ const schemaCommand = defineCommand({
|
|
|
13887
13759
|
const genOk = await generateFromFiles(schemaFiles, config);
|
|
13888
13760
|
s1.stop(genOk ? "Schema generated" : "Generation failed");
|
|
13889
13761
|
if (!genOk) {
|
|
13890
|
-
|
|
13762
|
+
fail();
|
|
13891
13763
|
return;
|
|
13892
13764
|
}
|
|
13893
13765
|
if (args.generate) {
|
|
@@ -13896,10 +13768,10 @@ const schemaCommand = defineCommand({
|
|
|
13896
13768
|
}
|
|
13897
13769
|
const s2 = spinner();
|
|
13898
13770
|
s2.start("Running migrations...");
|
|
13899
|
-
const migOk = await migrate(config);
|
|
13771
|
+
const migOk = await migrate(config, args.name);
|
|
13900
13772
|
s2.stop(migOk ? "Migrations applied" : "Migration failed");
|
|
13901
13773
|
if (!migOk) {
|
|
13902
|
-
|
|
13774
|
+
fail();
|
|
13903
13775
|
return;
|
|
13904
13776
|
}
|
|
13905
13777
|
outro("Done!");
|
|
@@ -13977,6 +13849,8 @@ function aiRoutes(config) {
|
|
|
13977
13849
|
//#endregion
|
|
13978
13850
|
//#region src/server/routes/data.ts
|
|
13979
13851
|
const FILE_REGEX = /\.json$/;
|
|
13852
|
+
const EXTRACTION_FILE_RE = /^[\w.-]+\.json$/;
|
|
13853
|
+
const TABLE_NAME_RE$1 = /^[a-z][a-z0-9_]*$/;
|
|
13980
13854
|
const TIMESTAMP_CLEANUP = /(\d{2})-(\d{2})-(\d{2})/;
|
|
13981
13855
|
const TIMESTAMP_TZ = /(\d{3})Z/;
|
|
13982
13856
|
function dataRoutes(config) {
|
|
@@ -14014,20 +13888,6 @@ function dataRoutes(config) {
|
|
|
14014
13888
|
return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
|
|
14015
13889
|
}
|
|
14016
13890
|
});
|
|
14017
|
-
app.get("/data/:name", async (c) => {
|
|
14018
|
-
const name$1 = c.req.param("name");
|
|
14019
|
-
const filePath = path.join(extractedDir, name$1);
|
|
14020
|
-
try {
|
|
14021
|
-
const content = await fs.readFile(filePath, "utf-8");
|
|
14022
|
-
return c.json({
|
|
14023
|
-
success: true,
|
|
14024
|
-
content,
|
|
14025
|
-
name: name$1
|
|
14026
|
-
});
|
|
14027
|
-
} catch {
|
|
14028
|
-
return c.json({ error: "Extraction result not found" }, 404);
|
|
14029
|
-
}
|
|
14030
|
-
});
|
|
14031
13891
|
app.get("/data/tables", async (c) => {
|
|
14032
13892
|
try {
|
|
14033
13893
|
const schemaDir = config.schemaPath;
|
|
@@ -14066,6 +13926,7 @@ function dataRoutes(config) {
|
|
|
14066
13926
|
});
|
|
14067
13927
|
app.get("/data/tables/:name", async (c) => {
|
|
14068
13928
|
const tableName = c.req.param("name");
|
|
13929
|
+
if (!TABLE_NAME_RE$1.test(tableName)) return c.json({ error: "Invalid table name" }, 400);
|
|
14069
13930
|
const sortField = c.req.query("sortField");
|
|
14070
13931
|
const sortOrder = c.req.query("sortOrder") || "asc";
|
|
14071
13932
|
let db;
|
|
@@ -14100,12 +13961,33 @@ function dataRoutes(config) {
|
|
|
14100
13961
|
db.close();
|
|
14101
13962
|
}
|
|
14102
13963
|
});
|
|
13964
|
+
app.get("/data/:name", async (c) => {
|
|
13965
|
+
const name$1 = c.req.param("name");
|
|
13966
|
+
if (name$1 !== path.basename(name$1) || !EXTRACTION_FILE_RE.test(name$1) || name$1.includes("..")) return c.json({ error: "Invalid extraction file name" }, 400);
|
|
13967
|
+
const filePath = path.join(extractedDir, name$1);
|
|
13968
|
+
try {
|
|
13969
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
13970
|
+
return c.json({
|
|
13971
|
+
success: true,
|
|
13972
|
+
content,
|
|
13973
|
+
name: name$1
|
|
13974
|
+
});
|
|
13975
|
+
} catch {
|
|
13976
|
+
return c.json({ error: "Extraction result not found" }, 404);
|
|
13977
|
+
}
|
|
13978
|
+
});
|
|
14103
13979
|
return app;
|
|
14104
13980
|
}
|
|
14105
13981
|
|
|
14106
13982
|
//#endregion
|
|
14107
13983
|
//#region src/server/routes/schema.ts
|
|
14108
13984
|
const execFileAsync = promisify(execFile);
|
|
13985
|
+
const SCHEMA_FILE_RE = /^[\w.-]+\.json$/;
|
|
13986
|
+
const TABLE_NAME_RE = /^[a-z][a-z0-9_]*$/;
|
|
13987
|
+
function resolveSchemaFile(schemaDir, name$1) {
|
|
13988
|
+
if (name$1 !== path.basename(name$1) || !SCHEMA_FILE_RE.test(name$1) || name$1.includes("..")) return null;
|
|
13989
|
+
return path.join(schemaDir, name$1);
|
|
13990
|
+
}
|
|
14109
13991
|
function schemaRoutes(config) {
|
|
14110
13992
|
const app = new Hono();
|
|
14111
13993
|
const schemaDir = config.schemaPath;
|
|
@@ -14118,8 +14000,8 @@ function schemaRoutes(config) {
|
|
|
14118
14000
|
return c.json(jsonFiles);
|
|
14119
14001
|
});
|
|
14120
14002
|
app.get("/schema/:name", async (c) => {
|
|
14121
|
-
const
|
|
14122
|
-
|
|
14003
|
+
const filePath = resolveSchemaFile(schemaDir, c.req.param("name"));
|
|
14004
|
+
if (!filePath) return c.json({ error: "Invalid schema file name" }, 400);
|
|
14123
14005
|
try {
|
|
14124
14006
|
const content = await fs.readFile(filePath, "utf-8");
|
|
14125
14007
|
return c.json(JSON.parse(content));
|
|
@@ -14128,8 +14010,8 @@ function schemaRoutes(config) {
|
|
|
14128
14010
|
}
|
|
14129
14011
|
});
|
|
14130
14012
|
app.post("/schema/:name", async (c) => {
|
|
14131
|
-
const
|
|
14132
|
-
|
|
14013
|
+
const filePath = resolveSchemaFile(schemaDir, c.req.param("name"));
|
|
14014
|
+
if (!filePath) return c.json({ error: "Invalid schema file name" }, 400);
|
|
14133
14015
|
try {
|
|
14134
14016
|
const body = await c.req.json();
|
|
14135
14017
|
await ensureDir();
|
|
@@ -14145,6 +14027,10 @@ function schemaRoutes(config) {
|
|
|
14145
14027
|
});
|
|
14146
14028
|
app.get("/prompt-snapshot/:name", async (c) => {
|
|
14147
14029
|
const name$1 = c.req.param("name");
|
|
14030
|
+
if (!TABLE_NAME_RE.test(name$1)) return c.json({
|
|
14031
|
+
success: false,
|
|
14032
|
+
error: "Invalid table name"
|
|
14033
|
+
}, 400);
|
|
14148
14034
|
const aiexDir = path.dirname(schemaDir);
|
|
14149
14035
|
const snapshotPath = path.join(aiexDir, "extracted", `${name$1}.prompt.md`);
|
|
14150
14036
|
try {
|
|
@@ -14161,8 +14047,8 @@ function schemaRoutes(config) {
|
|
|
14161
14047
|
}
|
|
14162
14048
|
});
|
|
14163
14049
|
app.delete("/schema/:name", async (c) => {
|
|
14164
|
-
const
|
|
14165
|
-
|
|
14050
|
+
const filePath = resolveSchemaFile(schemaDir, c.req.param("name"));
|
|
14051
|
+
if (!filePath) return c.json({ error: "Invalid schema file name" }, 400);
|
|
14166
14052
|
try {
|
|
14167
14053
|
await fs.unlink(filePath);
|
|
14168
14054
|
return c.json({ success: true });
|
|
@@ -14239,9 +14125,10 @@ function schemaRoutes(config) {
|
|
|
14239
14125
|
|
|
14240
14126
|
//#endregion
|
|
14241
14127
|
//#region src/server/index.ts
|
|
14128
|
+
const LOCAL_ORIGIN_RE = /^https?:\/\/(?:localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/;
|
|
14242
14129
|
function createApp(config, staticDir) {
|
|
14243
14130
|
const app = new Hono();
|
|
14244
|
-
app.use("*", cors());
|
|
14131
|
+
app.use("*", cors({ origin: (origin) => LOCAL_ORIGIN_RE.test(origin) ? origin : null }));
|
|
14245
14132
|
app.route("/api", schemaRoutes(config));
|
|
14246
14133
|
app.route("/api", aiRoutes(config));
|
|
14247
14134
|
app.route("/api", dataRoutes(config));
|
|
@@ -14328,7 +14215,7 @@ runMain(defineCommand({
|
|
|
14328
14215
|
meta: {
|
|
14329
14216
|
name,
|
|
14330
14217
|
version,
|
|
14331
|
-
description
|
|
14218
|
+
description
|
|
14332
14219
|
},
|
|
14333
14220
|
subCommands
|
|
14334
14221
|
}));
|