@mindexec/cli 0.2.340 → 0.2.342
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/codex-runtime.js +255 -31
- package/package.json +1 -1
- package/remote-hub.js +80 -2
- package/scripts/remote-fast-live-rate-smoke.mjs +19 -3
- package/scripts/remote-fast-mdm-browser-smoke.mjs +28 -2
- package/scripts/remote-hub-smoke.mjs +32 -2
- package/server.js +1363 -28
- package/wwwroot/_headers +50 -17
- package/wwwroot/assets/AdminDashboardPage-B2vz2Px9.css +1 -0
- package/wwwroot/assets/AdminDashboardPage-DpUfWSRs.js +1 -0
- package/wwwroot/assets/AppSidebar-CBqvLonm.js +1 -0
- package/wwwroot/assets/AuthPages-Cd5fYgU0.js +1 -0
- package/wwwroot/assets/AuthPages-DFGWKWuB.css +1 -0
- package/wwwroot/assets/CodePage-Bncc352E.css +1 -0
- package/wwwroot/assets/CodePage-D9-cUf4A.js +87 -0
- package/wwwroot/assets/CompanyCorePage-ChBnq1ve.css +1 -0
- package/wwwroot/assets/CompanyCorePage-D0byTW77.js +13 -0
- package/wwwroot/assets/ExecutionModePage-DtMDlqYc.js +18 -0
- package/wwwroot/assets/ExecutionModePage-TLuld9l3.css +1 -0
- package/wwwroot/assets/LaunchLeadCapture-CiRI1shz.css +1 -0
- package/wwwroot/assets/LaunchLeadCapture-CqeoHfvb.js +1 -0
- package/wwwroot/assets/MarketingHome-DPzaYzA_.css +1 -0
- package/wwwroot/assets/MarketingHome-DbWyEAya.js +1 -0
- package/wwwroot/assets/MindCanvas-CME1KpAo.js +48 -0
- package/wwwroot/assets/MindCanvas-DiQlUDJu.css +1 -0
- package/wwwroot/assets/PlanMasterPage-CJ36rep-.css +1 -0
- package/wwwroot/assets/PlanMasterPage-mhlZZK19.js +4 -0
- package/wwwroot/assets/PricingPage-Cg_0i_ZR.css +1 -0
- package/wwwroot/assets/PricingPage-zVu8-CrF.js +1 -0
- package/wwwroot/assets/ToolPages-DIB187pZ.css +1 -0
- package/wwwroot/assets/ToolPages-DTSqKzQd.js +28 -0
- package/wwwroot/assets/YouTubeSearchPage-IPPa_BIH.css +1 -0
- package/wwwroot/assets/YouTubeSearchPage-xGiaLNqk.js +4 -0
- package/wwwroot/assets/app-runtime-xD2Z3NdN.js +1 -0
- package/wwwroot/assets/canvas-runtime-D1gfvqKp.js +44 -0
- package/wwwroot/assets/code-agent-runtime-B5PPZd1t.js +74 -0
- package/wwwroot/assets/executionModeSettings-NJqurj-o.js +1 -0
- package/wwwroot/assets/index-CP_xejf2.css +1 -0
- package/wwwroot/assets/index-CZS-9WFu.js +2 -0
- package/wwwroot/assets/marketingTools-DN_rnHeB.js +4 -0
- package/wwwroot/assets/mindCanvasSearchWorker-BzPMsHOB.js +1 -0
- package/wwwroot/assets/mindexecution-mindcanvas.png +0 -0
- package/wwwroot/assets/mindexecution-prod-home-current.png +0 -0
- package/wwwroot/assets/mindexecution-prod-pricing-current.png +0 -0
- package/wwwroot/assets/pricingCheckoutShell-O-DnwmbU.js +1 -0
- package/wwwroot/assets/runtimeSettingsPersistenceProjection-BoNWmYjU.js +1 -0
- package/wwwroot/assets/storage-CGDupGH4.js +1 -0
- package/wwwroot/assets/supabaseAuthAdapter-C3z334Qw.js +44 -0
- package/wwwroot/assets/toolHandoff-D5e5f7t5.js +4 -0
- package/wwwroot/assets/vendor-icons-oiW_NVNO.js +681 -0
- package/wwwroot/assets/vendor-msgpack-BE8aAsr3.js +1 -0
- package/wwwroot/assets/vendor-react-BXzpOyCS.js +40 -0
- package/wwwroot/favicon.svg +7 -0
- package/wwwroot/index.html +22 -736
- package/wwwroot/manifest.webmanifest +18 -21
- package/wwwroot/robots.txt +1 -1
- package/wwwroot/service-worker.js +5 -31
- package/wwwroot/sitemap.xml +21 -9
- package/wwwroot/MindExecution.Web.styles.css +0 -3
- package/wwwroot/_content/MindExecution.Plugins.Admin/css/admin-dashboard.css +0 -546
- package/wwwroot/_content/MindExecution.Plugins.Directory/MindExecution.Plugins.Directory.u7utcng611.bundle.scp.css +0 -7
- package/wwwroot/_content/MindExecution.Plugins.Directory/background.png +0 -0
- package/wwwroot/_content/MindExecution.Plugins.Directory/directory-manager.js +0 -202
- package/wwwroot/_content/MindExecution.Plugins.Directory/exampleJsInterop.js +0 -6
- package/wwwroot/_content/MindExecution.Plugins.YouTube/css/youtube-search.css +0 -251
- package/wwwroot/_content/MindExecution.Shared/MindExecution.Shared.wsano1j4wp.bundle.scp.css +0 -4
- package/wwwroot/_content/MindExecution.Shared/css/admin-dashboard.css +0 -559
- package/wwwroot/_content/MindExecution.Shared/css/app.css +0 -1
- package/wwwroot/_content/MindExecution.Shared/css/mind-map-overrides.css +0 -3705
- package/wwwroot/_content/MindExecution.Shared/fonts/NotoSansKR-Bold.ttf +0 -0
- package/wwwroot/_content/MindExecution.Shared/fonts/NotoSansKR-Regular.ttf +0 -0
- package/wwwroot/_content/MindExecution.Shared/js/agent-visualization.js +0 -359
- package/wwwroot/_content/MindExecution.Shared/js/background-themes.js +0 -1631
- package/wwwroot/_content/MindExecution.Shared/js/code-master.js +0 -8316
- package/wwwroot/_content/MindExecution.Shared/js/file-system-helper.js +0 -639
- package/wwwroot/_content/MindExecution.Shared/js/helpers/InfiniteGridHelper.js +0 -109
- package/wwwroot/_content/MindExecution.Shared/js/marked.min.js +0 -69
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +0 -12909
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js.backup +0 -1059
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +0 -24635
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-dev-guards.js +0 -325
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-dnd.js +0 -1491
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-dnd.js.bak +0 -434
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-glow-shader.js +0 -260
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-interactions.js +0 -7829
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-plan-worker.js +0 -160
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-renderer.js +0 -10400
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-logic-workers.js +0 -977
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-menu-manager.js +0 -1531
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-multi-select.js +0 -1716
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-node-search-worker.js +0 -554
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-nodes.js +0 -4578
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-object-manager.js +0 -489
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-object-manager.js.backup +0 -372
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-pipeline.js +0 -2203
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-text-lod-system.js +0 -646
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-text-overlay-v2.js +0 -4735
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-texture-factory.js +0 -2383
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-texture-factory.js.backup +0 -1258
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-visibility-worker.js +0 -890
- package/wwwroot/_content/MindExecution.Shared/js/mindmap-toolbar.js +0 -639
- package/wwwroot/_content/MindExecution.Shared/js/native-drop-handler.js +0 -170
- package/wwwroot/_content/MindExecution.Shared/js/plan-master.js +0 -788
- package/wwwroot/_content/MindExecution.Shared/js/renderers/CSS3DRenderer.js +0 -90
- package/wwwroot/_content/MindExecution.Shared/js/texture-worker-manager.js +0 -188
- package/wwwroot/_content/MindExecution.Shared/js/texture-worker.js +0 -208
- package/wwwroot/_content/MindExecution.Shared/js/three.min.js +0 -6
- package/wwwroot/_content/MindExecution.Shared/js/titlebar-handler.js +0 -191
- package/wwwroot/_content/MindExecution.Shared/js/token-manager.js +0 -37
- package/wwwroot/_content/MindExecution.Shared/js/token-worker.js +0 -28
- package/wwwroot/_content/MindExecution.Shared/js/troika-bundle.js +0 -5626
- package/wwwroot/_content/MindExecution.Shared/js/troika-bundle.js.map +0 -7
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/css/all.min.css +0 -9
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-brands-400.ttf +0 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-brands-400.woff2 +0 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-regular-400.ttf +0 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-regular-400.woff2 +0 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-solid-900.ttf +0 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-solid-900.woff2 +0 -0
- package/wwwroot/_content/MindExecution.Shared/models/all-MiniLM-L6-v2-quantized.onnx +0 -0
- package/wwwroot/_content/MindExecution.Shared/models/vocab.txt +0 -30522
- package/wwwroot/_framework/Google.Protobuf.9h59ukbel7.dll +0 -0
- package/wwwroot/_framework/Markdig.d1j7v41cl1.dll +0 -0
- package/wwwroot/_framework/MessagePack.Annotations.l6qv48kgpt.dll +0 -0
- package/wwwroot/_framework/MessagePack.eqoptzx9d5.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Authorization.k7dsih5y5g.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Components.6nyje9sa0g.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Components.Authorization.iycd6unprw.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Components.Web.487u3twia4.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Components.WebAssembly.d0gcnmlxxz.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Metadata.h4yevl9adi.dll +0 -0
- package/wwwroot/_framework/Microsoft.CSharp.8bsm8vx6su.dll +0 -0
- package/wwwroot/_framework/Microsoft.Data.Sqlite.jdlxgv2jtg.dll +0 -0
- package/wwwroot/_framework/Microsoft.EntityFrameworkCore.4gjazp7kjf.dll +0 -0
- package/wwwroot/_framework/Microsoft.EntityFrameworkCore.Abstractions.gocudnvz7b.dll +0 -0
- package/wwwroot/_framework/Microsoft.EntityFrameworkCore.Relational.lt4rsvinuo.dll +0 -0
- package/wwwroot/_framework/Microsoft.EntityFrameworkCore.Sqlite.69luj0fa9r.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Caching.Abstractions.364t4jh3zz.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Caching.Memory.izlxhpzosu.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Configuration.8zq7hh41o7.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Configuration.Abstractions.8if74zs6ea.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Configuration.Json.duvlngw8i0.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.DependencyInjection.Abstractions.t2hh9kvx0o.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.DependencyInjection.n4tg99oy8l.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.DependencyModel.h0d06ixk3e.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Logging.Abstractions.rl32bkx2sd.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Logging.dlht1xei0t.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Options.qeunebioml.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Primitives.18cr6vnuuz.dll +0 -0
- package/wwwroot/_framework/Microsoft.IO.RecyclableMemoryStream.r915vovvw4.dll +0 -0
- package/wwwroot/_framework/Microsoft.IdentityModel.Abstractions.1ejljk3erv.dll +0 -0
- package/wwwroot/_framework/Microsoft.IdentityModel.JsonWebTokens.1596zr8gne.dll +0 -0
- package/wwwroot/_framework/Microsoft.IdentityModel.Logging.229uyvpgio.dll +0 -0
- package/wwwroot/_framework/Microsoft.IdentityModel.Tokens.9sibtajc9f.dll +0 -0
- package/wwwroot/_framework/Microsoft.JSInterop.WebAssembly.ryia5gxiad.dll +0 -0
- package/wwwroot/_framework/Microsoft.JSInterop.ew9vz9o332.dll +0 -0
- package/wwwroot/_framework/Microsoft.ML.OnnxRuntime.w9deo1m5ss.dll +0 -0
- package/wwwroot/_framework/Microsoft.ML.Tokenizers.cm2vuv2z61.dll +0 -0
- package/wwwroot/_framework/Microsoft.NET.StringTools.3qbrf4v2ki.dll +0 -0
- package/wwwroot/_framework/MimeMapping.og9ys58ylm.dll +0 -0
- package/wwwroot/_framework/MindExecution.Core.y7ffihhajj.dll +0 -0
- package/wwwroot/_framework/MindExecution.Kernel.l5y3qroa7p.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.Admin.uuf238xa0h.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.Business.nyr3v25v48.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.Concept.l9z9tx9svt.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.Directory.ju87t8h3zs.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.PlanMaster.krn3jgvjpa.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.YouTube.5m53srfud6.dll +0 -0
- package/wwwroot/_framework/MindExecution.Shared.ojp3psugsm.dll +0 -0
- package/wwwroot/_framework/MindExecution.Web.82k6ktlkfg.dll +0 -0
- package/wwwroot/_framework/Newtonsoft.Json.a56zs13vug.dll +0 -0
- package/wwwroot/_framework/SQLitePCLRaw.batteries_v2.rrd1nzawpp.dll +0 -0
- package/wwwroot/_framework/SQLitePCLRaw.core.1dxloztpfz.dll +0 -0
- package/wwwroot/_framework/SQLitePCLRaw.provider.e_sqlite3.oekyzl53i1.dll +0 -0
- package/wwwroot/_framework/Supabase.Core.s1pkj4aj0l.dll +0 -0
- package/wwwroot/_framework/Supabase.Functions.qz4nu782sg.dll +0 -0
- package/wwwroot/_framework/Supabase.Gotrue.twah27pkik.dll +0 -0
- package/wwwroot/_framework/Supabase.Postgrest.gmuuv369ih.dll +0 -0
- package/wwwroot/_framework/Supabase.Realtime.ox3kchdy3w.dll +0 -0
- package/wwwroot/_framework/Supabase.Storage.fnjnepaowr.dll +0 -0
- package/wwwroot/_framework/Supabase.azmaw5pgcz.dll +0 -0
- package/wwwroot/_framework/System.Collections.23yxgetbju.dll +0 -0
- package/wwwroot/_framework/System.Collections.Concurrent.vow3rm1dku.dll +0 -0
- package/wwwroot/_framework/System.Collections.Immutable.ap9596utv5.dll +0 -0
- package/wwwroot/_framework/System.Collections.NonGeneric.npjkaz40oc.dll +0 -0
- package/wwwroot/_framework/System.Collections.Specialized.ugkjbs6p02.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.Annotations.clwo0z2oyu.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.Primitives.end4v0xe2c.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.TypeConverter.tgtp5sm4iv.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.wupoltkk1t.dll +0 -0
- package/wwwroot/_framework/System.Console.9dik0wogo2.dll +0 -0
- package/wwwroot/_framework/System.Data.Common.4v8jejsiu0.dll +0 -0
- package/wwwroot/_framework/System.Diagnostics.DiagnosticSource.e2q75ondtq.dll +0 -0
- package/wwwroot/_framework/System.Diagnostics.Process.9736yjnxs8.dll +0 -0
- package/wwwroot/_framework/System.Diagnostics.TraceSource.h9al53gbbw.dll +0 -0
- package/wwwroot/_framework/System.Diagnostics.Tracing.h4bcp2fo98.dll +0 -0
- package/wwwroot/_framework/System.Drawing.64oovy8qts.dll +0 -0
- package/wwwroot/_framework/System.Drawing.Primitives.o6jiqpgbgl.dll +0 -0
- package/wwwroot/_framework/System.Formats.Asn1.rylx5ipd40.dll +0 -0
- package/wwwroot/_framework/System.IO.Compression.iceabaupns.dll +0 -0
- package/wwwroot/_framework/System.IO.Pipelines.uw8csd3mlz.dll +0 -0
- package/wwwroot/_framework/System.IdentityModel.Tokens.Jwt.t67es60z5b.dll +0 -0
- package/wwwroot/_framework/System.Linq.Expressions.ty95ava37f.dll +0 -0
- package/wwwroot/_framework/System.Linq.Queryable.hs2195jrwy.dll +0 -0
- package/wwwroot/_framework/System.Linq.hssodjwmlf.dll +0 -0
- package/wwwroot/_framework/System.Memory.1k78n7wdxb.dll +0 -0
- package/wwwroot/_framework/System.Net.Http.3br8rfql4c.dll +0 -0
- package/wwwroot/_framework/System.Net.Http.Json.860wbh17d8.dll +0 -0
- package/wwwroot/_framework/System.Net.NetworkInformation.e3wr00853o.dll +0 -0
- package/wwwroot/_framework/System.Net.Ping.r5cw4mf1a4.dll +0 -0
- package/wwwroot/_framework/System.Net.Primitives.ksxwiwlvhu.dll +0 -0
- package/wwwroot/_framework/System.Net.WebSockets.6rt3n3gl2q.dll +0 -0
- package/wwwroot/_framework/System.Net.WebSockets.Client.z3usrzo7rz.dll +0 -0
- package/wwwroot/_framework/System.Numerics.Tensors.0c7z4mt3on.dll +0 -0
- package/wwwroot/_framework/System.Numerics.Vectors.lbdzx8reja.dll +0 -0
- package/wwwroot/_framework/System.ObjectModel.yct1gdirzf.dll +0 -0
- package/wwwroot/_framework/System.Private.CoreLib.c1dbswx1b2.dll +0 -0
- package/wwwroot/_framework/System.Private.Uri.zp9kmg0z93.dll +0 -0
- package/wwwroot/_framework/System.Private.Xml.Linq.lgv2n0akl4.dll +0 -0
- package/wwwroot/_framework/System.Private.Xml.dpsk8g304y.dll +0 -0
- package/wwwroot/_framework/System.Reactive.t3fuon548l.dll +0 -0
- package/wwwroot/_framework/System.Reflection.Emit.ILGeneration.1tcuz2cmbk.dll +0 -0
- package/wwwroot/_framework/System.Reflection.Emit.Lightweight.ddt2wylovg.dll +0 -0
- package/wwwroot/_framework/System.Reflection.Emit.d8vkadiwhg.dll +0 -0
- package/wwwroot/_framework/System.Reflection.Primitives.cpsl71xd1z.dll +0 -0
- package/wwwroot/_framework/System.Runtime.InteropServices.31vjgsfk1o.dll +0 -0
- package/wwwroot/_framework/System.Runtime.InteropServices.JavaScript.pn2wvizzet.dll +0 -0
- package/wwwroot/_framework/System.Runtime.InteropServices.RuntimeInformation.l5rk496q70.dll +0 -0
- package/wwwroot/_framework/System.Runtime.Intrinsics.0zee9qcqfy.dll +0 -0
- package/wwwroot/_framework/System.Runtime.Loader.xw2jr9wl92.dll +0 -0
- package/wwwroot/_framework/System.Runtime.Numerics.ezj1dfyvbj.dll +0 -0
- package/wwwroot/_framework/System.Runtime.Serialization.Formatters.0y019e9zkr.dll +0 -0
- package/wwwroot/_framework/System.Runtime.Serialization.Primitives.bia5wb62c8.dll +0 -0
- package/wwwroot/_framework/System.Runtime.h9cduidfkh.dll +0 -0
- package/wwwroot/_framework/System.Security.Claims.2r18wim2rl.dll +0 -0
- package/wwwroot/_framework/System.Security.Cryptography.qqgybpoucx.dll +0 -0
- package/wwwroot/_framework/System.Text.Encoding.Extensions.9t3hs6kyll.dll +0 -0
- package/wwwroot/_framework/System.Text.Encodings.Web.wftjfh2crk.dll +0 -0
- package/wwwroot/_framework/System.Text.Json.0v0qgmri0w.dll +0 -0
- package/wwwroot/_framework/System.Text.RegularExpressions.cvkox11l6l.dll +0 -0
- package/wwwroot/_framework/System.Threading.Channels.419493szqu.dll +0 -0
- package/wwwroot/_framework/System.Threading.Thread.xhmys87xh5.dll +0 -0
- package/wwwroot/_framework/System.Threading.b66vzsz9g1.dll +0 -0
- package/wwwroot/_framework/System.Transactions.Local.7zfffdvnwf.dll +0 -0
- package/wwwroot/_framework/System.Web.HttpUtility.9up6xfbtuq.dll +0 -0
- package/wwwroot/_framework/System.Xml.Linq.n5rzv9nbf7.dll +0 -0
- package/wwwroot/_framework/System.Xml.ReaderWriter.ag8pilllob.dll +0 -0
- package/wwwroot/_framework/System.Xml.XDocument.sn51jas17n.dll +0 -0
- package/wwwroot/_framework/System.brmz7yk5qh.dll +0 -0
- package/wwwroot/_framework/Websocket.Client.vapounvmnl.dll +0 -0
- package/wwwroot/_framework/blazor.boot.json +0 -305
- package/wwwroot/_framework/blazor.webassembly.js +0 -1
- package/wwwroot/_framework/dotnet.js +0 -4
- package/wwwroot/_framework/dotnet.native.boem75ye5i.wasm +0 -0
- package/wwwroot/_framework/dotnet.native.qc8g39g30v.js +0 -16
- package/wwwroot/_framework/dotnet.runtime.opaiwunc3t.js +0 -4
- package/wwwroot/_framework/icudt_CJK.tjcz0u77k5.dat +0 -0
- package/wwwroot/_framework/icudt_EFIGS.tptq2av103.dat +0 -0
- package/wwwroot/_framework/icudt_no_CJK.lfu7j35m59.dat +0 -0
- package/wwwroot/_framework/netstandard.yvr3prsx0x.dll +0 -0
- package/wwwroot/appsettings.json +0 -83
- package/wwwroot/icon-192.png +0 -0
- package/wwwroot/icon-512.png +0 -0
- package/wwwroot/js/marketing-tool.js +0 -180
- package/wwwroot/service-worker-assets.js +0 -857
package/server.js
CHANGED
|
@@ -1588,8 +1588,15 @@ const CONTENT_TYPE_BY_EXTENSION = new Map([
|
|
|
1588
1588
|
['.mov', 'video/quicktime'],
|
|
1589
1589
|
['.m4v', 'video/mp4'],
|
|
1590
1590
|
['.pdf', 'application/pdf'],
|
|
1591
|
-
['.
|
|
1592
|
-
['.
|
|
1591
|
+
['.js', 'text/javascript; charset=utf-8'],
|
|
1592
|
+
['.mjs', 'text/javascript; charset=utf-8'],
|
|
1593
|
+
['.css', 'text/css; charset=utf-8'],
|
|
1594
|
+
['.html', 'text/html; charset=utf-8'],
|
|
1595
|
+
['.txt', 'text/plain; charset=utf-8'],
|
|
1596
|
+
['.json', 'application/json; charset=utf-8'],
|
|
1597
|
+
['.map', 'application/json; charset=utf-8'],
|
|
1598
|
+
['.webmanifest', 'application/manifest+json; charset=utf-8'],
|
|
1599
|
+
['.wasm', 'application/wasm']
|
|
1593
1600
|
]);
|
|
1594
1601
|
|
|
1595
1602
|
function detectContentTypeFromHeader(header) {
|
|
@@ -2000,6 +2007,47 @@ app.get('/api/assets/resolve', async (req, res) => {
|
|
|
2000
2007
|
});
|
|
2001
2008
|
});
|
|
2002
2009
|
|
|
2010
|
+
async function trySendPackagedWebAppAsset(req, res, mountPath) {
|
|
2011
|
+
if (!WEB_APP_ROOT || !['GET', 'HEAD'].includes(String(req.method || '').toUpperCase())) {
|
|
2012
|
+
return false;
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
let requestPath = getMountedAssetRequestPath(req, mountPath);
|
|
2016
|
+
try {
|
|
2017
|
+
requestPath = decodeURIComponent(requestPath);
|
|
2018
|
+
} catch {
|
|
2019
|
+
return false;
|
|
2020
|
+
}
|
|
2021
|
+
|
|
2022
|
+
if (!requestPath || requestPath.includes('\0')) {
|
|
2023
|
+
return false;
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
const packagedAssetsRoot = path.resolve(WEB_APP_ROOT, String(mountPath || '').replace(/^\/+/, ''));
|
|
2027
|
+
const packagedAssetPath = path.resolve(packagedAssetsRoot, requestPath);
|
|
2028
|
+
if (!isPathWithin(packagedAssetsRoot, packagedAssetPath)) {
|
|
2029
|
+
return false;
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
let stats = null;
|
|
2033
|
+
try {
|
|
2034
|
+
stats = await fs.stat(packagedAssetPath);
|
|
2035
|
+
} catch {
|
|
2036
|
+
return false;
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
if (!stats.isFile()) {
|
|
2040
|
+
return false;
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
await sendResolvedAssetFile(req, res, packagedAssetPath, {
|
|
2044
|
+
notFoundMessage: 'Web app asset not found',
|
|
2045
|
+
errorScope: 'web',
|
|
2046
|
+
cacheControl: 'public, max-age=31536000, immutable'
|
|
2047
|
+
});
|
|
2048
|
+
return true;
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2003
2051
|
// Static file serving for assets (direct image loading - bypasses base64 encoding)
|
|
2004
2052
|
// This allows browsers to directly fetch images via http://127.0.0.1:5147/assets/filename.png
|
|
2005
2053
|
app.use('/assets', async (req, res, next) => {
|
|
@@ -2034,11 +2082,15 @@ app.use('/assets', async (req, res, next) => {
|
|
|
2034
2082
|
normalizedRequestPath,
|
|
2035
2083
|
['.png', '.jpg', '.jpeg', '.webp', '.gif', '.bmp', '.svg', '.mp4', '.webm', '.mov']
|
|
2036
2084
|
);
|
|
2037
|
-
}
|
|
2038
|
-
|
|
2039
|
-
if (!resolvedPath) {
|
|
2040
|
-
|
|
2041
|
-
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
if (!resolvedPath) {
|
|
2088
|
+
if (await trySendPackagedWebAppAsset(req, res, '/assets')) {
|
|
2089
|
+
return;
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
return res.status(404).json({ error: 'Asset not found' });
|
|
2093
|
+
}
|
|
2042
2094
|
|
|
2043
2095
|
return sendResolvedAssetFile(req, res, resolvedPath, {
|
|
2044
2096
|
notFoundMessage: 'Asset not found',
|
|
@@ -2138,6 +2190,13 @@ const PROTECTED_BRIDGE_ROUTES = [
|
|
|
2138
2190
|
{ method: 'POST', exact: '/api/dir/delete' },
|
|
2139
2191
|
{ method: 'POST', prefix: '/api/assets/' },
|
|
2140
2192
|
{ method: 'POST', exact: '/api/local-files/register' },
|
|
2193
|
+
{ method: 'POST', exact: '/api/evidence/save' },
|
|
2194
|
+
{ method: 'POST', exact: '/api/concept/define-composite' },
|
|
2195
|
+
{ method: 'GET', exact: '/api/concept/status' },
|
|
2196
|
+
{ method: 'GET', exact: '/api/concept/row' },
|
|
2197
|
+
{ method: 'GET', exact: '/api/concept/sqlite/row' },
|
|
2198
|
+
{ method: 'GET', exact: '/api/concept/embed/readiness' },
|
|
2199
|
+
{ method: 'POST', exact: '/api/concept/embed' },
|
|
2141
2200
|
{ method: 'POST', prefix: '/api/browser/act' },
|
|
2142
2201
|
{ method: 'GET', prefix: '/api/company-core/' },
|
|
2143
2202
|
{ method: 'POST', prefix: '/api/company-core/' },
|
|
@@ -2661,6 +2720,39 @@ function buildRemoteFrameBinaryPacket(frameEvent) {
|
|
|
2661
2720
|
}
|
|
2662
2721
|
|
|
2663
2722
|
const frame = frameEvent.frame || {};
|
|
2723
|
+
const droppedByAgent = Number(frame.droppedByAgent ?? frameEvent.droppedByAgent ?? 0);
|
|
2724
|
+
const dirtyRectSource = frame.dirtyRectCount
|
|
2725
|
+
?? frame.dirtyRegionCount
|
|
2726
|
+
?? frameEvent.dirtyRectCount
|
|
2727
|
+
?? frameEvent.dirtyRegionCount
|
|
2728
|
+
?? (Array.isArray(frame.dirtyRects) ? frame.dirtyRects.length : undefined)
|
|
2729
|
+
?? (Array.isArray(frameEvent.dirtyRects) ? frameEvent.dirtyRects.length : undefined)
|
|
2730
|
+
?? 0;
|
|
2731
|
+
const dirtyRectCount = Number(dirtyRectSource);
|
|
2732
|
+
const dirtyRatioSource = frame.dirtyPixelRatio
|
|
2733
|
+
?? frame.dirtyRatio
|
|
2734
|
+
?? frame.dirtyAreaRatio
|
|
2735
|
+
?? frame.changedPixelRatio
|
|
2736
|
+
?? frameEvent.dirtyPixelRatio
|
|
2737
|
+
?? frameEvent.dirtyRatio
|
|
2738
|
+
?? frameEvent.dirtyAreaRatio
|
|
2739
|
+
?? frameEvent.changedPixelRatio
|
|
2740
|
+
?? 0;
|
|
2741
|
+
const dirtyRatioNumber = Number(dirtyRatioSource);
|
|
2742
|
+
const normalizedDirtyPixelRatio = Number.isFinite(dirtyRatioNumber) && dirtyRatioNumber >= 0
|
|
2743
|
+
? dirtyRatioNumber <= 1
|
|
2744
|
+
? dirtyRatioNumber
|
|
2745
|
+
: dirtyRatioNumber <= 100
|
|
2746
|
+
? dirtyRatioNumber / 100
|
|
2747
|
+
: 1
|
|
2748
|
+
: 0;
|
|
2749
|
+
const deltaValue = frame.deltaEncoded ?? frame.isDeltaEncoded ?? frame.deltaFrame
|
|
2750
|
+
?? frameEvent.deltaEncoded ?? frameEvent.isDeltaEncoded ?? frameEvent.deltaFrame;
|
|
2751
|
+
const deltaEncoded = typeof deltaValue === 'boolean'
|
|
2752
|
+
? deltaValue
|
|
2753
|
+
: typeof deltaValue === 'number'
|
|
2754
|
+
? deltaValue > 0
|
|
2755
|
+
: /^(1|true|yes|on|delta)$/i.test(String(deltaValue || '').trim());
|
|
2664
2756
|
const metadata = {
|
|
2665
2757
|
type: 'remote.frame.binary',
|
|
2666
2758
|
kind: frameEvent.kind || 'live',
|
|
@@ -2678,7 +2770,16 @@ function buildRemoteFrameBinaryPacket(frameEvent) {
|
|
|
2678
2770
|
transport: frame.transport || '',
|
|
2679
2771
|
contentHash: frame.contentHash || '',
|
|
2680
2772
|
captureMs: Number(frame.captureMs || 0) || 0,
|
|
2681
|
-
sameContentStreak: Number(frame.sameContentStreak || 0) || 0
|
|
2773
|
+
sameContentStreak: Number(frame.sameContentStreak || 0) || 0,
|
|
2774
|
+
droppedByAgent: Number.isFinite(droppedByAgent) && droppedByAgent >= 0
|
|
2775
|
+
? Math.round(droppedByAgent)
|
|
2776
|
+
: 0,
|
|
2777
|
+
dirtyRectCount: Number.isFinite(dirtyRectCount) && dirtyRectCount >= 0
|
|
2778
|
+
? Math.round(dirtyRectCount)
|
|
2779
|
+
: 0,
|
|
2780
|
+
dirtyPixelRatio: normalizedDirtyPixelRatio,
|
|
2781
|
+
codec: String(frame.codec || frame.encoder || frame.encoding || frameEvent.codec || frameEvent.encoder || frameEvent.encoding || '').slice(0, 80),
|
|
2782
|
+
deltaEncoded
|
|
2682
2783
|
};
|
|
2683
2784
|
const metaBuffer = Buffer.from(JSON.stringify(metadata), 'utf8');
|
|
2684
2785
|
const header = Buffer.allocUnsafe(4);
|
|
@@ -10958,7 +11059,7 @@ function scoreSearchResult(query, item) {
|
|
|
10958
11059
|
return score;
|
|
10959
11060
|
}
|
|
10960
11061
|
|
|
10961
|
-
function filterSearchResults(query, items, maxResults) {
|
|
11062
|
+
function filterSearchResults(query, items, maxResults) {
|
|
10962
11063
|
const clampedMax = Math.max(1, Math.min(Number(maxResults) || 5, 8));
|
|
10963
11064
|
const list = Array.isArray(items) ? items : [];
|
|
10964
11065
|
if (!requiresSearchRelevanceFilter(query)) {
|
|
@@ -10969,10 +11070,29 @@ function filterSearchResults(query, items, maxResults) {
|
|
|
10969
11070
|
.map(item => ({ item, score: scoreSearchResult(query, item) }))
|
|
10970
11071
|
.filter(entry => entry.score > 0)
|
|
10971
11072
|
.sort((a, b) => b.score - a.score)
|
|
10972
|
-
.map(entry => entry.item)
|
|
10973
|
-
.slice(0, clampedMax);
|
|
10974
|
-
}
|
|
10975
|
-
|
|
11073
|
+
.map(entry => entry.item)
|
|
11074
|
+
.slice(0, clampedMax);
|
|
11075
|
+
}
|
|
11076
|
+
|
|
11077
|
+
function extractDirectSearchUrl(query) {
|
|
11078
|
+
const match = String(query || '').match(/https?:\/\/[^\s"'<>),]+/i);
|
|
11079
|
+
if (!match) {
|
|
11080
|
+
return '';
|
|
11081
|
+
}
|
|
11082
|
+
|
|
11083
|
+
try {
|
|
11084
|
+
const parsed = new URL(match[0]);
|
|
11085
|
+
if (parsed.protocol === 'http:' || parsed.protocol === 'https:') {
|
|
11086
|
+
return parsed.toString();
|
|
11087
|
+
}
|
|
11088
|
+
} catch {
|
|
11089
|
+
return '';
|
|
11090
|
+
}
|
|
11091
|
+
|
|
11092
|
+
return '';
|
|
11093
|
+
}
|
|
11094
|
+
|
|
11095
|
+
async function searchBing(query, maxResults = 5) {
|
|
10976
11096
|
const clampedMax = Math.max(1, Math.min(Number(maxResults) || 5, 8));
|
|
10977
11097
|
const searchQuery = expandSearchQuery(query);
|
|
10978
11098
|
const url = `https://www.bing.com/search?q=${encodeURIComponent(searchQuery)}`;
|
|
@@ -10998,8 +11118,22 @@ async function searchBing(query, maxResults = 5) {
|
|
|
10998
11118
|
};
|
|
10999
11119
|
}
|
|
11000
11120
|
|
|
11001
|
-
async function searchWeb(query, maxResults = 5) {
|
|
11121
|
+
async function searchWeb(query, maxResults = 5) {
|
|
11002
11122
|
const searchQuery = expandSearchQuery(query);
|
|
11123
|
+
const directUrl = extractDirectSearchUrl(searchQuery);
|
|
11124
|
+
if (directUrl) {
|
|
11125
|
+
return {
|
|
11126
|
+
query: searchQuery,
|
|
11127
|
+
source: 'direct-url',
|
|
11128
|
+
retrievedAt: new Date().toISOString(),
|
|
11129
|
+
items: [{
|
|
11130
|
+
title: 'Direct URL evidence',
|
|
11131
|
+
url: directUrl,
|
|
11132
|
+
snippet: `Direct URL extracted from the WebResearch query: ${directUrl}`
|
|
11133
|
+
}]
|
|
11134
|
+
};
|
|
11135
|
+
}
|
|
11136
|
+
|
|
11003
11137
|
const providers = [
|
|
11004
11138
|
['duckduckgo', searchDuckDuckGo],
|
|
11005
11139
|
['brave', searchBrave],
|
|
@@ -11034,7 +11168,7 @@ async function searchWeb(query, maxResults = 5) {
|
|
|
11034
11168
|
throw error;
|
|
11035
11169
|
}
|
|
11036
11170
|
|
|
11037
|
-
async function fetchWebPage(url, maxChars = 12000) {
|
|
11171
|
+
async function fetchWebPage(url, maxChars = 12000) {
|
|
11038
11172
|
let parsedUrl;
|
|
11039
11173
|
try {
|
|
11040
11174
|
parsedUrl = new URL(url);
|
|
@@ -11083,10 +11217,1104 @@ async function fetchWebPage(url, maxChars = 12000) {
|
|
|
11083
11217
|
contentType,
|
|
11084
11218
|
truncated,
|
|
11085
11219
|
retrievedAt: new Date().toISOString()
|
|
11086
|
-
};
|
|
11087
|
-
}
|
|
11088
|
-
|
|
11089
|
-
function
|
|
11220
|
+
};
|
|
11221
|
+
}
|
|
11222
|
+
|
|
11223
|
+
function clampEvidenceText(value, maxLength = 4000) {
|
|
11224
|
+
const text = String(value ?? '').replace(/\r\n/g, '\n').replace(/\r/g, '\n').trim();
|
|
11225
|
+
if (!text) {
|
|
11226
|
+
return '';
|
|
11227
|
+
}
|
|
11228
|
+
return text.length <= maxLength ? text : `${text.slice(0, Math.max(0, maxLength - 3)).trimEnd()}...`;
|
|
11229
|
+
}
|
|
11230
|
+
|
|
11231
|
+
function evidenceArray(value, maxItems = 12, maxItemLength = 500) {
|
|
11232
|
+
const source = Array.isArray(value) ? value : [];
|
|
11233
|
+
const seen = new Set();
|
|
11234
|
+
const items = [];
|
|
11235
|
+
for (const item of source) {
|
|
11236
|
+
const text = clampEvidenceText(item, maxItemLength);
|
|
11237
|
+
const key = text.toLowerCase();
|
|
11238
|
+
if (!text || seen.has(key)) {
|
|
11239
|
+
continue;
|
|
11240
|
+
}
|
|
11241
|
+
seen.add(key);
|
|
11242
|
+
items.push(text);
|
|
11243
|
+
if (items.length >= maxItems) {
|
|
11244
|
+
break;
|
|
11245
|
+
}
|
|
11246
|
+
}
|
|
11247
|
+
return items;
|
|
11248
|
+
}
|
|
11249
|
+
|
|
11250
|
+
function slugifyEvidence(value, maxLength = 56) {
|
|
11251
|
+
const slug = String(value || 'evidence')
|
|
11252
|
+
.normalize('NFKD')
|
|
11253
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
11254
|
+
.replace(/[^a-zA-Z0-9]+/g, '-')
|
|
11255
|
+
.replace(/^-+|-+$/g, '')
|
|
11256
|
+
.toLowerCase();
|
|
11257
|
+
return (slug || 'evidence').slice(0, maxLength).replace(/-+$/g, '') || 'evidence';
|
|
11258
|
+
}
|
|
11259
|
+
|
|
11260
|
+
function safeEvidenceDirectory(baseDir, relativeDirectory) {
|
|
11261
|
+
const base = path.resolve(baseDir);
|
|
11262
|
+
const raw = String(relativeDirectory || '').trim();
|
|
11263
|
+
if (!raw) {
|
|
11264
|
+
return base;
|
|
11265
|
+
}
|
|
11266
|
+
|
|
11267
|
+
const safeSegments = raw
|
|
11268
|
+
.replaceAll('\\', '/')
|
|
11269
|
+
.split('/')
|
|
11270
|
+
.map(segment => slugifyEvidence(segment, 40))
|
|
11271
|
+
.filter(Boolean)
|
|
11272
|
+
.slice(0, 4);
|
|
11273
|
+
const target = path.resolve(base, ...safeSegments);
|
|
11274
|
+
if (!isPathWithin(base, target)) {
|
|
11275
|
+
const err = new Error('Evidence directory must stay under the evidence cache.');
|
|
11276
|
+
err.statusCode = 400;
|
|
11277
|
+
throw err;
|
|
11278
|
+
}
|
|
11279
|
+
return target;
|
|
11280
|
+
}
|
|
11281
|
+
|
|
11282
|
+
function normalizeEvidenceUrl(value) {
|
|
11283
|
+
const text = clampEvidenceText(value, 1200);
|
|
11284
|
+
if (!text) {
|
|
11285
|
+
return '';
|
|
11286
|
+
}
|
|
11287
|
+
|
|
11288
|
+
try {
|
|
11289
|
+
const parsed = new URL(text);
|
|
11290
|
+
if (parsed.protocol === 'http:' || parsed.protocol === 'https:') {
|
|
11291
|
+
return parsed.toString();
|
|
11292
|
+
}
|
|
11293
|
+
} catch {
|
|
11294
|
+
// SourceUrl is optional. Invalid values are ignored instead of persisted.
|
|
11295
|
+
}
|
|
11296
|
+
|
|
11297
|
+
return '';
|
|
11298
|
+
}
|
|
11299
|
+
|
|
11300
|
+
function normalizeStructuredEvidence(value) {
|
|
11301
|
+
const source = value && typeof value === 'object' ? value : {};
|
|
11302
|
+
const sourceUrl = normalizeEvidenceUrl(source.sourceUrl || source.SourceUrl);
|
|
11303
|
+
const sourcePath = clampEvidenceText(source.sourcePath || source.SourcePath, 1200);
|
|
11304
|
+
return {
|
|
11305
|
+
Schema: clampEvidenceText(source.schema || source.Schema || 'facts', 80) || 'facts',
|
|
11306
|
+
SourceType: clampEvidenceText(source.sourceType || source.SourceType || 'web', 80) || 'web',
|
|
11307
|
+
SourceUrl: sourceUrl || undefined,
|
|
11308
|
+
SourcePath: sourcePath || undefined,
|
|
11309
|
+
Title: clampEvidenceText(source.title || source.Title, 240),
|
|
11310
|
+
Summary: clampEvidenceText(source.summary || source.Summary, 2000),
|
|
11311
|
+
Facts: evidenceArray(source.facts || source.Facts, 16, 600),
|
|
11312
|
+
Dates: evidenceArray(source.dates || source.Dates, 12, 120),
|
|
11313
|
+
Links: evidenceArray(source.links || source.Links, 16, 1200),
|
|
11314
|
+
Prices: evidenceArray(source.prices || source.Prices, 12, 120),
|
|
11315
|
+
CharCount: Math.max(0, Math.min(Number(source.charCount || source.CharCount || 0) || 0, 1000000)),
|
|
11316
|
+
ExtractedAtUtc: clampEvidenceText(source.structuredAt || source.extractedAt || source.ExtractedAtUtc, 80) || new Date().toISOString()
|
|
11317
|
+
};
|
|
11318
|
+
}
|
|
11319
|
+
|
|
11320
|
+
function normalizeEvidenceMetadata(value, kind, sourceUrl) {
|
|
11321
|
+
const source = value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
11322
|
+
const metadata = {};
|
|
11323
|
+
for (const [key, item] of Object.entries(source)) {
|
|
11324
|
+
const safeKey = String(key || '').replace(/[^a-zA-Z0-9_.:-]/g, '').slice(0, 80);
|
|
11325
|
+
const safeValue = clampEvidenceText(item, 500);
|
|
11326
|
+
if (safeKey && safeValue) {
|
|
11327
|
+
metadata[safeKey] = safeValue;
|
|
11328
|
+
}
|
|
11329
|
+
}
|
|
11330
|
+
|
|
11331
|
+
if (!metadata.kind) {
|
|
11332
|
+
metadata.kind = kind;
|
|
11333
|
+
}
|
|
11334
|
+
|
|
11335
|
+
if (sourceUrl) {
|
|
11336
|
+
try {
|
|
11337
|
+
metadata.sourceHost = new URL(sourceUrl).host;
|
|
11338
|
+
} catch {
|
|
11339
|
+
metadata.sourceHost = sourceUrl;
|
|
11340
|
+
}
|
|
11341
|
+
}
|
|
11342
|
+
|
|
11343
|
+
return metadata;
|
|
11344
|
+
}
|
|
11345
|
+
|
|
11346
|
+
function buildEvidenceResponse(record) {
|
|
11347
|
+
return {
|
|
11348
|
+
success: true,
|
|
11349
|
+
id: record.Id,
|
|
11350
|
+
kind: record.Kind,
|
|
11351
|
+
title: record.Title,
|
|
11352
|
+
query: record.Query,
|
|
11353
|
+
sourceUrl: record.SourceUrl,
|
|
11354
|
+
sourcePath: record.SourcePath,
|
|
11355
|
+
excerpt: record.Excerpt,
|
|
11356
|
+
notes: record.Notes,
|
|
11357
|
+
path: record.Path,
|
|
11358
|
+
sha256: record.Sha256,
|
|
11359
|
+
capturedAt: record.CapturedAtUtc,
|
|
11360
|
+
metadata: record.Metadata,
|
|
11361
|
+
structured: record.Structured
|
|
11362
|
+
};
|
|
11363
|
+
}
|
|
11364
|
+
|
|
11365
|
+
async function saveEvidenceRecord(request = {}) {
|
|
11366
|
+
const capturedAt = new Date();
|
|
11367
|
+
const structured = normalizeStructuredEvidence(request.structured || request.Structured);
|
|
11368
|
+
const kind = clampEvidenceText(request.kind || request.Kind || 'evidence', 120) || 'evidence';
|
|
11369
|
+
const sourceUrl = normalizeEvidenceUrl(request.sourceUrl || request.SourceUrl) || structured.SourceUrl || '';
|
|
11370
|
+
const title = clampEvidenceText(request.title || request.Title || structured.Title || request.query || request.Query || sourceUrl || kind, 240);
|
|
11371
|
+
const query = clampEvidenceText(request.query || request.Query, 500);
|
|
11372
|
+
const sourcePath = clampEvidenceText(request.sourcePath || request.SourcePath || structured.SourcePath, 1200);
|
|
11373
|
+
const excerpt = clampEvidenceText(request.excerpt || request.Excerpt || structured.Summary, 2400);
|
|
11374
|
+
const notes = clampEvidenceText(request.notes || request.Notes, 2000);
|
|
11375
|
+
const metadata = normalizeEvidenceMetadata(request.metadata || request.Metadata, kind, sourceUrl);
|
|
11376
|
+
const baseEvidenceDir = path.join(getAiPath(), 'external', 'evidence');
|
|
11377
|
+
const targetDir = safeEvidenceDirectory(baseEvidenceDir, request.relativeDirectory || request.RelativeDirectory);
|
|
11378
|
+
const slugSource = title || query || sourceUrl || sourcePath || kind || 'evidence';
|
|
11379
|
+
const fileName = `${capturedAt.toISOString().replace(/[-:]/g, '').replace(/\.\d{3}Z$/, 'Z')}-${slugifyEvidence(slugSource)}.json`;
|
|
11380
|
+
const fullPath = path.resolve(targetDir, fileName);
|
|
11381
|
+
if (!isPathWithin(baseEvidenceDir, fullPath)) {
|
|
11382
|
+
const err = new Error('Evidence path must stay under the evidence cache.');
|
|
11383
|
+
err.statusCode = 400;
|
|
11384
|
+
throw err;
|
|
11385
|
+
}
|
|
11386
|
+
|
|
11387
|
+
const relativePath = normalizePathForClient(path.relative(workspacePath, fullPath));
|
|
11388
|
+
const id = `evidence-${capturedAt.toISOString().replace(/[-:T.]/g, '').slice(0, 14)}-${crypto.randomUUID().replace(/-/g, '').slice(0, 8)}`;
|
|
11389
|
+
const record = {
|
|
11390
|
+
Id: id,
|
|
11391
|
+
Kind: kind,
|
|
11392
|
+
Title: title,
|
|
11393
|
+
Query: query || undefined,
|
|
11394
|
+
SourceUrl: sourceUrl || undefined,
|
|
11395
|
+
SourcePath: sourcePath || undefined,
|
|
11396
|
+
Excerpt: excerpt,
|
|
11397
|
+
Notes: notes || undefined,
|
|
11398
|
+
CapturedAtUtc: capturedAt.toISOString(),
|
|
11399
|
+
Structured: structured,
|
|
11400
|
+
Metadata: metadata,
|
|
11401
|
+
Path: relativePath
|
|
11402
|
+
};
|
|
11403
|
+
|
|
11404
|
+
const unsignedJson = JSON.stringify(record, null, 2);
|
|
11405
|
+
record.Sha256 = crypto.createHash('sha256').update(unsignedJson, 'utf8').digest('hex');
|
|
11406
|
+
const finalJson = `${JSON.stringify(record, null, 2)}\n`;
|
|
11407
|
+
await writeFileAtomically(fullPath, finalJson, 'utf8');
|
|
11408
|
+
return record;
|
|
11409
|
+
}
|
|
11410
|
+
|
|
11411
|
+
const CONCEPT_HASH_ALGORITHM = 'xxHash64(seed=0, utf8-trim)';
|
|
11412
|
+
const CONCEPT_EMBEDDING_MODEL = 'local-xxhash64-preview-16';
|
|
11413
|
+
const CONCEPT_EMBED_LIVE_CONFIRM_VALUE = 'I_UNDERSTAND_THIS_CALLS_EMBEDDING_PROVIDER';
|
|
11414
|
+
const CONCEPT_U64_MASK = (1n << 64n) - 1n;
|
|
11415
|
+
const CONCEPT_I64_MAX = (1n << 63n) - 1n;
|
|
11416
|
+
const CONCEPT_U64_SIZE = 1n << 64n;
|
|
11417
|
+
const CONCEPT_PRIME64_1 = 11400714785074694791n;
|
|
11418
|
+
const CONCEPT_PRIME64_2 = 14029467366897019727n;
|
|
11419
|
+
const CONCEPT_PRIME64_3 = 1609587929392839161n;
|
|
11420
|
+
const CONCEPT_PRIME64_4 = 9650029242287828579n;
|
|
11421
|
+
const CONCEPT_PRIME64_5 = 2870177450012600261n;
|
|
11422
|
+
let nodeSqliteModulePromise = null;
|
|
11423
|
+
|
|
11424
|
+
function conceptU64(value) {
|
|
11425
|
+
return BigInt.asUintN(64, value);
|
|
11426
|
+
}
|
|
11427
|
+
|
|
11428
|
+
function conceptRotateLeft(value, count) {
|
|
11429
|
+
const shift = BigInt(count);
|
|
11430
|
+
return conceptU64((conceptU64(value) << shift) | (conceptU64(value) >> (64n - shift)));
|
|
11431
|
+
}
|
|
11432
|
+
|
|
11433
|
+
function conceptReadUInt32LE(data, offset) {
|
|
11434
|
+
return Number(data[offset])
|
|
11435
|
+
| (Number(data[offset + 1]) << 8)
|
|
11436
|
+
| (Number(data[offset + 2]) << 16)
|
|
11437
|
+
| (Number(data[offset + 3]) << 24);
|
|
11438
|
+
}
|
|
11439
|
+
|
|
11440
|
+
function conceptReadUInt64LE(data, offset) {
|
|
11441
|
+
let value = 0n;
|
|
11442
|
+
for (let index = 0; index < 8; index += 1) {
|
|
11443
|
+
value |= BigInt(data[offset + index]) << BigInt(index * 8);
|
|
11444
|
+
}
|
|
11445
|
+
return conceptU64(value);
|
|
11446
|
+
}
|
|
11447
|
+
|
|
11448
|
+
function conceptXxHash64Round(acc, input) {
|
|
11449
|
+
let value = conceptU64(acc + conceptU64(input * CONCEPT_PRIME64_2));
|
|
11450
|
+
value = conceptRotateLeft(value, 31);
|
|
11451
|
+
return conceptU64(value * CONCEPT_PRIME64_1);
|
|
11452
|
+
}
|
|
11453
|
+
|
|
11454
|
+
function conceptXxHash64MergeRound(acc, value) {
|
|
11455
|
+
let next = conceptU64(acc ^ conceptXxHash64Round(0n, value));
|
|
11456
|
+
next = conceptU64(next * CONCEPT_PRIME64_1 + CONCEPT_PRIME64_4);
|
|
11457
|
+
return next;
|
|
11458
|
+
}
|
|
11459
|
+
|
|
11460
|
+
function conceptXxHash64(bytes, seed = 0n) {
|
|
11461
|
+
const data = Buffer.isBuffer(bytes) ? bytes : Buffer.from(bytes || []);
|
|
11462
|
+
const len = data.length;
|
|
11463
|
+
let index = 0;
|
|
11464
|
+
let h64;
|
|
11465
|
+
|
|
11466
|
+
if (len >= 32) {
|
|
11467
|
+
let v1 = conceptU64(seed + CONCEPT_PRIME64_1 + CONCEPT_PRIME64_2);
|
|
11468
|
+
let v2 = conceptU64(seed + CONCEPT_PRIME64_2);
|
|
11469
|
+
let v3 = conceptU64(seed);
|
|
11470
|
+
let v4 = conceptU64(seed - CONCEPT_PRIME64_1);
|
|
11471
|
+
const limit = len - 32;
|
|
11472
|
+
while (index <= limit) {
|
|
11473
|
+
v1 = conceptXxHash64Round(v1, conceptReadUInt64LE(data, index)); index += 8;
|
|
11474
|
+
v2 = conceptXxHash64Round(v2, conceptReadUInt64LE(data, index)); index += 8;
|
|
11475
|
+
v3 = conceptXxHash64Round(v3, conceptReadUInt64LE(data, index)); index += 8;
|
|
11476
|
+
v4 = conceptXxHash64Round(v4, conceptReadUInt64LE(data, index)); index += 8;
|
|
11477
|
+
}
|
|
11478
|
+
h64 = conceptU64(
|
|
11479
|
+
conceptRotateLeft(v1, 1)
|
|
11480
|
+
+ conceptRotateLeft(v2, 7)
|
|
11481
|
+
+ conceptRotateLeft(v3, 12)
|
|
11482
|
+
+ conceptRotateLeft(v4, 18)
|
|
11483
|
+
);
|
|
11484
|
+
h64 = conceptXxHash64MergeRound(h64, v1);
|
|
11485
|
+
h64 = conceptXxHash64MergeRound(h64, v2);
|
|
11486
|
+
h64 = conceptXxHash64MergeRound(h64, v3);
|
|
11487
|
+
h64 = conceptXxHash64MergeRound(h64, v4);
|
|
11488
|
+
} else {
|
|
11489
|
+
h64 = conceptU64(seed + CONCEPT_PRIME64_5);
|
|
11490
|
+
}
|
|
11491
|
+
|
|
11492
|
+
h64 = conceptU64(h64 + BigInt(len));
|
|
11493
|
+
while (index <= len - 8) {
|
|
11494
|
+
const k1 = conceptXxHash64Round(0n, conceptReadUInt64LE(data, index));
|
|
11495
|
+
h64 = conceptU64(h64 ^ k1);
|
|
11496
|
+
h64 = conceptU64(conceptRotateLeft(h64, 27) * CONCEPT_PRIME64_1 + CONCEPT_PRIME64_4);
|
|
11497
|
+
index += 8;
|
|
11498
|
+
}
|
|
11499
|
+
if (index <= len - 4) {
|
|
11500
|
+
h64 = conceptU64(h64 ^ (BigInt(conceptReadUInt32LE(data, index) >>> 0) * CONCEPT_PRIME64_1));
|
|
11501
|
+
h64 = conceptU64(conceptRotateLeft(h64, 23) * CONCEPT_PRIME64_2 + CONCEPT_PRIME64_3);
|
|
11502
|
+
index += 4;
|
|
11503
|
+
}
|
|
11504
|
+
while (index < len) {
|
|
11505
|
+
h64 = conceptU64(h64 ^ (BigInt(data[index]) * CONCEPT_PRIME64_5));
|
|
11506
|
+
h64 = conceptU64(conceptRotateLeft(h64, 11) * CONCEPT_PRIME64_1);
|
|
11507
|
+
index += 1;
|
|
11508
|
+
}
|
|
11509
|
+
|
|
11510
|
+
h64 = conceptU64(h64 ^ (h64 >> 33n));
|
|
11511
|
+
h64 = conceptU64(h64 * CONCEPT_PRIME64_2);
|
|
11512
|
+
h64 = conceptU64(h64 ^ (h64 >> 29n));
|
|
11513
|
+
h64 = conceptU64(h64 * CONCEPT_PRIME64_3);
|
|
11514
|
+
h64 = conceptU64(h64 ^ (h64 >> 32n));
|
|
11515
|
+
return h64 & CONCEPT_U64_MASK;
|
|
11516
|
+
}
|
|
11517
|
+
|
|
11518
|
+
function conceptHash64Hex(signature) {
|
|
11519
|
+
const clean = String(signature || '').trim();
|
|
11520
|
+
if (!clean) {
|
|
11521
|
+
const err = new Error('signature is required');
|
|
11522
|
+
err.statusCode = 400;
|
|
11523
|
+
throw err;
|
|
11524
|
+
}
|
|
11525
|
+
return `0x${conceptXxHash64(Buffer.from(clean, 'utf8')).toString(16).padStart(16, '0')}`;
|
|
11526
|
+
}
|
|
11527
|
+
|
|
11528
|
+
function normalizeConceptHex64(value, field = 'id') {
|
|
11529
|
+
const text = String(value || '').trim().toLowerCase();
|
|
11530
|
+
if (!/^0x[0-9a-f]{16}$/.test(text)) {
|
|
11531
|
+
const err = new Error(`${field} must be 0x[0-9a-f]{16}`);
|
|
11532
|
+
err.statusCode = 400;
|
|
11533
|
+
throw err;
|
|
11534
|
+
}
|
|
11535
|
+
return text;
|
|
11536
|
+
}
|
|
11537
|
+
|
|
11538
|
+
function conceptSqlKeyString(hex64) {
|
|
11539
|
+
const unsigned = BigInt(hex64);
|
|
11540
|
+
return unsigned > CONCEPT_I64_MAX
|
|
11541
|
+
? (unsigned - CONCEPT_U64_SIZE).toString()
|
|
11542
|
+
: unsigned.toString();
|
|
11543
|
+
}
|
|
11544
|
+
|
|
11545
|
+
async function loadNodeSqliteModule() {
|
|
11546
|
+
if (!nodeSqliteModulePromise) {
|
|
11547
|
+
nodeSqliteModulePromise = import('node:sqlite').catch(err => {
|
|
11548
|
+
nodeSqliteModulePromise = null;
|
|
11549
|
+
throw err;
|
|
11550
|
+
});
|
|
11551
|
+
}
|
|
11552
|
+
return nodeSqliteModulePromise;
|
|
11553
|
+
}
|
|
11554
|
+
|
|
11555
|
+
function normalizeConceptSequence(ir) {
|
|
11556
|
+
const text = String(ir || '').replace(/\r\n/g, '\n').replace(/\r/g, '\n').trim();
|
|
11557
|
+
if (!text) {
|
|
11558
|
+
const err = new Error('ir is required');
|
|
11559
|
+
err.statusCode = 400;
|
|
11560
|
+
throw err;
|
|
11561
|
+
}
|
|
11562
|
+
if (text.length > 240000) {
|
|
11563
|
+
const err = new Error('ir is too large');
|
|
11564
|
+
err.statusCode = 413;
|
|
11565
|
+
throw err;
|
|
11566
|
+
}
|
|
11567
|
+
|
|
11568
|
+
let parsed;
|
|
11569
|
+
try {
|
|
11570
|
+
parsed = JSON.parse(text);
|
|
11571
|
+
} catch (parseErr) {
|
|
11572
|
+
const err = new Error(`ir must be valid ConceptSequence JSON: ${parseErr?.message || parseErr}`);
|
|
11573
|
+
err.statusCode = 400;
|
|
11574
|
+
throw err;
|
|
11575
|
+
}
|
|
11576
|
+
const literals = Array.isArray(parsed?.literals) ? parsed.literals : [];
|
|
11577
|
+
const instructions = Array.isArray(parsed?.instructions) ? parsed.instructions : [];
|
|
11578
|
+
if (instructions.length === 0) {
|
|
11579
|
+
const err = new Error('ir must include a non-empty instructions array');
|
|
11580
|
+
err.statusCode = 400;
|
|
11581
|
+
throw err;
|
|
11582
|
+
}
|
|
11583
|
+
return { body: text, literals, instructions };
|
|
11584
|
+
}
|
|
11585
|
+
|
|
11586
|
+
function deterministicConceptVector(signature, description, dimensions = 16) {
|
|
11587
|
+
const size = Math.max(4, Math.min(64, Math.trunc(Number(dimensions) || 16)));
|
|
11588
|
+
const input = `${signature}\n\nDescription: ${description || ''}`;
|
|
11589
|
+
return Array.from({ length: size }, (_, index) => {
|
|
11590
|
+
const hash = BigInt(conceptHash64Hex(`${input}#${index}`));
|
|
11591
|
+
const normalized = Number(hash & 0xffffn) / 32767.5 - 1;
|
|
11592
|
+
return Number(normalized.toFixed(6));
|
|
11593
|
+
});
|
|
11594
|
+
}
|
|
11595
|
+
|
|
11596
|
+
function serializeConceptFloatVectorBase64(vector) {
|
|
11597
|
+
const values = Array.isArray(vector) ? vector : [];
|
|
11598
|
+
const buffer = Buffer.alloc(values.length * 4);
|
|
11599
|
+
values.forEach((value, index) => {
|
|
11600
|
+
buffer.writeFloatLE(Number(value) || 0, index * 4);
|
|
11601
|
+
});
|
|
11602
|
+
return buffer.toString('base64');
|
|
11603
|
+
}
|
|
11604
|
+
|
|
11605
|
+
async function readJsonIfExists(filePath, fallback) {
|
|
11606
|
+
try {
|
|
11607
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
11608
|
+
return JSON.parse(content);
|
|
11609
|
+
} catch (err) {
|
|
11610
|
+
if (err?.code === 'ENOENT') {
|
|
11611
|
+
return fallback;
|
|
11612
|
+
}
|
|
11613
|
+
throw err;
|
|
11614
|
+
}
|
|
11615
|
+
}
|
|
11616
|
+
|
|
11617
|
+
function normalizeNullableConceptText(value) {
|
|
11618
|
+
const text = String(value ?? '').trim();
|
|
11619
|
+
return text ? text : null;
|
|
11620
|
+
}
|
|
11621
|
+
|
|
11622
|
+
function conceptEmbeddingBlobFromBase64(base64) {
|
|
11623
|
+
const text = String(base64 || '').trim();
|
|
11624
|
+
if (!text) return null;
|
|
11625
|
+
return Buffer.from(text, 'base64');
|
|
11626
|
+
}
|
|
11627
|
+
|
|
11628
|
+
function conceptSqliteRowFromRecord(record) {
|
|
11629
|
+
const concept = record?.Concept || {};
|
|
11630
|
+
const sqlKey = String(concept.SqlKey || conceptSqlKeyString(normalizeConceptHex64(concept.Id, 'id'))).trim();
|
|
11631
|
+
return {
|
|
11632
|
+
id: BigInt(sqlKey),
|
|
11633
|
+
idText: sqlKey,
|
|
11634
|
+
signature: String(concept.Signature || ''),
|
|
11635
|
+
body: normalizeNullableConceptText(concept.Body),
|
|
11636
|
+
category: normalizeNullableConceptText(concept.Category),
|
|
11637
|
+
conceptType: normalizeNullableConceptText(concept.ConceptType),
|
|
11638
|
+
createdUtc: normalizeNullableConceptText(concept.CreatedUtc),
|
|
11639
|
+
updatedUtc: normalizeNullableConceptText(concept.UpdatedUtc),
|
|
11640
|
+
description: normalizeNullableConceptText(concept.Description),
|
|
11641
|
+
embedding: conceptEmbeddingBlobFromBase64(concept.EmbeddingBase64),
|
|
11642
|
+
embeddingModel: normalizeNullableConceptText(concept.EmbeddingModel),
|
|
11643
|
+
embeddingUpdatedUtc: normalizeNullableConceptText(concept.EmbeddingUpdatedUtc)
|
|
11644
|
+
};
|
|
11645
|
+
}
|
|
11646
|
+
|
|
11647
|
+
function initializeConceptSqliteDatabase(db) {
|
|
11648
|
+
db.exec(`
|
|
11649
|
+
PRAGMA journal_mode=WAL;
|
|
11650
|
+
PRAGMA synchronous=NORMAL;
|
|
11651
|
+
PRAGMA temp_store=MEMORY;
|
|
11652
|
+
CREATE TABLE IF NOT EXISTS tbl_concepts (
|
|
11653
|
+
id INTEGER PRIMARY KEY,
|
|
11654
|
+
signature TEXT NOT NULL,
|
|
11655
|
+
body TEXT NULL,
|
|
11656
|
+
category TEXT NULL,
|
|
11657
|
+
concept_type TEXT NULL,
|
|
11658
|
+
created_utc TEXT NULL,
|
|
11659
|
+
updated_utc TEXT NULL,
|
|
11660
|
+
description TEXT NULL,
|
|
11661
|
+
embedding BLOB NULL,
|
|
11662
|
+
embedding_model TEXT NULL,
|
|
11663
|
+
embedding_updated_utc TEXT NULL
|
|
11664
|
+
);
|
|
11665
|
+
CREATE INDEX IF NOT EXISTS idx_tbl_concepts_category ON tbl_concepts(category);
|
|
11666
|
+
`);
|
|
11667
|
+
}
|
|
11668
|
+
|
|
11669
|
+
function bindConceptSqliteReadBigInts(statement) {
|
|
11670
|
+
if (typeof statement?.setReadBigInts === 'function') {
|
|
11671
|
+
statement.setReadBigInts(true);
|
|
11672
|
+
}
|
|
11673
|
+
return statement;
|
|
11674
|
+
}
|
|
11675
|
+
|
|
11676
|
+
function normalizeConceptSqliteRow(row, sqlitePath) {
|
|
11677
|
+
if (!row) return null;
|
|
11678
|
+
const embedding = row.embedding ? Buffer.from(row.embedding) : null;
|
|
11679
|
+
const idValue = typeof row.id === 'bigint' ? row.id : BigInt(row.id);
|
|
11680
|
+
const hex = `0x${BigInt.asUintN(64, idValue).toString(16).padStart(16, '0')}`;
|
|
11681
|
+
return {
|
|
11682
|
+
success: true,
|
|
11683
|
+
provider: 'LocalBridgeNativeSQLiteConceptStore',
|
|
11684
|
+
adapterState: 'native-sqlite',
|
|
11685
|
+
originalTable: 'tbl_concepts',
|
|
11686
|
+
sqlitePath,
|
|
11687
|
+
id: hex,
|
|
11688
|
+
sqlKey: idValue.toString(),
|
|
11689
|
+
signature: row.signature || '',
|
|
11690
|
+
body: row.body || null,
|
|
11691
|
+
category: row.category || '',
|
|
11692
|
+
conceptType: row.concept_type || null,
|
|
11693
|
+
createdAt: row.created_utc || null,
|
|
11694
|
+
updatedAt: row.updated_utc || null,
|
|
11695
|
+
description: row.description || null,
|
|
11696
|
+
embeddingBase64: embedding ? embedding.toString('base64') : null,
|
|
11697
|
+
embeddingBytes: embedding ? embedding.length : 0,
|
|
11698
|
+
embeddingModel: row.embedding_model || null,
|
|
11699
|
+
embeddingUpdatedAt: row.embedding_updated_utc || null
|
|
11700
|
+
};
|
|
11701
|
+
}
|
|
11702
|
+
|
|
11703
|
+
function buildConceptCompositeResponse(record) {
|
|
11704
|
+
return {
|
|
11705
|
+
success: true,
|
|
11706
|
+
id: record.Concept.Id,
|
|
11707
|
+
sqlKey: record.Concept.SqlKey,
|
|
11708
|
+
signature: record.Concept.Signature,
|
|
11709
|
+
category: record.Concept.Category,
|
|
11710
|
+
conceptType: record.Concept.ConceptType,
|
|
11711
|
+
path: record.Path,
|
|
11712
|
+
indexPath: record.IndexPath,
|
|
11713
|
+
sha256: record.Sha256,
|
|
11714
|
+
hashAlgorithm: record.HashAlgorithm,
|
|
11715
|
+
embeddingModel: record.Concept.EmbeddingModel,
|
|
11716
|
+
embeddingVector: record.Concept.EmbeddingVector,
|
|
11717
|
+
embeddingBase64: record.Concept.EmbeddingBase64,
|
|
11718
|
+
nativeSqlite: record.NativeSqlite || null,
|
|
11719
|
+
updatedAt: record.Concept.UpdatedUtc
|
|
11720
|
+
};
|
|
11721
|
+
}
|
|
11722
|
+
|
|
11723
|
+
async function saveConceptCompositeRecord(request = {}) {
|
|
11724
|
+
const nowUtc = new Date().toISOString();
|
|
11725
|
+
const signature = clampEvidenceText(request.signature || request.Signature, 500);
|
|
11726
|
+
const id = normalizeConceptHex64(request.id || request.Id || conceptHash64Hex(signature), 'id');
|
|
11727
|
+
const derivedId = conceptHash64Hex(signature);
|
|
11728
|
+
if (id !== derivedId) {
|
|
11729
|
+
const err = new Error(`signature does not match id. signature->id=${derivedId}, id=${id}`);
|
|
11730
|
+
err.statusCode = 400;
|
|
11731
|
+
throw err;
|
|
11732
|
+
}
|
|
11733
|
+
|
|
11734
|
+
const sequence = normalizeConceptSequence(request.ir || request.IR || request.body || request.Body);
|
|
11735
|
+
const description = clampEvidenceText(request.description || request.Description, 2400);
|
|
11736
|
+
const category = clampEvidenceText(request.category || request.Category || 'Composite.Dynamic', 160) || 'Composite.Dynamic';
|
|
11737
|
+
const conceptType = clampEvidenceText(request.conceptType || request.ConceptType || 'Axiom', 80) || 'Axiom';
|
|
11738
|
+
const vector = deterministicConceptVector(signature, description, request.embeddingDimensions || request.EmbeddingDimensions || 16);
|
|
11739
|
+
const baseConceptDir = path.resolve(getAiPath(), 'concepts');
|
|
11740
|
+
const rowDir = path.resolve(baseConceptDir, 'rows');
|
|
11741
|
+
const fileName = `${id.slice(2)}-${slugifyEvidence(signature, 64)}.json`;
|
|
11742
|
+
const fullPath = path.resolve(rowDir, fileName);
|
|
11743
|
+
const indexPath = path.resolve(baseConceptDir, 'tbl_concepts.rows.json');
|
|
11744
|
+
|
|
11745
|
+
if (!isPathWithin(baseConceptDir, fullPath) || !isPathWithin(baseConceptDir, indexPath)) {
|
|
11746
|
+
const err = new Error('Concept path must stay under the concept cache.');
|
|
11747
|
+
err.statusCode = 400;
|
|
11748
|
+
throw err;
|
|
11749
|
+
}
|
|
11750
|
+
|
|
11751
|
+
const relativePath = normalizePathForClient(path.relative(workspacePath, fullPath));
|
|
11752
|
+
const relativeIndexPath = normalizePathForClient(path.relative(workspacePath, indexPath));
|
|
11753
|
+
const conceptRow = {
|
|
11754
|
+
Id: id,
|
|
11755
|
+
SqlKey: conceptSqlKeyString(id),
|
|
11756
|
+
Signature: signature,
|
|
11757
|
+
Body: sequence.body,
|
|
11758
|
+
Category: category,
|
|
11759
|
+
ConceptType: conceptType,
|
|
11760
|
+
CreatedUtc: nowUtc,
|
|
11761
|
+
UpdatedUtc: nowUtc,
|
|
11762
|
+
Description: description || undefined,
|
|
11763
|
+
EmbeddingVector: vector,
|
|
11764
|
+
EmbeddingBase64: serializeConceptFloatVectorBase64(vector),
|
|
11765
|
+
EmbeddingModel: CONCEPT_EMBEDDING_MODEL,
|
|
11766
|
+
EmbeddingUpdatedUtc: nowUtc,
|
|
11767
|
+
AtomCount: sequence.instructions.length,
|
|
11768
|
+
LiteralCount: sequence.literals.length
|
|
11769
|
+
};
|
|
11770
|
+
const record = {
|
|
11771
|
+
Schema: 'MindExecution.Kernel.Store.ConceptConcept/v1',
|
|
11772
|
+
Store: {
|
|
11773
|
+
Provider: 'LocalBridgeJsonConceptStore',
|
|
11774
|
+
OriginalTable: 'tbl_concepts',
|
|
11775
|
+
Notes: 'JSON row projection for local React parity; LocalBridge also mirrors the row into native SQLite tbl_concepts.'
|
|
11776
|
+
},
|
|
11777
|
+
HashAlgorithm: CONCEPT_HASH_ALGORITHM,
|
|
11778
|
+
Concept: conceptRow,
|
|
11779
|
+
Path: relativePath,
|
|
11780
|
+
IndexPath: relativeIndexPath
|
|
11781
|
+
};
|
|
11782
|
+
|
|
11783
|
+
const unsignedJson = JSON.stringify(record, null, 2);
|
|
11784
|
+
record.Sha256 = crypto.createHash('sha256').update(unsignedJson, 'utf8').digest('hex');
|
|
11785
|
+
await writeFileAtomically(fullPath, `${JSON.stringify(record, null, 2)}\n`, 'utf8');
|
|
11786
|
+
|
|
11787
|
+
const currentIndex = await readJsonIfExists(indexPath, {
|
|
11788
|
+
Schema: 'MindExecution.Kernel.Store.ConceptConceptIndex/v1',
|
|
11789
|
+
Store: 'LocalBridgeJsonConceptStore',
|
|
11790
|
+
HashAlgorithm: CONCEPT_HASH_ALGORITHM,
|
|
11791
|
+
Rows: []
|
|
11792
|
+
});
|
|
11793
|
+
const rows = Array.isArray(currentIndex.Rows) ? currentIndex.Rows : [];
|
|
11794
|
+
const nextRows = [
|
|
11795
|
+
{
|
|
11796
|
+
Id: conceptRow.Id,
|
|
11797
|
+
SqlKey: conceptRow.SqlKey,
|
|
11798
|
+
Signature: conceptRow.Signature,
|
|
11799
|
+
Category: conceptRow.Category,
|
|
11800
|
+
ConceptType: conceptRow.ConceptType,
|
|
11801
|
+
UpdatedUtc: conceptRow.UpdatedUtc,
|
|
11802
|
+
AtomCount: conceptRow.AtomCount,
|
|
11803
|
+
LiteralCount: conceptRow.LiteralCount,
|
|
11804
|
+
Path: relativePath,
|
|
11805
|
+
Sha256: record.Sha256
|
|
11806
|
+
},
|
|
11807
|
+
...rows.filter(row => String(row?.Id || '').toLowerCase() !== conceptRow.Id)
|
|
11808
|
+
].slice(0, 512);
|
|
11809
|
+
|
|
11810
|
+
const nextIndex = {
|
|
11811
|
+
Schema: 'MindExecution.Kernel.Store.ConceptConceptIndex/v1',
|
|
11812
|
+
Store: 'LocalBridgeJsonConceptStore',
|
|
11813
|
+
HashAlgorithm: CONCEPT_HASH_ALGORITHM,
|
|
11814
|
+
UpdatedUtc: nowUtc,
|
|
11815
|
+
RowCount: nextRows.length,
|
|
11816
|
+
Rows: nextRows
|
|
11817
|
+
};
|
|
11818
|
+
await writeFileAtomically(indexPath, `${JSON.stringify(nextIndex, null, 2)}\n`, 'utf8');
|
|
11819
|
+
record.NativeSqlite = await upsertConceptNativeSqlite(record);
|
|
11820
|
+
return record;
|
|
11821
|
+
}
|
|
11822
|
+
|
|
11823
|
+
function getConceptStorePaths() {
|
|
11824
|
+
const baseConceptDir = path.resolve(getAiPath(), 'concepts');
|
|
11825
|
+
const rowDir = path.resolve(baseConceptDir, 'rows');
|
|
11826
|
+
const indexPath = path.resolve(baseConceptDir, 'tbl_concepts.rows.json');
|
|
11827
|
+
const sqlitePath = path.resolve(baseConceptDir, 'mind_concepts.db');
|
|
11828
|
+
return { baseConceptDir, rowDir, indexPath, sqlitePath };
|
|
11829
|
+
}
|
|
11830
|
+
|
|
11831
|
+
async function upsertConceptNativeSqlite(record) {
|
|
11832
|
+
const { DatabaseSync } = await loadNodeSqliteModule();
|
|
11833
|
+
const { baseConceptDir, sqlitePath } = getConceptStorePaths();
|
|
11834
|
+
if (!isPathWithin(baseConceptDir, sqlitePath)) {
|
|
11835
|
+
const err = new Error('Concept SQLite path must stay under the concept cache.');
|
|
11836
|
+
err.statusCode = 400;
|
|
11837
|
+
throw err;
|
|
11838
|
+
}
|
|
11839
|
+
|
|
11840
|
+
await fs.mkdir(baseConceptDir, { recursive: true });
|
|
11841
|
+
const sqliteRow = conceptSqliteRowFromRecord(record);
|
|
11842
|
+
const db = new DatabaseSync(sqlitePath, { readOnly: false });
|
|
11843
|
+
try {
|
|
11844
|
+
initializeConceptSqliteDatabase(db);
|
|
11845
|
+
db.exec('BEGIN IMMEDIATE;');
|
|
11846
|
+
try {
|
|
11847
|
+
db.prepare(`
|
|
11848
|
+
INSERT INTO tbl_concepts (id, signature, body, category, concept_type, created_utc, updated_utc, description, embedding, embedding_model, embedding_updated_utc)
|
|
11849
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
11850
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
11851
|
+
signature=excluded.signature,
|
|
11852
|
+
body=excluded.body,
|
|
11853
|
+
category=excluded.category,
|
|
11854
|
+
concept_type=excluded.concept_type,
|
|
11855
|
+
created_utc=excluded.created_utc,
|
|
11856
|
+
updated_utc=excluded.updated_utc,
|
|
11857
|
+
description=excluded.description,
|
|
11858
|
+
embedding=excluded.embedding,
|
|
11859
|
+
embedding_model=excluded.embedding_model,
|
|
11860
|
+
embedding_updated_utc=excluded.embedding_updated_utc;
|
|
11861
|
+
`).run(
|
|
11862
|
+
sqliteRow.id,
|
|
11863
|
+
sqliteRow.signature,
|
|
11864
|
+
sqliteRow.body,
|
|
11865
|
+
sqliteRow.category,
|
|
11866
|
+
sqliteRow.conceptType,
|
|
11867
|
+
sqliteRow.createdUtc,
|
|
11868
|
+
sqliteRow.updatedUtc,
|
|
11869
|
+
sqliteRow.description,
|
|
11870
|
+
sqliteRow.embedding,
|
|
11871
|
+
sqliteRow.embeddingModel,
|
|
11872
|
+
sqliteRow.embeddingUpdatedUtc
|
|
11873
|
+
);
|
|
11874
|
+
db.exec('COMMIT;');
|
|
11875
|
+
} catch (err) {
|
|
11876
|
+
try { db.exec('ROLLBACK;'); } catch {}
|
|
11877
|
+
throw err;
|
|
11878
|
+
}
|
|
11879
|
+
|
|
11880
|
+
const countRow = db.prepare('SELECT COUNT(*) AS row_count FROM tbl_concepts;').get();
|
|
11881
|
+
const relativeSqlitePath = normalizePathForClient(path.relative(workspacePath, sqlitePath));
|
|
11882
|
+
return {
|
|
11883
|
+
success: true,
|
|
11884
|
+
provider: 'LocalBridgeNativeSQLiteConceptStore',
|
|
11885
|
+
adapterState: 'native-sqlite',
|
|
11886
|
+
originalTable: 'tbl_concepts',
|
|
11887
|
+
sqlitePath: relativeSqlitePath,
|
|
11888
|
+
rowCount: Number(countRow?.row_count || 0),
|
|
11889
|
+
lastSqlKey: sqliteRow.idText,
|
|
11890
|
+
lastId: record?.Concept?.Id || null
|
|
11891
|
+
};
|
|
11892
|
+
} finally {
|
|
11893
|
+
db.close();
|
|
11894
|
+
}
|
|
11895
|
+
}
|
|
11896
|
+
|
|
11897
|
+
async function readConceptNativeSqliteRowById(id) {
|
|
11898
|
+
const normalizedId = normalizeConceptHex64(id, 'id');
|
|
11899
|
+
const { DatabaseSync } = await loadNodeSqliteModule();
|
|
11900
|
+
const { baseConceptDir, sqlitePath } = getConceptStorePaths();
|
|
11901
|
+
if (!isPathWithin(baseConceptDir, sqlitePath)) {
|
|
11902
|
+
const err = new Error('Concept SQLite path must stay under the concept cache.');
|
|
11903
|
+
err.statusCode = 400;
|
|
11904
|
+
throw err;
|
|
11905
|
+
}
|
|
11906
|
+
|
|
11907
|
+
try {
|
|
11908
|
+
await fs.access(sqlitePath);
|
|
11909
|
+
} catch {
|
|
11910
|
+
const err = new Error('Concept native SQLite database has not been created yet.');
|
|
11911
|
+
err.statusCode = 404;
|
|
11912
|
+
throw err;
|
|
11913
|
+
}
|
|
11914
|
+
|
|
11915
|
+
const db = new DatabaseSync(sqlitePath, { readOnly: true });
|
|
11916
|
+
try {
|
|
11917
|
+
const sqlKey = BigInt(conceptSqlKeyString(normalizedId));
|
|
11918
|
+
const statement = bindConceptSqliteReadBigInts(db.prepare(`
|
|
11919
|
+
SELECT id, signature, body, category, concept_type, created_utc, updated_utc, description, embedding, embedding_model, embedding_updated_utc
|
|
11920
|
+
FROM tbl_concepts
|
|
11921
|
+
WHERE id = ?
|
|
11922
|
+
LIMIT 1;
|
|
11923
|
+
`));
|
|
11924
|
+
const row = statement.get(sqlKey);
|
|
11925
|
+
if (!row) {
|
|
11926
|
+
const err = new Error(`Concept SQLite row not found: ${normalizedId}`);
|
|
11927
|
+
err.statusCode = 404;
|
|
11928
|
+
throw err;
|
|
11929
|
+
}
|
|
11930
|
+
const relativeSqlitePath = normalizePathForClient(path.relative(workspacePath, sqlitePath));
|
|
11931
|
+
return normalizeConceptSqliteRow(row, relativeSqlitePath);
|
|
11932
|
+
} finally {
|
|
11933
|
+
db.close();
|
|
11934
|
+
}
|
|
11935
|
+
}
|
|
11936
|
+
|
|
11937
|
+
async function readConceptStoreIndex() {
|
|
11938
|
+
const { baseConceptDir, indexPath } = getConceptStorePaths();
|
|
11939
|
+
if (!isPathWithin(baseConceptDir, indexPath)) {
|
|
11940
|
+
const err = new Error('Concept index path must stay under the concept cache.');
|
|
11941
|
+
err.statusCode = 400;
|
|
11942
|
+
throw err;
|
|
11943
|
+
}
|
|
11944
|
+
|
|
11945
|
+
const fallback = {
|
|
11946
|
+
Schema: 'MindExecution.Kernel.Store.ConceptConceptIndex/v1',
|
|
11947
|
+
Store: 'LocalBridgeJsonConceptStore',
|
|
11948
|
+
HashAlgorithm: CONCEPT_HASH_ALGORITHM,
|
|
11949
|
+
UpdatedUtc: null,
|
|
11950
|
+
RowCount: 0,
|
|
11951
|
+
Rows: []
|
|
11952
|
+
};
|
|
11953
|
+
const index = await readJsonIfExists(indexPath, fallback);
|
|
11954
|
+
const rows = Array.isArray(index.Rows) ? index.Rows : [];
|
|
11955
|
+
return {
|
|
11956
|
+
...fallback,
|
|
11957
|
+
...index,
|
|
11958
|
+
Rows: rows,
|
|
11959
|
+
RowCount: Number.isFinite(Number(index.RowCount)) ? Number(index.RowCount) : rows.length,
|
|
11960
|
+
Path: normalizePathForClient(path.relative(workspacePath, indexPath))
|
|
11961
|
+
};
|
|
11962
|
+
}
|
|
11963
|
+
|
|
11964
|
+
async function readConceptNativeSqliteStatus() {
|
|
11965
|
+
const { baseConceptDir, sqlitePath } = getConceptStorePaths();
|
|
11966
|
+
const relativeSqlitePath = normalizePathForClient(path.relative(workspacePath, sqlitePath));
|
|
11967
|
+
try {
|
|
11968
|
+
const { DatabaseSync } = await loadNodeSqliteModule();
|
|
11969
|
+
await fs.access(sqlitePath);
|
|
11970
|
+
const db = new DatabaseSync(sqlitePath, { readOnly: true });
|
|
11971
|
+
try {
|
|
11972
|
+
const tableRows = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='tbl_concepts' LIMIT 1;").all();
|
|
11973
|
+
const hasTable = tableRows.length > 0;
|
|
11974
|
+
const rowCount = hasTable ? Number(db.prepare('SELECT COUNT(*) AS row_count FROM tbl_concepts;').get()?.row_count || 0) : 0;
|
|
11975
|
+
const columnRows = hasTable ? db.prepare('PRAGMA table_info(tbl_concepts);').all() : [];
|
|
11976
|
+
return {
|
|
11977
|
+
success: true,
|
|
11978
|
+
provider: 'LocalBridgeNativeSQLiteConceptStore',
|
|
11979
|
+
adapterState: hasTable ? 'native-sqlite' : 'native-sqlite-pending',
|
|
11980
|
+
originalTable: 'tbl_concepts',
|
|
11981
|
+
sqlitePath: relativeSqlitePath,
|
|
11982
|
+
rowCount,
|
|
11983
|
+
hasTable,
|
|
11984
|
+
columns: columnRows.map(row => String(row.name || '')).filter(Boolean)
|
|
11985
|
+
};
|
|
11986
|
+
} finally {
|
|
11987
|
+
db.close();
|
|
11988
|
+
}
|
|
11989
|
+
} catch (err) {
|
|
11990
|
+
if (err?.code === 'ENOENT') {
|
|
11991
|
+
return {
|
|
11992
|
+
success: true,
|
|
11993
|
+
provider: 'LocalBridgeNativeSQLiteConceptStore',
|
|
11994
|
+
adapterState: 'native-sqlite-pending',
|
|
11995
|
+
originalTable: 'tbl_concepts',
|
|
11996
|
+
sqlitePath: relativeSqlitePath,
|
|
11997
|
+
rowCount: 0,
|
|
11998
|
+
hasTable: false,
|
|
11999
|
+
columns: []
|
|
12000
|
+
};
|
|
12001
|
+
}
|
|
12002
|
+
return {
|
|
12003
|
+
success: false,
|
|
12004
|
+
provider: 'LocalBridgeNativeSQLiteConceptStore',
|
|
12005
|
+
adapterState: 'native-sqlite-error',
|
|
12006
|
+
originalTable: 'tbl_concepts',
|
|
12007
|
+
sqlitePath: relativeSqlitePath,
|
|
12008
|
+
rowCount: 0,
|
|
12009
|
+
hasTable: false,
|
|
12010
|
+
columns: [],
|
|
12011
|
+
error: err?.message || String(err)
|
|
12012
|
+
};
|
|
12013
|
+
}
|
|
12014
|
+
}
|
|
12015
|
+
|
|
12016
|
+
function buildConceptStoreStatusResponse(index, nativeSqlite = null) {
|
|
12017
|
+
const rows = Array.isArray(index.Rows) ? index.Rows : [];
|
|
12018
|
+
return {
|
|
12019
|
+
success: true,
|
|
12020
|
+
provider: 'LocalBridgeJsonConceptStore',
|
|
12021
|
+
adapterState: 'json-row-projection',
|
|
12022
|
+
originalTable: 'tbl_concepts',
|
|
12023
|
+
schema: index.Schema || 'MindExecution.Kernel.Store.ConceptConceptIndex/v1',
|
|
12024
|
+
hashAlgorithm: index.HashAlgorithm || CONCEPT_HASH_ALGORITHM,
|
|
12025
|
+
embeddingModel: CONCEPT_EMBEDDING_MODEL,
|
|
12026
|
+
rowCount: rows.length,
|
|
12027
|
+
indexPath: index.Path,
|
|
12028
|
+
updatedAt: index.UpdatedUtc || null,
|
|
12029
|
+
latestRows: rows.slice(0, 12).map(row => ({
|
|
12030
|
+
id: row.Id,
|
|
12031
|
+
sqlKey: row.SqlKey,
|
|
12032
|
+
signature: row.Signature,
|
|
12033
|
+
category: row.Category,
|
|
12034
|
+
conceptType: row.ConceptType,
|
|
12035
|
+
atomCount: row.AtomCount,
|
|
12036
|
+
literalCount: row.LiteralCount,
|
|
12037
|
+
path: row.Path,
|
|
12038
|
+
sha256: row.Sha256,
|
|
12039
|
+
updatedAt: row.UpdatedUtc
|
|
12040
|
+
})),
|
|
12041
|
+
sqliteReadyColumns: [
|
|
12042
|
+
'Id',
|
|
12043
|
+
'SqlKey',
|
|
12044
|
+
'Signature',
|
|
12045
|
+
'Body',
|
|
12046
|
+
'Category',
|
|
12047
|
+
'ConceptType',
|
|
12048
|
+
'Description',
|
|
12049
|
+
'EmbeddingVector',
|
|
12050
|
+
'EmbeddingBase64',
|
|
12051
|
+
'EmbeddingModel',
|
|
12052
|
+
'AtomCount',
|
|
12053
|
+
'LiteralCount',
|
|
12054
|
+
'CreatedUtc',
|
|
12055
|
+
'UpdatedUtc'
|
|
12056
|
+
],
|
|
12057
|
+
paidEmbeddingAdapterState: 'adapter-gated',
|
|
12058
|
+
nativeSqliteAdapterState: nativeSqlite?.adapterState || 'native-sqlite-pending',
|
|
12059
|
+
nativeSqlite
|
|
12060
|
+
};
|
|
12061
|
+
}
|
|
12062
|
+
|
|
12063
|
+
async function readConceptCompositeRecordById(id) {
|
|
12064
|
+
const normalizedId = normalizeConceptHex64(id, 'id');
|
|
12065
|
+
const index = await readConceptStoreIndex();
|
|
12066
|
+
const row = (Array.isArray(index.Rows) ? index.Rows : []).find(item => String(item?.Id || '').toLowerCase() === normalizedId);
|
|
12067
|
+
if (!row?.Path) {
|
|
12068
|
+
const err = new Error(`Concept row not found: ${normalizedId}`);
|
|
12069
|
+
err.statusCode = 404;
|
|
12070
|
+
throw err;
|
|
12071
|
+
}
|
|
12072
|
+
|
|
12073
|
+
const fullPath = path.resolve(workspacePath, String(row.Path));
|
|
12074
|
+
const { baseConceptDir } = getConceptStorePaths();
|
|
12075
|
+
if (!isPathWithin(baseConceptDir, fullPath)) {
|
|
12076
|
+
const err = new Error('Concept row path must stay under the concept cache.');
|
|
12077
|
+
err.statusCode = 400;
|
|
12078
|
+
throw err;
|
|
12079
|
+
}
|
|
12080
|
+
|
|
12081
|
+
const record = JSON.parse(await fs.readFile(fullPath, 'utf8'));
|
|
12082
|
+
if (String(record?.Concept?.Id || '').toLowerCase() !== normalizedId) {
|
|
12083
|
+
const err = new Error(`Concept row id mismatch: expected ${normalizedId}`);
|
|
12084
|
+
err.statusCode = 409;
|
|
12085
|
+
throw err;
|
|
12086
|
+
}
|
|
12087
|
+
return record;
|
|
12088
|
+
}
|
|
12089
|
+
|
|
12090
|
+
function getConceptEmbeddingProviderConfig() {
|
|
12091
|
+
const baseUrl = String(
|
|
12092
|
+
process.env.MINDEXEC_CONCEPT_EMBED_BASE_URL
|
|
12093
|
+
|| process.env.OPENAI_BASE_URL
|
|
12094
|
+
|| process.env.OPENROUTER_BASE_URL
|
|
12095
|
+
|| 'https://api.openai.com/v1'
|
|
12096
|
+
).trim().replace(/\/+$/, '');
|
|
12097
|
+
const model = String(
|
|
12098
|
+
process.env.MINDEXEC_CONCEPT_EMBED_MODEL
|
|
12099
|
+
|| process.env.OPENAI_EMBEDDING_MODEL
|
|
12100
|
+
|| 'text-embedding-3-small'
|
|
12101
|
+
).trim();
|
|
12102
|
+
const apiKey = String(
|
|
12103
|
+
process.env.MINDEXEC_CONCEPT_EMBED_API_KEY
|
|
12104
|
+
|| process.env.OPENAI_API_KEY
|
|
12105
|
+
|| process.env.OPENROUTER_API_KEY
|
|
12106
|
+
|| ''
|
|
12107
|
+
).trim();
|
|
12108
|
+
const confirm = String(process.env.MINDEXEC_CONCEPT_EMBED_LIVE_CONFIRM || '').trim();
|
|
12109
|
+
return {
|
|
12110
|
+
baseUrl,
|
|
12111
|
+
model,
|
|
12112
|
+
apiKey,
|
|
12113
|
+
hasApiKey: Boolean(apiKey) && !apiKey.includes('__PUT_YOUR_KEY_HERE__'),
|
|
12114
|
+
confirm,
|
|
12115
|
+
confirmed: confirm === CONCEPT_EMBED_LIVE_CONFIRM_VALUE
|
|
12116
|
+
};
|
|
12117
|
+
}
|
|
12118
|
+
|
|
12119
|
+
function buildConceptEmbeddingReadinessResponse() {
|
|
12120
|
+
const config = getConceptEmbeddingProviderConfig();
|
|
12121
|
+
const url = new URL(`${config.baseUrl}/embeddings`);
|
|
12122
|
+
return {
|
|
12123
|
+
success: true,
|
|
12124
|
+
provider: 'OpenAI-compatible embeddings',
|
|
12125
|
+
adapterState: config.confirmed && config.hasApiKey ? 'available-opt-in' : 'adapter-gated',
|
|
12126
|
+
confirmationEnv: 'MINDEXEC_CONCEPT_EMBED_LIVE_CONFIRM',
|
|
12127
|
+
requiredConfirmation: CONCEPT_EMBED_LIVE_CONFIRM_VALUE,
|
|
12128
|
+
confirmationState: config.confirmed ? 'confirmed' : 'missing',
|
|
12129
|
+
apiKeyState: config.hasApiKey ? 'present' : 'missing',
|
|
12130
|
+
baseUrlHost: url.host,
|
|
12131
|
+
endpointPath: url.pathname,
|
|
12132
|
+
model: config.model,
|
|
12133
|
+
inputPolicy: 'signature + "\\n\\nDescription: " + description',
|
|
12134
|
+
storesEmbeddingBase64: true,
|
|
12135
|
+
defaultRunMode: 'blocked-until-confirmed'
|
|
12136
|
+
};
|
|
12137
|
+
}
|
|
12138
|
+
|
|
12139
|
+
function normalizeConceptEmbeddingRequest(request = {}) {
|
|
12140
|
+
const signature = clampEvidenceText(request.signature || request.Signature, 500);
|
|
12141
|
+
const description = clampEvidenceText(request.description || request.Description, 2400);
|
|
12142
|
+
if (!signature.trim()) {
|
|
12143
|
+
const err = new Error('signature is required');
|
|
12144
|
+
err.statusCode = 400;
|
|
12145
|
+
throw err;
|
|
12146
|
+
}
|
|
12147
|
+
if (!description.trim()) {
|
|
12148
|
+
const err = new Error('description is required');
|
|
12149
|
+
err.statusCode = 400;
|
|
12150
|
+
throw err;
|
|
12151
|
+
}
|
|
12152
|
+
return {
|
|
12153
|
+
signature: signature.trim(),
|
|
12154
|
+
description: description.trim(),
|
|
12155
|
+
category: clampEvidenceText(request.category || request.Category || '', 160),
|
|
12156
|
+
conceptType: clampEvidenceText(request.conceptType || request.ConceptType || 'Axiom', 80) || 'Axiom'
|
|
12157
|
+
};
|
|
12158
|
+
}
|
|
12159
|
+
|
|
12160
|
+
async function callConceptEmbeddingProvider(input, config) {
|
|
12161
|
+
const controller = new AbortController();
|
|
12162
|
+
const timeout = setTimeout(() => controller.abort(), 45000);
|
|
12163
|
+
try {
|
|
12164
|
+
const response = await fetch(`${config.baseUrl}/embeddings`, {
|
|
12165
|
+
method: 'POST',
|
|
12166
|
+
headers: {
|
|
12167
|
+
'Authorization': `Bearer ${config.apiKey}`,
|
|
12168
|
+
'Content-Type': 'application/json'
|
|
12169
|
+
},
|
|
12170
|
+
body: JSON.stringify({ model: config.model, input }),
|
|
12171
|
+
signal: controller.signal
|
|
12172
|
+
});
|
|
12173
|
+
const text = await response.text();
|
|
12174
|
+
if (!response.ok) {
|
|
12175
|
+
const err = new Error(`OpenAI-compatible embeddings error ${response.status}: ${text.slice(0, 500)}`);
|
|
12176
|
+
err.statusCode = 502;
|
|
12177
|
+
throw err;
|
|
12178
|
+
}
|
|
12179
|
+
let payload;
|
|
12180
|
+
try {
|
|
12181
|
+
payload = text ? JSON.parse(text) : {};
|
|
12182
|
+
} catch (parseErr) {
|
|
12183
|
+
const err = new Error(`Embedding provider returned invalid JSON: ${parseErr?.message || parseErr}`);
|
|
12184
|
+
err.statusCode = 502;
|
|
12185
|
+
throw err;
|
|
12186
|
+
}
|
|
12187
|
+
const embedding = payload?.data?.[0]?.embedding;
|
|
12188
|
+
if (!Array.isArray(embedding) || embedding.length === 0) {
|
|
12189
|
+
const err = new Error('Embedding provider returned an empty embedding.');
|
|
12190
|
+
err.statusCode = 502;
|
|
12191
|
+
throw err;
|
|
12192
|
+
}
|
|
12193
|
+
if (embedding.length > 16384) {
|
|
12194
|
+
const err = new Error(`Embedding vector too large: ${embedding.length}`);
|
|
12195
|
+
err.statusCode = 413;
|
|
12196
|
+
throw err;
|
|
12197
|
+
}
|
|
12198
|
+
return embedding.map(value => Number(value) || 0);
|
|
12199
|
+
} finally {
|
|
12200
|
+
clearTimeout(timeout);
|
|
12201
|
+
}
|
|
12202
|
+
}
|
|
12203
|
+
|
|
12204
|
+
async function upsertConceptEmbeddingRecord(request = {}) {
|
|
12205
|
+
const normalized = normalizeConceptEmbeddingRequest(request);
|
|
12206
|
+
const config = getConceptEmbeddingProviderConfig();
|
|
12207
|
+
if (!config.confirmed) {
|
|
12208
|
+
const err = new Error(`Embedding provider calls require MINDEXEC_CONCEPT_EMBED_LIVE_CONFIRM=${CONCEPT_EMBED_LIVE_CONFIRM_VALUE}`);
|
|
12209
|
+
err.statusCode = 403;
|
|
12210
|
+
throw err;
|
|
12211
|
+
}
|
|
12212
|
+
if (!config.hasApiKey) {
|
|
12213
|
+
const err = new Error('Embedding provider API key is missing from server environment.');
|
|
12214
|
+
err.statusCode = 403;
|
|
12215
|
+
throw err;
|
|
12216
|
+
}
|
|
12217
|
+
|
|
12218
|
+
const id = conceptHash64Hex(normalized.signature);
|
|
12219
|
+
let existing = null;
|
|
12220
|
+
try {
|
|
12221
|
+
existing = await readConceptCompositeRecordById(id);
|
|
12222
|
+
} catch (err) {
|
|
12223
|
+
if (Number(err?.statusCode) !== 404) throw err;
|
|
12224
|
+
}
|
|
12225
|
+
|
|
12226
|
+
const input = `${normalized.signature}\n\nDescription: ${normalized.description}`;
|
|
12227
|
+
const vector = await callConceptEmbeddingProvider(input, config);
|
|
12228
|
+
const nowUtc = new Date().toISOString();
|
|
12229
|
+
const { baseConceptDir, rowDir, indexPath } = getConceptStorePaths();
|
|
12230
|
+
const fileName = existing?.Path
|
|
12231
|
+
? path.basename(existing.Path)
|
|
12232
|
+
: `${id.slice(2)}-${slugifyEvidence(normalized.signature, 64)}.json`;
|
|
12233
|
+
const fullPath = existing?.Path
|
|
12234
|
+
? path.resolve(workspacePath, existing.Path)
|
|
12235
|
+
: path.resolve(rowDir, fileName);
|
|
12236
|
+
|
|
12237
|
+
if (!isPathWithin(baseConceptDir, fullPath) || !isPathWithin(baseConceptDir, indexPath)) {
|
|
12238
|
+
const err = new Error('Concept embedding path must stay under the concept cache.');
|
|
12239
|
+
err.statusCode = 400;
|
|
12240
|
+
throw err;
|
|
12241
|
+
}
|
|
12242
|
+
|
|
12243
|
+
const relativePath = normalizePathForClient(path.relative(workspacePath, fullPath));
|
|
12244
|
+
const relativeIndexPath = normalizePathForClient(path.relative(workspacePath, indexPath));
|
|
12245
|
+
const previousConcept = existing?.Concept || {};
|
|
12246
|
+
const conceptRow = {
|
|
12247
|
+
Id: id,
|
|
12248
|
+
SqlKey: conceptSqlKeyString(id),
|
|
12249
|
+
Signature: normalized.signature,
|
|
12250
|
+
Body: previousConcept.Body,
|
|
12251
|
+
Category: normalized.category || previousConcept.Category || '',
|
|
12252
|
+
ConceptType: normalized.conceptType || previousConcept.ConceptType || 'Axiom',
|
|
12253
|
+
CreatedUtc: previousConcept.CreatedUtc || nowUtc,
|
|
12254
|
+
UpdatedUtc: nowUtc,
|
|
12255
|
+
Description: normalized.description,
|
|
12256
|
+
EmbeddingVector: vector,
|
|
12257
|
+
EmbeddingBase64: serializeConceptFloatVectorBase64(vector),
|
|
12258
|
+
EmbeddingModel: config.model,
|
|
12259
|
+
EmbeddingUpdatedUtc: nowUtc,
|
|
12260
|
+
AtomCount: Number(previousConcept.AtomCount || 0),
|
|
12261
|
+
LiteralCount: Number(previousConcept.LiteralCount || 0)
|
|
12262
|
+
};
|
|
12263
|
+
const record = {
|
|
12264
|
+
Schema: 'MindExecution.Kernel.Store.ConceptConcept/v1',
|
|
12265
|
+
Store: {
|
|
12266
|
+
Provider: 'LocalBridgeJsonConceptStore',
|
|
12267
|
+
OriginalTable: 'tbl_concepts',
|
|
12268
|
+
Notes: 'OpenAI-compatible embedding provider result stored as JSON row projection and mirrored into native SQLite tbl_concepts.'
|
|
12269
|
+
},
|
|
12270
|
+
HashAlgorithm: CONCEPT_HASH_ALGORITHM,
|
|
12271
|
+
Concept: conceptRow,
|
|
12272
|
+
Path: relativePath,
|
|
12273
|
+
IndexPath: relativeIndexPath
|
|
12274
|
+
};
|
|
12275
|
+
|
|
12276
|
+
const unsignedJson = JSON.stringify(record, null, 2);
|
|
12277
|
+
record.Sha256 = crypto.createHash('sha256').update(unsignedJson, 'utf8').digest('hex');
|
|
12278
|
+
await writeFileAtomically(fullPath, `${JSON.stringify(record, null, 2)}\n`, 'utf8');
|
|
12279
|
+
|
|
12280
|
+
const currentIndex = await readJsonIfExists(indexPath, {
|
|
12281
|
+
Schema: 'MindExecution.Kernel.Store.ConceptConceptIndex/v1',
|
|
12282
|
+
Store: 'LocalBridgeJsonConceptStore',
|
|
12283
|
+
HashAlgorithm: CONCEPT_HASH_ALGORITHM,
|
|
12284
|
+
Rows: []
|
|
12285
|
+
});
|
|
12286
|
+
const rows = Array.isArray(currentIndex.Rows) ? currentIndex.Rows : [];
|
|
12287
|
+
const nextRows = [
|
|
12288
|
+
{
|
|
12289
|
+
Id: conceptRow.Id,
|
|
12290
|
+
SqlKey: conceptRow.SqlKey,
|
|
12291
|
+
Signature: conceptRow.Signature,
|
|
12292
|
+
Category: conceptRow.Category,
|
|
12293
|
+
ConceptType: conceptRow.ConceptType,
|
|
12294
|
+
UpdatedUtc: conceptRow.UpdatedUtc,
|
|
12295
|
+
AtomCount: conceptRow.AtomCount,
|
|
12296
|
+
LiteralCount: conceptRow.LiteralCount,
|
|
12297
|
+
Path: relativePath,
|
|
12298
|
+
Sha256: record.Sha256,
|
|
12299
|
+
EmbeddingModel: conceptRow.EmbeddingModel,
|
|
12300
|
+
EmbeddingUpdatedUtc: conceptRow.EmbeddingUpdatedUtc
|
|
12301
|
+
},
|
|
12302
|
+
...rows.filter(row => String(row?.Id || '').toLowerCase() !== conceptRow.Id)
|
|
12303
|
+
].slice(0, 512);
|
|
12304
|
+
const nextIndex = {
|
|
12305
|
+
Schema: 'MindExecution.Kernel.Store.ConceptConceptIndex/v1',
|
|
12306
|
+
Store: 'LocalBridgeJsonConceptStore',
|
|
12307
|
+
HashAlgorithm: CONCEPT_HASH_ALGORITHM,
|
|
12308
|
+
UpdatedUtc: nowUtc,
|
|
12309
|
+
RowCount: nextRows.length,
|
|
12310
|
+
Rows: nextRows
|
|
12311
|
+
};
|
|
12312
|
+
await writeFileAtomically(indexPath, `${JSON.stringify(nextIndex, null, 2)}\n`, 'utf8');
|
|
12313
|
+
record.NativeSqlite = await upsertConceptNativeSqlite(record);
|
|
12314
|
+
return record;
|
|
12315
|
+
}
|
|
12316
|
+
|
|
12317
|
+
function parseHtmlAttributes(attrs) {
|
|
11090
12318
|
const result = {};
|
|
11091
12319
|
const regex = /([A-Za-z_:][-A-Za-z0-9_:.]*)\s*=\s*["']([^"']*)["']/g;
|
|
11092
12320
|
let match;
|
|
@@ -12644,9 +13872,9 @@ app.post('/api/web/search', async (req, res) => {
|
|
|
12644
13872
|
}
|
|
12645
13873
|
});
|
|
12646
13874
|
|
|
12647
|
-
app.post('/api/web/fetch', async (req, res) => {
|
|
12648
|
-
try {
|
|
12649
|
-
const { url, maxChars = 12000 } = req.body || {};
|
|
13875
|
+
app.post('/api/web/fetch', async (req, res) => {
|
|
13876
|
+
try {
|
|
13877
|
+
const { url, maxChars = 12000 } = req.body || {};
|
|
12650
13878
|
if (!url || !String(url).trim()) {
|
|
12651
13879
|
return res.status(400).json({ error: 'URL is required' });
|
|
12652
13880
|
}
|
|
@@ -12662,12 +13890,119 @@ app.post('/api/web/fetch', async (req, res) => {
|
|
|
12662
13890
|
console.error('[Web/Fetch] Error:', err);
|
|
12663
13891
|
const statusCode = Number(err?.statusCode) || 500;
|
|
12664
13892
|
res.status(statusCode).json({ error: err?.message || 'Web fetch failed' });
|
|
12665
|
-
}
|
|
12666
|
-
});
|
|
12667
|
-
|
|
12668
|
-
app.post('/api/
|
|
12669
|
-
try {
|
|
12670
|
-
const
|
|
13893
|
+
}
|
|
13894
|
+
});
|
|
13895
|
+
|
|
13896
|
+
app.post('/api/evidence/save', async (req, res) => {
|
|
13897
|
+
try {
|
|
13898
|
+
const record = await saveEvidenceRecord(req.body || {});
|
|
13899
|
+
logToolAction(
|
|
13900
|
+
'Evidence.Save',
|
|
13901
|
+
`${formatKeyValue('path', tone(record.Path, 'path'))} ${formatKeyValue('kind', record.Kind)} ${formatKeyValue('source', shortenText(record.SourceUrl || record.SourcePath || '-', 100))}`,
|
|
13902
|
+
'success');
|
|
13903
|
+
res.json(buildEvidenceResponse(record));
|
|
13904
|
+
} catch (err) {
|
|
13905
|
+
console.error('[Evidence/Save] Error:', err);
|
|
13906
|
+
const statusCode = Number(err?.statusCode) || 500;
|
|
13907
|
+
res.status(statusCode).json({ success: false, error: err?.message || 'Evidence save failed' });
|
|
13908
|
+
}
|
|
13909
|
+
});
|
|
13910
|
+
|
|
13911
|
+
app.post('/api/concept/define-composite', async (req, res) => {
|
|
13912
|
+
try {
|
|
13913
|
+
const record = await saveConceptCompositeRecord(req.body || {});
|
|
13914
|
+
logToolAction(
|
|
13915
|
+
'Concept.DefineComposite',
|
|
13916
|
+
`${formatKeyValue('id', record.Concept.Id)} ${formatKeyValue('path', tone(record.Path, 'path'))} ${formatKeyValue('atoms', record.Concept.AtomCount)}`,
|
|
13917
|
+
'success');
|
|
13918
|
+
res.json(buildConceptCompositeResponse(record));
|
|
13919
|
+
} catch (err) {
|
|
13920
|
+
console.error('[Concept/DefineComposite] Error:', err);
|
|
13921
|
+
const statusCode = Number(err?.statusCode) || 500;
|
|
13922
|
+
res.status(statusCode).json({ success: false, error: err?.message || 'Concept composite save failed' });
|
|
13923
|
+
}
|
|
13924
|
+
});
|
|
13925
|
+
|
|
13926
|
+
app.get('/api/concept/status', async (req, res) => {
|
|
13927
|
+
try {
|
|
13928
|
+
const index = await readConceptStoreIndex();
|
|
13929
|
+
const nativeSqlite = await readConceptNativeSqliteStatus();
|
|
13930
|
+
const response = buildConceptStoreStatusResponse(index, nativeSqlite);
|
|
13931
|
+
logToolAction(
|
|
13932
|
+
'Concept.Status',
|
|
13933
|
+
`${formatKeyValue('rows', response.rowCount)} ${formatKeyValue('store', response.adapterState)} ${formatKeyValue('sqlite', response.nativeSqliteAdapterState)} ${formatKeyValue('index', tone(response.indexPath || '-', 'path'))}`,
|
|
13934
|
+
response.adapterState === 'json-row-projection' ? 'bridge' : 'warn');
|
|
13935
|
+
res.json(response);
|
|
13936
|
+
} catch (err) {
|
|
13937
|
+
console.error('[Concept/Status] Error:', err);
|
|
13938
|
+
const statusCode = Number(err?.statusCode) || 500;
|
|
13939
|
+
res.status(statusCode).json({ success: false, error: err?.message || 'Concept status failed' });
|
|
13940
|
+
}
|
|
13941
|
+
});
|
|
13942
|
+
|
|
13943
|
+
app.get('/api/concept/row', async (req, res) => {
|
|
13944
|
+
try {
|
|
13945
|
+
const record = await readConceptCompositeRecordById(req.query?.id || req.query?.Id);
|
|
13946
|
+
logToolAction(
|
|
13947
|
+
'Concept.Row',
|
|
13948
|
+
`${formatKeyValue('id', record.Concept.Id)} ${formatKeyValue('path', tone(record.Path, 'path'))} ${formatKeyValue('atoms', record.Concept.AtomCount)}`,
|
|
13949
|
+
'bridge');
|
|
13950
|
+
res.json(buildConceptCompositeResponse(record));
|
|
13951
|
+
} catch (err) {
|
|
13952
|
+
console.error('[Concept/Row] Error:', err);
|
|
13953
|
+
const statusCode = Number(err?.statusCode) || 500;
|
|
13954
|
+
res.status(statusCode).json({ success: false, error: err?.message || 'Concept row read failed' });
|
|
13955
|
+
}
|
|
13956
|
+
});
|
|
13957
|
+
|
|
13958
|
+
app.get('/api/concept/sqlite/row', async (req, res) => {
|
|
13959
|
+
try {
|
|
13960
|
+
const response = await readConceptNativeSqliteRowById(req.query?.id || req.query?.Id);
|
|
13961
|
+
logToolAction(
|
|
13962
|
+
'Concept.SQLite.Row',
|
|
13963
|
+
`${formatKeyValue('id', response.id)} ${formatKeyValue('path', tone(response.sqlitePath, 'path'))} ${formatKeyValue('bytes', response.embeddingBytes)}`,
|
|
13964
|
+
'bridge');
|
|
13965
|
+
res.json(response);
|
|
13966
|
+
} catch (err) {
|
|
13967
|
+
console.error('[Concept/SQLite/Row] Error:', err);
|
|
13968
|
+
const statusCode = Number(err?.statusCode) || 500;
|
|
13969
|
+
res.status(statusCode).json({ success: false, error: err?.message || 'Concept SQLite row read failed' });
|
|
13970
|
+
}
|
|
13971
|
+
});
|
|
13972
|
+
|
|
13973
|
+
app.get('/api/concept/embed/readiness', async (req, res) => {
|
|
13974
|
+
try {
|
|
13975
|
+
const response = buildConceptEmbeddingReadinessResponse();
|
|
13976
|
+
logToolAction(
|
|
13977
|
+
'Concept.Embed.Readiness',
|
|
13978
|
+
`${formatKeyValue('state', response.adapterState)} ${formatKeyValue('model', response.model)} ${formatKeyValue('endpoint', `${response.baseUrlHost}${response.endpointPath}`)}`,
|
|
13979
|
+
response.adapterState === 'available-opt-in' ? 'bridge' : 'warn');
|
|
13980
|
+
res.json(response);
|
|
13981
|
+
} catch (err) {
|
|
13982
|
+
console.error('[Concept/Embed/Readiness] Error:', err);
|
|
13983
|
+
const statusCode = Number(err?.statusCode) || 500;
|
|
13984
|
+
res.status(statusCode).json({ success: false, error: err?.message || 'Concept embed readiness failed' });
|
|
13985
|
+
}
|
|
13986
|
+
});
|
|
13987
|
+
|
|
13988
|
+
app.post('/api/concept/embed', async (req, res) => {
|
|
13989
|
+
try {
|
|
13990
|
+
const record = await upsertConceptEmbeddingRecord(req.body || {});
|
|
13991
|
+
logToolAction(
|
|
13992
|
+
'Concept.Embed',
|
|
13993
|
+
`${formatKeyValue('id', record.Concept.Id)} ${formatKeyValue('dim', Array.isArray(record.Concept.EmbeddingVector) ? record.Concept.EmbeddingVector.length : 0)} ${formatKeyValue('model', record.Concept.EmbeddingModel)}`,
|
|
13994
|
+
'success');
|
|
13995
|
+
res.json(buildConceptCompositeResponse(record));
|
|
13996
|
+
} catch (err) {
|
|
13997
|
+
console.error('[Concept/Embed] Error:', err);
|
|
13998
|
+
const statusCode = Number(err?.statusCode) || 500;
|
|
13999
|
+
res.status(statusCode).json({ success: false, error: err?.message || 'Concept embed failed' });
|
|
14000
|
+
}
|
|
14001
|
+
});
|
|
14002
|
+
|
|
14003
|
+
app.post('/api/browser/open', async (req, res) => {
|
|
14004
|
+
try {
|
|
14005
|
+
const { url } = req.body || {};
|
|
12671
14006
|
if (!url || !String(url).trim()) {
|
|
12672
14007
|
return res.status(400).json({ error: 'URL is required' });
|
|
12673
14008
|
}
|