@fangorn-network/westmarch 2026.10.29 → 2026.11.4-dev
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/docs/app-to-agent.md +61 -625
- package/package.json +12 -17
- package/site/dist/assets/__vite-browser-external-D2U8RZpp.js +1 -0
- package/site/dist/assets/embed.worker-CmS57Zti.js +1 -0
- package/site/dist/assets/index-Djs8f08m.js +8 -0
- package/site/dist/assets/rolldown-runtime-COiEfhsA.js +1 -0
- package/site/dist/assets/{transformers.web-BTyOEJ0C.js → transformers.web-CwR_IYQV.js} +1 -1
- package/site/dist/index.html +3 -4
- package/site/worker.js +115 -338
- package/src/agent/agent-card.js +33 -45
- package/src/agent/mcp.js +168 -371
- package/src/agent/tools.js +2 -1
- package/src/agent/view-tools.js +4 -56
- package/src/agent/x402.js +182 -369
- package/src/core/roles.js +6 -6
- package/src/core/shard.js +4 -4
- package/src/discover/apps.js +67 -81
- package/src/discover/directory.js +2 -2
- package/src/market/reactions.js +21 -15
- package/src/publish/devnet.js +69 -18
- package/src/publish/init.js +1 -1
- package/src/publish/ship.js +74 -275
- package/src/publish/view.js +52 -53
- package/template/README.md +9 -11
- package/template/package.json +1 -1
- package/plugin/scripts/fx.mjs +0 -266
- package/site/dist/assets/AccountNotFoundScreen-C4njXc69-DyVH4CEz.js +0 -1
- package/site/dist/assets/AddFundsSelectionScreen-RAoCn7ej-Dz1--SS9.js +0 -31
- package/site/dist/assets/Address-H8kD1d9O-BdFZmRwI.js +0 -17
- package/site/dist/assets/AffirmativeConsentScreen-BG0MJxku-CxaCAisL.js +0 -6
- package/site/dist/assets/AllowlistRejectionScreen-Cae6e1Od-JGk7vndN.js +0 -1
- package/site/dist/assets/ApiController-CTLbMCcH.js +0 -5
- package/site/dist/assets/ArrowsRightLeftIcon-B8g9adpz.js +0 -1
- package/site/dist/assets/AuthenticateWithWalletScreen-CU6hIcFT-CXD9_OP8.js +0 -1
- package/site/dist/assets/AwaitingEvmToSolBridgingScreen-D0e_sZMS-BtJCglvU.js +0 -1
- package/site/dist/assets/AwaitingExternalEthereumTransferScreen-ur5HL4R7-BgC2TsqH.js +0 -1
- package/site/dist/assets/AwaitingPasswordlessCodeScreen-DRHz76mM-B9OzLeEO.js +0 -103
- package/site/dist/assets/AwaitingSolToEvmBridgingScreen-CdLRrGD2-C7r5snUL.js +0 -1
- package/site/dist/assets/BridgeNetworkSelectionView-CFGjB2nO-BTV0NRio.js +0 -68
- package/site/dist/assets/CaptchaScreen-DbpvkIGx-7rSZIuM-.js +0 -1
- package/site/dist/assets/CheckCircleIcon-B1l17ioc.js +0 -1
- package/site/dist/assets/CheckCircleIcon-BGSI8nKf.js +0 -1
- package/site/dist/assets/Checkbox-D1EDeo41-BUfq0w99.js +0 -52
- package/site/dist/assets/ChevronDownIcon-B6uJvPHu.js +0 -1
- package/site/dist/assets/Chip-CZKIKt9K-r9Nk__0-.js +0 -26
- package/site/dist/assets/CoinbaseOnrampStatusScreen-BbyCJDXL-DWWNHxmR.js +0 -16
- package/site/dist/assets/ConnectEmailForm-B-VRE0MN-CRQwS0Xu.js +0 -3
- package/site/dist/assets/ConnectLedgerScreen-DWHABGot-CZcCt31O.js +0 -10
- package/site/dist/assets/ConnectOnlyLandingScreen-CZYx9Bmp-C5IOf-SQ.js +0 -1
- package/site/dist/assets/ConnectOnlyStatusScreen-DCRzjxHx-cwg74F3A.js +0 -1
- package/site/dist/assets/ConnectOrCreateScreen-CUUYUO07-D28oeK6b.js +0 -1
- package/site/dist/assets/ConnectPhoneForm-Dek5xn4C-EEdkKeTp.js +0 -95
- package/site/dist/assets/ConnectWalletView-DqI-PTvX-C2mEzukj.js +0 -74
- package/site/dist/assets/ConnectionStatusScreen-fUfROm9m-CH_7r8iV.js +0 -7
- package/site/dist/assets/ConnectionStatusScreen-fUfROm9m-Z33kis0B.js +0 -1
- package/site/dist/assets/ConnectorUtil-DH4NePk5.js +0 -21
- package/site/dist/assets/ConstantsUtil-DmLsRHAl.js +0 -198
- package/site/dist/assets/CopyToClipboard-i_OQSBJr-_G88JCVR.js +0 -39
- package/site/dist/assets/CopyableText-CQapvaMr-CGGfc_zM.js +0 -28
- package/site/dist/assets/CrossAppAuthScreen-CLw7ymZq-C9Okoc0V.js +0 -1
- package/site/dist/assets/CustomLandingScreenView-Cm_MBSyX-D2l6hdSl.js +0 -22
- package/site/dist/assets/DelegatedActionsConsentScreen-DYF2U4y5-Dda3KKqS.js +0 -1
- package/site/dist/assets/DelegatedActionsRevokeScreen-bPp6Uwyh-DG8kJPt1.js +0 -1
- package/site/dist/assets/DepositAddressAddressStepView-4vdkb55L-CcOUfn6f.js +0 -187
- package/site/dist/assets/DepositAddressScreen-DBLRs7aI-DeituDNh.js +0 -8
- package/site/dist/assets/DepositAddressV3Screen-CDqIEMQw-FDg6K14-.js +0 -1
- package/site/dist/assets/EmailInputForm-Cqo1mda8-BmbxvPHC.js +0 -124
- package/site/dist/assets/EmbeddedWalletConnectingScreen-D4T7DUzs-B05CQ9rx.js +0 -1
- package/site/dist/assets/EmbeddedWalletCreatedScreen-D7WhW5ve-Cxd1b9XH.js +0 -1
- package/site/dist/assets/EmbeddedWalletKeyExportScreen-CqV4NYQ3-CrJy0ViX.js +0 -23
- package/site/dist/assets/EmbeddedWalletOnAccountCreateScreen-BoKb3Q2S-Bakaa3zu.js +0 -1
- package/site/dist/assets/EmbeddedWalletPasswordUpdateScreen-D3rMlqS7-j78vKrcj.js +0 -1
- package/site/dist/assets/EmbeddedWalletPasswordUpdateSplashScreen-BPFkWJeE-D3dr7W9_.js +0 -1
- package/site/dist/assets/EnrollTotp-Dibew4dp-BXbYV8nI.js +0 -66
- package/site/dist/assets/EnvelopeIcon-DjPofnRI.js +0 -1
- package/site/dist/assets/ErrorBanner-BcpGRt0h-BhH6_V-9.js +0 -21
- package/site/dist/assets/ErrorMessage-D8VaAP5m-Bs7uX2a9.js +0 -8
- package/site/dist/assets/ErrorScreen-DipdTWzE-BgPRgnOb.js +0 -4
- package/site/dist/assets/ErrorScreen-DipdTWzE-CvxXC6pz.js +0 -1
- package/site/dist/assets/ExclamationCircleIcon-BE-WGrut.js +0 -1
- package/site/dist/assets/ExclamationTriangleIcon-Ca1Xlc_f.js +0 -1
- package/site/dist/assets/FarcasterConnectStatusScreen-51tjUxqq-De2JvZdV.js +0 -75
- package/site/dist/assets/FarcasterSignerStatusScreen-6x-Uh95G-bLp3hXoO.js +0 -28
- package/site/dist/assets/FiatOnrampScreen-BAhYeiTI-Jr6D6JiZ.js +0 -491
- package/site/dist/assets/FingerPrintIcon-DOCbS93y.js +0 -1
- package/site/dist/assets/FundSolWalletWithExternalSolanaWallet-WtLwYaOl-A_G5kfa1.js +0 -1
- package/site/dist/assets/FundWalletMethodHeader-BWNkokCT-LPv35wkD.js +0 -1
- package/site/dist/assets/FundWithBankDepositScreen-DajkHxBD-0hfGrfvf.js +0 -58
- package/site/dist/assets/FundingEditAmountScreen-CpvpiO4M-Dz0s_NWR.js +0 -1
- package/site/dist/assets/FundingMethodSelectionScreen-Db7vhRlE-ZGm-3-Io.js +0 -1
- package/site/dist/assets/GlobeAltIcon-BBRl2MMn.js +0 -1
- package/site/dist/assets/GooglePay-B53WnudL-BGiVpB8y.js +0 -1
- package/site/dist/assets/HCaptchaWrapper-CUi9LJsp-CHdfIeD_.js +0 -4
- package/site/dist/assets/InAppBrowserLoginNotPossible-BMR9br1T-Cgoiow3m.js +0 -1
- package/site/dist/assets/InfoBanner-Cb3p1z12-_YqQmRiu.js +0 -22
- package/site/dist/assets/InjectedWalletIcon-DLcYOGDj-tuIrKQHH.js +0 -1
- package/site/dist/assets/InstallWalletScreen-DTA8dwLv-BMU_wa61.js +0 -1
- package/site/dist/assets/JsonTree-BHzNC-ic-DcVr0YF0.js +0 -34
- package/site/dist/assets/LabelXs-oqZNqbm_-CNprGVQM.js +0 -6
- package/site/dist/assets/LandingScreen-CGWUoSUG-fH6rsQen.js +0 -1
- package/site/dist/assets/Layouts-BMRfo5hw-e-sepi6F.js +0 -77
- package/site/dist/assets/Link-BdDilT2T-BdwlRJch.js +0 -40
- package/site/dist/assets/LinkConflictScreen-C3ZEPsgl-BXKN2Qm5.js +0 -77
- package/site/dist/assets/LinkEmailScreen-dKo9frwc-Cyn7Q8p1.js +0 -1
- package/site/dist/assets/LinkPasskeyScreen-zbrl_AI_-CWiqnwLM.js +0 -117
- package/site/dist/assets/LinkPasskeyScreen-zbrl_AI_-YmDevJzf.js +0 -1
- package/site/dist/assets/LinkPhoneScreen-oIUpfj0w-h7shW-Ay.js +0 -1
- package/site/dist/assets/Loader-UAZqxsnw-DJEVblm1.js +0 -62
- package/site/dist/assets/LoadingSkeleton-BMsgO5PV-D2atjsP5.js +0 -17
- package/site/dist/assets/LockClosedIcon-9EFzWK1C.js +0 -1
- package/site/dist/assets/LoginFailedScreen-CN0dJV6U-By3Si77a.js +0 -1
- package/site/dist/assets/ManualTransferScreen-CHqcuqbs-BAHPY8rs.js +0 -1
- package/site/dist/assets/MfaAuthEnrollmentFlowScreen-Dj7gPTRC-CLjffFG1.js +0 -1
- package/site/dist/assets/MfaAuthVerifyFlowScreen-DbFpyWMy-BmQg1Y61.js +0 -1
- package/site/dist/assets/MfaEnrollmentFlowScreen-DhLnGgnr-DmBtTtlw.js +0 -1
- package/site/dist/assets/MfaVerifyFlowScreen-C_XPjMRP-4a683Bmf.js +0 -1
- package/site/dist/assets/ModalFooter-BCuEK_nz-C_71qsaz.js +0 -403
- package/site/dist/assets/MoonpayStatusScreen-CzTUtokc-DEHHcEf8.js +0 -16
- package/site/dist/assets/OAuthStatusScreen-ufbOa-da-BjAb_WsY.js +0 -1
- package/site/dist/assets/OpenLink-CUpJ1mOr-BLWFsPOW.js +0 -39
- package/site/dist/assets/PasskeySelectSignupOrLogin-xh2ScC_l-2PJTJxX-.js +0 -1
- package/site/dist/assets/PasskeyStatusScreen-Bla8MaOk-DCEg761l.js +0 -6
- package/site/dist/assets/PasswordRecoveryScreen-awGXZkQk-8nVjNc8k.js +0 -20
- package/site/dist/assets/PhArrowCircleDown-D97G-BOA.js +0 -14
- package/site/dist/assets/PhArrowClockwise-DVgyFuez.js +0 -14
- package/site/dist/assets/PhArrowDown-87b1BizM.js +0 -14
- package/site/dist/assets/PhArrowLeft-Da0MfnbK.js +0 -14
- package/site/dist/assets/PhArrowRight-AdrIL4DW.js +0 -14
- package/site/dist/assets/PhArrowSquareOut-Bk2CMG3I.js +0 -14
- package/site/dist/assets/PhArrowUp-4sgyKPGx.js +0 -14
- package/site/dist/assets/PhArrowUpRight-BNghD2zq.js +0 -14
- package/site/dist/assets/PhArrowsClockwise-BXRn1GEl.js +0 -14
- package/site/dist/assets/PhArrowsDownUp-DM09Jo_3.js +0 -14
- package/site/dist/assets/PhArrowsLeftRight-MuKBLUoF.js +0 -14
- package/site/dist/assets/PhBank-fHbgCqqZ.js +0 -14
- package/site/dist/assets/PhBrowser-2-9m-AkM.js +0 -14
- package/site/dist/assets/PhCaretDown-BDNabFuL.js +0 -14
- package/site/dist/assets/PhCaretLeft-CI460R-A.js +0 -14
- package/site/dist/assets/PhCaretRight-D7ZS3Ls8.js +0 -14
- package/site/dist/assets/PhCaretUp-C-iIfyvO.js +0 -14
- package/site/dist/assets/PhCheck-DxQXn57r.js +0 -14
- package/site/dist/assets/PhCircleHalf-MJZeRBGF.js +0 -14
- package/site/dist/assets/PhClock-x3MS3Mwi.js +0 -14
- package/site/dist/assets/PhCompass-hYn3HhGN.js +0 -14
- package/site/dist/assets/PhCopy-CWNYcABI.js +0 -14
- package/site/dist/assets/PhCreditCard-Fy4pzwtt.js +0 -14
- package/site/dist/assets/PhCurrencyDollar-BgiaenCi.js +0 -14
- package/site/dist/assets/PhDesktop-CxrzCSv5.js +0 -14
- package/site/dist/assets/PhDeviceMobile-CsyA5Goi.js +0 -14
- package/site/dist/assets/PhDotsThree-D-k1BiYg.js +0 -14
- package/site/dist/assets/PhEnvelope-D8kzeNox.js +0 -14
- package/site/dist/assets/PhFunnelSimple-CfQs5DAW.js +0 -14
- package/site/dist/assets/PhGlobe-DvmSc9_A.js +0 -14
- package/site/dist/assets/PhIdentificationCard-CfkZm-5K.js +0 -14
- package/site/dist/assets/PhImage-Cf0J2ZfJ.js +0 -14
- package/site/dist/assets/PhInfo-Bwi51-2X.js +0 -14
- package/site/dist/assets/PhLightbulb-C4FZV7Es.js +0 -14
- package/site/dist/assets/PhMagnifyingGlass-C9u8jSCJ.js +0 -14
- package/site/dist/assets/PhPaperPlaneRight-zxQVvPLX.js +0 -14
- package/site/dist/assets/PhPlus-C4UoW-2n.js +0 -14
- package/site/dist/assets/PhPower-CFyWDmgD.js +0 -14
- package/site/dist/assets/PhPuzzlePiece-BjoNVfST.js +0 -14
- package/site/dist/assets/PhQrCode-CP3tFauY.js +0 -14
- package/site/dist/assets/PhQuestion-wOWJBd3G.js +0 -14
- package/site/dist/assets/PhQuestionMark-CV0k9C0Y.js +0 -14
- package/site/dist/assets/PhSealCheck-vIKzREuN.js +0 -14
- package/site/dist/assets/PhSignOut-CxELV-i0.js +0 -14
- package/site/dist/assets/PhSpinner-CGDmbzUd.js +0 -14
- package/site/dist/assets/PhTrash-C9PD0SAt.js +0 -14
- package/site/dist/assets/PhUser-0sWNXQeZ.js +0 -14
- package/site/dist/assets/PhVault-6JTskUcC.js +0 -14
- package/site/dist/assets/PhWarning-CoKs3gz6.js +0 -14
- package/site/dist/assets/PhWarningCircle-BXHw1fCt.js +0 -14
- package/site/dist/assets/PhX-DX0SFIqC.js +0 -14
- package/site/dist/assets/PhoneIcon-CZ47md80.js +0 -1
- package/site/dist/assets/PinInput-DbZ0b1i1-BrTXu3Km.js +0 -247
- package/site/dist/assets/PrivyPluginContext-DA-yS5vO-CY60yubk.js +0 -1
- package/site/dist/assets/QrCode-DbnZwlkH-CcMrWV5D.js +0 -22
- package/site/dist/assets/RecoveryOAuthStatusScreen-CsgtTI2x-DgeDnHOK.js +0 -1
- package/site/dist/assets/RecoveryPasswordCreateScreen-Be-qJ-LU-CvJJwLhK.js +0 -1
- package/site/dist/assets/RecoverySelectionScreen-D1iGtpmi-CADtGtSV.js +0 -7
- package/site/dist/assets/SIWXUtil-Cpiv91-M.js +0 -1
- package/site/dist/assets/Screen-D30meWsY-vEusJ7KX.js +0 -175
- package/site/dist/assets/ScreenHeader-CHmc4-Lu-BvGTLg53.js +0 -31
- package/site/dist/assets/ScreenLayout-OwaQQcxH-cfOTmyl0.js +0 -1
- package/site/dist/assets/SelectSourceAsset-CWFog6gm-DxYklZYs.js +0 -140
- package/site/dist/assets/SetAutomaticRecoveryScreen-BO_OEqAZ-oeqeo05x.js +0 -14
- package/site/dist/assets/SetWalletPasswordForm-DwCTVtAh-BxFee9UA.js +0 -11
- package/site/dist/assets/ShieldCheckIcon-eFjsosCA.js +0 -1
- package/site/dist/assets/SignRequestScreen-BHKv32KR-z8ixfIma.js +0 -26
- package/site/dist/assets/SolanaWalletConnector-C7Lqk-Wz-Bc_lvdiF.js +0 -1
- package/site/dist/assets/StackedContainer-B2vaEl56-Do5dXB8-.js +0 -24
- package/site/dist/assets/StandardSignAndSendTransactionScreen-CfhIXVtd-DudetZAc.js +0 -20
- package/site/dist/assets/Subtitle-CV-2yKE4-DV0o1av3.js +0 -13
- package/site/dist/assets/TelegramAuthScreen-UL9zLfO8-Bo3sONvf.js +0 -1
- package/site/dist/assets/Title-BnzYV3Is-C3qOPnO_.js +0 -7
- package/site/dist/assets/TodoList-DnyULl18-BvxvubbF.js +0 -36
- package/site/dist/assets/TransactionDetails-e9nesl30-WWflkOIi.js +0 -109
- package/site/dist/assets/TransactionErrorView-BDBNqA_f-CotYKcgf.js +0 -178
- package/site/dist/assets/TransferFromWalletScreen-Qvn1Yuno-sVFlWqa8.js +0 -31
- package/site/dist/assets/TransferOrBridgeLoadingScreen-Dl1I_iIz-CV2-mY19.js +0 -6
- package/site/dist/assets/TurnstileWrapper-B7sNddys-oPbuMTQt.js +0 -1
- package/site/dist/assets/UpdateEmailScreen-DVOhPV0H-D_mjSpAy.js +0 -1
- package/site/dist/assets/UpdatePhoneScreen-CXRswTNZ-6RLG0ahv.js +0 -1
- package/site/dist/assets/UserLimitReachedScreen-5we2DHn8-CaVN0bti.js +0 -1
- package/site/dist/assets/Value-DTgR824E-Bp6WGZZm.js +0 -27
- package/site/dist/assets/WalletCards-DH1rqayz-D3cOTb9x.js +0 -1
- package/site/dist/assets/WalletIcon-DOIZhb2l.js +0 -1
- package/site/dist/assets/WalletInfoCard-sq_2wgFg-bOqfl5MA.js +0 -29
- package/site/dist/assets/WalletInterstitialScreen-Sh7LfsAh-DWaVkMCA.js +0 -1
- package/site/dist/assets/WalletLink-DK5LB5Ha-DjUZvqs-.js +0 -20
- package/site/dist/assets/WalletOverflowButton-bfCnp-9T-B6P7DQXA.js +0 -1
- package/site/dist/assets/WarningBanner-ZZqCEtZK-Bc2YKZb7.js +0 -21
- package/site/dist/assets/__vite-browser-external-NciY4Vu1.js +0 -1
- package/site/dist/assets/_esm-BZP3cXTv.js +0 -1
- package/site/dist/assets/_esm-ZmzBJpEs.js +0 -6
- package/site/dist/assets/accounts-D4AXF17G.js +0 -1
- package/site/dist/assets/accounts-IkdFx9nq.js +0 -1
- package/site/dist/assets/analytics-mkkvFRju-BRBcadka.js +0 -1
- package/site/dist/assets/baseSepolia-Bn1j1Ysw.js +0 -1
- package/site/dist/assets/basic-Cz1YiCSk.js +0 -1575
- package/site/dist/assets/capitalizeFirstLetter-DmLYqXsO-DtOXx-2n.js +0 -1
- package/site/dist/assets/ccip-B1J3oTZx.js +0 -7
- package/site/dist/assets/ccip-Bd7261zy.js +0 -1
- package/site/dist/assets/ccip-D6EHKpjI.js +0 -1
- package/site/dist/assets/chain-scefkYIH.js +0 -5
- package/site/dist/assets/check-DHnllI8N.js +0 -1
- package/site/dist/assets/chevron-down-1y-r4bGO.js +0 -1
- package/site/dist/assets/circle-alert-OwxamXUX.js +0 -1
- package/site/dist/assets/circle-check-big-3sZGVC10.js +0 -1
- package/site/dist/assets/circle-x-DQjNUV9J.js +0 -1
- package/site/dist/assets/client-B-BpRtwY.js +0 -1
- package/site/dist/assets/client-BfIR1FvH.js +0 -9
- package/site/dist/assets/coinbase-DCPC2L_R-YEuIn3jh.js +0 -3
- package/site/dist/assets/copy-DMOX_yn7.js +0 -1
- package/site/dist/assets/core-GIEmxmAa.js +0 -12
- package/site/dist/assets/createLucideIcon-BsERoFTA.js +0 -1
- package/site/dist/assets/defineChain-B-SQDLTG.js +0 -1
- package/site/dist/assets/dijkstra-CY95afk4.js +0 -1
- package/site/dist/assets/dist-CoS6E-3x.js +0 -1
- package/site/dist/assets/dist-Cp6IXeJd.js +0 -1
- package/site/dist/assets/dist-CrNxmdZj.js +0 -1
- package/site/dist/assets/dist-DYGtf4F0.js +0 -16
- package/site/dist/assets/embed.worker-Cnl4VGr3.js +0 -1
- package/site/dist/assets/errors-BQ3N-RVt-CZPAWCgC.js +0 -1
- package/site/dist/assets/esm-C3DslVJx.js +0 -1
- package/site/dist/assets/esm-Ci1ogKuK.js +0 -1
- package/site/dist/assets/esm-Co94ENUV.js +0 -37
- package/site/dist/assets/esm-bb8SANZh.js +0 -1
- package/site/dist/assets/esm-n2lWo7kz.js +0 -1
- package/site/dist/assets/ethers-zTjbodk5-Cs648CnD.js +0 -1
- package/site/dist/assets/eventemitter3-Dzc_0Uq2.js +0 -1
- package/site/dist/assets/external-link-BBPG3rG7.js +0 -1
- package/site/dist/assets/farcaster-DPlSjvF5-CzBCmgyL.js +0 -1
- package/site/dist/assets/features-CuiHbgEJ.js +0 -2
- package/site/dist/assets/fingerprint-pattern-CjLtyIxB.js +0 -1
- package/site/dist/assets/floating-ui.react-DmaCfayr.js +0 -1
- package/site/dist/assets/floating-ui.react-dom-CaoMF8mP.js +0 -1
- package/site/dist/assets/formatErc20TokenAmount-BuPk9xcy-BVqOKQif.js +0 -1
- package/site/dist/assets/formatter-CVbp4SlJ.js +0 -1
- package/site/dist/assets/get-entropy-details-for-user-dHRH5Gpi-BNiOFXbK.js +0 -1
- package/site/dist/assets/getChainName-DjpPdUSc-DUyKDrnp.js +0 -1
- package/site/dist/assets/getErc20Balance-jXNpFf0N-q4bV8kQq.js +0 -1
- package/site/dist/assets/getErc20TokenInfo-BNTrzLMP-DcnTFrXN.js +0 -1
- package/site/dist/assets/getFormattedUsdFromLamports-De3U9GlO-Gx4_wxON.js +0 -1
- package/site/dist/assets/getUsdcMintAddress-BVgm9GRo-r2UnDeEy.js +0 -1
- package/site/dist/assets/guards-BIW-GiMJ-D3tWTQAR.js +0 -1
- package/site/dist/assets/hooks.module-BYZGfwDl.js +0 -1
- package/site/dist/assets/hourglass-D_GfQdJr.js +0 -1
- package/site/dist/assets/id-UqEwL2BI-CTlvRMA5.js +0 -1
- package/site/dist/assets/index-BdEw5wyl-kLbhqLbv.js +0 -1
- package/site/dist/assets/index-C2h3EneX.js +0 -8
- package/site/dist/assets/index-CWARkn2w-DxuckIFn.js +0 -61
- package/site/dist/assets/index-DvMddJcd-CNBb4VUn.js +0 -12
- package/site/dist/assets/index-YiCw0Y_x-Czl0tWfF.js +0 -436
- package/site/dist/assets/index.browser-B-i-Lj3J.js +0 -1
- package/site/dist/assets/index.browser-BMmUcykv.js +0 -1
- package/site/dist/assets/index.es-Crd0TyUS.js +0 -2
- package/site/dist/assets/index.es-DQbup1WG.js +0 -3
- package/site/dist/assets/isPaymentRequestAvailable-Bq1cemEn-Cjf3l05I.js +0 -1
- package/site/dist/assets/jsx-runtime-CndCZlyt.js +0 -1
- package/site/dist/assets/landmark-BZPqMFEf.js +0 -1
- package/site/dist/assets/lib-DGtzi2DK.js +0 -1
- package/site/dist/assets/localBatchGatewayRequest-B71J8sQ9.js +0 -29
- package/site/dist/assets/lock-DyN_c-ud.js +0 -1
- package/site/dist/assets/logger-CsXm3oIv-B0UYpNFI.js +0 -1
- package/site/dist/assets/mail-V_mcPb64.js +0 -1
- package/site/dist/assets/modal-context-CwmSeFcv-DPWNJrfK.js +0 -1
- package/site/dist/assets/native-BKj27wfc.js +0 -1
- package/site/dist/assets/ofetch.CWycOUEr-Duby3iHT.js +0 -1
- package/site/dist/assets/parseAbi-Csg-8t59.js +0 -2
- package/site/dist/assets/parseAbiParameters-BWbIMYe4.js +0 -1
- package/site/dist/assets/parseEther-CHS0GNkM.js +0 -1
- package/site/dist/assets/pkce-DXF0yKjP-7_VY-d83.js +0 -1
- package/site/dist/assets/preload-helper-CRzLMJPS.js +0 -1
- package/site/dist/assets/privy-context-81KmsBw2-DiR6-Yq8.js +0 -2
- package/site/dist/assets/property-DuZ9DLP4.js +0 -3
- package/site/dist/assets/react-BfYA1q0G.js +0 -1
- package/site/dist/assets/react-CK2HRI1t.js +0 -1
- package/site/dist/assets/react-DxGeY8B8.js +0 -1
- package/site/dist/assets/react-auth-sHnipzbS.js +0 -1
- package/site/dist/assets/react-dom-BI2Koe4o.js +0 -1
- package/site/dist/assets/reservoir-x-nGuZkT-BguVFH3D.js +0 -1
- package/site/dist/assets/rolldown-runtime-Bjp52BOI.js +0 -1
- package/site/dist/assets/safe-url-D7SRPu33-CkMedGro.js +0 -1
- package/site/dist/assets/secp256k1-BeYL8aZl.js +0 -1
- package/site/dist/assets/secp256k1-Bh4MSkhz.js +0 -1
- package/site/dist/assets/secp256k1-Ci4cqHl0.js +0 -1
- package/site/dist/assets/secp256k1-DsxXqbXv.js +0 -1
- package/site/dist/assets/secp256k1-N9RUmafO.js +0 -1
- package/site/dist/assets/serializeAuthorizationList-DGMik9Wx.js +0 -1
- package/site/dist/assets/serializeSignature-CWKpxoab.js +0 -2
- package/site/dist/assets/sha2-C6s7zZmb.js +0 -1
- package/site/dist/assets/shared-DRZUmnL5-BewE5wK8.js +0 -193
- package/site/dist/assets/shared-FM0rljBt-CxLACri_.js +0 -21
- package/site/dist/assets/shouldProceedtoEmbeddedWalletCreationFlow-B3vyavrh-BkAKsRNi.js +0 -1
- package/site/dist/assets/simulateTransaction-CfuOrae4-PjA_tGjX.js +0 -1
- package/site/dist/assets/smartphone-3p8nFSTE.js +0 -1
- package/site/dist/assets/src-BBjkfi-Q.js +0 -1
- package/site/dist/assets/storage-Ufl800Ne-1qCR2JMO.js +0 -8
- package/site/dist/assets/stringify-DqUj9VzO.js +0 -20
- package/site/dist/assets/stripe.esm-DEi2D291.js +0 -2
- package/site/dist/assets/styles-BsotlekN-Aq27nZGc.js +0 -9
- package/site/dist/assets/styles-Cm9H63WO-p_ic_dxE.js +0 -92
- package/site/dist/assets/styles-DVyDvTdj-CjsWqAld.js +0 -74
- package/site/dist/assets/styles-hslXy6xG-D5QHIrJU.js +0 -164
- package/site/dist/assets/telegram-B-JqnkqZ-Dqkm4rDn.js +0 -1
- package/site/dist/assets/to-ui-error-DWe-qwS3-Bi1HUQI9.js +0 -4
- package/site/dist/assets/toViemAccount-B5iDGq1b-CdFZwv07.js +0 -2
- package/site/dist/assets/transaction-BNTP-bFm-M5tJx8vY.js +0 -1
- package/site/dist/assets/transfer-6YztDh-t-BVQkTvG-.js +0 -1
- package/site/dist/assets/triangle-alert-BG3Qw-Hq.js +0 -1
- package/site/dist/assets/twitch-5IOe4sIQ-CaXHFlAu.js +0 -1
- package/site/dist/assets/types-4CuOD23i.js +0 -1
- package/site/dist/assets/use-headless-crypto-deposit-Yn-QRLB3-CQqeyhGY.js +0 -1
- package/site/dist/assets/use-unlink-wallet-BKK4_5Ur-C0xQN_Lp.js +0 -1
- package/site/dist/assets/useActiveWallet-B-yZYGc6-BkK6rFBm.js +0 -123
- package/site/dist/assets/useGetSolPrice-x7gfUIHJ-CLVXqv6I.js +0 -1
- package/site/dist/assets/useGetTokenPrice-CaoUkb79-DAXXs3rs.js +0 -1
- package/site/dist/assets/useI18n-C-5n_noF-CGpkgIVy.js +0 -1
- package/site/dist/assets/useWalletBalance-CZnP5f_f-Cfd64m4n.js +0 -1
- package/site/dist/assets/useWallets-X1ndvJ_U-CAYqg7Za.js +0 -1
- package/site/dist/assets/utils-BkR7EQjg.js +0 -1
- package/site/dist/assets/utils-DJhBNOZA.js +0 -1
- package/site/dist/assets/utils-DdckVfQr.js +0 -1
- package/site/dist/assets/w3m-modal-B4H_uiPH.js +0 -1174
- package/site/dist/assets/wallet-BNI12IYk.js +0 -1
- package/site/dist/assets/wallet-CITSaPlB.js +0 -2
- package/site/dist/assets/wallet-connect-BvJtUsDt-CVlSNIXP.js +0 -1
- package/site/dist/assets/walletconnect-registry-xxG8XLCb-BpzpBq5s.js +0 -1
- package/site/dist/assets/walletconnect-v2-3frQFwbg-CzZ6oybX.js +0 -12
- package/site/dist/assets/wui-ux-by-reown-XyHdtV1O.js +0 -1147
- package/site/dist/assets/x-gjDrY2rk.js +0 -1
- package/src/discover/explore.js +0 -291
- package/src/market/settle.js +0 -165
- package/src/market/terms.js +0 -200
- package/src/publish/cli.js +0 -336
- package/src/publish/envelope.js +0 -185
- package/src/publish/manifest.js +0 -142
package/src/publish/view.js
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
// westmarch-view --app my-app [--repo catalog …] --out site/view (a laptop, CI)
|
|
5
5
|
// site/worker.js, on a cron (the free tier)
|
|
6
6
|
//
|
|
7
|
-
// Reads the registry and storage and nothing else: every repo the app presents (
|
|
8
|
-
//
|
|
7
|
+
// Reads the registry and storage and nothing else: every repo the app presents (any
|
|
8
|
+
// publisher's repo of a name it lists), at their latest heads; the schema
|
|
9
9
|
// (app.json's `types` + `relations`) comes from the caller. Embeds only records the view does not hold
|
|
10
10
|
// yet, drops removed ones, and writes, through a store (a directory or an R2 bucket):
|
|
11
11
|
//
|
|
@@ -15,21 +15,20 @@
|
|
|
15
15
|
//
|
|
16
16
|
// Stateless: the view's own files are its state, and each domain's manifest names the head
|
|
17
17
|
// it was built from, so a run where no head moved reads one manifest per repo and nothing
|
|
18
|
-
// else. A repo the app stops presenting
|
|
18
|
+
// else. A repo the app stops presenting loses its domain on the next run.
|
|
19
19
|
//
|
|
20
|
-
// The layout is
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
// row shape {track_id, fields, v}, manifest and catalog keys;
|
|
20
|
+
// The layout is fixed, so any reader (shard.js, a tab, an agent) reads any app's view:
|
|
21
|
+
// - URL layout, domain names (`domainFor`: the publisher's address prefix and the repo),
|
|
22
|
+
// row shape {track_id, owner, fields, v}, manifest and catalog keys;
|
|
24
23
|
// - a record is a row: track_id = its CID, fields = payload + entityType (its type);
|
|
25
24
|
// - the schema: a declared type is embedded and shipped with exactly its role map;
|
|
26
|
-
// - the embedded text (`composeText`
|
|
25
|
+
// - the embedded text (`composeText`).
|
|
27
26
|
// The encoder is EmbeddingGemma (embed.js). Two runtimes of it agree closely but not bit for
|
|
28
27
|
// bit, so the manifest names its `embedder` and this refuses to append to a view another
|
|
29
28
|
// encoder built.
|
|
30
29
|
//
|
|
31
|
-
// ponytail: flat records
|
|
32
|
-
//
|
|
30
|
+
// ponytail: flat records: a record's neighbours aren't folded into its text, and publishers
|
|
31
|
+
// aren't fused by shared identity. A reference the schema
|
|
33
32
|
// declares is written onto its source row instead (`linkRelations`), which is all a
|
|
34
33
|
// serverless reader needs.
|
|
35
34
|
|
|
@@ -49,14 +48,13 @@ const MULTI = ["tags", "measures", "relations", "text"];
|
|
|
49
48
|
// Refit coverage once a domain has grown this many times over what it was fit on.
|
|
50
49
|
const COVERAGE_REFIT = 2;
|
|
51
50
|
|
|
52
|
-
// ── the contract
|
|
51
|
+
// ── the view's contract ────────────────────────────────────────
|
|
53
52
|
|
|
54
53
|
const slug = (s) => (String(s ?? "").replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() || "x");
|
|
55
|
-
/**
|
|
56
|
-
export const domainFor = (
|
|
57
|
-
`${slug(appId.slice(2, 10))}-${slug(owner.slice(2, 10))}-${slug(namespace)}`;
|
|
54
|
+
/** A domain's name in the view: the publisher's address prefix and the repo. */
|
|
55
|
+
export const domainFor = (owner, namespace) => `${slug(owner.slice(2, 10))}-${slug(namespace)}`;
|
|
58
56
|
|
|
59
|
-
/**
|
|
57
|
+
/** The text a row is embedded from, minus the `search_document: ` prefix that
|
|
60
58
|
* `embedDocumentDirect` adds itself. */
|
|
61
59
|
export function composeText(fields, rm) {
|
|
62
60
|
const tags = (rm.tags ?? []).map((t) => (typeof fields[t] === "string" ? fields[t] : "")).join(" ");
|
|
@@ -90,8 +88,8 @@ export function completeRoles(rm = {}) {
|
|
|
90
88
|
}
|
|
91
89
|
|
|
92
90
|
// ponytail: for a type the schema does not declare, a guess from field names and
|
|
93
|
-
// value lengths — enough to show and search something, and loud about it.
|
|
94
|
-
//
|
|
91
|
+
// value lengths — enough to show and search something, and loud about it. The fix is
|
|
92
|
+
// declaring the type.
|
|
95
93
|
export function guessRoles(rows) {
|
|
96
94
|
const keys = [...new Set(rows.flatMap((r) => Object.keys(r)))].filter((k) => k !== "entityType");
|
|
97
95
|
const find = (names) => keys.find((k) => names.includes(k.toLowerCase())) ?? null;
|
|
@@ -104,7 +102,7 @@ export function guessRoles(rows) {
|
|
|
104
102
|
});
|
|
105
103
|
}
|
|
106
104
|
|
|
107
|
-
/** Merge the declared types a domain holds (most common first)
|
|
105
|
+
/** Merge the declared types a domain holds (most common first). */
|
|
108
106
|
export function domainSpec(schema, tags) {
|
|
109
107
|
const decls = tags.map((t) => schema?.types?.[t]).filter(Boolean);
|
|
110
108
|
if (!decls.length) return null;
|
|
@@ -148,11 +146,10 @@ export async function network(name = process.env.FANGORN_NETWORK || "baseSepolia
|
|
|
148
146
|
return SupportedNetworks[name];
|
|
149
147
|
}
|
|
150
148
|
|
|
151
|
-
/** The IPFS gateway to read contents through: FANGORN_IPFS_GATEWAY, else the
|
|
152
|
-
*
|
|
149
|
+
/** The IPFS gateway to read contents through: FANGORN_IPFS_GATEWAY, else none (the SDK
|
|
150
|
+
* default, Fangorn's gateway). Not the deployer's CLI config: that would ship into the Worker. */
|
|
153
151
|
export function ipfsGateway() {
|
|
154
|
-
|
|
155
|
-
try { gateway ??= JSON.parse(readFileSync(`${process.env.HOME}/.fangorn/config.json`, "utf8")).pinataGateway || undefined; } catch { /* no CLI config */ }
|
|
152
|
+
const gateway = process.env.FANGORN_IPFS_GATEWAY || process.env.IPFS_GATEWAY;
|
|
156
153
|
return gateway && !/^https?:\/\//.test(gateway) ? `https://${gateway}` : gateway;
|
|
157
154
|
}
|
|
158
155
|
|
|
@@ -170,7 +167,7 @@ export async function readOnlyFangorn() {
|
|
|
170
167
|
* `<owner>/<repo>` to `{ records: [{id, cid, type, payload}] }`, every one presented.
|
|
171
168
|
* A build that must not touch the chain — a candidate recipe graded before it ships —
|
|
172
169
|
* runs the exact code a real one does. */
|
|
173
|
-
export function localFangorn(chain
|
|
170
|
+
export function localFangorn(chain) {
|
|
174
171
|
// Every version handed out is kept, so repoDiff can diff any two, as the SDK diffs two roots.
|
|
175
172
|
const versions = new Map();
|
|
176
173
|
const root = (k) => { const h = `0x${createHash("sha256").update(JSON.stringify(chain[k])).digest("hex")}`; versions.set(h, structuredClone(chain[k]?.records ?? [])); return h; };
|
|
@@ -182,9 +179,7 @@ export function localFangorn(chain, { appId, owner }) {
|
|
|
182
179
|
};
|
|
183
180
|
return {
|
|
184
181
|
engine: { repoDiff }, reads: 0,
|
|
185
|
-
|
|
186
|
-
getAppRegistry: () => ({ getAppOwner: async () => owner }),
|
|
187
|
-
appRepos: async () => Object.keys(chain).map((k) => ({ owner: k.split("/")[0], repo: k.split("/").slice(1).join("/"), root: root(k) })),
|
|
182
|
+
repos: async () => Object.keys(chain).map((k) => ({ owner: k.split("/")[0], repo: k.split("/").slice(1).join("/"), root: root(k) })),
|
|
188
183
|
readRepo: async function (o, repo) { this.reads++; const c = chain[`${o}/${repo}`]; return { tip: c ? root(`${o}/${repo}`) : null, contents: { records: c?.records ?? [] } }; },
|
|
189
184
|
};
|
|
190
185
|
}
|
|
@@ -285,26 +280,26 @@ const sha256 = (s) => createHash("sha256").update(s).digest("hex");
|
|
|
285
280
|
/**
|
|
286
281
|
* Bring the view up to date with what the app presents. `fangorn` is an SDK client (reads
|
|
287
282
|
* only); `schema` is app.json's { types, relations } (a type it leaves out is guessed); the view goes to `store`, or the directory `out`. `repos` narrows it to those repo
|
|
288
|
-
* names (every publisher's); without it, every repo
|
|
283
|
+
* names (every publisher's); without it, every repo. `fromBlock` must be
|
|
289
284
|
* at or before the first update to a repo the app presents, or a repo the scan misses is left out;
|
|
290
285
|
* left out, the SDK's deployment start. `embedBatch(texts)` embeds many at once where the
|
|
291
286
|
* encoder batches (a Worker's AI binding); `embedder` is what the manifest records.
|
|
292
|
-
* `presented` replaces the `
|
|
293
|
-
* ([{owner, repo, root}]
|
|
287
|
+
* `presented` replaces the `repos` scan with a list the caller keeps itself
|
|
288
|
+
* ([{owner, repo, root}]), as a Worker does across runs.
|
|
294
289
|
* Returns per-domain counts of what changed.
|
|
295
290
|
*/
|
|
296
291
|
export async function publishView({ fangorn, app, schema, repos, out, store = fsStore(out), fromBlock, presented, rebake = false,
|
|
297
292
|
embed = embedDocumentDirect, embedBatch = (ts) => Promise.all(ts.map(embed)),
|
|
298
|
-
embedder = EMBEDDER, log = console.log, shardRows = 20000, concurrency = 4
|
|
299
|
-
fangorn.setAppId(app);
|
|
300
|
-
const appId = fangorn.getAppId();
|
|
293
|
+
embedder = EMBEDDER, log = console.log, shardRows = 20000, concurrency = 4 }) {
|
|
301
294
|
schema = schemaOf(schema);
|
|
302
295
|
const declared = Object.keys(schema.types);
|
|
303
296
|
log(`schema: ${declared.length ? declared.join(", ") : "no declared types"}`);
|
|
304
297
|
const schemaHash = sha256(JSON.stringify(schema));
|
|
305
298
|
|
|
306
|
-
// Every repo the app presents, at its
|
|
307
|
-
|
|
299
|
+
// Every repo the app presents, at its latest head: one log scan.
|
|
300
|
+
// ponytail: open: any publisher's repo of a listed name, and with no names, every repo.
|
|
301
|
+
// Read the app's repo of citations instead once the SDK reads citations.
|
|
302
|
+
const listed = (presented ?? await retry(() => fangorn.repos(fromBlock == null ? {} : { fromBlock: BigInt(fromBlock) })))
|
|
308
303
|
// ponytail: "fangorn.schema" is where apps shipped before 2026-10-22 committed their schema; never data.
|
|
309
304
|
.filter((t) => t.repo !== "fangorn.schema" && (!repos?.length || repos.includes(t.repo)));
|
|
310
305
|
log(`${listed.length} repo(s) presented${repos?.length ? ` of ${repos.join(", ")}` : ""}`);
|
|
@@ -316,19 +311,19 @@ export async function publishView({ fangorn, app, schema, repos, out, store = fs
|
|
|
316
311
|
const queue = [...listed];
|
|
317
312
|
const worker = async () => {
|
|
318
313
|
for (let t; (t = queue.shift()) !== undefined;) {
|
|
319
|
-
const domain = domainFor(
|
|
314
|
+
const domain = domainFor(t.owner, t.repo);
|
|
320
315
|
live.add(domain);
|
|
321
316
|
// One repo failing (unreadable, the encoder out for the day) keeps its last view and
|
|
322
317
|
// does not stop the others; the next run tries it again.
|
|
323
318
|
const r = await publishDomain({ fangorn, store, schema, schemaHash, publisher: t.owner, repo: t.repo, head: t.root, domain,
|
|
324
|
-
dir: `cdn/domains/${domain}`, rebake, embedBatch, embedder, log, shardRows
|
|
319
|
+
dir: `cdn/domains/${domain}`, rebake, embedBatch, embedder, log, shardRows })
|
|
325
320
|
.catch((e) => { log(`${domain}: ✗ ${e.message}; left as it was`); return { added: 0, removed: 0, error: e.message }; });
|
|
326
321
|
if (r) report[domain] = r;
|
|
327
322
|
}
|
|
328
323
|
};
|
|
329
324
|
await Promise.all(Array.from({ length: concurrency }, worker));
|
|
330
325
|
|
|
331
|
-
// What the app no longer presents
|
|
326
|
+
// What the app no longer presents is not served.
|
|
332
327
|
for (const d of await store.list("cdn/domains")) {
|
|
333
328
|
if (live.has(d)) continue;
|
|
334
329
|
const m = await readJson(store, `cdn/domains/${d}/manifest`, null);
|
|
@@ -353,7 +348,7 @@ async function retry(f, tries = 6) {
|
|
|
353
348
|
}
|
|
354
349
|
|
|
355
350
|
const CHECKPOINT = 2048; // rows embedded between saves; a killed run redoes at most this many
|
|
356
|
-
async function publishDomain({ fangorn, store, schema, schemaHash, publisher, repo, head, domain, dir, rebake, embedBatch, embedder, log, shardRows
|
|
351
|
+
async function publishDomain({ fangorn, store, schema, schemaHash, publisher, repo, head, domain, dir, rebake, embedBatch, embedder, log, shardRows }) {
|
|
357
352
|
// The head the domain was built from, and the schema it was built under: neither moved,
|
|
358
353
|
// nothing to read. This is what keeps a cron run with nothing new to one read per repo.
|
|
359
354
|
const was = rebake ? null : await readJson(store, `${dir}/manifest`, null);
|
|
@@ -369,9 +364,11 @@ async function publishDomain({ fangorn, store, schema, schemaHash, publisher, re
|
|
|
369
364
|
? await retry(() => fangorn.engine.repoDiff(was.head, head)).catch((e) => { log(`${domain}: diff from ${was.head} failed (${e.message}); reading it whole`); return null; })
|
|
370
365
|
: null;
|
|
371
366
|
const got = diff?.superseded ? diff.puts : (await retry(() => fangorn.readRepo(publisher, repo))).contents.records;
|
|
372
|
-
//
|
|
373
|
-
const records = new Map(
|
|
374
|
-
.map(
|
|
367
|
+
// `@`-ids (`@card`, `@deposit/<generation>`) are the protocol's records, not the publisher's data.
|
|
368
|
+
const records = new Map(got.filter((r) => r.payload && typeof r.payload === "object" && !String(r.id).startsWith("@"))
|
|
369
|
+
.map((r) => [r.cid, { id: r.id, fields: { ...r.payload, entityType: r.type,
|
|
370
|
+
// A record its publisher sells (`fangorn commit --paid`): what a buyer quotes it by, and its price.
|
|
371
|
+
...(r.payload["@terms"]?.terms ? { sale: { publisher, repo, id: r.id, price: String(r.payload["@terms"].terms.price) } } : {}) } }]));
|
|
375
372
|
linkRelations(records, schema);
|
|
376
373
|
const fieldsOf = (cid) => records.get(cid).fields;
|
|
377
374
|
|
|
@@ -449,7 +446,7 @@ async function publishDomain({ fangorn, store, schema, schemaHash, publisher, re
|
|
|
449
446
|
const ids = fresh.slice(i, i + 32);
|
|
450
447
|
try {
|
|
451
448
|
const vs = await embedBatch(ids.map((id) => composeText(fieldsOf(id), rolesOf.get(fieldsOf(id).entityType))));
|
|
452
|
-
ids.forEach((id, j) => lines.push(JSON.stringify({ track_id: id, fields: fieldsOf(id), v: packVec(vs[j]) })));
|
|
449
|
+
ids.forEach((id, j) => lines.push(JSON.stringify({ track_id: id, owner: publisher, fields: fieldsOf(id), v: packVec(vs[j]) })));
|
|
453
450
|
} catch (e) {
|
|
454
451
|
// The encoder gave out (Workers AI's free daily allowance, say): keep what is embedded
|
|
455
452
|
// and come back for the rest. Nothing served yet, nothing to save: fail as before.
|
|
@@ -545,6 +542,8 @@ export async function writeCatalog(store) {
|
|
|
545
542
|
generated_at: Math.floor(Date.now() / 1000), embedding_model: EMBED_MODEL,
|
|
546
543
|
domains: domains.map((m) => ({
|
|
547
544
|
name: m.name, description: m.description, count: m.count, dim: m.dim,
|
|
545
|
+
// Whose it is: a reader can list publishers without opening a manifest.
|
|
546
|
+
...(m.filter?.owner?.length === 1 ? { publisher: m.filter.owner[0], repo: m.filter.repo?.[0] } : {}),
|
|
548
547
|
bytes: m.shards.reduce((s, x) => s + x.bytes, 0), shard_count: m.shards.length,
|
|
549
548
|
entity_types: m.entity_types.map((e) => e.type), manifest: `${m.name}/manifest.json`,
|
|
550
549
|
...(m.link_hosts?.length ? { link_hosts: m.link_hosts } : {}),
|
|
@@ -563,11 +562,11 @@ if (typeof process !== "undefined" && import.meta.url === `file://${process.argv
|
|
|
563
562
|
const manifestOf = (dir, d) => JSON.parse(readFileSync(`${dir}/cdn/domains/${d}/manifest`, "utf8"));
|
|
564
563
|
const rec = (cid, type, payload, id = cid) => ({ id, cid, type, payload });
|
|
565
564
|
|
|
566
|
-
//
|
|
567
|
-
eq(domainFor(
|
|
565
|
+
// The contract, pinned: domain names and embedded text never drift.
|
|
566
|
+
eq(domainFor("0x55cf6bd2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "media"), "55cf6bd2-media", "domain name: owner prefix and repo");
|
|
568
567
|
eq(composeText({ name: "Oak", family: "Fagaceae", description: "big", entityType: "t" },
|
|
569
568
|
completeRoles({ title: "name", tags: ["family"], text: ["description"] })),
|
|
570
|
-
"Title: Oak. Tags: Fagaceae. big", "embedded text
|
|
569
|
+
"Title: Oak. Tags: Fagaceae. big", "embedded text is pinned");
|
|
571
570
|
|
|
572
571
|
const APP = `0x${"ab".repeat(32)}`, OWNER = `0x${"11".repeat(20)}`, PUB = `0x${"22".repeat(20)}`;
|
|
573
572
|
const TAG = "shop.item.v1";
|
|
@@ -580,7 +579,7 @@ if (typeof process !== "undefined" && import.meta.url === `file://${process.argv
|
|
|
580
579
|
rec("c3", "shop.note.v1", { title: "Note", body: "an undeclared type, with a body long enough to count as its text field" }),
|
|
581
580
|
] },
|
|
582
581
|
};
|
|
583
|
-
const fangorn = localFangorn(chain
|
|
582
|
+
const fangorn = localFangorn(chain);
|
|
584
583
|
const embedded = [];
|
|
585
584
|
const embed = async (t) => { embedded.push(t); const v = new Array(EMBED_DIM).fill(0); for (const w of t.split(/\W+/)) if (w) v[w.length % EMBED_DIM] += 1; const n = Math.hypot(...v) || 1; return v.map((x) => x / n); };
|
|
586
585
|
const out = mkdtempSync(`${tmpdir()}/view-`);
|
|
@@ -594,7 +593,7 @@ if (typeof process !== "undefined" && import.meta.url === `file://${process.argv
|
|
|
594
593
|
embedded.length = 0; rmSync(`${out}/vectors.ndjson`);
|
|
595
594
|
const run = () => publishView({ fangorn, app: APP, schema, out, embed, log: () => {} });
|
|
596
595
|
|
|
597
|
-
const d = domainFor(
|
|
596
|
+
const d = domainFor(PUB, "shop");
|
|
598
597
|
const split = mkdtempSync(`${tmpdir()}/view-`);
|
|
599
598
|
await publishView({ fangorn, app: APP, schema, out: split, embed, log: () => {}, shardRows: 2 });
|
|
600
599
|
eq(manifestOf(split, d).shards.map((s) => s.count), [2, 1], "rows past shardRows go to the next shard");
|
|
@@ -640,13 +639,13 @@ if (typeof process !== "undefined" && import.meta.url === `file://${process.argv
|
|
|
640
639
|
const { rolesFrom } = await import("../core/roles.js");
|
|
641
640
|
eq(getRow(got, "b2", rolesFrom([m]))?.id, "c2b", "get by the publisher's own id, not the CID");
|
|
642
641
|
|
|
643
|
-
//
|
|
642
|
+
// The app stops presenting the repo, and its domain stops being served.
|
|
644
643
|
const shop = chain[`${PUB}/shop`];
|
|
645
644
|
delete chain[`${PUB}/shop`];
|
|
646
645
|
eq((await run())[d], { added: 0, removed: 2, dropped: true }, "a repo the app no longer presents is dropped");
|
|
647
646
|
eq([existsSync(`${out}/cdn/domains/${d}`), JSON.parse(readFileSync(`${out}/cdn/catalog`, "utf8")).domains], [false, []], "with its files and its catalog entry");
|
|
648
647
|
chain[`${PUB}/shop`] = shop;
|
|
649
|
-
eq((await run())[d], { added: 2, removed: 0 }, "and
|
|
648
|
+
eq((await run())[d], { added: 2, removed: 0 }, "and presenting it again brings it back");
|
|
650
649
|
|
|
651
650
|
const setEmbedder = (e) => { const x = manifestOf(out, d); x.embedder = e; x.head = "moved"; writeFileSync(`${out}/cdn/domains/${d}/manifest`, JSON.stringify(x)); };
|
|
652
651
|
setEmbedder({ ...EMBEDDER, runtime: "transformers.js cuda" });
|
|
@@ -660,7 +659,7 @@ if (typeof process !== "undefined" && import.meta.url === `file://${process.argv
|
|
|
660
659
|
chain[BIG] = { records: Array.from({ length: 80 }, (_, i) => ({ id: `r${i}`, cid: `big${i}`, type: "shop.item.v1", payload: { sku: `r${i}`, name: `Thing ${i}` } })) };
|
|
661
660
|
let budget = 40;
|
|
662
661
|
const capped = (ts) => (budget -= ts.length) < 0 ? Promise.reject(new Error("daily allowance used")) : Promise.all(ts.map(embed));
|
|
663
|
-
const bd = domainFor(
|
|
662
|
+
const bd = domainFor(PUB, "big");
|
|
664
663
|
eq((await publishView({ fangorn, app: APP, schema, out: big, repos: ["big"], embedBatch: capped, log: () => {} }))[bd],
|
|
665
664
|
{ added: 32, removed: 0, partial: true }, "an encoder that gives out keeps what it embedded");
|
|
666
665
|
eq([manifestOf(big, bd).count, manifestOf(big, bd).head], [32, null], "served, and the head not taken");
|
|
@@ -730,8 +729,8 @@ if (typeof process !== "undefined" && import.meta.url === `file://${process.argv
|
|
|
730
729
|
rec("i1", T, { item_id: "a#1", heading: "Rezone, committee", part_of: { local: "m" } }),
|
|
731
730
|
rec("i2", T, { item_id: "b#4", heading: "Rezone, council", cites: { local: "m" } }),
|
|
732
731
|
rec("m1", M, { matter_id: "plover:7", title: "Rezone" }, "m")] } };
|
|
733
|
-
const o = mkdtempSync(`${tmpdir()}/view-`), dr = domainFor(
|
|
734
|
-
const go = () => publishView({ fangorn: localFangorn(rel
|
|
732
|
+
const o = mkdtempSync(`${tmpdir()}/view-`), dr = domainFor(PUB, "civic");
|
|
733
|
+
const go = () => publishView({ fangorn: localFangorn(rel), app: APP, schema: relSchema, out: o, embed, log: () => {} });
|
|
735
734
|
const rows = async () => Object.fromEntries([...(await loadDomain(fsStore(o), `cdn/domains/${dr}`)).rows.values()]
|
|
736
735
|
.map((r) => [r.fields.heading ?? r.fields.title, r.fields.part_of ?? r.fields.cites ?? null]));
|
|
737
736
|
await go();
|
|
@@ -767,5 +766,5 @@ if (typeof process !== "undefined" && import.meta.url === `file://${process.argv
|
|
|
767
766
|
await r2.del(`cdn/domains/${d}`);
|
|
768
767
|
eq([...objs.keys()].filter((k) => k.includes(d)), [], "del removes a folder and everything under it");
|
|
769
768
|
}
|
|
770
|
-
console.log("view.js self-check ok — domain names and embedded text
|
|
769
|
+
console.log("view.js self-check ok — domain names and embedded text are stable, the schema is applied, an unmoved head reads nothing, additions ship as delta shards, removals compact the domain, an excluded repo is dropped and a restored one returns, the real reader sees exactly the live records by the publisher's id, another encoder's view is refused, declared references land on their source rows, and the view builds the same into R2");
|
|
771
770
|
}
|
package/template/README.md
CHANGED
|
@@ -2,22 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
This repo holds the app's recipe, not its data: what a record is (`app.json`), what a good
|
|
4
4
|
answer looks like (`eval/`), and the Worker that serves it (`wrangler.json`). It can be
|
|
5
|
-
public. The data lives on chain and IPFS, committed by
|
|
5
|
+
public. The data lives on chain and IPFS, committed by its publishers; the Worker
|
|
6
6
|
indexes it every 5 minutes, and serves the site, the view, `/mcp` and the agent card.
|
|
7
7
|
|
|
8
8
|
## Deploy
|
|
9
9
|
|
|
10
10
|
[](https://deploy.workers.cloudflare.com/?url=https://github.com/fangorn-network/westmarch/tree/main/template)
|
|
11
11
|
|
|
12
|
-
1.
|
|
13
|
-
2. Press the button. Name the Worker after the app (`my-app`) and its R2 bucket
|
|
12
|
+
1. Press the button. Name the Worker after the app (`my-app`) and its R2 bucket
|
|
14
13
|
`my-app-view`. Cloudflare copies this repo into your GitHub, makes the bucket and
|
|
15
14
|
deploys; every push to `main` deploys again.
|
|
16
|
-
|
|
17
|
-
app
|
|
15
|
+
2. At fangorn.network, give the app its Worker's URL. Your wallet creates the app's repo,
|
|
16
|
+
`<your wallet>:my-app`, and binds its card there.
|
|
18
17
|
|
|
19
|
-
An app name with a dot or an underscore can't be a Worker name
|
|
20
|
-
`app.json` to the name you claimed.
|
|
18
|
+
An app name with a dot or an underscore can't be a Worker name.
|
|
21
19
|
|
|
22
20
|
`npm run build` (`westmarch build`) is what Cloudflare runs: it builds the site and writes
|
|
23
21
|
the app's config into `wrangler.json`, without signing or deploying anything.
|
|
@@ -29,13 +27,13 @@ fields in `role_map`. Push, and the Worker follows.
|
|
|
29
27
|
|
|
30
28
|
## Publish data
|
|
31
29
|
|
|
32
|
-
Any
|
|
30
|
+
Any wallet commits records of its type, from anywhere:
|
|
33
31
|
|
|
34
32
|
```sh
|
|
35
33
|
echo '{"records":[{"id":"first","type":"my-app.item.v1","payload":{"id":"first","title":"Hello","text":"The first item.","tags":["demo"]}}]}' > items.json
|
|
36
|
-
fangorn
|
|
37
|
-
fangorn
|
|
38
|
-
fangorn
|
|
34
|
+
fangorn repo init items
|
|
35
|
+
fangorn commit items.json -m "first items"
|
|
36
|
+
fangorn push
|
|
39
37
|
```
|
|
40
38
|
|
|
41
39
|
The view picks it up within 5 minutes at `<url>/view`. A source that crawls something
|
package/template/package.json
CHANGED
package/plugin/scripts/fx.mjs
DELETED
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// The Fangorn app index, headless. One command per verb, JSON on stdout.
|
|
3
|
-
//
|
|
4
|
-
// WHY THERE IS NO MCP SERVER HERE
|
|
5
|
-
// -------------------------------
|
|
6
|
-
// An index that POINTS AT apps rather than hosting them needs no runtime of its
|
|
7
|
-
// own. Every verb below is a function `@fangorn/westmarch` already exports, and
|
|
8
|
-
// the agent's shell is the transport. Nobody has to stand up a server to be in
|
|
9
|
-
// the index — a publisher bakes a view, and that is the whole obligation.
|
|
10
|
-
//
|
|
11
|
-
// WHY THIS IS A PLUGIN AND NOT A PAGE
|
|
12
|
-
// -----------------------------------
|
|
13
|
-
// One thing here is not stateless: the taste kernel. It lives in
|
|
14
|
-
// ~/.fangorn/taste.json — on the filesystem, between the human and the agent —
|
|
15
|
-
// because it has to outlive any one app, any one tab and any one ORIGIN.
|
|
16
|
-
// localStorage cannot do that: a taste learned in fangorn.tv is invisible to the
|
|
17
|
-
// next app by construction, which is the whole reason apps keep rebuilding it.
|
|
18
|
-
// A file the agent can read is the shortest thing that carries it across.
|
|
19
|
-
//
|
|
20
|
-
// ponytail: a plaintext file, no wallet, no sync. `src/taste/vault.js` is the
|
|
21
|
-
// upgrade path — same object, sealed to a signature, kept in the graph — and it
|
|
22
|
-
// is worth doing the day the kernel needs to travel between machines, not now.
|
|
23
|
-
// ponytail: every command re-fetches its view. Fine at 917 rows, ~seconds at
|
|
24
|
-
// 42k; add a disk cache keyed by view URL when a big corpus makes it hurt.
|
|
25
|
-
|
|
26
|
-
import { homedir } from "node:os";
|
|
27
|
-
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
28
|
-
import { join } from "node:path";
|
|
29
|
-
import { configure, domainManifests, loadShard, trimView } from "../../src/core/shard.js";
|
|
30
|
-
import { findCorpora, sourcesFromChain } from "../../src/discover/directory.js";
|
|
31
|
-
import { linkOf, rolesFrom, textOf, titleOf } from "../../src/core/roles.js";
|
|
32
|
-
import { exportTaste, recommend, taste } from "../../src/taste/taste.js";
|
|
33
|
-
import { EMBED_MODEL, embedQuery, packVec, unpackVec } from "../../src/core/embed.js";
|
|
34
|
-
import { browse, describe, facet, getRow, neighbors, search } from "../../src/agent/tools.js";
|
|
35
|
-
|
|
36
|
-
const HOME = process.env.FANGORN_HOME ?? join(homedir(), ".fangorn");
|
|
37
|
-
const TASTE = join(HOME, "taste.json");
|
|
38
|
-
|
|
39
|
-
// ── the kernel on disk ───────────────────────────────────────────────────────
|
|
40
|
-
const store = () => { try { return JSON.parse(readFileSync(TASTE, "utf8")); } catch { return { model: EMBED_MODEL, likes: [], dislikes: [] }; } };
|
|
41
|
-
const save = (s) => { mkdirSync(HOME, { recursive: true }); writeFileSync(TASTE, JSON.stringify(s, null, 1)); };
|
|
42
|
-
/** Picks are stored PACKED (base64 int8, the shard encoding) and unpacked here.
|
|
43
|
-
* Storing the picks rather than only the derived vector is what keeps the
|
|
44
|
-
* kernel correctable: you can read what it was built from and drop one. */
|
|
45
|
-
const picks = (l = []) => l.map((p) => ({ ...p, vector: unpackVec(p.v) })).filter((p) => p.vector);
|
|
46
|
-
const kernel = (s = store()) => taste(picks(s.likes), picks(s.dislikes));
|
|
47
|
-
|
|
48
|
-
// ── args ─────────────────────────────────────────────────────────────────────
|
|
49
|
-
const argv = process.argv.slice(2);
|
|
50
|
-
const [cmd, ...rest] = argv;
|
|
51
|
-
const pos = rest.filter((a) => !a.startsWith("--"));
|
|
52
|
-
const flag = (n, d) => { const a = rest.find((x) => x.startsWith(`--${n}=`)); return a === undefined ? d : a.slice(n.length + 3); };
|
|
53
|
-
const num = (n, d) => { const v = flag(n); return v === undefined ? d : Number(v); };
|
|
54
|
-
const pairs = (s) => s ? Object.fromEntries(String(s).split(",").map((p) => p.split("=").map((x) => x.trim()))) : undefined;
|
|
55
|
-
const list = (s) => String(s ?? "").split(",").map((x) => x.trim()).filter(Boolean);
|
|
56
|
-
const out = (o) => console.log(JSON.stringify(o, null, 1));
|
|
57
|
-
const die = (m) => { console.error(m); process.exit(1); };
|
|
58
|
-
|
|
59
|
-
// ── a view, loaded ───────────────────────────────────────────────────────────
|
|
60
|
-
let roles = rolesFrom([], []);
|
|
61
|
-
async function load(view) {
|
|
62
|
-
if (!view) die("need a view URL");
|
|
63
|
-
const base = trimView(view);
|
|
64
|
-
configure({
|
|
65
|
-
resolveView: () => base,
|
|
66
|
-
// Roles must be ready BEFORE the first row is parsed: rowText runs during
|
|
67
|
-
// parsing, so deriving them afterwards leaves every row with empty text
|
|
68
|
-
// and lexical search silently matching nothing.
|
|
69
|
-
onManifests: (ms) => { roles = rolesFrom(ms); },
|
|
70
|
-
rowText: (f) => textOf(f, roles),
|
|
71
|
-
});
|
|
72
|
-
const rows = await loadShard(base);
|
|
73
|
-
roles = rolesFrom(domainManifests(), rows);
|
|
74
|
-
let model = null;
|
|
75
|
-
try { model = (await (await fetch(`${base}/cdn/catalog`)).json()).embedding_model ?? null; } catch { /* unranked, not fatal */ }
|
|
76
|
-
return { rows, roles, base, model };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/** A query vector, or null with the reason. Never throws: every verb here
|
|
80
|
-
* degrades to lexical and SAYS so rather than returning confident nonsense. */
|
|
81
|
-
const qvOf = async (q) => { try { return { qv: await embedQuery(q), why: null }; } catch (e) { return { qv: null, why: e?.message ?? String(e) }; } };
|
|
82
|
-
|
|
83
|
-
/** The corpus and the kernel must share an embedding space or cosine between
|
|
84
|
-
* them is noise that still looks like a score. */
|
|
85
|
-
const mismatch = (model, s) => model && s.model && model !== s.model
|
|
86
|
-
? `taste was built with ${s.model}, this corpus is ${model} — scores would be noise` : null;
|
|
87
|
-
|
|
88
|
-
const sources = async () => {
|
|
89
|
-
const f = flag("sources"); if (f) return list(f);
|
|
90
|
-
if (process.env.FANGORN_SOURCES) return list(process.env.FANGORN_SOURCES);
|
|
91
|
-
try { return JSON.parse(readFileSync(join(HOME, "sources.json"), "utf8")); } catch { /* none pinned */ }
|
|
92
|
-
return chainSources();
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
// Every app bound on chain, the scan fangorn-mcp's list-apps runs, on FANGORN_NETWORK
|
|
96
|
-
// (default arbitrumSepolia). From its AppRegistry's deployment; --from-block overrides.
|
|
97
|
-
async function chainSources() {
|
|
98
|
-
const [{ Fangorn }, { generatePrivateKey }, { network }] = await Promise.all([
|
|
99
|
-
import("@fangorn-network/sdk"), import("viem/accounts"), import("../../src/publish/view.js")]);
|
|
100
|
-
const config = await network();
|
|
101
|
-
const fangorn = Fangorn.create({ privateKey: generatePrivateKey(), config }); // reads only
|
|
102
|
-
const { sources } = await sourcesFromChain(fangorn, { fromBlock: BigInt(flag("from-block", String(config.appRegistryFromBlock))) });
|
|
103
|
-
return sources;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// ── verbs ────────────────────────────────────────────────────────────────────
|
|
107
|
-
switch (cmd) {
|
|
108
|
-
|
|
109
|
-
// WHICH app has this. Downloads no corpus — coverage centroids only, ~4KB each.
|
|
110
|
-
case "find": {
|
|
111
|
-
const src = await sources();
|
|
112
|
-
if (!src.length) die("no apps found on chain; pass --sources=a,b or write ~/.fangorn/sources.json");
|
|
113
|
-
out(await findCorpora(pos.join(" "), { sources: src, embed: embedQuery, model: EMBED_MODEL, limit: num("limit", 10) }));
|
|
114
|
-
break;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
case "describe": {
|
|
118
|
-
const { rows, roles: r, model } = await load(pos[0]);
|
|
119
|
-
out({
|
|
120
|
-
...describe(rows), model,
|
|
121
|
-
shape: r.declared ? "declared" : "sniffed",
|
|
122
|
-
title: r.title, subtitle: r.subtitle, tags: r.tags, text: r.text,
|
|
123
|
-
entityTypes: r.entityTypes, gates: r.gates,
|
|
124
|
-
// Where the reader goes next. The index's job ends here.
|
|
125
|
-
launch: r.launch, externalUrl: r.externalUrl, actions: r.actions,
|
|
126
|
-
});
|
|
127
|
-
break;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
case "browse": {
|
|
131
|
-
const { rows, roles: r } = await load(pos[0]);
|
|
132
|
-
out(browse(rows, r, { type: flag("type"), where: pairs(flag("where")), sort: flag("sort"),
|
|
133
|
-
desc: flag("asc") === undefined, limit: num("limit", 20), offset: num("offset", 0), fields: list(flag("fields")) }));
|
|
134
|
-
break;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
case "search": {
|
|
138
|
-
const { rows, roles: r } = await load(pos[0]);
|
|
139
|
-
const q = pos.slice(1).join(" ");
|
|
140
|
-
const { qv, why } = await qvOf(q);
|
|
141
|
-
out({ query: q, mode: qv ? "semantic where rows have vectors" : "lexical", ...(why ? { why } : {}),
|
|
142
|
-
hits: search(rows, q, r, { qv, limit: num("limit", 10), where: pairs(flag("where")), fields: list(flag("fields")) }) });
|
|
143
|
-
break;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
case "facet": {
|
|
147
|
-
const { rows } = await load(pos[0]);
|
|
148
|
-
out(facet(rows, pos[1], { limit: num("limit", 20), where: pairs(flag("where")) }));
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
case "row": {
|
|
153
|
-
const { rows, roles: r } = await load(pos[0]);
|
|
154
|
-
const g = getRow(rows, pos[1], r);
|
|
155
|
-
out(g ? { ...g, url: linkOf(rows.find((x) => x.id === g.id) ?? {}, r) } : null);
|
|
156
|
-
break;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
case "similar": {
|
|
160
|
-
const { rows, roles: r } = await load(pos[0]);
|
|
161
|
-
out(neighbors(rows, pos[1], r, { limit: num("limit", 10), fields: list(flag("fields")) }));
|
|
162
|
-
break;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// ── the kernel ───────────────────────────────────────────────────────────────
|
|
166
|
-
case "like": case "dislike": {
|
|
167
|
-
const { rows, roles: r, base, model } = await load(pos[0]);
|
|
168
|
-
const s = store();
|
|
169
|
-
const into = cmd === "like" ? s.likes : s.dislikes;
|
|
170
|
-
const added = [];
|
|
171
|
-
for (const id of pos.slice(1)) {
|
|
172
|
-
const row = rows.find((x) => x.id === id);
|
|
173
|
-
if (!row) { console.error(`no row ${id}`); continue; }
|
|
174
|
-
if (!row.vector) { console.error(`${id} has no vector — nothing to learn from`); continue; }
|
|
175
|
-
// Newest last: taste() weights by recency, so order in the file is signal.
|
|
176
|
-
const at = into.findIndex((p) => p.id === id);
|
|
177
|
-
if (at >= 0) into.splice(at, 1);
|
|
178
|
-
into.push({ id, title: titleOf(row, r), view: base, at: new Date().toISOString().slice(0, 10), v: packVec(Array.from(row.vector)) });
|
|
179
|
-
added.push(id);
|
|
180
|
-
}
|
|
181
|
-
s.model ??= model ?? EMBED_MODEL;
|
|
182
|
-
save(s);
|
|
183
|
-
const t = kernel(s);
|
|
184
|
-
out({ added, likes: s.likes.length, dislikes: s.dislikes.length, taste: t && exportTaste(t), file: TASTE });
|
|
185
|
-
break;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
case "forget": {
|
|
189
|
-
const s = store();
|
|
190
|
-
const drop = new Set(pos);
|
|
191
|
-
const before = s.likes.length + s.dislikes.length;
|
|
192
|
-
s.likes = s.likes.filter((p) => !drop.has(p.id));
|
|
193
|
-
s.dislikes = s.dislikes.filter((p) => !drop.has(p.id));
|
|
194
|
-
save(s);
|
|
195
|
-
out({ removed: before - s.likes.length - s.dislikes.length, likes: s.likes.length, dislikes: s.dislikes.length });
|
|
196
|
-
break;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
case "taste": {
|
|
200
|
-
const s = store();
|
|
201
|
-
const t = kernel(s);
|
|
202
|
-
out(t ? { model: s.model, n: t.n, from: t.from, rejected: t.rejected, drift: t.drift,
|
|
203
|
-
// Where each pick was learned. A kernel built in one publisher's
|
|
204
|
-
// corpus is meant to be pointed at another's — this is the record
|
|
205
|
-
// of whether it actually has been.
|
|
206
|
-
views: [...new Set([...s.likes, ...s.dislikes].map((p) => p.view))],
|
|
207
|
-
export: exportTaste(t), file: TASTE }
|
|
208
|
-
: { n: 0, file: TASTE, note: "nothing liked yet — `fx like <view> <id>`" });
|
|
209
|
-
break;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// The headline: rank a corpus by a taste learned somewhere else entirely.
|
|
213
|
-
case "recommend": {
|
|
214
|
-
const { rows, roles: r, model } = await load(pos[0]);
|
|
215
|
-
const s = store();
|
|
216
|
-
const t = kernel(s);
|
|
217
|
-
if (!t) die("no taste yet — `fx like <view> <id>` first");
|
|
218
|
-
const warn = mismatch(model, s);
|
|
219
|
-
if (warn) die(warn);
|
|
220
|
-
const seen = new Set([...s.likes, ...s.dislikes].map((p) => p.id));
|
|
221
|
-
out({ from: t.from, against: pos[0],
|
|
222
|
-
hits: recommend(rows, t, { limit: num("limit", 10), exclude: seen })
|
|
223
|
-
.map(({ row, score }) => ({ id: row.id, title: titleOf(row, r), score, url: linkOf(row, r) })) });
|
|
224
|
-
break;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// ── the handoff. The index points; the app does the work. ────────────────────
|
|
228
|
-
case "launch": {
|
|
229
|
-
const { rows, roles: r } = await load(pos[0]);
|
|
230
|
-
const id = flag("row");
|
|
231
|
-
if (id) {
|
|
232
|
-
const row = rows.find((x) => x.id === id);
|
|
233
|
-
if (!row) die(`no row ${id}`);
|
|
234
|
-
out({ url: linkOf(row, r), title: titleOf(row, r) });
|
|
235
|
-
break;
|
|
236
|
-
}
|
|
237
|
-
if (!r.launch) die("this corpus declares no presentation.launch — nowhere to hand off to");
|
|
238
|
-
const t = kernel();
|
|
239
|
-
const fill = { taste: t ? JSON.stringify(exportTaste(t)) : "", q: pos.slice(1).join(" ") };
|
|
240
|
-
const url = String(r.launch).replace(/\{(\w+)\}/g, (_, k) => encodeURIComponent(fill[k] ?? ""));
|
|
241
|
-
const u = new URL(url);
|
|
242
|
-
if (u.protocol !== "https:" && u.protocol !== "http:") die(`refusing a ${u.protocol} launch URL`);
|
|
243
|
-
// The kernel travels in the URL because that is the only channel a page on
|
|
244
|
-
// someone else's origin can receive it on. It is the app's copy from here.
|
|
245
|
-
out({ url: u.toString(), carries: t ? { n: t.n, from: t.from } : null });
|
|
246
|
-
break;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
default:
|
|
250
|
-
console.log(`fx <verb>
|
|
251
|
-
|
|
252
|
-
find <query> [--sources=a,b|--from-block=N] which app has this. No corpus downloaded.
|
|
253
|
-
describe <view> rows, field coverage, roles, where it hands off
|
|
254
|
-
browse <view> [--type= --where=k=v --sort= --asc --limit= --offset=]
|
|
255
|
-
search <view> <query> [--where=k=v --limit=] semantic where rows have vectors, else lexical
|
|
256
|
-
facet <view> <field> [--where=k=v --limit=] count a field's values
|
|
257
|
-
row <view> <id> one record, whole
|
|
258
|
-
similar <view> <id> [--limit=] nearest by vector
|
|
259
|
-
|
|
260
|
-
like|dislike <view> <id...> teach the kernel. Writes ${TASTE}
|
|
261
|
-
forget <id...> drop picks from it
|
|
262
|
-
taste what it is, and what it was built from
|
|
263
|
-
recommend <view> [--limit=] rank ANY corpus by it
|
|
264
|
-
|
|
265
|
-
launch <view> [query] | launch <view> --row=<id> the handoff URL, carrying the kernel`);
|
|
266
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{$ as e,D as t}from"./privy-context-81KmsBw2-DiR6-Yq8.js";import{t as n}from"./jsx-runtime-CndCZlyt.js";import{t as r}from"./createLucideIcon-BsERoFTA.js";import{n as i}from"./modal-context-CwmSeFcv-DPWNJrfK.js";import{t as a}from"./ScreenLayout-OwaQQcxH-cfOTmyl0.js";var o=r(`circle-question-mark`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3`,key:`1u773s`}],[`path`,{d:`M12 17h.01`,key:`p32p05`}]]),s=n(),c=({title:e=`Account not found`,subtitle:t,appName:n=`this app`,ctaText:r=`Try logging in again`,onRetry:i})=>(0,s.jsx)(a,{title:e,subtitle:t||`Please try logging in again or go to ${n} to create an account.`,icon:o,iconVariant:`warning`,primaryCta:{label:r,onClick:i},watermark:!0}),l={component:()=>{let{navigate:n,setModalData:r,data:a}=i(),o=t(),{getAuthMeta:l,client:u}=e();return(0,s.jsx)(c,{appName:o?.name,onRetry:()=>{let e=l();r({...a,login:{...a?.login,...e?.disableSignup?{disableSignup:!0}:{}}}),u?.authFlow&&(u.authFlow=void 0),n(`LandingScreen`)}})}};export{l as AccountNotFoundScreen,l as default,c as AccountNotFoundScreenView};
|