onbuzz 4.3.0 → 4.5.0
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/package.json +1 -1
- package/src/core/__tests__/agentScheduler.visualizer.test.js +258 -0
- package/src/core/agentPool.js +4 -0
- package/src/core/agentScheduler.js +16 -1
- package/src/core/stateManager.js +5 -0
- package/src/index.js +34 -0
- package/src/interfaces/__tests__/agentContextRoutes.test.js +272 -0
- package/src/interfaces/__tests__/schedulerRoutes.test.js +176 -0
- package/src/interfaces/agentContextRoutes.js +257 -0
- package/src/interfaces/schedulerRoutes.js +50 -0
- package/src/interfaces/webServer.js +77 -20
- package/src/modules/widget/__tests__/acceptance.test.js +267 -0
- package/src/modules/widget/__tests__/codeAnalyzer.test.js +340 -0
- package/src/modules/widget/__tests__/eventBus.test.js +169 -0
- package/src/modules/widget/__tests__/galleryActions.test.js +290 -0
- package/src/modules/widget/__tests__/galleryStore.test.js +269 -0
- package/src/modules/widget/__tests__/isDisabled.test.js +41 -0
- package/src/modules/widget/__tests__/naming.test.js +204 -0
- package/src/modules/widget/__tests__/phishingScanner.test.js +75 -0
- package/src/modules/widget/__tests__/routes.test.js +678 -0
- package/src/modules/widget/__tests__/runtime.test.js +401 -0
- package/src/modules/widget/__tests__/schema.test.js +155 -0
- package/src/modules/widget/__tests__/upgrade.test.js +257 -0
- package/src/modules/widget/__tests__/versioning.test.js +309 -0
- package/src/modules/widget/__tests__/webComponentRuntime.test.js +565 -0
- package/src/modules/widget/__tests__/widgetTool.test.js +316 -0
- package/src/modules/widget/codeAnalyzer.js +351 -0
- package/src/modules/widget/galleryStore.js +324 -0
- package/src/modules/widget/index.js +38 -0
- package/src/modules/widget/phishingScanner.js +47 -0
- package/src/modules/widget/routes.js +435 -0
- package/src/modules/widget/runtime/bundle.js +640 -0
- package/src/modules/widget/runtime/webComponentBundle.js +470 -0
- package/src/modules/widget/schema.js +181 -0
- package/src/modules/widget/widgetTool.js +1389 -0
- package/src/services/__tests__/contextInjectionService.test.js +41 -0
- package/src/services/contextInjectionService.js +24 -0
- package/src/tools/__tests__/platformControlAgentTeam.test.js +623 -0
- package/src/tools/__tests__/platformControlAgentTeamPermissions.test.js +253 -0
- package/src/tools/__tests__/platformControlAncestry.test.js +131 -0
- package/src/tools/__tests__/platformControlCascade.test.js +177 -0
- package/src/tools/__tests__/platformControlPermissions.test.js +128 -0
- package/src/tools/__tests__/platformControlPersistence.test.js +134 -0
- package/src/tools/__tests__/platformControlTool.test.js +391 -0
- package/src/tools/__tests__/terminalDedup.test.js +324 -0
- package/src/tools/platformControl/ancestry.js +85 -0
- package/src/tools/platformControl/cascadeService.js +146 -0
- package/src/tools/platformControl/permissions.js +394 -0
- package/src/tools/platformControlTool.js +854 -0
- package/src/tools/terminalDedup.js +178 -0
- package/src/tools/terminalTool.js +28 -0
- package/src/utilities/constants.js +1 -1
- package/web-ui/build/index.html +2 -2
- package/web-ui/build/static/1c-Cxgysx0K.js +1 -0
- package/web-ui/build/static/abap-D9Pd8DUG.js +1 -0
- package/web-ui/build/static/abnf-CHs5P8yl.js +1 -0
- package/web-ui/build/static/abnf-D5OtFEZO.js +1 -0
- package/web-ui/build/static/accesslog-CTD5Frmr.js +1 -0
- package/web-ui/build/static/actionscript-BN0BKQI7.js +1 -0
- package/web-ui/build/static/actionscript-DQNwbYlU.js +1 -0
- package/web-ui/build/static/ada-8O7AmGii.js +1 -0
- package/web-ui/build/static/ada-p8y2qCLB.js +1 -0
- package/web-ui/build/static/agda-BzT4bKSx.js +1 -0
- package/web-ui/build/static/al-Caq7o9RG.js +1 -0
- package/web-ui/build/static/angelscript-DivMpSHf.js +1 -0
- package/web-ui/build/static/antlr4-B1D_tnKH.js +1 -0
- package/web-ui/build/static/apache-l88_LooT.js +1 -0
- package/web-ui/build/static/apacheconf-kaxXABFE.js +1 -0
- package/web-ui/build/static/apex-CSdSRWUv.js +1 -0
- package/web-ui/build/static/apl-CHwVg89T.js +1 -0
- package/web-ui/build/static/applescript-C64qdYZf.js +1 -0
- package/web-ui/build/static/applescript-CqTGrBVp.js +1 -0
- package/web-ui/build/static/aql-BwKKr7z7.js +1 -0
- package/web-ui/build/static/arcade-C6oqHEwh.js +1 -0
- package/web-ui/build/static/arduino-DB4E20Km.js +1 -0
- package/web-ui/build/static/arduino-DKpgmHjE.js +1 -0
- package/web-ui/build/static/arff-CBbf8E8O.js +1 -0
- package/web-ui/build/static/armasm-Bogg7lrz.js +1 -0
- package/web-ui/build/static/asciidoc-3ZlDsfKD.js +1 -0
- package/web-ui/build/static/asciidoc-Cc88g_au.js +1 -0
- package/web-ui/build/static/asm6502-B4rN-vZ1.js +1 -0
- package/web-ui/build/static/asmatmel-B8zZLWGk.js +1 -0
- package/web-ui/build/static/aspectj-XdNtCtbN.js +1 -0
- package/web-ui/build/static/aspnet-DZVKB5n1.js +1 -0
- package/web-ui/build/static/autohotkey-CxDWLQqM.js +1 -0
- package/web-ui/build/static/autohotkey-DJStPrtS.js +1 -0
- package/web-ui/build/static/autoit-BWirJOCg.js +1 -0
- package/web-ui/build/static/autoit-CJcfmsnl.js +1 -0
- package/web-ui/build/static/avisynth-C7JQe3L7.js +1 -0
- package/web-ui/build/static/avrasm-CMiuHQvu.js +1 -0
- package/web-ui/build/static/avro-idl-kaRVyxMP.js +1 -0
- package/web-ui/build/static/awk-CQ70Cyh1.js +1 -0
- package/web-ui/build/static/axapta-DRxAzlG8.js +1 -0
- package/web-ui/build/static/bash-B2XqEYpT.js +1 -0
- package/web-ui/build/static/bash-D-D1taMA.js +1 -0
- package/web-ui/build/static/basic-Da1x7OIZ.js +1 -0
- package/web-ui/build/static/basic-Dslk2ZwT.js +1 -0
- package/web-ui/build/static/batch-B0wJNPoF.js +1 -0
- package/web-ui/build/static/bbcode-BXDdc2HS.js +1 -0
- package/web-ui/build/static/bicep-iiH-nx9J.js +1 -0
- package/web-ui/build/static/birb-DuTqqibI.js +1 -0
- package/web-ui/build/static/bison-D1Hw6owA.js +1 -0
- package/web-ui/build/static/bnf-BRhzfr87.js +1 -0
- package/web-ui/build/static/bnf-u1Iy1Ku7.js +1 -0
- package/web-ui/build/static/brainfuck-C4R5VJ3_.js +1 -0
- package/web-ui/build/static/brainfuck-C8niWF0i.js +1 -0
- package/web-ui/build/static/brightscript-DavMfkHx.js +1 -0
- package/web-ui/build/static/bro-CEMPoYum.js +1 -0
- package/web-ui/build/static/bsl-COeqiMqc.js +1 -0
- package/web-ui/build/static/c-BaaVQwFt.js +1 -0
- package/web-ui/build/static/c-BvALLiMv.js +1 -0
- package/web-ui/build/static/c-like-C4yx6s7b.js +1 -0
- package/web-ui/build/static/cal-CSxgKgNR.js +1 -0
- package/web-ui/build/static/capnproto-C9cMEmIo.js +1 -0
- package/web-ui/build/static/ceylon-Dj67Lf2T.js +1 -0
- package/web-ui/build/static/cfscript-BhALECgj.js +1 -0
- package/web-ui/build/static/chaiscript-Cg5weNRB.js +1 -0
- package/web-ui/build/static/cil-BR-JCsPu.js +1 -0
- package/web-ui/build/static/clean-xJMmqZ4X.js +1 -0
- package/web-ui/build/static/clojure-9C3tRo_T.js +1 -0
- package/web-ui/build/static/clojure-C2KNwa0h.js +1 -0
- package/web-ui/build/static/clojure-repl-B-pke3nS.js +1 -0
- package/web-ui/build/static/cmake-C0BFHpjZ.js +1 -0
- package/web-ui/build/static/cmake-DYoa_Kz_.js +1 -0
- package/web-ui/build/static/cobol-Bj_qcMsY.js +1 -0
- package/web-ui/build/static/coffeescript-C2KEz8d0.js +1 -0
- package/web-ui/build/static/coffeescript-CQsP9N_M.js +1 -0
- package/web-ui/build/static/concurnas-Ceu24KQb.js +1 -0
- package/web-ui/build/static/coq-CP7VW0bo.js +1 -0
- package/web-ui/build/static/coq-DQry0I8v.js +1 -0
- package/web-ui/build/static/cos-DAjhu7pi.js +1 -0
- package/web-ui/build/static/cpp-BwHJ0JtK.js +1 -0
- package/web-ui/build/static/cpp-Dro3stzS.js +1 -0
- package/web-ui/build/static/crmsh-Bnwknpi9.js +1 -0
- package/web-ui/build/static/crystal-B7TVeIo6.js +1 -0
- package/web-ui/build/static/crystal-Cy5JlSrW.js +1 -0
- package/web-ui/build/static/csharp-CeouYZK3.js +1 -0
- package/web-ui/build/static/csharp-Dv2oxLAS.js +1 -0
- package/web-ui/build/static/cshtml-C9IRHsFH.js +1 -0
- package/web-ui/build/static/csp-C85pVqYT.js +1 -0
- package/web-ui/build/static/csp-MJntgwIj.js +1 -0
- package/web-ui/build/static/css-DWTfQjN4.js +1 -0
- package/web-ui/build/static/css-extras-BmVbsPjr.js +1 -0
- package/web-ui/build/static/csv-zUw-JkSo.js +1 -0
- package/web-ui/build/static/cypher-DQOOp0bG.js +1 -0
- package/web-ui/build/static/d-B7Cku9c8.js +1 -0
- package/web-ui/build/static/d-Lnzvs4Wd.js +1 -0
- package/web-ui/build/static/dart-CeK_W9Mg.js +1 -0
- package/web-ui/build/static/dart-Z5nwVCn_.js +1 -0
- package/web-ui/build/static/dataweave-Bv7GTsiJ.js +1 -0
- package/web-ui/build/static/dax-CxkNT7ml.js +1 -0
- package/web-ui/build/static/delphi-BnBBHmHI.js +1 -0
- package/web-ui/build/static/dhall-DzzkunJZ.js +1 -0
- package/web-ui/build/static/diff-BKZzYJzc.js +1 -0
- package/web-ui/build/static/diff-BfTiUZV3.js +1 -0
- package/web-ui/build/static/django-BY4l8873.js +1 -0
- package/web-ui/build/static/django-NRVGlUZ_.js +1 -0
- package/web-ui/build/static/dns-Dvc8YawT.js +1 -0
- package/web-ui/build/static/dns-zone-file-CkaiOrlK.js +1 -0
- package/web-ui/build/static/docker-BQXYNHPO.js +1 -0
- package/web-ui/build/static/dockerfile-CkHfYmB1.js +1 -0
- package/web-ui/build/static/dos-Cj0YcQAg.js +1 -0
- package/web-ui/build/static/dot-zgBkKTS-.js +1 -0
- package/web-ui/build/static/dsconfig-Yy07ZSap.js +1 -0
- package/web-ui/build/static/dts-DyTWnuFT.js +1 -0
- package/web-ui/build/static/dust-CKq7f4u7.js +1 -0
- package/web-ui/build/static/ebnf-DJRrwYUt.js +1 -0
- package/web-ui/build/static/ebnf-RHbRUELR.js +1 -0
- package/web-ui/build/static/editorconfig-BPnyfBW2.js +1 -0
- package/web-ui/build/static/eiffel-yj-2JB74.js +1 -0
- package/web-ui/build/static/ejs-DitQDEAj.js +1 -0
- package/web-ui/build/static/elixir-3QGdRPiZ.js +1 -0
- package/web-ui/build/static/elixir-DjVihWJd.js +1 -0
- package/web-ui/build/static/elm-BY6TIO5U.js +1 -0
- package/web-ui/build/static/elm-CRkIBVgc.js +1 -0
- package/web-ui/build/static/erb-Djhpl6Qv.js +1 -0
- package/web-ui/build/static/erb-T-e_0q4M.js +1 -0
- package/web-ui/build/static/erlang-BHne0Sow.js +1 -0
- package/web-ui/build/static/erlang-BwFMbXMn.js +1 -0
- package/web-ui/build/static/erlang-repl-BkeLNBB1.js +1 -0
- package/web-ui/build/static/etlua-C7wAJl9b.js +1 -0
- package/web-ui/build/static/excel-DxE1g8nj.js +1 -0
- package/web-ui/build/static/excel-formula-CJfyOSIQ.js +1 -0
- package/web-ui/build/static/factor-CoKZ2w9G.js +1 -0
- package/web-ui/build/static/false-R3UgYwdZ.js +1 -0
- package/web-ui/build/static/firestore-security-rules-Na-FK95T.js +1 -0
- package/web-ui/build/static/fix-CvUjGqrP.js +1 -0
- package/web-ui/build/static/flix-DZcdobtd.js +1 -0
- package/web-ui/build/static/flow-Bs4ybDfF.js +1 -0
- package/web-ui/build/static/fortran-Bo7HQHVz.js +1 -0
- package/web-ui/build/static/fortran-C01QKAjv.js +1 -0
- package/web-ui/build/static/fsharp-Bl0db-E4.js +1 -0
- package/web-ui/build/static/fsharp-CyZIu__H.js +1 -0
- package/web-ui/build/static/ftl-CWXbnuJ8.js +1 -0
- package/web-ui/build/static/gams-BqHeBOiK.js +1 -0
- package/web-ui/build/static/gap-Dotaw9CX.js +1 -0
- package/web-ui/build/static/gauss-BT78eAPL.js +1 -0
- package/web-ui/build/static/gcode-MKCsCHbV.js +1 -0
- package/web-ui/build/static/gcode-bZIzS7dq.js +1 -0
- package/web-ui/build/static/gdscript-BfFdzROd.js +1 -0
- package/web-ui/build/static/gedcom-C-0fkvQT.js +1 -0
- package/web-ui/build/static/gherkin-Bgefs1Ac.js +1 -0
- package/web-ui/build/static/gherkin-BwLhttSG.js +1 -0
- package/web-ui/build/static/git-Cf3XNFwK.js +1 -0
- package/web-ui/build/static/glsl-BRBvgtKX.js +1 -0
- package/web-ui/build/static/glsl-Ci0Ywihb.js +1 -0
- package/web-ui/build/static/gml-BGED3ZV5.js +1 -0
- package/web-ui/build/static/gml-Bo5ybH2Z.js +1 -0
- package/web-ui/build/static/gn-Dvq3uq8q.js +1 -0
- package/web-ui/build/static/go-DEXubI7V.js +1 -0
- package/web-ui/build/static/go-DQ-rOBtr.js +1 -0
- package/web-ui/build/static/go-module-CJ0C_rZQ.js +1 -0
- package/web-ui/build/static/golo-BMZyESOG.js +1 -0
- package/web-ui/build/static/gradle-DamtVT5m.js +1 -0
- package/web-ui/build/static/graphql-BERukF58.js +1 -0
- package/web-ui/build/static/groovy-B-WmRKEQ.js +1 -0
- package/web-ui/build/static/groovy-BzgGHCpW.js +1 -0
- package/web-ui/build/static/haml-B50hpu0J.js +1 -0
- package/web-ui/build/static/haml-vZAqNnLr.js +1 -0
- package/web-ui/build/static/handlebars-ChvSiZA5.js +1 -0
- package/web-ui/build/static/handlebars-z32GTNvC.js +1 -0
- package/web-ui/build/static/haskell-BWLVCHRl.js +1 -0
- package/web-ui/build/static/haskell-CZ4HT-QV.js +1 -0
- package/web-ui/build/static/haxe-Dff2UzKb.js +1 -0
- package/web-ui/build/static/haxe-DtUMfT4Y.js +1 -0
- package/web-ui/build/static/hcl-CPdCn21C.js +1 -0
- package/web-ui/build/static/hlsl-Ddnzpafa.js +1 -0
- package/web-ui/build/static/hoon-BmzYN5g6.js +1 -0
- package/web-ui/build/static/hpkp-Cf4BtYzp.js +1 -0
- package/web-ui/build/static/hsp-CtNdizh5.js +1 -0
- package/web-ui/build/static/hsts-ChmUnrWY.js +1 -0
- package/web-ui/build/static/htmlbars-FvxUz397.js +1 -0
- package/web-ui/build/static/http-C91BqIc4.js +1 -0
- package/web-ui/build/static/http-DUkMpz6R.js +1 -0
- package/web-ui/build/static/hy-BgEorqc6.js +1 -0
- package/web-ui/build/static/ichigojam-CyJ85XqZ.js +1 -0
- package/web-ui/build/static/icon-CWVwUSUB.js +1 -0
- package/web-ui/build/static/icu-message-format-DQ5Vf-57.js +1 -0
- package/web-ui/build/static/idris-25epvnkz.js +1 -0
- package/web-ui/build/static/iecst-D_Q4A3Ao.js +1 -0
- package/web-ui/build/static/ignore-Dn3TUem-.js +1 -0
- package/web-ui/build/static/index-1GAqwN2P.js +1029 -0
- package/web-ui/build/static/index-Bbt0N_qA.css +1 -0
- package/web-ui/build/static/index-COM0znG6.js +13 -0
- package/web-ui/build/static/index-Cq1FjdFd.js +1 -0
- package/web-ui/build/static/inform7-CFrNuUCE.js +1 -0
- package/web-ui/build/static/inform7-DKEqg7Td.js +1 -0
- package/web-ui/build/static/ini-C-WeV3rA.js +1 -0
- package/web-ui/build/static/ini-DNeLlQLb.js +1 -0
- package/web-ui/build/static/io-CHx2lS-R.js +1 -0
- package/web-ui/build/static/irpf90-D4fNrYKT.js +1 -0
- package/web-ui/build/static/isbl-BwxgZUmw.js +1 -0
- package/web-ui/build/static/j-EkuSi-Ss.js +1 -0
- package/web-ui/build/static/java-BtphFsNb.js +1 -0
- package/web-ui/build/static/java-D6Ksxtks.js +1 -0
- package/web-ui/build/static/javadoc-COfrpXIF.js +1 -0
- package/web-ui/build/static/javadoclike-C0DIBgSo.js +1 -0
- package/web-ui/build/static/javascript-D9_bdns_.js +1 -0
- package/web-ui/build/static/javastacktrace-BgesTIoE.js +1 -0
- package/web-ui/build/static/jboss-cli-BCBm8RaA.js +1 -0
- package/web-ui/build/static/jexl-Bur7gjJl.js +1 -0
- package/web-ui/build/static/jolie-CG2HtqVF.js +1 -0
- package/web-ui/build/static/jq-BjcZo4Ta.js +1 -0
- package/web-ui/build/static/js-extras-DPWP-xWb.js +1 -0
- package/web-ui/build/static/js-templates-BYQFylC_.js +1 -0
- package/web-ui/build/static/jsdoc-CiOxmgl5.js +1 -0
- package/web-ui/build/static/json-C2-b3Xpo.js +1 -0
- package/web-ui/build/static/json-D7ok2MJS.js +1 -0
- package/web-ui/build/static/json5-DRNOdkus.js +1 -0
- package/web-ui/build/static/jsonp-FFJzAxUk.js +1 -0
- package/web-ui/build/static/jsstacktrace-C4ki-LaP.js +1 -0
- package/web-ui/build/static/jsx-ZxGQpUNq.js +1 -0
- package/web-ui/build/static/julia-7ooB8a4b.js +1 -0
- package/web-ui/build/static/julia-DzjCRNEr.js +1 -0
- package/web-ui/build/static/julia-repl-pceaZSLt.js +1 -0
- package/web-ui/build/static/keepalived-BQgTZddo.js +1 -0
- package/web-ui/build/static/keyman-Cqlba6tn.js +1 -0
- package/web-ui/build/static/kotlin-BygmvqBG.js +1 -0
- package/web-ui/build/static/kotlin-DrN0ycN8.js +1 -0
- package/web-ui/build/static/kumir-YhasANvI.js +1 -0
- package/web-ui/build/static/kusto-LQa6MD2B.js +1 -0
- package/web-ui/build/static/lasso-Ca3RFbcE.js +1 -0
- package/web-ui/build/static/latex-BoQj21fG.js +1 -0
- package/web-ui/build/static/latex-ZxewREOs.js +1 -0
- package/web-ui/build/static/latte-40SpSG4q.js +1 -0
- package/web-ui/build/static/ldif-CzTJxBjJ.js +1 -0
- package/web-ui/build/static/leaf-DO9LaVNe.js +1 -0
- package/web-ui/build/static/less-BoClFdvD.js +1 -0
- package/web-ui/build/static/less-C1s1U6-n.js +1 -0
- package/web-ui/build/static/lilypond-D5wHKW8A.js +1 -0
- package/web-ui/build/static/liquid-BRQzL-S2.js +1 -0
- package/web-ui/build/static/lisp-8q-QRYKi.js +1 -0
- package/web-ui/build/static/lisp-J8TPaPPb.js +1 -0
- package/web-ui/build/static/livecodeserver-Dcr3yGmD.js +1 -0
- package/web-ui/build/static/livescript-BUEQmlAe.js +1 -0
- package/web-ui/build/static/livescript-DsId63Ot.js +1 -0
- package/web-ui/build/static/llvm-B3CCzYxo.js +1 -0
- package/web-ui/build/static/llvm-kQGfyqnj.js +1 -0
- package/web-ui/build/static/log-BlA5152b.js +1 -0
- package/web-ui/build/static/lolcode-8WRAMeb2.js +1 -0
- package/web-ui/build/static/lsl-BZUMQNE2.js +1 -0
- package/web-ui/build/static/lua-C4hJ-Gql.js +1 -0
- package/web-ui/build/static/lua-RxOeZV_z.js +1 -0
- package/web-ui/build/static/magma-U9kYv2QD.js +1 -0
- package/web-ui/build/static/makefile-1Cu2rVDg.js +1 -0
- package/web-ui/build/static/makefile-mmZ8lbad.js +1 -0
- package/web-ui/build/static/markdown-CCqDOXhR.js +1 -0
- package/web-ui/build/static/markdown-CVOmqzdD.js +1 -0
- package/web-ui/build/static/markup-templating-C7eiVR0j.js +1 -0
- package/web-ui/build/static/mathematica-BbKHQ6zH.js +1 -0
- package/web-ui/build/static/matlab-BbMwJ6T0.js +1 -0
- package/web-ui/build/static/matlab-gHn5UhMb.js +1 -0
- package/web-ui/build/static/maxima-CuB3n0ri.js +1 -0
- package/web-ui/build/static/maxscript-jhOix4gn.js +1 -0
- package/web-ui/build/static/mel-Bpjqa7Ec.js +1 -0
- package/web-ui/build/static/mel-QxMxBq03.js +1 -0
- package/web-ui/build/static/mercury-C8IdDyFB.js +1 -0
- package/web-ui/build/static/mermaid-v41WDixf.js +1 -0
- package/web-ui/build/static/mipsasm-kYH27KXy.js +1 -0
- package/web-ui/build/static/mizar-BCJI9Jxa.js +1 -0
- package/web-ui/build/static/mizar-BCxP_6pj.js +1 -0
- package/web-ui/build/static/mojolicious-C7DC_CUp.js +1 -0
- package/web-ui/build/static/mongodb-DvBX00WY.js +1 -0
- package/web-ui/build/static/monkey-B7KjOZtt.js +1 -0
- package/web-ui/build/static/monkey-CFKZd6lx.js +1 -0
- package/web-ui/build/static/moonscript-44jD_uAZ.js +1 -0
- package/web-ui/build/static/moonscript-B3KahKf5.js +1 -0
- package/web-ui/build/static/n1ql-CxJOkBbD.js +1 -0
- package/web-ui/build/static/n1ql-FJFE6P7E.js +1 -0
- package/web-ui/build/static/n4js-D5jJTGdO.js +1 -0
- package/web-ui/build/static/nand2tetris-hdl-DlsCaky2.js +1 -0
- package/web-ui/build/static/naniscript-C3YsvWgN.js +1 -0
- package/web-ui/build/static/nasm-DCGKvOZq.js +1 -0
- package/web-ui/build/static/neon-nyFNinx-.js +1 -0
- package/web-ui/build/static/nevod-C5PnMzAW.js +1 -0
- package/web-ui/build/static/nginx-BUgMakda.js +1 -0
- package/web-ui/build/static/nginx-C5JBKsuz.js +1 -0
- package/web-ui/build/static/nim-BFu6fQgc.js +1 -0
- package/web-ui/build/static/nim-D0uh-nR9.js +1 -0
- package/web-ui/build/static/nix-BiOn3l1e.js +1 -0
- package/web-ui/build/static/nix-tapJszPl.js +1 -0
- package/web-ui/build/static/node-repl-BTp9CFzE.js +1 -0
- package/web-ui/build/static/nsis-B7hV5A06.js +1 -0
- package/web-ui/build/static/nsis-DLshnCv-.js +1 -0
- package/web-ui/build/static/objectivec-BKjt_sKE.js +1 -0
- package/web-ui/build/static/objectivec-KUMYgk5w.js +1 -0
- package/web-ui/build/static/ocaml-CV2nKA_A.js +1 -0
- package/web-ui/build/static/ocaml-ZyZ-dXmE.js +1 -0
- package/web-ui/build/static/opencl-igIWfc0n.js +1 -0
- package/web-ui/build/static/openqasm-ByCPmCpS.js +1 -0
- package/web-ui/build/static/openscad-Db6ypam1.js +1 -0
- package/web-ui/build/static/oxygene-CBbaQWRB.js +1 -0
- package/web-ui/build/static/oz-lEl_mXVw.js +1 -0
- package/web-ui/build/static/parigp-c2FbheBr.js +1 -0
- package/web-ui/build/static/parser-Ba6uivHf.js +1 -0
- package/web-ui/build/static/parser3-Cm5cgVSQ.js +1 -0
- package/web-ui/build/static/pascal-JgY-dd52.js +1 -0
- package/web-ui/build/static/pascaligo-BjSdyegq.js +1 -0
- package/web-ui/build/static/pcaxis-CDdxDfqJ.js +1 -0
- package/web-ui/build/static/peoplecode-BCPhsbK6.js +1 -0
- package/web-ui/build/static/perl-ClVPikLH.js +1 -0
- package/web-ui/build/static/perl-pRjXJ4uc.js +1 -0
- package/web-ui/build/static/pf-D6VrFfuf.js +1 -0
- package/web-ui/build/static/pgsql-DAv4ezCU.js +1 -0
- package/web-ui/build/static/php-Bz3Bn1G_.js +1 -0
- package/web-ui/build/static/php-extras-B8k1hZ7O.js +1 -0
- package/web-ui/build/static/php-template-DJJiMC8Q.js +1 -0
- package/web-ui/build/static/php-zCXGNRnB.js +1 -0
- package/web-ui/build/static/phpdoc-CpnPjGDk.js +1 -0
- package/web-ui/build/static/plaintext-BRkRKfKN.js +1 -0
- package/web-ui/build/static/plsql-BARhkvBo.js +1 -0
- package/web-ui/build/static/pony-guYTDEtj.js +1 -0
- package/web-ui/build/static/powerquery-DcM2Yj3O.js +1 -0
- package/web-ui/build/static/powershell-DJ8ftCxt.js +1 -0
- package/web-ui/build/static/powershell-DSRUQzqt.js +1 -0
- package/web-ui/build/static/processing-BCmW5Adu.js +1 -0
- package/web-ui/build/static/processing-DDMjYIa-.js +1 -0
- package/web-ui/build/static/profile-C9J13WXr.js +1 -0
- package/web-ui/build/static/prolog-CUyUfIUU.js +1 -0
- package/web-ui/build/static/prolog-wjvrQEy3.js +1 -0
- package/web-ui/build/static/promql-BkN3_kL1.js +1 -0
- package/web-ui/build/static/properties-B7zGUFLC.js +1 -0
- package/web-ui/build/static/properties-DHKWbrVz.js +1 -0
- package/web-ui/build/static/protobuf-CVwMi4py.js +1 -0
- package/web-ui/build/static/protobuf-CWUzVSVD.js +1 -0
- package/web-ui/build/static/psl-DdX6HMd3.js +1 -0
- package/web-ui/build/static/pug-D-Sn469u.js +1 -0
- package/web-ui/build/static/puppet-B6ZR9-D4.js +1 -0
- package/web-ui/build/static/puppet-m66LRiIo.js +1 -0
- package/web-ui/build/static/pure-7deZH-sc.js +1 -0
- package/web-ui/build/static/purebasic-DQLUcurt.js +1 -0
- package/web-ui/build/static/purebasic-DYMw9jTh.js +1 -0
- package/web-ui/build/static/purescript-DpysoAya.js +1 -0
- package/web-ui/build/static/python-D66_vufV.js +1 -0
- package/web-ui/build/static/python-DYxaIENO.js +1 -0
- package/web-ui/build/static/python-repl-DPjvQNxf.js +1 -0
- package/web-ui/build/static/q-DDHNKITB.js +1 -0
- package/web-ui/build/static/q-xV1Q9ILw.js +1 -0
- package/web-ui/build/static/qml-DSENM1u-.js +1 -0
- package/web-ui/build/static/qml-DfhbPQ-t.js +1 -0
- package/web-ui/build/static/qore-LQCffrzv.js +1 -0
- package/web-ui/build/static/qsharp-BcSf2ZGH.js +1 -0
- package/web-ui/build/static/r-Dc6GR0yQ.js +1 -0
- package/web-ui/build/static/r-vludgk3t.js +1 -0
- package/web-ui/build/static/racket-DJYIkQwh.js +1 -0
- package/web-ui/build/static/reason-D75i_ede.js +1 -0
- package/web-ui/build/static/reasonml-DhRXKjo3.js +1 -0
- package/web-ui/build/static/regex-D67iENuu.js +1 -0
- package/web-ui/build/static/rego-CJ2Eeb4g.js +1 -0
- package/web-ui/build/static/renpy-DUDNyFqb.js +1 -0
- package/web-ui/build/static/rest-Dn7SYTNt.js +1 -0
- package/web-ui/build/static/rib-BVUY5dIb.js +1 -0
- package/web-ui/build/static/rip-Bu9K3Hu9.js +1 -0
- package/web-ui/build/static/roboconf-CUzY2sLf.js +1 -0
- package/web-ui/build/static/roboconf-DBEmoD-Z.js +1 -0
- package/web-ui/build/static/robotframework-70EV7ffL.js +1 -0
- package/web-ui/build/static/routeros-KgfwmDVO.js +1 -0
- package/web-ui/build/static/rsl-D3oCnFGa.js +1 -0
- package/web-ui/build/static/ruby-Dqa0HtB4.js +1 -0
- package/web-ui/build/static/ruby-PeJYeL87.js +1 -0
- package/web-ui/build/static/ruleslanguage-vo3eM_mz.js +1 -0
- package/web-ui/build/static/rust-CwU6t4_Y.js +1 -0
- package/web-ui/build/static/rust-WXADYh9r.js +1 -0
- package/web-ui/build/static/sas-Cg6ADdDH.js +1 -0
- package/web-ui/build/static/sas-DWoEaeXv.js +1 -0
- package/web-ui/build/static/sass-DbHJHeBV.js +1 -0
- package/web-ui/build/static/scala-B6oE2QKr.js +1 -0
- package/web-ui/build/static/scala-NFQGPaYa.js +1 -0
- package/web-ui/build/static/scheme-C8Jx4oX7.js +1 -0
- package/web-ui/build/static/scheme-CUMBJaUf.js +1 -0
- package/web-ui/build/static/scilab-D1VqsdSy.js +1 -0
- package/web-ui/build/static/scss-CSH87oUD.js +1 -0
- package/web-ui/build/static/scss-GLX6NNDB.js +1 -0
- package/web-ui/build/static/shell-CbOhN21M.js +1 -0
- package/web-ui/build/static/shell-session-BQPdJJZS.js +1 -0
- package/web-ui/build/static/smali-BYbEOQX5.js +1 -0
- package/web-ui/build/static/smali-DcoYSibw.js +1 -0
- package/web-ui/build/static/smalltalk-CQkedD8N.js +1 -0
- package/web-ui/build/static/smalltalk-DihI81Cd.js +1 -0
- package/web-ui/build/static/smarty-RRvllERL.js +1 -0
- package/web-ui/build/static/sml-BJkMhBLU.js +1 -0
- package/web-ui/build/static/sml-Bm2IN0wP.js +1 -0
- package/web-ui/build/static/solidity-CsCW8kyX.js +1 -0
- package/web-ui/build/static/solution-file-B5YSxWQt.js +1 -0
- package/web-ui/build/static/soy-Dek2_YCW.js +1 -0
- package/web-ui/build/static/sparql-BeTxhWa4.js +1 -0
- package/web-ui/build/static/splunk-spl-hq6BW85c.js +1 -0
- package/web-ui/build/static/sqf-C-u4en-i.js +1 -0
- package/web-ui/build/static/sqf-DP0IhDYt.js +1 -0
- package/web-ui/build/static/sql-BzL0uonb.js +1 -0
- package/web-ui/build/static/sql-Zy6tV_us.js +1 -0
- package/web-ui/build/static/sql_more-BP2G6Vh5.js +1 -0
- package/web-ui/build/static/squirrel-C3MnMYx5.js +1 -0
- package/web-ui/build/static/stan-7iKo211G.js +1 -0
- package/web-ui/build/static/stan-C1lcIZjJ.js +1 -0
- package/web-ui/build/static/stata-DJ6GKcaw.js +1 -0
- package/web-ui/build/static/step21-Pg-uClDB.js +1 -0
- package/web-ui/build/static/stylus-DFAxYuRi.js +1 -0
- package/web-ui/build/static/stylus-DT6xc_Nv.js +1 -0
- package/web-ui/build/static/subunit-aGvGJXZZ.js +1 -0
- package/web-ui/build/static/swift-Sqmdmb4O.js +1 -0
- package/web-ui/build/static/swift-cUX-MVl4.js +1 -0
- package/web-ui/build/static/systemd-qIaU0Trg.js +1 -0
- package/web-ui/build/static/t4-cs-DtO6Bgg1.js +1 -0
- package/web-ui/build/static/t4-templating-DSSM2N5M.js +1 -0
- package/web-ui/build/static/t4-vb-tKIiE5uC.js +1 -0
- package/web-ui/build/static/taggerscript-Dt2Kgr-W.js +1 -0
- package/web-ui/build/static/tap-BMEgEMIk.js +1 -0
- package/web-ui/build/static/tap-C4TdzsNz.js +1 -0
- package/web-ui/build/static/tcl-B6k4Af9f.js +1 -0
- package/web-ui/build/static/tcl-Dq4_i5q5.js +1 -0
- package/web-ui/build/static/textile-C0uqAPk0.js +1 -0
- package/web-ui/build/static/thrift-DybQEjaA.js +1 -0
- package/web-ui/build/static/toml-DG1a2FSS.js +1 -0
- package/web-ui/build/static/tp-BwdfEEST.js +1 -0
- package/web-ui/build/static/tremor-JSTukmt-.js +1 -0
- package/web-ui/build/static/tsx-YUfsqzPf.js +1 -0
- package/web-ui/build/static/tt2-D9A_ACnF.js +1 -0
- package/web-ui/build/static/turtle-BKxwLa_-.js +1 -0
- package/web-ui/build/static/twig-BeEDK9Ri.js +1 -0
- package/web-ui/build/static/twig-TnOWwD7-.js +1 -0
- package/web-ui/build/static/typescript-BjZl8C3q.js +1 -0
- package/web-ui/build/static/typescript-qtW5Xh-j.js +1 -0
- package/web-ui/build/static/typoscript-Dj4sO7Jx.js +1 -0
- package/web-ui/build/static/unrealscript-DInimzNQ.js +1 -0
- package/web-ui/build/static/uorazor-B_9tFVKw.js +1 -0
- package/web-ui/build/static/uri-CTuMA7_k.js +1 -0
- package/web-ui/build/static/v-CvE0Ujqx.js +1 -0
- package/web-ui/build/static/vala-CLGf3xEs.js +1 -0
- package/web-ui/build/static/vala-Dm8LmEpm.js +1 -0
- package/web-ui/build/static/vbnet-Cwm2TjGP.js +1 -0
- package/web-ui/build/static/vbnet-LCd9GiMJ.js +1 -0
- package/web-ui/build/static/vbscript-DVj94_-y.js +1 -0
- package/web-ui/build/static/vbscript-html-CDHtSX-o.js +1 -0
- package/web-ui/build/static/velocity-C-OrhdDf.js +1 -0
- package/web-ui/build/static/verilog-Bh18N7TM.js +1 -0
- package/web-ui/build/static/verilog-C-YNXb8j.js +1 -0
- package/web-ui/build/static/vhdl-BFNm41_R.js +1 -0
- package/web-ui/build/static/vhdl-CyLgBDKk.js +1 -0
- package/web-ui/build/static/vim-BTafUqR0.js +1 -0
- package/web-ui/build/static/vim-Xg1pEHJe.js +1 -0
- package/web-ui/build/static/visual-basic-CDgUOlvq.js +1 -0
- package/web-ui/build/static/warpscript-1ELDmkt5.js +1 -0
- package/web-ui/build/static/wasm-C25KdQk5.js +1 -0
- package/web-ui/build/static/web-idl-CsdVYgpL.js +1 -0
- package/web-ui/build/static/wiki-4RrZuyhV.js +1 -0
- package/web-ui/build/static/wolfram-DMiRIwvp.js +1 -0
- package/web-ui/build/static/wren-Vk5PBcVB.js +1 -0
- package/web-ui/build/static/x86asm-D9TFTgye.js +1 -0
- package/web-ui/build/static/xeora-SAn_K3Ts.js +1 -0
- package/web-ui/build/static/xl-Da2Fl8D9.js +1 -0
- package/web-ui/build/static/xml-CeLm6l4V.js +1 -0
- package/web-ui/build/static/xml-doc-DypYH408.js +1 -0
- package/web-ui/build/static/xojo-CrfMiv1-.js +1 -0
- package/web-ui/build/static/xquery-8tOqVkgP.js +1 -0
- package/web-ui/build/static/xquery-CLOnNPtx.js +1 -0
- package/web-ui/build/static/yaml-CXiycPmU.js +1 -0
- package/web-ui/build/static/yaml-cIKjKW-H.js +1 -0
- package/web-ui/build/static/yang-KVshO9Ce.js +1 -0
- package/web-ui/build/static/zephir-B88JNqlj.js +1 -0
- package/web-ui/build/static/zig-C6GYIeFs.js +1 -0
- package/web-ui/build/static/1c-BdLpzMAL.js +0 -1
- package/web-ui/build/static/abap-CDwRvs0G.js +0 -1
- package/web-ui/build/static/abnf-BI7p3j5a.js +0 -1
- package/web-ui/build/static/abnf-CNv3r7Uy.js +0 -1
- package/web-ui/build/static/accesslog-C06B6TeF.js +0 -1
- package/web-ui/build/static/actionscript-4rvU1xh_.js +0 -1
- package/web-ui/build/static/actionscript-hzeSNpz-.js +0 -1
- package/web-ui/build/static/ada-BKQHlNbk.js +0 -1
- package/web-ui/build/static/ada-C-cG6Cnx.js +0 -1
- package/web-ui/build/static/agda-BLGp6bzV.js +0 -1
- package/web-ui/build/static/al-D1v7f7zb.js +0 -1
- package/web-ui/build/static/angelscript-C6fH5Phl.js +0 -1
- package/web-ui/build/static/antlr4-CkeL19Pe.js +0 -1
- package/web-ui/build/static/apache-JdORoIBq.js +0 -1
- package/web-ui/build/static/apacheconf-CapiFi2H.js +0 -1
- package/web-ui/build/static/apex-B9woB7hA.js +0 -1
- package/web-ui/build/static/apl-lmFlegeo.js +0 -1
- package/web-ui/build/static/applescript-BHhW-aLP.js +0 -1
- package/web-ui/build/static/applescript-ss_o-t9Q.js +0 -1
- package/web-ui/build/static/aql-BLNeECob.js +0 -1
- package/web-ui/build/static/arcade-CFXIdOiD.js +0 -1
- package/web-ui/build/static/arduino-BnvFM4Uv.js +0 -1
- package/web-ui/build/static/arduino-COqLsxBH.js +0 -1
- package/web-ui/build/static/arff-D29LT0W3.js +0 -1
- package/web-ui/build/static/armasm-4vnDbtEO.js +0 -1
- package/web-ui/build/static/asciidoc-B5enjW-U.js +0 -1
- package/web-ui/build/static/asciidoc-DXDLuzat.js +0 -1
- package/web-ui/build/static/asm6502-BlmY96A-.js +0 -1
- package/web-ui/build/static/asmatmel-DsTJaam3.js +0 -1
- package/web-ui/build/static/aspectj-CWKdyALZ.js +0 -1
- package/web-ui/build/static/aspnet-BMb5ovzr.js +0 -1
- package/web-ui/build/static/autohotkey-Bnt4L8Sq.js +0 -1
- package/web-ui/build/static/autohotkey-FJP6t7LP.js +0 -1
- package/web-ui/build/static/autoit-D_uma-t5.js +0 -1
- package/web-ui/build/static/autoit-tV1DvCag.js +0 -1
- package/web-ui/build/static/avisynth-C3EGWRqZ.js +0 -1
- package/web-ui/build/static/avrasm-SPYupzKN.js +0 -1
- package/web-ui/build/static/avro-idl-BVy35bGz.js +0 -1
- package/web-ui/build/static/awk-bd20WYWO.js +0 -1
- package/web-ui/build/static/axapta-rMrFdrRa.js +0 -1
- package/web-ui/build/static/bash-B6JbRSpw.js +0 -1
- package/web-ui/build/static/bash-CjDn8CS1.js +0 -1
- package/web-ui/build/static/basic-1cr_KdjO.js +0 -1
- package/web-ui/build/static/basic-VjzNgL1A.js +0 -1
- package/web-ui/build/static/batch-xKrSAbnh.js +0 -1
- package/web-ui/build/static/bbcode-D_oXQoMX.js +0 -1
- package/web-ui/build/static/bicep-DHCLyehu.js +0 -1
- package/web-ui/build/static/birb-LnKeXfOt.js +0 -1
- package/web-ui/build/static/bison-D1Y9rGkL.js +0 -1
- package/web-ui/build/static/bnf-Dmfxl80x.js +0 -1
- package/web-ui/build/static/bnf-Dr4hlA3O.js +0 -1
- package/web-ui/build/static/brainfuck-BLTIahWA.js +0 -1
- package/web-ui/build/static/brainfuck-DfZP16Cx.js +0 -1
- package/web-ui/build/static/brightscript-YT7Nr8GN.js +0 -1
- package/web-ui/build/static/bro-Cn2KhPkj.js +0 -1
- package/web-ui/build/static/bsl-DFyeWkvL.js +0 -1
- package/web-ui/build/static/c-B8jd4ks-.js +0 -1
- package/web-ui/build/static/c-CTVZoi8i.js +0 -1
- package/web-ui/build/static/c-like-BYR8sR5E.js +0 -1
- package/web-ui/build/static/cal-D7KqKxTg.js +0 -1
- package/web-ui/build/static/capnproto-Bl9dDXU4.js +0 -1
- package/web-ui/build/static/ceylon-DrCHmREL.js +0 -1
- package/web-ui/build/static/cfscript-C0sNdmMo.js +0 -1
- package/web-ui/build/static/chaiscript-LgrVMZR5.js +0 -1
- package/web-ui/build/static/cil-CCNfQAo8.js +0 -1
- package/web-ui/build/static/clean-DDw0s_-o.js +0 -1
- package/web-ui/build/static/clojure-BFxsxcbQ.js +0 -1
- package/web-ui/build/static/clojure-BgMU8fA8.js +0 -1
- package/web-ui/build/static/clojure-repl-C174HUrZ.js +0 -1
- package/web-ui/build/static/cmake-C6hjTvGt.js +0 -1
- package/web-ui/build/static/cmake-CcnmaxXV.js +0 -1
- package/web-ui/build/static/cobol-DiLCdCf7.js +0 -1
- package/web-ui/build/static/coffeescript-CGB29Opz.js +0 -1
- package/web-ui/build/static/coffeescript-DV3V4J6g.js +0 -1
- package/web-ui/build/static/concurnas-Cgdt5ES1.js +0 -1
- package/web-ui/build/static/coq-BbiJDyLq.js +0 -1
- package/web-ui/build/static/coq-DvsBabEJ.js +0 -1
- package/web-ui/build/static/cos-B7_pvH_X.js +0 -1
- package/web-ui/build/static/cpp-416w6yHT.js +0 -1
- package/web-ui/build/static/cpp-pz382MTt.js +0 -1
- package/web-ui/build/static/crmsh-BeYTFuCW.js +0 -1
- package/web-ui/build/static/crystal-BRtDR8RG.js +0 -1
- package/web-ui/build/static/crystal-BZJgl_sw.js +0 -1
- package/web-ui/build/static/csharp-BQ-0v8VA.js +0 -1
- package/web-ui/build/static/csharp-MlHfKRW4.js +0 -1
- package/web-ui/build/static/cshtml-DtS0T24q.js +0 -1
- package/web-ui/build/static/csp-6DGTWGnA.js +0 -1
- package/web-ui/build/static/csp-CvvAXfUJ.js +0 -1
- package/web-ui/build/static/css-DJmvg-kI.js +0 -1
- package/web-ui/build/static/css-extras-qVKXZ1K5.js +0 -1
- package/web-ui/build/static/csv-HN89Dabm.js +0 -1
- package/web-ui/build/static/cypher-zqUo_NN4.js +0 -1
- package/web-ui/build/static/d-BDzMr17q.js +0 -1
- package/web-ui/build/static/d-DV4MmaJ0.js +0 -1
- package/web-ui/build/static/dart-BFkAPQxN.js +0 -1
- package/web-ui/build/static/dart-mlgsSLDz.js +0 -1
- package/web-ui/build/static/dataweave-BQWIxcgu.js +0 -1
- package/web-ui/build/static/dax-FY1jMN3E.js +0 -1
- package/web-ui/build/static/delphi-D85b-0Yr.js +0 -1
- package/web-ui/build/static/dhall-C8db-g46.js +0 -1
- package/web-ui/build/static/diff-BHBVMWZm.js +0 -1
- package/web-ui/build/static/diff-Bet-lyrd.js +0 -1
- package/web-ui/build/static/django-CFm4coNe.js +0 -1
- package/web-ui/build/static/django-DN9SMkSp.js +0 -1
- package/web-ui/build/static/dns-C4yo4DHG.js +0 -1
- package/web-ui/build/static/dns-zone-file-B3o4w8rf.js +0 -1
- package/web-ui/build/static/docker-BxxsATcw.js +0 -1
- package/web-ui/build/static/dockerfile-BKIud8Xh.js +0 -1
- package/web-ui/build/static/dos-G9yNAV_a.js +0 -1
- package/web-ui/build/static/dot-CdN-GBnW.js +0 -1
- package/web-ui/build/static/dsconfig-DZ5R9lQR.js +0 -1
- package/web-ui/build/static/dts-DwetpYRu.js +0 -1
- package/web-ui/build/static/dust-DzEHgUuI.js +0 -1
- package/web-ui/build/static/ebnf-COJZCCYQ.js +0 -1
- package/web-ui/build/static/ebnf-CkdHWCBJ.js +0 -1
- package/web-ui/build/static/editorconfig-Bd3ywZZQ.js +0 -1
- package/web-ui/build/static/eiffel-C1Qk3pq5.js +0 -1
- package/web-ui/build/static/ejs-DxCI_S1L.js +0 -1
- package/web-ui/build/static/elixir-BIIHBb4p.js +0 -1
- package/web-ui/build/static/elixir-Cs4wFfMY.js +0 -1
- package/web-ui/build/static/elm-CXqZthrB.js +0 -1
- package/web-ui/build/static/elm-DBguvIDg.js +0 -1
- package/web-ui/build/static/erb-BPbVhlMt.js +0 -1
- package/web-ui/build/static/erb-DvRAcKbN.js +0 -1
- package/web-ui/build/static/erlang-BUKDJMhm.js +0 -1
- package/web-ui/build/static/erlang-iWD1_psr.js +0 -1
- package/web-ui/build/static/erlang-repl-CjXC9U4C.js +0 -1
- package/web-ui/build/static/etlua-nQ8GCNAu.js +0 -1
- package/web-ui/build/static/excel-D8YfiDAv.js +0 -1
- package/web-ui/build/static/excel-formula-CdZZRE7Y.js +0 -1
- package/web-ui/build/static/factor-wiNoX051.js +0 -1
- package/web-ui/build/static/false-CsZdI-HD.js +0 -1
- package/web-ui/build/static/firestore-security-rules-9yXT_i-6.js +0 -1
- package/web-ui/build/static/fix-BsV5RZTa.js +0 -1
- package/web-ui/build/static/flix-rATD1-Qx.js +0 -1
- package/web-ui/build/static/flow-B4UMzoDr.js +0 -1
- package/web-ui/build/static/fortran-CavcrRz8.js +0 -1
- package/web-ui/build/static/fortran-DVZjWi__.js +0 -1
- package/web-ui/build/static/fsharp-BCVsmzkR.js +0 -1
- package/web-ui/build/static/fsharp-Cj6zPGzQ.js +0 -1
- package/web-ui/build/static/ftl-C5VdFKkz.js +0 -1
- package/web-ui/build/static/gams-CT90XmM8.js +0 -1
- package/web-ui/build/static/gap-Ch518Ngd.js +0 -1
- package/web-ui/build/static/gauss-DTmMb1xB.js +0 -1
- package/web-ui/build/static/gcode-BLc6YjFp.js +0 -1
- package/web-ui/build/static/gcode-DYtkCbZZ.js +0 -1
- package/web-ui/build/static/gdscript-xrcGCBEi.js +0 -1
- package/web-ui/build/static/gedcom-DMOuE70a.js +0 -1
- package/web-ui/build/static/gherkin-BoEzs1SS.js +0 -1
- package/web-ui/build/static/gherkin-DHanA7dz.js +0 -1
- package/web-ui/build/static/git-BwT7p7t_.js +0 -1
- package/web-ui/build/static/glsl-C3_TTBJ-.js +0 -1
- package/web-ui/build/static/glsl-Do3cCE-W.js +0 -1
- package/web-ui/build/static/gml-CWSUBiZ2.js +0 -1
- package/web-ui/build/static/gml-wrCAzzgE.js +0 -1
- package/web-ui/build/static/gn-DqmZ0Qq_.js +0 -1
- package/web-ui/build/static/go-DLiparlr.js +0 -1
- package/web-ui/build/static/go-i67Zsx3x.js +0 -1
- package/web-ui/build/static/go-module-S33FcrvV.js +0 -1
- package/web-ui/build/static/golo-DZ7qHIok.js +0 -1
- package/web-ui/build/static/gradle-BTVIAud8.js +0 -1
- package/web-ui/build/static/graphql-BRc7dV6d.js +0 -1
- package/web-ui/build/static/groovy-C0xCDIoi.js +0 -1
- package/web-ui/build/static/groovy-CqfENDj5.js +0 -1
- package/web-ui/build/static/haml-DGEmWQaf.js +0 -1
- package/web-ui/build/static/haml-Uc13XeLh.js +0 -1
- package/web-ui/build/static/handlebars-2pDOu-qZ.js +0 -1
- package/web-ui/build/static/handlebars-fvNs6C2z.js +0 -1
- package/web-ui/build/static/haskell-C_0PdpI7.js +0 -1
- package/web-ui/build/static/haskell-DPiywQAr.js +0 -1
- package/web-ui/build/static/haxe-B-Jmpi4X.js +0 -1
- package/web-ui/build/static/haxe-BnwqHNBF.js +0 -1
- package/web-ui/build/static/hcl-BkCp99Ns.js +0 -1
- package/web-ui/build/static/hlsl-Dhtz76rF.js +0 -1
- package/web-ui/build/static/hoon-DLvY-xJE.js +0 -1
- package/web-ui/build/static/hpkp-DqGdkrWa.js +0 -1
- package/web-ui/build/static/hsp-uyhbGChx.js +0 -1
- package/web-ui/build/static/hsts-B_hdMfTA.js +0 -1
- package/web-ui/build/static/htmlbars-DBm6s2XZ.js +0 -1
- package/web-ui/build/static/http-BJx-7pVa.js +0 -1
- package/web-ui/build/static/http-BNr6-Kd5.js +0 -1
- package/web-ui/build/static/hy-CCeD6Z5O.js +0 -1
- package/web-ui/build/static/ichigojam-HlQ9_0Cd.js +0 -1
- package/web-ui/build/static/icon-BVRGWnBS.js +0 -1
- package/web-ui/build/static/icu-message-format-DrOF-VCL.js +0 -1
- package/web-ui/build/static/idris-BTtsUKQZ.js +0 -1
- package/web-ui/build/static/iecst-C8fkotHg.js +0 -1
- package/web-ui/build/static/ignore-9L0_iQf0.js +0 -1
- package/web-ui/build/static/index-5biw7ctT.js +0 -1
- package/web-ui/build/static/index-C6XLF9dS.js +0 -734
- package/web-ui/build/static/index-CTO5ggyx.css +0 -1
- package/web-ui/build/static/index-CU7QxI6e.js +0 -13
- package/web-ui/build/static/inform7-DrLS7QKe.js +0 -1
- package/web-ui/build/static/inform7-GeduJ02-.js +0 -1
- package/web-ui/build/static/ini-ClRWklj4.js +0 -1
- package/web-ui/build/static/ini-CnWkQt74.js +0 -1
- package/web-ui/build/static/io-DLrwKpJi.js +0 -1
- package/web-ui/build/static/irpf90-D2n0wokI.js +0 -1
- package/web-ui/build/static/isbl-DF3cf2zG.js +0 -1
- package/web-ui/build/static/j-DFQ008Ab.js +0 -1
- package/web-ui/build/static/java-BXn0NYGW.js +0 -1
- package/web-ui/build/static/java-DwyOtG2R.js +0 -1
- package/web-ui/build/static/javadoc-7lKDS9yO.js +0 -1
- package/web-ui/build/static/javadoclike-UZC5a-I2.js +0 -1
- package/web-ui/build/static/javascript-BVwVipxy.js +0 -1
- package/web-ui/build/static/javastacktrace-Dysb6pma.js +0 -1
- package/web-ui/build/static/jboss-cli-DnBJbhvD.js +0 -1
- package/web-ui/build/static/jexl-Xt80RITf.js +0 -1
- package/web-ui/build/static/jolie-K583lEAy.js +0 -1
- package/web-ui/build/static/jq-DzZu56Cz.js +0 -1
- package/web-ui/build/static/js-extras-Cnbo_FPE.js +0 -1
- package/web-ui/build/static/js-templates-ChGVoxvZ.js +0 -1
- package/web-ui/build/static/jsdoc-7PKg08vo.js +0 -1
- package/web-ui/build/static/json-CS8btz_1.js +0 -1
- package/web-ui/build/static/json-NWyA8Y-S.js +0 -1
- package/web-ui/build/static/json5-BTuuCOka.js +0 -1
- package/web-ui/build/static/jsonp-CddCenzG.js +0 -1
- package/web-ui/build/static/jsstacktrace-Iz7J77qQ.js +0 -1
- package/web-ui/build/static/jsx-KHA4XV99.js +0 -1
- package/web-ui/build/static/julia-DBE7YTR3.js +0 -1
- package/web-ui/build/static/julia-DhbxCJBI.js +0 -1
- package/web-ui/build/static/julia-repl-DMdm1IG1.js +0 -1
- package/web-ui/build/static/keepalived-B7vqYV9X.js +0 -1
- package/web-ui/build/static/keyman-BgxIO8fq.js +0 -1
- package/web-ui/build/static/kotlin-DkKt1c_W.js +0 -1
- package/web-ui/build/static/kotlin-DkVwHXV3.js +0 -1
- package/web-ui/build/static/kumir-ByisfWMX.js +0 -1
- package/web-ui/build/static/kusto-D0PVadiC.js +0 -1
- package/web-ui/build/static/lasso-DUqlKJ-V.js +0 -1
- package/web-ui/build/static/latex-B_KNiR3P.js +0 -1
- package/web-ui/build/static/latex-CAna5qNt.js +0 -1
- package/web-ui/build/static/latte-IGkHLrSc.js +0 -1
- package/web-ui/build/static/ldif-COEZfOAo.js +0 -1
- package/web-ui/build/static/leaf-zSqkBknP.js +0 -1
- package/web-ui/build/static/less-BZ7CLYuK.js +0 -1
- package/web-ui/build/static/less-DTOaHWfJ.js +0 -1
- package/web-ui/build/static/lilypond-CXVSkLeK.js +0 -1
- package/web-ui/build/static/liquid-C-anTr0A.js +0 -1
- package/web-ui/build/static/lisp-CadxWoyo.js +0 -1
- package/web-ui/build/static/lisp-hkvi2iDB.js +0 -1
- package/web-ui/build/static/livecodeserver-CHrsuOkQ.js +0 -1
- package/web-ui/build/static/livescript-B3gz-3aB.js +0 -1
- package/web-ui/build/static/livescript-DnHL9ghu.js +0 -1
- package/web-ui/build/static/llvm-BahggCBp.js +0 -1
- package/web-ui/build/static/llvm-CmHdko4Y.js +0 -1
- package/web-ui/build/static/log-Czikd_pI.js +0 -1
- package/web-ui/build/static/lolcode-Ch49C9Zh.js +0 -1
- package/web-ui/build/static/lsl-C-VWBCeP.js +0 -1
- package/web-ui/build/static/lua-CUvtI6AS.js +0 -1
- package/web-ui/build/static/lua-z6ZTYh0E.js +0 -1
- package/web-ui/build/static/magma-n2Gm1_JJ.js +0 -1
- package/web-ui/build/static/makefile-CV719aL9.js +0 -1
- package/web-ui/build/static/makefile-D3XU9qyi.js +0 -1
- package/web-ui/build/static/markdown-B7ecawDo.js +0 -1
- package/web-ui/build/static/markdown-BAZuKAWm.js +0 -1
- package/web-ui/build/static/markup-templating-CkJ0kvIz.js +0 -1
- package/web-ui/build/static/mathematica-DeYzfKBj.js +0 -1
- package/web-ui/build/static/matlab-CkL4qFcf.js +0 -1
- package/web-ui/build/static/matlab-DyeBcYxN.js +0 -1
- package/web-ui/build/static/maxima-BYkoTgQQ.js +0 -1
- package/web-ui/build/static/maxscript-DF4yyx_y.js +0 -1
- package/web-ui/build/static/mel-Cvinm-ul.js +0 -1
- package/web-ui/build/static/mel-DuhIFj6N.js +0 -1
- package/web-ui/build/static/mercury-BgIQH4Io.js +0 -1
- package/web-ui/build/static/mermaid-Cu_HXPUU.js +0 -1
- package/web-ui/build/static/mipsasm-Bgjx3kJk.js +0 -1
- package/web-ui/build/static/mizar-D6qzNoqS.js +0 -1
- package/web-ui/build/static/mizar-_PkxIqXq.js +0 -1
- package/web-ui/build/static/mojolicious-DUGLQPxV.js +0 -1
- package/web-ui/build/static/mongodb-BLMBcuTL.js +0 -1
- package/web-ui/build/static/monkey-C5k7PFu0.js +0 -1
- package/web-ui/build/static/monkey-DXGsKsbX.js +0 -1
- package/web-ui/build/static/moonscript-1TthCNMT.js +0 -1
- package/web-ui/build/static/moonscript-DqJs0-Md.js +0 -1
- package/web-ui/build/static/n1ql-Bwd4nK-7.js +0 -1
- package/web-ui/build/static/n1ql-hfjCkL2y.js +0 -1
- package/web-ui/build/static/n4js-gwCvxndi.js +0 -1
- package/web-ui/build/static/nand2tetris-hdl-CRRkn3L9.js +0 -1
- package/web-ui/build/static/naniscript-C_wnlSUo.js +0 -1
- package/web-ui/build/static/nasm-DX-Dob1L.js +0 -1
- package/web-ui/build/static/neon-vJIHxlBH.js +0 -1
- package/web-ui/build/static/nevod-Bax1uE4z.js +0 -1
- package/web-ui/build/static/nginx-BQS7w2F8.js +0 -1
- package/web-ui/build/static/nginx-Bt8431vM.js +0 -1
- package/web-ui/build/static/nim-0PFojGir.js +0 -1
- package/web-ui/build/static/nim-BQVxzPdc.js +0 -1
- package/web-ui/build/static/nix-C1td4KJd.js +0 -1
- package/web-ui/build/static/nix-CGOaQ4S_.js +0 -1
- package/web-ui/build/static/node-repl-BsAGA-kF.js +0 -1
- package/web-ui/build/static/nsis-B8d23hVv.js +0 -1
- package/web-ui/build/static/nsis-CRfGDpKw.js +0 -1
- package/web-ui/build/static/objectivec-CVrobj9V.js +0 -1
- package/web-ui/build/static/objectivec-DcVwp8g9.js +0 -1
- package/web-ui/build/static/ocaml-b8Cm2pBQ.js +0 -1
- package/web-ui/build/static/ocaml-mP-4C0uB.js +0 -1
- package/web-ui/build/static/opencl--Qo9pjSM.js +0 -1
- package/web-ui/build/static/openqasm-Dt7vKzox.js +0 -1
- package/web-ui/build/static/openscad-By-SEqIm.js +0 -1
- package/web-ui/build/static/oxygene-BifGHmAP.js +0 -1
- package/web-ui/build/static/oz-DHXFoY_V.js +0 -1
- package/web-ui/build/static/parigp-CQEx84-o.js +0 -1
- package/web-ui/build/static/parser-DevuQ_YA.js +0 -1
- package/web-ui/build/static/parser3-IBmULMjM.js +0 -1
- package/web-ui/build/static/pascal-hHG_VNBq.js +0 -1
- package/web-ui/build/static/pascaligo-DcXZnXMD.js +0 -1
- package/web-ui/build/static/pcaxis-paqvl2ov.js +0 -1
- package/web-ui/build/static/peoplecode-T-lVjo6Q.js +0 -1
- package/web-ui/build/static/perl-BrrOfxJA.js +0 -1
- package/web-ui/build/static/perl-DwF9DDkX.js +0 -1
- package/web-ui/build/static/pf-CCvQZiY2.js +0 -1
- package/web-ui/build/static/pgsql-DYZXTARb.js +0 -1
- package/web-ui/build/static/php-C8P7LrqU.js +0 -1
- package/web-ui/build/static/php-Jh4xpwhM.js +0 -1
- package/web-ui/build/static/php-extras-Ddj6zZ2a.js +0 -1
- package/web-ui/build/static/php-template-D0846ZMl.js +0 -1
- package/web-ui/build/static/phpdoc-DU8hHiT4.js +0 -1
- package/web-ui/build/static/plaintext-BpAdoq1j.js +0 -1
- package/web-ui/build/static/plsql-DjRpUwV7.js +0 -1
- package/web-ui/build/static/pony-C91UDOZB.js +0 -1
- package/web-ui/build/static/powerquery-CbFt66kY.js +0 -1
- package/web-ui/build/static/powershell-Bpd_CmgV.js +0 -1
- package/web-ui/build/static/powershell-C0-63tFn.js +0 -1
- package/web-ui/build/static/processing-COoELNkd.js +0 -1
- package/web-ui/build/static/processing-DovufXGj.js +0 -1
- package/web-ui/build/static/profile-DSijKis_.js +0 -1
- package/web-ui/build/static/prolog-BPJoWbIS.js +0 -1
- package/web-ui/build/static/prolog-Cs4I3Exr.js +0 -1
- package/web-ui/build/static/promql-aIfsISjo.js +0 -1
- package/web-ui/build/static/properties-DWHgjzpz.js +0 -1
- package/web-ui/build/static/properties-k4Dmn8BE.js +0 -1
- package/web-ui/build/static/protobuf-HvnZbIjE.js +0 -1
- package/web-ui/build/static/protobuf-bqbMMmGn.js +0 -1
- package/web-ui/build/static/psl-KbjBRrbA.js +0 -1
- package/web-ui/build/static/pug-DJVp_q_q.js +0 -1
- package/web-ui/build/static/puppet-DloEWvDZ.js +0 -1
- package/web-ui/build/static/puppet-WFgyaopG.js +0 -1
- package/web-ui/build/static/pure-483zjlGE.js +0 -1
- package/web-ui/build/static/purebasic-CZ8DdKkF.js +0 -1
- package/web-ui/build/static/purebasic-dlQReKmz.js +0 -1
- package/web-ui/build/static/purescript-BQnFvaU3.js +0 -1
- package/web-ui/build/static/python-CZ8lWs1l.js +0 -1
- package/web-ui/build/static/python-SU3ESoh4.js +0 -1
- package/web-ui/build/static/python-repl-BBkzrvQe.js +0 -1
- package/web-ui/build/static/q-DTmVFt9r.js +0 -1
- package/web-ui/build/static/q-DtzT8sxS.js +0 -1
- package/web-ui/build/static/qml-B5F36arQ.js +0 -1
- package/web-ui/build/static/qml-BGRIPpl3.js +0 -1
- package/web-ui/build/static/qore-CRS2zeE4.js +0 -1
- package/web-ui/build/static/qsharp-C4Tv2HNI.js +0 -1
- package/web-ui/build/static/r-BrIQscI_.js +0 -1
- package/web-ui/build/static/r-C1dTwrK3.js +0 -1
- package/web-ui/build/static/racket-CY5XtMxt.js +0 -1
- package/web-ui/build/static/reason-BOspKOui.js +0 -1
- package/web-ui/build/static/reasonml-CI0bWekr.js +0 -1
- package/web-ui/build/static/regex-Bu9fRM2h.js +0 -1
- package/web-ui/build/static/rego-DPs1L6rM.js +0 -1
- package/web-ui/build/static/renpy-CqxG8TUa.js +0 -1
- package/web-ui/build/static/rest-DVBf_JOU.js +0 -1
- package/web-ui/build/static/rib-C7f1MpLJ.js +0 -1
- package/web-ui/build/static/rip-CnDVKjn3.js +0 -1
- package/web-ui/build/static/roboconf-B3CDWS-p.js +0 -1
- package/web-ui/build/static/roboconf-Cl96yvBS.js +0 -1
- package/web-ui/build/static/robotframework-BitHYBrT.js +0 -1
- package/web-ui/build/static/routeros-CfrP9irD.js +0 -1
- package/web-ui/build/static/rsl-CGblvP8t.js +0 -1
- package/web-ui/build/static/ruby-CJyKAxoz.js +0 -1
- package/web-ui/build/static/ruby-KT7L0c-N.js +0 -1
- package/web-ui/build/static/ruleslanguage-_MWgFm9V.js +0 -1
- package/web-ui/build/static/rust-DAiMZG-s.js +0 -1
- package/web-ui/build/static/rust-Dmpa9JNg.js +0 -1
- package/web-ui/build/static/sas-CQltIY6v.js +0 -1
- package/web-ui/build/static/sas-aM67MfcZ.js +0 -1
- package/web-ui/build/static/sass-DEBoFRRa.js +0 -1
- package/web-ui/build/static/scala-Cd5U29aY.js +0 -1
- package/web-ui/build/static/scala-DzaGwcFi.js +0 -1
- package/web-ui/build/static/scheme-Cqqy_i9p.js +0 -1
- package/web-ui/build/static/scheme-cIT7gYIT.js +0 -1
- package/web-ui/build/static/scilab-DkyaqVYN.js +0 -1
- package/web-ui/build/static/scss-Cyi-dRZB.js +0 -1
- package/web-ui/build/static/scss-D_mUdkix.js +0 -1
- package/web-ui/build/static/shell-BF_xfQdX.js +0 -1
- package/web-ui/build/static/shell-session-C4TwlI5u.js +0 -1
- package/web-ui/build/static/smali-CvYqcvZD.js +0 -1
- package/web-ui/build/static/smali-DdJm0lGk.js +0 -1
- package/web-ui/build/static/smalltalk-B4v_uFAj.js +0 -1
- package/web-ui/build/static/smalltalk-BHk9orPf.js +0 -1
- package/web-ui/build/static/smarty-DCURdYbE.js +0 -1
- package/web-ui/build/static/sml-BFUDbMt7.js +0 -1
- package/web-ui/build/static/sml-BIbfLMH_.js +0 -1
- package/web-ui/build/static/solidity-fyryqi43.js +0 -1
- package/web-ui/build/static/solution-file-DoPZY9rL.js +0 -1
- package/web-ui/build/static/soy-AjVmvggx.js +0 -1
- package/web-ui/build/static/sparql-C4-CLrDw.js +0 -1
- package/web-ui/build/static/splunk-spl-DclxQT5j.js +0 -1
- package/web-ui/build/static/sqf-CuCGayd3.js +0 -1
- package/web-ui/build/static/sqf-uK9OZDXX.js +0 -1
- package/web-ui/build/static/sql-B0Pqn1rt.js +0 -1
- package/web-ui/build/static/sql-DlNrMSaF.js +0 -1
- package/web-ui/build/static/sql_more-BmwYd1jA.js +0 -1
- package/web-ui/build/static/squirrel-PzIoP6WH.js +0 -1
- package/web-ui/build/static/stan-BZe07EwD.js +0 -1
- package/web-ui/build/static/stan-De1mVh5w.js +0 -1
- package/web-ui/build/static/stata-Dt6KIbHG.js +0 -1
- package/web-ui/build/static/step21-5If4hNHF.js +0 -1
- package/web-ui/build/static/stylus-Cfsl-liy.js +0 -1
- package/web-ui/build/static/stylus-V2q0pGFi.js +0 -1
- package/web-ui/build/static/subunit-Dw4nCzI8.js +0 -1
- package/web-ui/build/static/swift-CNMLwgfO.js +0 -1
- package/web-ui/build/static/swift-HUQ5YZQh.js +0 -1
- package/web-ui/build/static/systemd-C8DE2Z5C.js +0 -1
- package/web-ui/build/static/t4-cs-C_Ey5AJK.js +0 -1
- package/web-ui/build/static/t4-templating-DwnTc5zw.js +0 -1
- package/web-ui/build/static/t4-vb-C-0KWoPY.js +0 -1
- package/web-ui/build/static/taggerscript-Bv6_taGx.js +0 -1
- package/web-ui/build/static/tap-CFDvzug8.js +0 -1
- package/web-ui/build/static/tap-CdJ_Enrg.js +0 -1
- package/web-ui/build/static/tcl-BAEseFnT.js +0 -1
- package/web-ui/build/static/tcl-BS59XADk.js +0 -1
- package/web-ui/build/static/textile-a8y5rAtB.js +0 -1
- package/web-ui/build/static/thrift-D7V-eNGh.js +0 -1
- package/web-ui/build/static/toml-D8cwTEse.js +0 -1
- package/web-ui/build/static/tp-hIAhc2bK.js +0 -1
- package/web-ui/build/static/tremor-Czk4wryK.js +0 -1
- package/web-ui/build/static/tsx-BOeSrzC2.js +0 -1
- package/web-ui/build/static/tt2-BHVJTkSt.js +0 -1
- package/web-ui/build/static/turtle-BOWLWZq7.js +0 -1
- package/web-ui/build/static/twig-CiL22hfc.js +0 -1
- package/web-ui/build/static/twig-fnjh9nSd.js +0 -1
- package/web-ui/build/static/typescript-BXgo8AbH.js +0 -1
- package/web-ui/build/static/typescript-Bd_EcNlS.js +0 -1
- package/web-ui/build/static/typoscript-OvQoCcN-.js +0 -1
- package/web-ui/build/static/unrealscript-Dw9u3aN1.js +0 -1
- package/web-ui/build/static/uorazor-BYmWZy9R.js +0 -1
- package/web-ui/build/static/uri-cZEKPhfB.js +0 -1
- package/web-ui/build/static/v-DCUw5P5w.js +0 -1
- package/web-ui/build/static/vala-BeMIXdl5.js +0 -1
- package/web-ui/build/static/vala-Dchv0k-k.js +0 -1
- package/web-ui/build/static/vbnet-CYNUkFEn.js +0 -1
- package/web-ui/build/static/vbnet-DJpHrZ4P.js +0 -1
- package/web-ui/build/static/vbscript-html-eSFLndJq.js +0 -1
- package/web-ui/build/static/vbscript-uo6pZmjr.js +0 -1
- package/web-ui/build/static/velocity-BZ4IThJR.js +0 -1
- package/web-ui/build/static/verilog-CaEouCrk.js +0 -1
- package/web-ui/build/static/verilog-D_yjfQsL.js +0 -1
- package/web-ui/build/static/vhdl-3zobHypY.js +0 -1
- package/web-ui/build/static/vhdl-DfMoYPtq.js +0 -1
- package/web-ui/build/static/vim-DBVHHc5J.js +0 -1
- package/web-ui/build/static/vim-DillbvCO.js +0 -1
- package/web-ui/build/static/visual-basic-C7H7McST.js +0 -1
- package/web-ui/build/static/warpscript-BKjx-dEN.js +0 -1
- package/web-ui/build/static/wasm-AVgQyIgy.js +0 -1
- package/web-ui/build/static/web-idl-BNNIYzG6.js +0 -1
- package/web-ui/build/static/wiki-CLfpaX63.js +0 -1
- package/web-ui/build/static/wolfram-DUecju0s.js +0 -1
- package/web-ui/build/static/wren-DOzRaRuS.js +0 -1
- package/web-ui/build/static/x86asm-FxnmOy9a.js +0 -1
- package/web-ui/build/static/xeora-u3RdEzzL.js +0 -1
- package/web-ui/build/static/xl-DRkSDCgX.js +0 -1
- package/web-ui/build/static/xml-d39yV6YW.js +0 -1
- package/web-ui/build/static/xml-doc-CAsyFkZk.js +0 -1
- package/web-ui/build/static/xojo-C82wULba.js +0 -1
- package/web-ui/build/static/xquery-CdvxjAIl.js +0 -1
- package/web-ui/build/static/xquery-ClPcUh76.js +0 -1
- package/web-ui/build/static/yaml-C5_f2N79.js +0 -1
- package/web-ui/build/static/yaml-ZJm6Uydk.js +0 -1
- package/web-ui/build/static/yang-BR7aZNbT.js +0 -1
- package/web-ui/build/static/zephir-CnL3vXXJ.js +0 -1
- package/web-ui/build/static/zig-e5ovIuAu.js +0 -1
|
@@ -0,0 +1,1389 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WidgetTool — agent-facing tool for rendering custom UI widgets inline
|
|
3
|
+
* in the chat stream. Two modes:
|
|
4
|
+
*
|
|
5
|
+
* kind: 'html' — static HTML+CSS, rendered in an iframe with sandbox=""
|
|
6
|
+
* (no scripts, no forms, no same-origin). Safe for
|
|
7
|
+
* visualisations, decorated callouts, infographics.
|
|
8
|
+
*
|
|
9
|
+
* kind: 'jsx' — Preact+htm render code, rendered in an iframe with
|
|
10
|
+
* sandbox="allow-scripts" (scripts only, no same-origin).
|
|
11
|
+
* Can round-trip user interactions back to the agent
|
|
12
|
+
* via the loxia.sendEvent() SDK baked into the runtime.
|
|
13
|
+
*
|
|
14
|
+
* Agents invoke:
|
|
15
|
+
* { toolId: 'widget', action: 'render', kind, content, widgetId?, props? }
|
|
16
|
+
* { toolId: 'widget', action: 'update', widgetId, props }
|
|
17
|
+
* { toolId: 'widget', action: 'destroy', widgetId }
|
|
18
|
+
* { toolId: 'widget', action: 'list' }
|
|
19
|
+
*
|
|
20
|
+
* Results come back as a tool-result the frontend WidgetRenderer picks up
|
|
21
|
+
* and hands to <IframeWidget>. Agent-visible output intentionally does
|
|
22
|
+
* NOT echo the full content — the content lives in the message feed once,
|
|
23
|
+
* inside the iframe's srcdoc.
|
|
24
|
+
*
|
|
25
|
+
* State lives on the tool instance (Map<agentId, Map<widgetId, widget>>).
|
|
26
|
+
* LRU-evicted per-agent beyond MAX_WIDGETS_PER_AGENT so a runaway agent
|
|
27
|
+
* can't OOM the process.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import { EventEmitter } from 'events';
|
|
31
|
+
import { BaseTool } from '../../tools/baseTool.js';
|
|
32
|
+
import {
|
|
33
|
+
validateRenderParams,
|
|
34
|
+
validateUpdateParams,
|
|
35
|
+
validateDestroyParams,
|
|
36
|
+
validateListVersionsParams,
|
|
37
|
+
validateGetVersionParams,
|
|
38
|
+
validateSetMainParams,
|
|
39
|
+
validateRenameParams,
|
|
40
|
+
normalizeName,
|
|
41
|
+
WIDGET_LIMITS,
|
|
42
|
+
} from './schema.js';
|
|
43
|
+
import { scanForPhishingKeywords } from './phishingScanner.js';
|
|
44
|
+
import { GalleryStore } from './galleryStore.js';
|
|
45
|
+
import { analyzeWidgetCode } from './codeAnalyzer.js';
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Generate an opaque, sortable version id. Sortability isn't relied on
|
|
49
|
+
* for ordering (the versions array is chronological by insertion) but
|
|
50
|
+
* helps with audit logs and debugging.
|
|
51
|
+
*/
|
|
52
|
+
function generateVersionId() {
|
|
53
|
+
return 'v-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 8);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Build a version record from a render payload. Each version captures
|
|
58
|
+
* everything needed to re-mount the widget at that version: kind,
|
|
59
|
+
* content, initial props, the phishing-scan result at write time, and
|
|
60
|
+
* size in UTF-8 bytes.
|
|
61
|
+
*/
|
|
62
|
+
function buildVersion({ kind, content, props }) {
|
|
63
|
+
return {
|
|
64
|
+
versionId: generateVersionId(),
|
|
65
|
+
kind,
|
|
66
|
+
content,
|
|
67
|
+
props: props || {},
|
|
68
|
+
phishingHits: scanForPhishingKeywords(content),
|
|
69
|
+
size: Buffer.byteLength(content, 'utf8'),
|
|
70
|
+
createdAt: new Date().toISOString(),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Mirror the active version's content/kind/props/etc. onto the widget
|
|
76
|
+
* record's top-level fields. This keeps every existing consumer
|
|
77
|
+
* (frontend WidgetRenderer, /api/widget/audit, list action, tests)
|
|
78
|
+
* working without changes — they read `.content` / `.kind` / `.props`
|
|
79
|
+
* and they get the active (main) version's values.
|
|
80
|
+
*
|
|
81
|
+
* Mutates `widget` in place and returns it for chaining.
|
|
82
|
+
*/
|
|
83
|
+
function mirrorActiveVersion(widget) {
|
|
84
|
+
const main = widget.versions.find(v => v.versionId === widget.mainVersionId)
|
|
85
|
+
|| widget.versions[widget.versions.length - 1];
|
|
86
|
+
widget.kind = main.kind;
|
|
87
|
+
widget.content = main.content;
|
|
88
|
+
widget.props = main.props;
|
|
89
|
+
widget.phishingHits = main.phishingHits;
|
|
90
|
+
widget.size = main.size;
|
|
91
|
+
widget.updatedAt = main.createdAt; // "active version's effective-since time"
|
|
92
|
+
// Latest-rendered timestamp lives separately so audit/UI can show
|
|
93
|
+
// "last rendered" even if the user pinned an older version as main.
|
|
94
|
+
widget.lastRenderedAt = widget.versions[widget.versions.length - 1].createdAt;
|
|
95
|
+
return widget;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export class WidgetTool extends BaseTool {
|
|
99
|
+
constructor(config = {}, logger = null) {
|
|
100
|
+
super(config, logger);
|
|
101
|
+
this.id = 'widget';
|
|
102
|
+
|
|
103
|
+
// Map<agentId, Map<widgetId, widget>> — widgets are per-agent so
|
|
104
|
+
// listings don't leak across the tenancy boundary.
|
|
105
|
+
this._widgetsByAgent = new Map();
|
|
106
|
+
// Monotonic counter for auto-generated ids (user-friendly + unique).
|
|
107
|
+
this._nextAutoId = 1;
|
|
108
|
+
|
|
109
|
+
// Gallery (cross-session shared widget catalog). Lazy — created on
|
|
110
|
+
// first share/list-gallery/render-from-gallery call. Tests/route
|
|
111
|
+
// handlers can replace this with a custom-filePath instance via
|
|
112
|
+
// `setGalleryStore(...)` so they don't touch the user's real file.
|
|
113
|
+
this._gallery = null;
|
|
114
|
+
|
|
115
|
+
// Event bus for widget-state mutations. The web server bridges this
|
|
116
|
+
// to a WebSocket `widget_changed` message so the frontend artifacts
|
|
117
|
+
// panel stays in sync without depending on the chat feed (which is
|
|
118
|
+
// lazy-loaded — older messages may not be mounted, so feed-only
|
|
119
|
+
// observation misses widgets that exist on the backend).
|
|
120
|
+
//
|
|
121
|
+
// Emitted event:
|
|
122
|
+
// 'widget-changed' { agentId, widgetId, changeType, summary, templateId? }
|
|
123
|
+
//
|
|
124
|
+
// changeType ∈ 'rendered' | 'updated' | 'destroyed' | 'main-set'
|
|
125
|
+
// | 'shared' | 'unshared' | 'upgrade-applied'
|
|
126
|
+
//
|
|
127
|
+
// For 'destroyed', `summary` is null and `widgetId` is the removed id.
|
|
128
|
+
this.events = new EventEmitter();
|
|
129
|
+
// Don't crash the process if the bus has no listener attached yet
|
|
130
|
+
// (e.g. tests, or the web server is starting up).
|
|
131
|
+
this.events.setMaxListeners(50);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Build the summary shape consumed by the artifacts panel and the
|
|
136
|
+
* `widget_changed` WS push. Matches the per-row shape returned by
|
|
137
|
+
* `_list(agentId)` so the frontend can use a single code path.
|
|
138
|
+
* @private
|
|
139
|
+
*/
|
|
140
|
+
_buildSummary(widget) {
|
|
141
|
+
if (!widget) return null;
|
|
142
|
+
return {
|
|
143
|
+
widgetId: widget.widgetId,
|
|
144
|
+
name: widget.name || null,
|
|
145
|
+
kind: widget.kind,
|
|
146
|
+
createdAt: widget.createdAt,
|
|
147
|
+
updatedAt: widget.updatedAt,
|
|
148
|
+
lastRenderedAt: widget.lastRenderedAt,
|
|
149
|
+
size: widget.size,
|
|
150
|
+
phishingHits: widget.phishingHits,
|
|
151
|
+
versionCount: widget.versions ? widget.versions.length : 0,
|
|
152
|
+
mainVersionId: widget.mainVersionId,
|
|
153
|
+
linkedGalleryTemplateId: widget.linkedGalleryTemplateId || null,
|
|
154
|
+
linkedGalleryVersion: widget.linkedGalleryVersion || null,
|
|
155
|
+
divergedFromGallery: !!widget.divergedFromGallery,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Emit a widget-changed event. Wrapped in a try/catch so a buggy
|
|
161
|
+
* listener can never break the tool call itself — the widget mutation
|
|
162
|
+
* has already happened by the time we emit.
|
|
163
|
+
* @private
|
|
164
|
+
*/
|
|
165
|
+
_emitChange(agentId, widgetId, changeType, widget, extra = {}) {
|
|
166
|
+
try {
|
|
167
|
+
this.events.emit('widget-changed', {
|
|
168
|
+
agentId,
|
|
169
|
+
widgetId,
|
|
170
|
+
changeType,
|
|
171
|
+
summary: widget ? this._buildSummary(widget) : null,
|
|
172
|
+
...extra,
|
|
173
|
+
});
|
|
174
|
+
} catch (err) {
|
|
175
|
+
this.logger?.warn?.('widget-changed listener threw', { error: err?.message });
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** Allow tests / routes / app boot to inject a configured GalleryStore. */
|
|
180
|
+
setGalleryStore(store) { this._gallery = store; }
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Lazy-init helper. Returns a GalleryStore — defaults to ~/.loxia/widget-gallery.json.
|
|
184
|
+
* @private
|
|
185
|
+
*/
|
|
186
|
+
_galleryStore() {
|
|
187
|
+
if (!this._gallery) this._gallery = new GalleryStore({ logger: this.logger });
|
|
188
|
+
return this._gallery;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
getDescription() {
|
|
192
|
+
return `
|
|
193
|
+
Widget Tool: Render custom UI widgets inline in the message stream.
|
|
194
|
+
|
|
195
|
+
USAGE:
|
|
196
|
+
\`\`\`json
|
|
197
|
+
{ "toolId": "widget", "action": "render", "kind": "html", "content": "<div>...</div>" }
|
|
198
|
+
\`\`\`
|
|
199
|
+
|
|
200
|
+
ACTIONS:
|
|
201
|
+
- render — mount or replace a widget. kind: 'html' (static) or 'jsx' (interactive)
|
|
202
|
+
- update — replace props on an existing widget (jsx only; triggers re-render)
|
|
203
|
+
- destroy — remove a widget from the stream
|
|
204
|
+
- list — return { widgetId, kind, createdAt, size } for all widgets this agent owns
|
|
205
|
+
- list-capabilities — return a structured report of every global, hook, primitive,
|
|
206
|
+
namespace alias, and "not implemented" API with rewrite paths.
|
|
207
|
+
Call this any time you're unsure what's available, or after
|
|
208
|
+
a WIDGET RENDER ERROR mentions an undefined identifier.
|
|
209
|
+
|
|
210
|
+
KINDS:
|
|
211
|
+
- **html**: static HTML+CSS. Script tags, inline handlers, and <form> submissions
|
|
212
|
+
are blocked by the sandbox. Images allowed from 'data:' and 'blob:' URIs only.
|
|
213
|
+
Use this for visualisations, decorated callouts, and anything that doesn't
|
|
214
|
+
need interactivity.
|
|
215
|
+
|
|
216
|
+
- **webcomponent** (RECOMMENDED for interactive widgets): you write a class
|
|
217
|
+
that extends LoxiaElement (an HTMLElement subclass), then call
|
|
218
|
+
loxia.render(YourClass, initialProps). Standard web platform — no JSX,
|
|
219
|
+
no hooks, no namespace imports. The agent surface is just:
|
|
220
|
+
class MyWidget extends LoxiaElement {
|
|
221
|
+
state = { count: 0 };
|
|
222
|
+
template(state) {
|
|
223
|
+
return \`
|
|
224
|
+
<div>
|
|
225
|
+
<span>Count: \${state.count}</span>
|
|
226
|
+
<button data-bind-click="increment">+1</button>
|
|
227
|
+
<input data-bind="name" value="\${state.name || ''}" placeholder="Name" />
|
|
228
|
+
</div>
|
|
229
|
+
\`;
|
|
230
|
+
}
|
|
231
|
+
increment() { this.setState({ count: this.state.count + 1 }); }
|
|
232
|
+
}
|
|
233
|
+
loxia.render(MyWidget, window.__loxiaInitialProps);
|
|
234
|
+
|
|
235
|
+
EVENT WIRING — THE PRIMARY PATTERN:
|
|
236
|
+
|
|
237
|
+
Use addEventListener inside this.afterRender(root). This is web-standard,
|
|
238
|
+
typo-proof, gives full Event API access (AbortSignal, { once, capture,
|
|
239
|
+
passive }, custom events, event delegation), and works for events
|
|
240
|
+
data-on-<event> can't express. afterRender(root) runs after EVERY render
|
|
241
|
+
(including post-setState), so listeners attached there survive state
|
|
242
|
+
updates — innerHTML is rewritten on each render, but the hook re-attaches
|
|
243
|
+
your listeners on the fresh DOM each time.
|
|
244
|
+
|
|
245
|
+
Example:
|
|
246
|
+
class MyWidget extends LoxiaElement {
|
|
247
|
+
state = { count: 0 };
|
|
248
|
+
increment() { this.setState({ count: this.state.count + 1 }); }
|
|
249
|
+
afterRender(root) {
|
|
250
|
+
root.querySelector('#bumpBtn').addEventListener('click', () => this.increment());
|
|
251
|
+
root.querySelector('#nameInput').addEventListener('input', (e) => {
|
|
252
|
+
this.setState({ name: e.target.value });
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
template(state) {
|
|
256
|
+
return \`<div>
|
|
257
|
+
<span>Count: \${state.count}</span>
|
|
258
|
+
<button id="bumpBtn">+1</button>
|
|
259
|
+
<input id="nameInput" placeholder="Name" />
|
|
260
|
+
</div>\`;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
loxia.render(MyWidget, window.__loxiaInitialProps);
|
|
264
|
+
|
|
265
|
+
Why afterRender and NOT onMount: onMount fires once on first connection.
|
|
266
|
+
setState rewrites innerHTML, which destroys all DOM listeners attached
|
|
267
|
+
in onMount. They silently stop firing on the first re-render. afterRender
|
|
268
|
+
is the only correct place to attach listeners that need to survive state.
|
|
269
|
+
|
|
270
|
+
AUTO-WIRING SHORTCUTS (optional ergonomics, only for the simple cases):
|
|
271
|
+
|
|
272
|
+
data-bind="key" → input/change events update state[key] automatically.
|
|
273
|
+
Useful for two-way binding text/number inputs.
|
|
274
|
+
data-on-<event>="methodName" → fires any DOM event → calls this.methodName(e).
|
|
275
|
+
Concise alternative to addEventListener for
|
|
276
|
+
trivial cases. Works for any browser event name
|
|
277
|
+
(click, input, keydown, pointerdown, dblclick,
|
|
278
|
+
wheel, transitionend, …).
|
|
279
|
+
\`this\` inside the handler is the LoxiaElement.
|
|
280
|
+
|
|
281
|
+
DO NOT USE for local interactivity:
|
|
282
|
+
|
|
283
|
+
✗ data-emit="name"
|
|
284
|
+
Sends a postMessage to the AGENT — does NOT call your method on click.
|
|
285
|
+
The button click will appear to do nothing locally; the agent receives
|
|
286
|
+
an event on its NEXT TURN. Use ONLY when you specifically want to
|
|
287
|
+
notify the agent (e.g. "user clicked submit, fetch fresh data").
|
|
288
|
+
For a click that should run a local method, use addEventListener
|
|
289
|
+
in afterRender or data-on-click="methodName".
|
|
290
|
+
|
|
291
|
+
✗ Inline onclick="this.foo()" / onchange="…"
|
|
292
|
+
Runs in iframe global scope; \`this\` is the element, not your class.
|
|
293
|
+
|
|
294
|
+
✗ data-bind-click / data-action / data-handler / data-onclick / data-on:click
|
|
295
|
+
Not recognized. The runtime now auto-rewrites these to data-on-<event>
|
|
296
|
+
AND surfaces a warning, but it's better to write data-on-click directly.
|
|
297
|
+
|
|
298
|
+
✗ addEventListener in onMount()
|
|
299
|
+
Dies on the first setState because innerHTML is rewritten. Use afterRender.
|
|
300
|
+
|
|
301
|
+
SHADOW DOM:
|
|
302
|
+
LoxiaElement attaches a shadow root in its constructor, so this.shadowRoot
|
|
303
|
+
is always available. template()'s output is written to shadowRoot.innerHTML.
|
|
304
|
+
CSS scoped to your widget (in the template's <style>) does NOT leak out;
|
|
305
|
+
CSS custom properties (--gray-500, --loxia-600) DO pierce in. Use
|
|
306
|
+
this.shadowRoot.querySelector / addEventListener for direct DOM access.
|
|
307
|
+
|
|
308
|
+
CRITICAL — HOW TO MOUNT (the #1 failure mode):
|
|
309
|
+
ALWAYS end your code with:
|
|
310
|
+
loxia.render(YourClass, window.__loxiaInitialProps);
|
|
311
|
+
|
|
312
|
+
Do NOT do any of these — they will produce a "Your widget did not mount" error:
|
|
313
|
+
✗ customElements.define('your-tag', YourClass); // by itself
|
|
314
|
+
✗ document.body.appendChild(document.createElement('your-tag'));
|
|
315
|
+
✗ new YourClass(); // without appending
|
|
316
|
+
✗ class YourClass { ... } // forgetting the loxia.render call entirely
|
|
317
|
+
|
|
318
|
+
loxia.render handles registration, instantiation, and mounting in one call.
|
|
319
|
+
|
|
320
|
+
PROP UPDATES from agent:
|
|
321
|
+
When you call widget.update with new props, the iframe receives them
|
|
322
|
+
and the base class's handleUpdate(props) is called (default: setState).
|
|
323
|
+
Override handleUpdate() if you want custom merge logic.
|
|
324
|
+
|
|
325
|
+
ESCAPE HATCH: extend HTMLElement directly if you want raw DOM control.
|
|
326
|
+
loxia.render still mounts you and bridges events to the agent.
|
|
327
|
+
|
|
328
|
+
- **jsx**: interactive mini-Preact widget rendered in a null-origin
|
|
329
|
+
sandbox iframe. This is NOT React, NOT Preact, NOT a Node environment.
|
|
330
|
+
Read the GLOBALS list below BEFORE writing code — every identifier you
|
|
331
|
+
reference must appear there or it will ReferenceError at runtime.
|
|
332
|
+
|
|
333
|
+
═══════════════════════════════════════════════════════════════════
|
|
334
|
+
THE COMPLETE LIST OF GLOBALS AVAILABLE INSIDE YOUR WIDGET
|
|
335
|
+
═══════════════════════════════════════════════════════════════════
|
|
336
|
+
All available as bare identifiers, as properties on \`h\`, and on
|
|
337
|
+
\`loxia\` — pick whichever you like:
|
|
338
|
+
|
|
339
|
+
h(type, props, ...children) — hyperscript (VDOM node constructor)
|
|
340
|
+
html\`…\` — htm tagged-template, compiles to h()
|
|
341
|
+
LoxiaCard, LoxiaButton, LoxiaInput, LoxiaText,
|
|
342
|
+
LoxiaMetric, LoxiaRow, LoxiaCol — component primitives
|
|
343
|
+
|
|
344
|
+
Hooks — these DO work, scoped to the ROOT component:
|
|
345
|
+
|
|
346
|
+
useState(initial) → [value, setValue]
|
|
347
|
+
useEffect(fn, deps) → runs fn after render when deps change;
|
|
348
|
+
fn may return a cleanup function
|
|
349
|
+
useMemo(compute, deps) → cached value
|
|
350
|
+
useCallback(fn, deps) → cached function reference
|
|
351
|
+
useRef(initial) → { current } — stable across renders
|
|
352
|
+
useReducer(reducer, init[, i])→ [state, dispatch] — implemented as
|
|
353
|
+
a useState wrapper
|
|
354
|
+
|
|
355
|
+
loxia-only APIs:
|
|
356
|
+
|
|
357
|
+
loxia.render(Component, props) — mount; call this last
|
|
358
|
+
loxia.sendEvent({ type, payload }) — send event up to the agent
|
|
359
|
+
loxia.onUpdate(fn) — subscribe to prop updates
|
|
360
|
+
loxia.requestHeight(px) — manual height override
|
|
361
|
+
|
|
362
|
+
Browser APIs (standard in every iframe):
|
|
363
|
+
|
|
364
|
+
document, window, console, setTimeout, setInterval, clearTimeout,
|
|
365
|
+
clearInterval, Promise, JSON, Math, Date, Array, Object, String,
|
|
366
|
+
Number, Boolean, Map, Set, Symbol, Error
|
|
367
|
+
|
|
368
|
+
═══════════════════════════════════════════════════════════════════
|
|
369
|
+
NOT AVAILABLE
|
|
370
|
+
═══════════════════════════════════════════════════════════════════
|
|
371
|
+
|
|
372
|
+
HARD ERRORS (ReferenceError — environment doesn't provide them):
|
|
373
|
+
✗ JSX angle-bracket syntax (bare <div>...) → use html\`<div>...\`
|
|
374
|
+
✗ import, require, export → iframe is null-origin, no modules
|
|
375
|
+
✗ fetch, XMLHttpRequest, WebSocket → CSP blocks all network
|
|
376
|
+
✗ localStorage, sessionStorage, cookies → null origin, no storage
|
|
377
|
+
✗ indexedDB → null origin
|
|
378
|
+
✗ Any npm package (lodash, d3, chart.js, ...) → none are loaded
|
|
379
|
+
✗ process, global, Buffer → this is a browser, not Node
|
|
380
|
+
✗ Hooks in NESTED components → hooks are call-order-keyed
|
|
381
|
+
on the ROOT component. Lift nested state up.
|
|
382
|
+
|
|
383
|
+
NAMED "NOT IMPLEMENTED" ERRORS (APIs that LOOK available via namespaces
|
|
384
|
+
but throw with a specific message so you know exactly what to change):
|
|
385
|
+
|
|
386
|
+
Class components — "X is not implemented … use a function component":
|
|
387
|
+
✗ Component, PureComponent
|
|
388
|
+
✗ \`class App extends React.Component { ... }\` → rewrite as
|
|
389
|
+
a function component with useState.
|
|
390
|
+
|
|
391
|
+
React/Preact APIs beyond the 6 supported hooks:
|
|
392
|
+
✗ useContext, useLayoutEffect, useImperativeHandle,
|
|
393
|
+
useDeferredValue, useTransition, useId, useSyncExternalStore,
|
|
394
|
+
useErrorBoundary
|
|
395
|
+
✗ createContext, createRef, forwardRef, memo, lazy, Suspense,
|
|
396
|
+
StrictMode, Children, cloneElement, isValidElement
|
|
397
|
+
|
|
398
|
+
When you hit these, the error message names the API and lists
|
|
399
|
+
supported alternatives. Example rewrites:
|
|
400
|
+
- useContext(Context) → prop-drill or move state to agent
|
|
401
|
+
- useLayoutEffect(fn, deps) → useEffect(fn, deps) is close enough
|
|
402
|
+
- Component class → function App() { ... useState ... }
|
|
403
|
+
|
|
404
|
+
For a PROGRAMMATIC list (with rewrite paths for each), call
|
|
405
|
+
{ "toolId": "widget", "action": "list-capabilities" }.
|
|
406
|
+
|
|
407
|
+
NAMES THAT ARE AVAILABLE but don't contain what you think:
|
|
408
|
+
- React / ReactDOM / preact / htmPreact / preactHooks / htm — ALL
|
|
409
|
+
alias to the same widget-runtime bundle. They have useState,
|
|
410
|
+
useEffect, useMemo, useCallback, useRef, h, html, createElement,
|
|
411
|
+
Fragment. They do NOT have Component, forwardRef, Suspense, etc.
|
|
412
|
+
(see NOT IMPLEMENTED above).
|
|
413
|
+
|
|
414
|
+
═══════════════════════════════════════════════════════════════════
|
|
415
|
+
TEMPLATE ATTRIBUTE SYNTAX — GOTCHAS
|
|
416
|
+
═══════════════════════════════════════════════════════════════════
|
|
417
|
+
|
|
418
|
+
Inside html\`...\` templates, interpolation uses \${expr}. Attributes
|
|
419
|
+
with non-string values (objects, functions) need the \${...} wrapper.
|
|
420
|
+
|
|
421
|
+
INLINE STYLE AS AN OBJECT — the common mistake:
|
|
422
|
+
|
|
423
|
+
✗ <div style="{ color: 'red' }"> ← wrong: string literal,
|
|
424
|
+
div has no real styling
|
|
425
|
+
✗ <div style="\${styleObj}"> ← wrong: coerced to string
|
|
426
|
+
✓ <div style=\${{ color: 'red' }}> ← correct: object interp
|
|
427
|
+
✓ <div style=\${styleObj}> ← correct: object variable
|
|
428
|
+
|
|
429
|
+
The outer \${...} is the template interpolation; the inner {...} is the
|
|
430
|
+
JS object literal. When an agent uses style="\${expr}" (with the quotes
|
|
431
|
+
closing INSIDE the interpolation), the runtime treats the whole thing
|
|
432
|
+
as a string and your styling gets silently ignored.
|
|
433
|
+
|
|
434
|
+
SAME RULE for event handlers and any non-string attribute:
|
|
435
|
+
|
|
436
|
+
✓ <button onClick=\${fn}> ← unquoted interpolation
|
|
437
|
+
✓ <input value=\${s}>
|
|
438
|
+
✗ <button onClick="\${fn}"> ← string "function..."
|
|
439
|
+
✗ <input value="\${s}"> ← stringified
|
|
440
|
+
|
|
441
|
+
Quoted interpolations are only right for STRING attributes:
|
|
442
|
+
|
|
443
|
+
✓ <div class=\${cls}> or class="\${cls}" ← both OK (both strings)
|
|
444
|
+
✓ <a href=\${url}> ← url is a string anyway
|
|
445
|
+
|
|
446
|
+
═══════════════════════════════════════════════════════════════════
|
|
447
|
+
STATE MODEL
|
|
448
|
+
═══════════════════════════════════════════════════════════════════
|
|
449
|
+
|
|
450
|
+
Two patterns — pick based on who needs the state.
|
|
451
|
+
|
|
452
|
+
(A) LOCAL STATE (useState): keep it in the widget. Good for form
|
|
453
|
+
inputs, hover effects, expand/collapse, etc. — anything the
|
|
454
|
+
agent doesn't need to reason about.
|
|
455
|
+
|
|
456
|
+
(B) AGENT-OWNED STATE (sendEvent + widget.update): the widget is a
|
|
457
|
+
view, the agent is the state machine. Good for state the agent
|
|
458
|
+
should track or persist (final decisions, completed selections).
|
|
459
|
+
|
|
460
|
+
Combine both freely: keep typing/dragging state local with useState,
|
|
461
|
+
and sendEvent only on submit/commit.
|
|
462
|
+
|
|
463
|
+
═══════════════════════════════════════════════════════════════════
|
|
464
|
+
MINIMAL WORKING EXAMPLES
|
|
465
|
+
═══════════════════════════════════════════════════════════════════
|
|
466
|
+
|
|
467
|
+
Pattern A — local counter with useState:
|
|
468
|
+
|
|
469
|
+
return function App() {
|
|
470
|
+
const [count, setCount] = useState(0);
|
|
471
|
+
return html\`
|
|
472
|
+
<div style=\${{ padding: 16 }}>
|
|
473
|
+
<div>Count: \${count}</div>
|
|
474
|
+
<button onClick=\${() => setCount(count + 1)}>+1</button>
|
|
475
|
+
</div>
|
|
476
|
+
\`;
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
Pattern B — agent-owned counter:
|
|
480
|
+
|
|
481
|
+
return function App({ count = 0 }) {
|
|
482
|
+
return html\`
|
|
483
|
+
<div>
|
|
484
|
+
<div>Count: \${count}</div>
|
|
485
|
+
<button onClick=\${() => loxia.sendEvent({ type: 'increment' })}>
|
|
486
|
+
+1
|
|
487
|
+
</button>
|
|
488
|
+
</div>
|
|
489
|
+
\`;
|
|
490
|
+
};
|
|
491
|
+
// Agent handles the 'increment' event and calls widget.update({ count: count + 1 }).
|
|
492
|
+
|
|
493
|
+
PREFERRED: bare identifiers. They always work, no namespace juggling:
|
|
494
|
+
// just use them directly, no destructure, no import:
|
|
495
|
+
const [n, setN] = useState(0);
|
|
496
|
+
useEffect(() => { ... }, []);
|
|
497
|
+
|
|
498
|
+
Namespace destructure patterns (all equivalent, all work):
|
|
499
|
+
const { useState, useEffect } = h;
|
|
500
|
+
const { useState, useEffect } = htmPreact;
|
|
501
|
+
const { useState, useEffect } = preact;
|
|
502
|
+
const { useState, useEffect } = preactHooks;
|
|
503
|
+
const { useState, useEffect } = React;
|
|
504
|
+
const { useState, useEffect } = hooks;
|
|
505
|
+
|
|
506
|
+
The following global names ALL point at the same hooks bundle so you
|
|
507
|
+
can reach for whichever name you remember — the widget runtime aliases
|
|
508
|
+
them aggressively:
|
|
509
|
+
|
|
510
|
+
htmPreact, htm_preact, preactHtm, htm, Htm,
|
|
511
|
+
preact, Preact, preactjs,
|
|
512
|
+
preactHooks, PreactHooks, preact_hooks, hooks, Hooks,
|
|
513
|
+
React, react, reactHooks, ReactHooks, react_hooks,
|
|
514
|
+
preactStandalone, preact_standalone,
|
|
515
|
+
ReactDOM.render(vnode, target), ReactDOM.createRoot(x).render(vnode)
|
|
516
|
+
|
|
517
|
+
If you reach for a name not in that list, add a fallback:
|
|
518
|
+
const useState = (globalThis.useState || h.useState);
|
|
519
|
+
|
|
520
|
+
NOT IMPLEMENTED (will throw a specific "X is not implemented" error
|
|
521
|
+
you'll see in the next-turn feedback — then switch to the supported
|
|
522
|
+
APIs): useLayoutEffect, useImperativeHandle, useContext, useReducer,
|
|
523
|
+
useDeferredValue, useTransition, useId, useSyncExternalStore,
|
|
524
|
+
createContext, createRef, forwardRef, memo, lazy, Suspense, StrictMode,
|
|
525
|
+
Children, cloneElement, isValidElement.
|
|
526
|
+
|
|
527
|
+
═══════════════════════════════════════════════════════════════════
|
|
528
|
+
FEEDBACK LOOP
|
|
529
|
+
═══════════════════════════════════════════════════════════════════
|
|
530
|
+
|
|
531
|
+
When the iframe throws (undefined identifier, bad syntax, handler
|
|
532
|
+
error), a tool result arrives on your NEXT turn shaped like a normal
|
|
533
|
+
failure:
|
|
534
|
+
|
|
535
|
+
[widget] {
|
|
536
|
+
"toolId": "widget",
|
|
537
|
+
"status": "failed",
|
|
538
|
+
"result": {
|
|
539
|
+
"success": false,
|
|
540
|
+
"action": "render",
|
|
541
|
+
"widgetId": "<id>",
|
|
542
|
+
"error": "WIDGET RENDER ERROR — widget \"<id>\" failed during \"<phase>\": <message>. Your widget code did not execute; fix the error and call widget.render again.",
|
|
543
|
+
"phase": "render" | "runtime" | "async" | "runtime-setup",
|
|
544
|
+
"message": "<short cause>",
|
|
545
|
+
"stack": "<stack or (no stack)>"
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
IMPORTANT: the tool CALL returning { success: true } only means the
|
|
550
|
+
backend STORED your widget — it does NOT mean it rendered. If the
|
|
551
|
+
next turn shows a widget tool-result with status:"failed" or the
|
|
552
|
+
error string "WIDGET RENDER ERROR", your widget is broken. FIX the
|
|
553
|
+
specific error from result.message (not guess a different cause) and
|
|
554
|
+
re-issue widget.render.
|
|
555
|
+
|
|
556
|
+
Repeated identical errors are suppressed to protect your context —
|
|
557
|
+
you get at most 5 distinct errors per widget. If you keep hitting
|
|
558
|
+
the same cause, re-read GLOBALS AVAILABLE above before trying again.
|
|
559
|
+
|
|
560
|
+
Common first-try mistakes that produce __widgetError:
|
|
561
|
+
- Using hooks (useState, useEffect, useMemo, useRef) → ReferenceError
|
|
562
|
+
- Importing / requiring packages → ReferenceError: require not defined
|
|
563
|
+
- Calling fetch / XMLHttpRequest → blocked by CSP
|
|
564
|
+
- Writing bare JSX angle-bracket syntax → parse error
|
|
565
|
+
- Assuming React / ReactDOM / preact are globals → ReferenceError
|
|
566
|
+
|
|
567
|
+
PARAMETERS:
|
|
568
|
+
- kind (required): 'html' | 'jsx'
|
|
569
|
+
- content (required): the payload. HTML string for 'html'; JS render function body for 'jsx'
|
|
570
|
+
- widgetId (optional): stable id so you can update/destroy later. Auto-generated if omitted.
|
|
571
|
+
- props (optional): initial props for jsx widgets; merged on render and update.
|
|
572
|
+
|
|
573
|
+
LIMITS:
|
|
574
|
+
- Max ${WIDGET_LIMITS.MAX_CONTENT_BYTES / 1024} KB per widget payload
|
|
575
|
+
- Max ${WIDGET_LIMITS.MAX_WIDGETS_PER_AGENT} concurrent widgets per agent (oldest evicted)
|
|
576
|
+
|
|
577
|
+
SAFETY:
|
|
578
|
+
- Widgets run in a sandboxed iframe with null origin. They cannot read your
|
|
579
|
+
cookies, make network requests, or touch the parent page.
|
|
580
|
+
- If your content includes credential-shaped prompts ("password", "login",
|
|
581
|
+
"credit card" etc.), the user will see a stronger confirmation modal
|
|
582
|
+
before rendering. That is normal and expected — phishing-shape detection
|
|
583
|
+
protects users; it does not indicate a bug in your widget.
|
|
584
|
+
- The user may disable custom widgets entirely per-agent via the widget
|
|
585
|
+
configurator. When disabled, render calls return { disabled: true }
|
|
586
|
+
and the widget is not shown.`;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
getSupportedActions() {
|
|
590
|
+
return [
|
|
591
|
+
'render', 'update', 'destroy', 'list', 'list-capabilities',
|
|
592
|
+
// Versioning — each render appends a new version. Agent (and
|
|
593
|
+
// user) can promote a version as main or fetch any version's content.
|
|
594
|
+
'list-versions', 'get-version', 'set-main',
|
|
595
|
+
// Naming — set/clear a human-friendly display name (cosmetic;
|
|
596
|
+
// widgetId remains the stable identifier).
|
|
597
|
+
'rename',
|
|
598
|
+
// Gallery — cross-session catalog of shared widget templates.
|
|
599
|
+
'share-to-gallery', 'unshare-from-gallery',
|
|
600
|
+
'list-gallery', 'render-from-gallery',
|
|
601
|
+
// Upgrade-awareness for gallery-linked widgets.
|
|
602
|
+
'check-upgrade', 'apply-upgrade',
|
|
603
|
+
];
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
async execute(params, context = {}) {
|
|
607
|
+
if (!params || typeof params !== 'object') {
|
|
608
|
+
return { success: false, error: 'params must be an object' };
|
|
609
|
+
}
|
|
610
|
+
const action = params.action || 'render';
|
|
611
|
+
const agentId = context?.agentId || 'unknown';
|
|
612
|
+
|
|
613
|
+
// Per-agent kill switch via toolConfig. When the agent has not been
|
|
614
|
+
// granted custom-widget permission, calls short-circuit with a
|
|
615
|
+
// helpful message so the agent knows not to retry.
|
|
616
|
+
const effectiveConfig = this.getEffectiveConfig(context, { allowCustomCode: false });
|
|
617
|
+
const allowed = effectiveConfig.allowCustomCode !== false; // default allowed when unspecified
|
|
618
|
+
|
|
619
|
+
switch (action) {
|
|
620
|
+
case 'render': return this._render(agentId, params, { allowed, context });
|
|
621
|
+
case 'update': return this._update(agentId, params, { allowed });
|
|
622
|
+
case 'destroy': return this._destroy(agentId, params);
|
|
623
|
+
case 'list': return this._list(agentId);
|
|
624
|
+
case 'list-capabilities': return this._listCapabilities();
|
|
625
|
+
case 'list-versions': return this._listVersions(agentId, params);
|
|
626
|
+
case 'get-version': return this._getVersion(agentId, params);
|
|
627
|
+
case 'set-main': return this._setMain(agentId, params);
|
|
628
|
+
case 'rename': return this._rename(agentId, params);
|
|
629
|
+
case 'share-to-gallery': return this._shareToGallery(agentId, params, context);
|
|
630
|
+
case 'unshare-from-gallery': return this._unshareFromGallery(agentId, params);
|
|
631
|
+
case 'list-gallery': return this._listGallery(params);
|
|
632
|
+
case 'render-from-gallery': return this._renderFromGallery(agentId, params, { allowed });
|
|
633
|
+
case 'check-upgrade': return this._checkUpgrade(agentId, params);
|
|
634
|
+
case 'apply-upgrade': return this._applyUpgrade(agentId, params, { allowed });
|
|
635
|
+
default: return { success: false, error: `Unknown action: ${action}. Supported: ${this.getSupportedActions().join(', ')}` };
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Machine-readable capabilities report. Returned to the agent on
|
|
641
|
+
* `widget.list-capabilities` AND embedded in every render-failure so
|
|
642
|
+
* the agent has a programmatic way to see what IS available without
|
|
643
|
+
* re-parsing the long prose description.
|
|
644
|
+
*
|
|
645
|
+
* Keep this list IN SYNC with the runtime bundle — the tests pin this
|
|
646
|
+
* against runtime/bundle.js so drift is caught at CI time.
|
|
647
|
+
*/
|
|
648
|
+
_listCapabilities() {
|
|
649
|
+
return {
|
|
650
|
+
success: true,
|
|
651
|
+
action: 'list-capabilities',
|
|
652
|
+
capabilities: {
|
|
653
|
+
kinds: {
|
|
654
|
+
html: 'static HTML+CSS, no scripts (sandbox="")',
|
|
655
|
+
jsx: 'Preact + htm runtime; hooks (useState/useEffect/...), h(), html``',
|
|
656
|
+
webcomponent: 'class extends LoxiaElement; standard web platform, no custom runtime quirks. RECOMMENDED for new interactive widgets.',
|
|
657
|
+
},
|
|
658
|
+
webcomponent: {
|
|
659
|
+
baseClass: 'LoxiaElement (extends HTMLElement)',
|
|
660
|
+
mountApi: 'loxia.render(YourClass, initialProps) — registers a unique tag, instantiates, mounts to #root',
|
|
661
|
+
ergonomics: {
|
|
662
|
+
'class field state = {...}': 'initial state',
|
|
663
|
+
'this.setState(updater)': 'merge OR pass a function for prev-state updates; triggers re-render',
|
|
664
|
+
'this.template(state) → string': 'override; return innerHTML',
|
|
665
|
+
'this.emit(type, payload)': 'send event to agent (alias for loxia.sendEvent with type set)',
|
|
666
|
+
'this.handleUpdate(newProps)': 'called when agent posts widget.update; default setState(newProps)',
|
|
667
|
+
'this.onMount() / this.onUnmount()': 'lifecycle; called from connectedCallback / disconnectedCallback',
|
|
668
|
+
'this.afterRender(root)': 'called AFTER every render (including post-setState). Sanctioned hook for manual addEventListener — listeners attached here survive setState because they\'re re-attached on the fresh DOM. (onMount fires only once; addEventListener calls there die on the first re-render.)',
|
|
669
|
+
},
|
|
670
|
+
autoWiredAttrs: {
|
|
671
|
+
'data-bind="key"': 'input/change → setState({key: value}) (numeric inputs auto-coerced)',
|
|
672
|
+
'data-emit="name"': 'click → emit(name, { state }) — sends to AGENT',
|
|
673
|
+
'data-on-<event>="methodName"': 'ANY DOM event (click, input, keydown, pointerdown, dragover, wheel, transitionend, …) → this.methodName(event) — calls LOCAL instance method',
|
|
674
|
+
'data-payload="{...}"': 'JSON payload merged into the emit (optional, data-emit only)',
|
|
675
|
+
},
|
|
676
|
+
escapeHatch: 'You can extend HTMLElement directly. loxia.render still mounts you. Use attributeChangedCallback for prop updates in that path.',
|
|
677
|
+
},
|
|
678
|
+
// Every name that can appear as a bare identifier and works.
|
|
679
|
+
globals: [
|
|
680
|
+
// VDOM primitives
|
|
681
|
+
'h', 'html', 'createElement', 'Fragment',
|
|
682
|
+
// Hooks (all implemented — safe to use)
|
|
683
|
+
'useState', 'useEffect', 'useMemo', 'useCallback', 'useRef', 'useReducer',
|
|
684
|
+
// Component primitives
|
|
685
|
+
'LoxiaCard', 'LoxiaButton', 'LoxiaInput', 'LoxiaText',
|
|
686
|
+
'LoxiaMetric', 'LoxiaRow', 'LoxiaCol',
|
|
687
|
+
],
|
|
688
|
+
// Objects the agent can use as namespaces — all alias the same bundle.
|
|
689
|
+
namespaces: {
|
|
690
|
+
aliased: [
|
|
691
|
+
'htmPreact', 'htm_preact', 'preactHtm', 'htm', 'Htm',
|
|
692
|
+
'preact', 'Preact', 'preactjs',
|
|
693
|
+
'preactHooks', 'PreactHooks', 'preact_hooks', 'hooks', 'Hooks',
|
|
694
|
+
'React', 'react', 'reactHooks', 'ReactHooks', 'react_hooks',
|
|
695
|
+
'preactStandalone', 'preact_standalone',
|
|
696
|
+
],
|
|
697
|
+
reactDomShim: ['ReactDOM.render(vnode, el)', 'ReactDOM.createRoot(el).render(vnode)'],
|
|
698
|
+
},
|
|
699
|
+
// loxia namespace — widget-specific APIs.
|
|
700
|
+
loxia: {
|
|
701
|
+
'loxia.render(Component, props)': 'mount the root component (call this last)',
|
|
702
|
+
'loxia.sendEvent({type, payload})': 'send event to the agent; arrives next turn as a tool-result',
|
|
703
|
+
'loxia.onUpdate(fn)': 'subscribe to prop updates from agent widget.update',
|
|
704
|
+
'loxia.requestHeight(px)': 'manually override iframe height',
|
|
705
|
+
},
|
|
706
|
+
// Browser APIs the iframe has (standard, always available).
|
|
707
|
+
browserApis: [
|
|
708
|
+
'document', 'window', 'console', 'setTimeout', 'setInterval',
|
|
709
|
+
'clearTimeout', 'clearInterval', 'Promise', 'JSON', 'Math',
|
|
710
|
+
'Date', 'Array', 'Object', 'String', 'Number', 'Boolean',
|
|
711
|
+
'Map', 'Set', 'Symbol', 'Error',
|
|
712
|
+
],
|
|
713
|
+
// Named errors — using any of these throws with a specific message.
|
|
714
|
+
notImplemented: {
|
|
715
|
+
classes: ['Component', 'PureComponent'],
|
|
716
|
+
functions: [
|
|
717
|
+
'useLayoutEffect', 'useImperativeHandle', 'useContext',
|
|
718
|
+
'useDeferredValue', 'useTransition', 'useId',
|
|
719
|
+
'useSyncExternalStore', 'useErrorBoundary',
|
|
720
|
+
'createContext', 'createRef', 'forwardRef', 'memo',
|
|
721
|
+
'lazy', 'Suspense', 'StrictMode',
|
|
722
|
+
'Children', 'cloneElement', 'isValidElement',
|
|
723
|
+
],
|
|
724
|
+
rewritePaths: {
|
|
725
|
+
'useContext(Ctx)': 'prop-drill, OR move the state to the agent via sendEvent + widget.update',
|
|
726
|
+
'useLayoutEffect': 'useEffect is a close substitute (fires after paint instead of before)',
|
|
727
|
+
'useReducer': 'IMPLEMENTED — you can use it directly. (Older docs said not; now supported.)',
|
|
728
|
+
'forwardRef': 'refs to child components are not supported; use useRef for DOM nodes only',
|
|
729
|
+
'memo(Component)': 'memoize derived values with useMemo inside the component instead',
|
|
730
|
+
'Component / class': 'rewrite as a function component — function App(){ const [s,setS]=useState(); ... }',
|
|
731
|
+
},
|
|
732
|
+
},
|
|
733
|
+
// Hard errors — things that throw ReferenceError.
|
|
734
|
+
hardErrors: [
|
|
735
|
+
'fetch', 'XMLHttpRequest', 'WebSocket',
|
|
736
|
+
'localStorage', 'sessionStorage', 'cookies', 'indexedDB',
|
|
737
|
+
'import', 'require', 'export',
|
|
738
|
+
'process', 'global', 'Buffer',
|
|
739
|
+
'Any npm package (lodash, d3, chart.js, react-router, etc.)',
|
|
740
|
+
],
|
|
741
|
+
// Security and scope constraints — immutable, just informational.
|
|
742
|
+
constraints: {
|
|
743
|
+
sandbox: 'null-origin iframe — no cookies, no network, no parent-page access',
|
|
744
|
+
maxContentBytes: WIDGET_LIMITS.MAX_CONTENT_BYTES,
|
|
745
|
+
maxWidgetsPerAgent: WIDGET_LIMITS.MAX_WIDGETS_PER_AGENT,
|
|
746
|
+
hooksScope: 'hooks are call-order-keyed on the ROOT component — nested components can\'t use hooks; lift state up',
|
|
747
|
+
stateModel: 'function components only, no classes',
|
|
748
|
+
},
|
|
749
|
+
},
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
_render(agentId, params, { allowed, context }) {
|
|
754
|
+
const v = validateRenderParams(params);
|
|
755
|
+
if (!v.valid) return { success: false, error: v.error };
|
|
756
|
+
|
|
757
|
+
if (!allowed) {
|
|
758
|
+
return {
|
|
759
|
+
success: false,
|
|
760
|
+
disabled: true,
|
|
761
|
+
error: 'Custom widgets are disabled for this agent. Enable in the widget configurator.',
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const widgetId = params.widgetId || this._generateWidgetId(params.kind);
|
|
766
|
+
const newVersion = buildVersion({
|
|
767
|
+
kind: params.kind,
|
|
768
|
+
content: params.content,
|
|
769
|
+
props: params.props,
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
const widget = this._appendVersion(agentId, widgetId, newVersion);
|
|
773
|
+
|
|
774
|
+
// Optional display name: only set on FIRST render (so subsequent
|
|
775
|
+
// renders don't accidentally clear or change a name the user picked).
|
|
776
|
+
// To rename an existing widget, use the dedicated `rename` action.
|
|
777
|
+
const requestedName = normalizeName(params.name);
|
|
778
|
+
if (requestedName && !widget.name) {
|
|
779
|
+
widget.name = requestedName;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
this.logger?.info?.('Widget rendered', {
|
|
783
|
+
agentId, widgetId,
|
|
784
|
+
kind: widget.kind,
|
|
785
|
+
size: widget.size,
|
|
786
|
+
versionId: newVersion.versionId,
|
|
787
|
+
versionCount: widget.versions.length,
|
|
788
|
+
phishingFlags: newVersion.phishingHits.length,
|
|
789
|
+
});
|
|
790
|
+
|
|
791
|
+
this._emitChange(agentId, widgetId, 'rendered', widget);
|
|
792
|
+
|
|
793
|
+
// Static analysis — surface "looks broken even before rendering"
|
|
794
|
+
// findings (typo attributes, unreferenced handler-shaped methods).
|
|
795
|
+
// Fed back through the tool result so the agent's NEXT turn sees
|
|
796
|
+
// them and can ship a corrected render without waiting for the
|
|
797
|
+
// user to interact with a half-broken widget. iframe-side runtime
|
|
798
|
+
// warnings still fire when the widget actually mounts; the two
|
|
799
|
+
// sources are complementary (this catches things at submission
|
|
800
|
+
// time, the runtime catches things that depend on actual DOM
|
|
801
|
+
// shape after innerHTML).
|
|
802
|
+
const { warnings: codeWarnings } = analyzeWidgetCode(params.content, params.kind);
|
|
803
|
+
|
|
804
|
+
return {
|
|
805
|
+
success: true,
|
|
806
|
+
action: 'render',
|
|
807
|
+
widgetId,
|
|
808
|
+
versionId: newVersion.versionId,
|
|
809
|
+
versionCount: widget.versions.length,
|
|
810
|
+
widget,
|
|
811
|
+
...(codeWarnings.length > 0 && { warnings: codeWarnings }),
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
_update(agentId, params, { allowed }) {
|
|
816
|
+
const v = validateUpdateParams(params);
|
|
817
|
+
if (!v.valid) return { success: false, error: v.error };
|
|
818
|
+
|
|
819
|
+
if (!allowed) {
|
|
820
|
+
return { success: false, disabled: true, error: 'Custom widgets are disabled for this agent.' };
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
const agentWidgets = this._widgetsByAgent.get(agentId);
|
|
824
|
+
const widget = agentWidgets?.get(params.widgetId);
|
|
825
|
+
if (!widget) {
|
|
826
|
+
return { success: false, error: `Widget not found: ${params.widgetId}` };
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
widget.props = { ...widget.props, ...params.props };
|
|
830
|
+
widget.updatedAt = new Date().toISOString();
|
|
831
|
+
|
|
832
|
+
this.logger?.info?.('Widget updated', { agentId, widgetId: params.widgetId });
|
|
833
|
+
this._emitChange(agentId, params.widgetId, 'updated', widget);
|
|
834
|
+
return { success: true, action: 'update', widgetId: params.widgetId, widget };
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
_destroy(agentId, params) {
|
|
838
|
+
const v = validateDestroyParams(params);
|
|
839
|
+
if (!v.valid) return { success: false, error: v.error };
|
|
840
|
+
const agentWidgets = this._widgetsByAgent.get(agentId);
|
|
841
|
+
if (!agentWidgets?.has(params.widgetId)) {
|
|
842
|
+
return { success: false, error: `Widget not found: ${params.widgetId}` };
|
|
843
|
+
}
|
|
844
|
+
agentWidgets.delete(params.widgetId);
|
|
845
|
+
this.logger?.info?.('Widget destroyed', { agentId, widgetId: params.widgetId });
|
|
846
|
+
this._emitChange(agentId, params.widgetId, 'destroyed', null);
|
|
847
|
+
return { success: true, action: 'destroy', widgetId: params.widgetId };
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
_list(agentId) {
|
|
851
|
+
const agentWidgets = this._widgetsByAgent.get(agentId);
|
|
852
|
+
if (!agentWidgets) return { success: true, widgets: [] };
|
|
853
|
+
// Project to a list-summary shape — names match what the frontend
|
|
854
|
+
// artifacts panel needs to render a card without fetching content.
|
|
855
|
+
const widgets = Array.from(agentWidgets.values()).map(w => ({
|
|
856
|
+
widgetId: w.widgetId,
|
|
857
|
+
name: w.name || null,
|
|
858
|
+
kind: w.kind,
|
|
859
|
+
createdAt: w.createdAt,
|
|
860
|
+
updatedAt: w.updatedAt,
|
|
861
|
+
lastRenderedAt: w.lastRenderedAt,
|
|
862
|
+
size: w.size,
|
|
863
|
+
phishingHits: w.phishingHits,
|
|
864
|
+
versionCount: w.versions.length,
|
|
865
|
+
mainVersionId: w.mainVersionId,
|
|
866
|
+
// Gallery linkage (filled in by Phase 4 — null today). Listed
|
|
867
|
+
// here so the frontend can render the share state without a
|
|
868
|
+
// second round-trip.
|
|
869
|
+
linkedGalleryTemplateId: w.linkedGalleryTemplateId || null,
|
|
870
|
+
linkedGalleryVersion: w.linkedGalleryVersion || null,
|
|
871
|
+
divergedFromGallery: !!w.divergedFromGallery,
|
|
872
|
+
}));
|
|
873
|
+
return { success: true, widgets };
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
/**
|
|
877
|
+
* `list-versions { widgetId }` — return the version history for a
|
|
878
|
+
* widget without including each version's content. Useful for the
|
|
879
|
+
* artifacts panel's version dropdown.
|
|
880
|
+
*/
|
|
881
|
+
_listVersions(agentId, params) {
|
|
882
|
+
const v = validateListVersionsParams(params);
|
|
883
|
+
if (!v.valid) return { success: false, error: v.error };
|
|
884
|
+
const widget = this._widgetsByAgent.get(agentId)?.get(params.widgetId);
|
|
885
|
+
if (!widget) return { success: false, error: `Widget not found: ${params.widgetId}` };
|
|
886
|
+
return {
|
|
887
|
+
success: true,
|
|
888
|
+
action: 'list-versions',
|
|
889
|
+
widgetId: widget.widgetId,
|
|
890
|
+
mainVersionId: widget.mainVersionId,
|
|
891
|
+
// Chronological — oldest first; the latest version is at the end.
|
|
892
|
+
versions: widget.versions.map(v => ({
|
|
893
|
+
versionId: v.versionId,
|
|
894
|
+
kind: v.kind,
|
|
895
|
+
size: v.size,
|
|
896
|
+
createdAt: v.createdAt,
|
|
897
|
+
phishingHits: v.phishingHits,
|
|
898
|
+
// content omitted on purpose — fetch with get-version
|
|
899
|
+
})),
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/** `get-version { widgetId, versionId }` — fetch a specific version's content. */
|
|
904
|
+
_getVersion(agentId, params) {
|
|
905
|
+
const v = validateGetVersionParams(params);
|
|
906
|
+
if (!v.valid) return { success: false, error: v.error };
|
|
907
|
+
const widget = this._widgetsByAgent.get(agentId)?.get(params.widgetId);
|
|
908
|
+
if (!widget) return { success: false, error: `Widget not found: ${params.widgetId}` };
|
|
909
|
+
const version = widget.versions.find(x => x.versionId === params.versionId);
|
|
910
|
+
if (!version) {
|
|
911
|
+
return {
|
|
912
|
+
success: false,
|
|
913
|
+
error: `Version not found: ${params.versionId}. Available: ${widget.versions.map(x => x.versionId).join(', ')}`,
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
return { success: true, action: 'get-version', widgetId: widget.widgetId, version };
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
/**
|
|
920
|
+
* `set-main { widgetId, versionId }` — promote a version to be the
|
|
921
|
+
* active one. The widget's mirrored top-level fields update so the
|
|
922
|
+
* frontend's next render uses the chosen content.
|
|
923
|
+
*/
|
|
924
|
+
_setMain(agentId, params) {
|
|
925
|
+
const v = validateSetMainParams(params);
|
|
926
|
+
if (!v.valid) return { success: false, error: v.error };
|
|
927
|
+
const widget = this._widgetsByAgent.get(agentId)?.get(params.widgetId);
|
|
928
|
+
if (!widget) return { success: false, error: `Widget not found: ${params.widgetId}` };
|
|
929
|
+
const exists = widget.versions.some(x => x.versionId === params.versionId);
|
|
930
|
+
if (!exists) {
|
|
931
|
+
return {
|
|
932
|
+
success: false,
|
|
933
|
+
error: `Version not found: ${params.versionId}. Available: ${widget.versions.map(x => x.versionId).join(', ')}`,
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
widget.mainVersionId = params.versionId;
|
|
937
|
+
mirrorActiveVersion(widget);
|
|
938
|
+
this.logger?.info?.('Widget main version set', {
|
|
939
|
+
agentId, widgetId: widget.widgetId, mainVersionId: params.versionId,
|
|
940
|
+
});
|
|
941
|
+
this._emitChange(agentId, widget.widgetId, 'main-set', widget);
|
|
942
|
+
return { success: true, action: 'set-main', widgetId: widget.widgetId, widget };
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
/**
|
|
946
|
+
* `rename { widgetId, name }` — set/clear the human-friendly display name.
|
|
947
|
+
* Pass null/'' to clear (revert to widgetId-as-display).
|
|
948
|
+
* Names are NOT unique per agent — multiple widgets can share a name;
|
|
949
|
+
* widgetId remains the stable identifier.
|
|
950
|
+
*/
|
|
951
|
+
_rename(agentId, params) {
|
|
952
|
+
const v = validateRenameParams(params);
|
|
953
|
+
if (!v.valid) return { success: false, error: v.error };
|
|
954
|
+
const widget = this._widgetsByAgent.get(agentId)?.get(params.widgetId);
|
|
955
|
+
if (!widget) return { success: false, error: `Widget not found: ${params.widgetId}` };
|
|
956
|
+
|
|
957
|
+
const previous = widget.name || null;
|
|
958
|
+
if (v.clear) {
|
|
959
|
+
widget.name = null;
|
|
960
|
+
} else {
|
|
961
|
+
// validator returns the trimmed canonical form when valid.
|
|
962
|
+
widget.name = v.normalized != null ? v.normalized : String(params.name).trim();
|
|
963
|
+
}
|
|
964
|
+
widget.updatedAt = new Date().toISOString();
|
|
965
|
+
|
|
966
|
+
this.logger?.info?.('Widget renamed', {
|
|
967
|
+
agentId, widgetId: widget.widgetId,
|
|
968
|
+
from: previous, to: widget.name,
|
|
969
|
+
});
|
|
970
|
+
this._emitChange(agentId, widget.widgetId, 'renamed', widget, {
|
|
971
|
+
previousName: previous,
|
|
972
|
+
});
|
|
973
|
+
return {
|
|
974
|
+
success: true, action: 'rename',
|
|
975
|
+
widgetId: widget.widgetId,
|
|
976
|
+
name: widget.name,
|
|
977
|
+
previousName: previous,
|
|
978
|
+
widget,
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
/**
|
|
983
|
+
* Append a new version to a widget (or create a new widget for the
|
|
984
|
+
* agent if none exists). Returns the (mutated) widget record.
|
|
985
|
+
*
|
|
986
|
+
* Enforces TWO independent caps:
|
|
987
|
+
* - MAX_VERSIONS_PER_WIDGET — drop oldest version once we exceed
|
|
988
|
+
* - MAX_WIDGETS_PER_AGENT — drop oldest widget once we exceed
|
|
989
|
+
*
|
|
990
|
+
* Mark `divergedFromGallery` if the widget was linked to a gallery
|
|
991
|
+
* template — once the agent renders new content, it's no longer
|
|
992
|
+
* tracking upstream and shouldn't show upgrade prompts.
|
|
993
|
+
*
|
|
994
|
+
* @private
|
|
995
|
+
*/
|
|
996
|
+
_appendVersion(agentId, widgetId, version) {
|
|
997
|
+
let agentWidgets = this._widgetsByAgent.get(agentId);
|
|
998
|
+
if (!agentWidgets) {
|
|
999
|
+
agentWidgets = new Map();
|
|
1000
|
+
this._widgetsByAgent.set(agentId, agentWidgets);
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
let widget = agentWidgets.get(widgetId);
|
|
1004
|
+
const now = new Date().toISOString();
|
|
1005
|
+
|
|
1006
|
+
if (!widget) {
|
|
1007
|
+
widget = {
|
|
1008
|
+
widgetId,
|
|
1009
|
+
versions: [version],
|
|
1010
|
+
mainVersionId: version.versionId,
|
|
1011
|
+
createdAt: now,
|
|
1012
|
+
// Gallery linkage fields — initialized null; render-from-gallery
|
|
1013
|
+
// (Phase 4) sets them; subsequent local renders will set
|
|
1014
|
+
// divergedFromGallery=true via the branch below.
|
|
1015
|
+
linkedGalleryTemplateId: null,
|
|
1016
|
+
linkedGalleryVersion: null,
|
|
1017
|
+
divergedFromGallery: false,
|
|
1018
|
+
};
|
|
1019
|
+
agentWidgets.set(widgetId, widget);
|
|
1020
|
+
} else {
|
|
1021
|
+
// Bump LRU recency by re-inserting at the end of the agent's map.
|
|
1022
|
+
agentWidgets.delete(widgetId);
|
|
1023
|
+
agentWidgets.set(widgetId, widget);
|
|
1024
|
+
|
|
1025
|
+
widget.versions.push(version);
|
|
1026
|
+
widget.mainVersionId = version.versionId;
|
|
1027
|
+
|
|
1028
|
+
// Cap version history per widget — drop oldest, keep main if it
|
|
1029
|
+
// would otherwise be evicted (rare: would need >MAX renders since
|
|
1030
|
+
// mainVersionId was set on a since-evicted version).
|
|
1031
|
+
while (widget.versions.length > WIDGET_LIMITS.MAX_VERSIONS_PER_WIDGET) {
|
|
1032
|
+
const evicted = widget.versions.shift();
|
|
1033
|
+
this.logger?.debug?.('Widget version evicted', {
|
|
1034
|
+
agentId, widgetId, versionId: evicted.versionId,
|
|
1035
|
+
});
|
|
1036
|
+
if (evicted.versionId === widget.mainVersionId) {
|
|
1037
|
+
// Defensive: re-pin to oldest remaining version so we never
|
|
1038
|
+
// dangle an invalid mainVersionId.
|
|
1039
|
+
widget.mainVersionId = widget.versions[0].versionId;
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
// Linked-to-gallery widgets diverge as soon as the agent renders
|
|
1044
|
+
// anything that isn't the linked content. We don't compare bytes
|
|
1045
|
+
// (cheaper + safer to assume divergence on any local render).
|
|
1046
|
+
if (widget.linkedGalleryTemplateId) {
|
|
1047
|
+
widget.divergedFromGallery = true;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
mirrorActiveVersion(widget);
|
|
1052
|
+
|
|
1053
|
+
// Per-agent widget cap.
|
|
1054
|
+
while (agentWidgets.size > WIDGET_LIMITS.MAX_WIDGETS_PER_AGENT) {
|
|
1055
|
+
const oldestKey = agentWidgets.keys().next().value;
|
|
1056
|
+
agentWidgets.delete(oldestKey);
|
|
1057
|
+
this.logger?.debug?.('Widget evicted (LRU)', { agentId, widgetId: oldestKey });
|
|
1058
|
+
}
|
|
1059
|
+
return widget;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
_generateWidgetId(kind) {
|
|
1063
|
+
const n = this._nextAutoId++;
|
|
1064
|
+
return `w-${kind}-${n}-${Date.now().toString(36)}`;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
// ──────────────────────────────────────────────────────────────────
|
|
1068
|
+
// Gallery — cross-session shared widget catalog.
|
|
1069
|
+
// ──────────────────────────────────────────────────────────────────
|
|
1070
|
+
|
|
1071
|
+
/**
|
|
1072
|
+
* `share-to-gallery { widgetId, title?, tags? }` — publish the
|
|
1073
|
+
* widget's CURRENT MAIN VERSION to the gallery as a new template.
|
|
1074
|
+
* Re-sharing the same widget bumps the template's version (so other
|
|
1075
|
+
* sessions can detect upgrades). The agent's local widget gets a
|
|
1076
|
+
* `linkedGalleryTemplateId` pointing at the new template — until the
|
|
1077
|
+
* agent renders new content and `divergedFromGallery` flips.
|
|
1078
|
+
*/
|
|
1079
|
+
async _shareToGallery(agentId, params, context) {
|
|
1080
|
+
const widgetId = params?.widgetId;
|
|
1081
|
+
if (typeof widgetId !== 'string' || !widgetId) {
|
|
1082
|
+
return { success: false, error: 'widgetId is required' };
|
|
1083
|
+
}
|
|
1084
|
+
const widget = this._widgetsByAgent.get(agentId)?.get(widgetId);
|
|
1085
|
+
if (!widget) return { success: false, error: `Widget not found: ${widgetId}` };
|
|
1086
|
+
|
|
1087
|
+
const gallery = this._galleryStore();
|
|
1088
|
+
try {
|
|
1089
|
+
const { templateId, version, entry } = await gallery.share(widget, {
|
|
1090
|
+
agentId,
|
|
1091
|
+
agentName: context?.agentName || null,
|
|
1092
|
+
sessionId: context?.sessionId || null,
|
|
1093
|
+
title: params.title,
|
|
1094
|
+
tags: params.tags,
|
|
1095
|
+
forkedFrom: widget.linkedGalleryTemplateId || null,
|
|
1096
|
+
});
|
|
1097
|
+
// Link the widget to the freshly-created template. Reset the
|
|
1098
|
+
// diverged flag — we just synced upstream.
|
|
1099
|
+
widget.linkedGalleryTemplateId = templateId;
|
|
1100
|
+
widget.linkedGalleryVersion = version;
|
|
1101
|
+
widget.divergedFromGallery = false;
|
|
1102
|
+
this.logger?.info?.('Widget shared to gallery', { agentId, widgetId, templateId, version });
|
|
1103
|
+
this._emitChange(agentId, widgetId, 'shared', widget, { templateId, templateVersion: version });
|
|
1104
|
+
return {
|
|
1105
|
+
success: true, action: 'share-to-gallery',
|
|
1106
|
+
templateId, version, entry,
|
|
1107
|
+
widget: this._summarizeWidget(widget),
|
|
1108
|
+
};
|
|
1109
|
+
} catch (err) {
|
|
1110
|
+
return { success: false, error: err.message };
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
/**
|
|
1115
|
+
* `unshare-from-gallery { templateId }` — remove a template from the
|
|
1116
|
+
* gallery. Local widgets keep working but lose their upstream link
|
|
1117
|
+
* (cleared on the matching widget if any).
|
|
1118
|
+
*/
|
|
1119
|
+
async _unshareFromGallery(agentId, params) {
|
|
1120
|
+
const templateId = params?.templateId;
|
|
1121
|
+
if (typeof templateId !== 'string' || !templateId) {
|
|
1122
|
+
return { success: false, error: 'templateId is required' };
|
|
1123
|
+
}
|
|
1124
|
+
const gallery = this._galleryStore();
|
|
1125
|
+
const removed = await gallery.unshare(templateId);
|
|
1126
|
+
// Clear the link on any local widget that pointed at this template.
|
|
1127
|
+
const agentWidgets = this._widgetsByAgent.get(agentId);
|
|
1128
|
+
if (agentWidgets) {
|
|
1129
|
+
for (const w of agentWidgets.values()) {
|
|
1130
|
+
if (w.linkedGalleryTemplateId === templateId) {
|
|
1131
|
+
w.linkedGalleryTemplateId = null;
|
|
1132
|
+
w.linkedGalleryVersion = null;
|
|
1133
|
+
w.divergedFromGallery = false;
|
|
1134
|
+
// Each affected widget gets its own change event so the
|
|
1135
|
+
// frontend can refresh badges without a full re-fetch.
|
|
1136
|
+
this._emitChange(agentId, w.widgetId, 'unshared', w, { templateId });
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
return {
|
|
1141
|
+
success: removed,
|
|
1142
|
+
action: 'unshare-from-gallery',
|
|
1143
|
+
templateId,
|
|
1144
|
+
removed,
|
|
1145
|
+
...(removed ? {} : { error: `Template not found: ${templateId}` }),
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
/**
|
|
1150
|
+
* `list-gallery { tag?, agentId? }` — list templates available in
|
|
1151
|
+
* the gallery, optionally filtered. Content is included so the agent
|
|
1152
|
+
* can preview before render-from-gallery; for very large galleries a
|
|
1153
|
+
* future call will return summaries only.
|
|
1154
|
+
*/
|
|
1155
|
+
async _listGallery(params = {}) {
|
|
1156
|
+
const gallery = this._galleryStore();
|
|
1157
|
+
const filter = {};
|
|
1158
|
+
if (params.tag) filter.tag = String(params.tag).slice(0, 32);
|
|
1159
|
+
if (params.agentId) filter.agentId = String(params.agentId).slice(0, 128);
|
|
1160
|
+
const entries = await gallery.list(filter);
|
|
1161
|
+
return {
|
|
1162
|
+
success: true,
|
|
1163
|
+
action: 'list-gallery',
|
|
1164
|
+
count: entries.length,
|
|
1165
|
+
templates: entries.map(e => ({
|
|
1166
|
+
templateId: e.templateId,
|
|
1167
|
+
version: e.version,
|
|
1168
|
+
title: e.title,
|
|
1169
|
+
kind: e.kind,
|
|
1170
|
+
tags: e.tags,
|
|
1171
|
+
sharedBy: e.sharedBy,
|
|
1172
|
+
sharedAt: e.sharedAt,
|
|
1173
|
+
renderCount: e.renderCount,
|
|
1174
|
+
starred: e.starred,
|
|
1175
|
+
forkedFrom: e.forkedFrom,
|
|
1176
|
+
phishingHits: e.phishingHits,
|
|
1177
|
+
size: (e.content || '').length,
|
|
1178
|
+
})),
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
/**
|
|
1183
|
+
* `render-from-gallery { templateId, widgetId?, props? }` — instantiate
|
|
1184
|
+
* a gallery template into the agent's local widgets. The new local
|
|
1185
|
+
* widget is LINKED to the gallery template via `linkedGalleryTemplateId`,
|
|
1186
|
+
* so the upgrade-prompt machinery (Phase 4) can later compare versions.
|
|
1187
|
+
*/
|
|
1188
|
+
async _renderFromGallery(agentId, params, { allowed }) {
|
|
1189
|
+
const templateId = params?.templateId;
|
|
1190
|
+
if (typeof templateId !== 'string' || !templateId) {
|
|
1191
|
+
return { success: false, error: 'templateId is required' };
|
|
1192
|
+
}
|
|
1193
|
+
if (!allowed) {
|
|
1194
|
+
return {
|
|
1195
|
+
success: false, disabled: true,
|
|
1196
|
+
error: 'Custom widgets are disabled for this agent. Enable in the widget configurator.',
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
const gallery = this._galleryStore();
|
|
1200
|
+
const tpl = await gallery.get(templateId);
|
|
1201
|
+
if (!tpl) return { success: false, error: `Template not found: ${templateId}` };
|
|
1202
|
+
|
|
1203
|
+
const widgetId = params.widgetId || this._generateWidgetId(tpl.kind);
|
|
1204
|
+
const merged = { ...(tpl.defaultProps || {}), ...(params.props || {}) };
|
|
1205
|
+
|
|
1206
|
+
const newVersion = buildVersion({
|
|
1207
|
+
kind: tpl.kind,
|
|
1208
|
+
content: tpl.content,
|
|
1209
|
+
props: merged,
|
|
1210
|
+
});
|
|
1211
|
+
// Append normally, then mark linkage. Note: _appendVersion would
|
|
1212
|
+
// otherwise flip divergedFromGallery to true, so we set linkage
|
|
1213
|
+
// AFTER the append (to a fresh widget; no prior linkage).
|
|
1214
|
+
const widget = this._appendVersion(agentId, widgetId, newVersion);
|
|
1215
|
+
widget.linkedGalleryTemplateId = templateId;
|
|
1216
|
+
widget.linkedGalleryVersion = tpl.version;
|
|
1217
|
+
widget.divergedFromGallery = false;
|
|
1218
|
+
|
|
1219
|
+
// Bump the template's render counter — useful "popular templates" metric.
|
|
1220
|
+
await gallery.bumpRenderCount(templateId);
|
|
1221
|
+
|
|
1222
|
+
this.logger?.info?.('Widget rendered from gallery', { agentId, widgetId, templateId, version: tpl.version });
|
|
1223
|
+
this._emitChange(agentId, widgetId, 'rendered', widget, { templateId, templateVersion: tpl.version });
|
|
1224
|
+
return {
|
|
1225
|
+
success: true, action: 'render-from-gallery',
|
|
1226
|
+
widgetId, versionId: newVersion.versionId,
|
|
1227
|
+
templateId, templateVersion: tpl.version,
|
|
1228
|
+
widget,
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
/**
|
|
1233
|
+
* `check-upgrade { widgetId }` — for a gallery-linked widget,
|
|
1234
|
+
* report whether a newer template version is available.
|
|
1235
|
+
*
|
|
1236
|
+
* Result shape:
|
|
1237
|
+
* { success, hasUpgrade, currentVersion, latestVersion, latestTemplateId,
|
|
1238
|
+
* diverged, sharedAt, ... }
|
|
1239
|
+
*
|
|
1240
|
+
* Returns hasUpgrade=false (with a reason) when the widget isn't
|
|
1241
|
+
* linked OR has diverged (local edits broke the link).
|
|
1242
|
+
*/
|
|
1243
|
+
async _checkUpgrade(agentId, params) {
|
|
1244
|
+
const widgetId = params?.widgetId;
|
|
1245
|
+
if (typeof widgetId !== 'string' || !widgetId) {
|
|
1246
|
+
return { success: false, error: 'widgetId is required' };
|
|
1247
|
+
}
|
|
1248
|
+
const widget = this._widgetsByAgent.get(agentId)?.get(widgetId);
|
|
1249
|
+
if (!widget) return { success: false, error: `Widget not found: ${widgetId}` };
|
|
1250
|
+
|
|
1251
|
+
if (!widget.linkedGalleryTemplateId) {
|
|
1252
|
+
return {
|
|
1253
|
+
success: true, action: 'check-upgrade', widgetId,
|
|
1254
|
+
hasUpgrade: false, reason: 'not-linked',
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
if (widget.divergedFromGallery) {
|
|
1258
|
+
return {
|
|
1259
|
+
success: true, action: 'check-upgrade', widgetId,
|
|
1260
|
+
hasUpgrade: false, reason: 'diverged',
|
|
1261
|
+
linkedTemplateId: widget.linkedGalleryTemplateId,
|
|
1262
|
+
currentVersion: widget.linkedGalleryVersion,
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
const gallery = this._galleryStore();
|
|
1267
|
+
const latest = await gallery.findLatestForOrigin(widget.linkedGalleryTemplateId);
|
|
1268
|
+
if (!latest) {
|
|
1269
|
+
// The linked template was removed from the gallery (unshared upstream).
|
|
1270
|
+
return {
|
|
1271
|
+
success: true, action: 'check-upgrade', widgetId,
|
|
1272
|
+
hasUpgrade: false, reason: 'linked-template-missing',
|
|
1273
|
+
linkedTemplateId: widget.linkedGalleryTemplateId,
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
const hasUpgrade = latest.version > (widget.linkedGalleryVersion || 0);
|
|
1277
|
+
return {
|
|
1278
|
+
success: true, action: 'check-upgrade', widgetId,
|
|
1279
|
+
hasUpgrade,
|
|
1280
|
+
currentVersion: widget.linkedGalleryVersion,
|
|
1281
|
+
latestVersion: latest.version,
|
|
1282
|
+
latestTemplateId: latest.templateId,
|
|
1283
|
+
sharedAt: latest.sharedAt,
|
|
1284
|
+
sharedBy: latest.sharedBy,
|
|
1285
|
+
};
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
/**
|
|
1289
|
+
* `apply-upgrade { widgetId }` — pull the latest gallery version
|
|
1290
|
+
* into the linked widget AS A NEW LOCAL VERSION. The user keeps the
|
|
1291
|
+
* old version in their history (so they can revert via set-main).
|
|
1292
|
+
*
|
|
1293
|
+
* Refuses if the widget has diverged — that means the user/agent
|
|
1294
|
+
* edited locally, and we don't want to silently overwrite their work.
|
|
1295
|
+
*/
|
|
1296
|
+
async _applyUpgrade(agentId, params, { allowed }) {
|
|
1297
|
+
const widgetId = params?.widgetId;
|
|
1298
|
+
if (typeof widgetId !== 'string' || !widgetId) {
|
|
1299
|
+
return { success: false, error: 'widgetId is required' };
|
|
1300
|
+
}
|
|
1301
|
+
if (!allowed) {
|
|
1302
|
+
return {
|
|
1303
|
+
success: false, disabled: true,
|
|
1304
|
+
error: 'Custom widgets are disabled for this agent.',
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
const widget = this._widgetsByAgent.get(agentId)?.get(widgetId);
|
|
1308
|
+
if (!widget) return { success: false, error: `Widget not found: ${widgetId}` };
|
|
1309
|
+
if (!widget.linkedGalleryTemplateId) {
|
|
1310
|
+
return { success: false, error: 'Widget is not linked to any gallery template.' };
|
|
1311
|
+
}
|
|
1312
|
+
if (widget.divergedFromGallery) {
|
|
1313
|
+
return {
|
|
1314
|
+
success: false,
|
|
1315
|
+
error: 'Widget has been edited locally and diverged from the gallery template. Refusing to overwrite local edits — share again or fork.',
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
const gallery = this._galleryStore();
|
|
1320
|
+
const latest = await gallery.findLatestForOrigin(widget.linkedGalleryTemplateId);
|
|
1321
|
+
if (!latest) {
|
|
1322
|
+
return { success: false, error: 'Linked gallery template no longer exists (was unshared upstream).' };
|
|
1323
|
+
}
|
|
1324
|
+
if (latest.version <= (widget.linkedGalleryVersion || 0)) {
|
|
1325
|
+
return {
|
|
1326
|
+
success: false,
|
|
1327
|
+
error: 'Already on the latest version. Nothing to upgrade.',
|
|
1328
|
+
};
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
// Capture the linkage BEFORE we mutate it — we need to report the
|
|
1332
|
+
// "fromVersion" in the result, and the log entry needs the actual
|
|
1333
|
+
// upgrade arc, not the post-upgrade values.
|
|
1334
|
+
const fromTemplateId = widget.linkedGalleryTemplateId;
|
|
1335
|
+
const fromVersion = widget.linkedGalleryVersion;
|
|
1336
|
+
|
|
1337
|
+
// Append a new local version with the latest content. Important:
|
|
1338
|
+
// _appendVersion would normally flip divergedFromGallery=true on a
|
|
1339
|
+
// linked widget; we restore it to false (and bump linkedVersion)
|
|
1340
|
+
// AFTER the append because this IS the upstream sync.
|
|
1341
|
+
const newVersion = buildVersion({
|
|
1342
|
+
kind: latest.kind,
|
|
1343
|
+
content: latest.content,
|
|
1344
|
+
props: widget.props || latest.defaultProps || {},
|
|
1345
|
+
});
|
|
1346
|
+
this._appendVersion(agentId, widgetId, newVersion);
|
|
1347
|
+
widget.linkedGalleryTemplateId = latest.templateId;
|
|
1348
|
+
widget.linkedGalleryVersion = latest.version;
|
|
1349
|
+
widget.divergedFromGallery = false;
|
|
1350
|
+
await gallery.bumpRenderCount(latest.templateId);
|
|
1351
|
+
this.logger?.info?.('Widget upgraded from gallery', {
|
|
1352
|
+
agentId, widgetId,
|
|
1353
|
+
from: { templateId: fromTemplateId, version: fromVersion },
|
|
1354
|
+
to: { templateId: latest.templateId, version: latest.version },
|
|
1355
|
+
});
|
|
1356
|
+
this._emitChange(agentId, widgetId, 'upgrade-applied', widget, {
|
|
1357
|
+
fromVersion, toVersion: latest.version,
|
|
1358
|
+
});
|
|
1359
|
+
return {
|
|
1360
|
+
success: true, action: 'apply-upgrade', widgetId,
|
|
1361
|
+
newVersionId: newVersion.versionId,
|
|
1362
|
+
fromVersion,
|
|
1363
|
+
toVersion: latest.version,
|
|
1364
|
+
widget,
|
|
1365
|
+
};
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
/** Compact summary used by share-to-gallery (no full versions[] payload). */
|
|
1369
|
+
_summarizeWidget(w) {
|
|
1370
|
+
return {
|
|
1371
|
+
widgetId: w.widgetId,
|
|
1372
|
+
kind: w.kind,
|
|
1373
|
+
versionCount: w.versions.length,
|
|
1374
|
+
mainVersionId: w.mainVersionId,
|
|
1375
|
+
linkedGalleryTemplateId: w.linkedGalleryTemplateId,
|
|
1376
|
+
linkedGalleryVersion: w.linkedGalleryVersion,
|
|
1377
|
+
divergedFromGallery: w.divergedFromGallery,
|
|
1378
|
+
};
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
/** Test-only helper: total widget count across all agents. */
|
|
1382
|
+
_totalWidgetCount() {
|
|
1383
|
+
let n = 0;
|
|
1384
|
+
for (const m of this._widgetsByAgent.values()) n += m.size;
|
|
1385
|
+
return n;
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
export default WidgetTool;
|