@fangorn-network/westmarch 2026.10.27-dev → 2026.10.28
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/dist/ts/eval.js +0 -0
- package/package.json +11 -11
- package/site/worker.js +27 -8
- package/src/agent/agent-card.js +18 -1
- package/src/agent/mcp.js +15 -5
- package/src/discover/apps.js +15 -1
- package/src/publish/ship.js +27 -6
- package/src/publish/view.js +134 -40
- package/template/package.json +1 -1
- 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/roles-BDPDWrwo.js +0 -1
- package/site/dist/assets/roles-DKPW79Ca.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/transformers.web-BTyOEJ0C.js +0 -40
- package/site/dist/assets/transformers.web-CUZUFjAK.js +0 -49
- 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/site/dist/index.html +0 -21
- package/site/dist/theme.css +0 -7
package/dist/ts/eval.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fangorn-network/westmarch",
|
|
3
|
-
"version": "2026.10.
|
|
3
|
+
"version": "2026.10.28",
|
|
4
4
|
"description": "all-in-one builder for fangorn apps",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"@fangorn-network/markov": "^0.1.0"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
|
-
"@fangorn-network/sdk": "^2026.10.
|
|
48
|
+
"@fangorn-network/sdk": "^2026.10.27-dev",
|
|
49
49
|
"@huggingface/transformers": "^4.2.0",
|
|
50
50
|
"@noble/curves": "^1.9.1",
|
|
51
51
|
"viem": "^2.55.1"
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@fangorn-network/sdk": "^2026.10.
|
|
59
|
+
"@fangorn-network/sdk": "^2026.10.27-dev",
|
|
60
60
|
"@huggingface/transformers": "^4.2.0",
|
|
61
61
|
"@noble/curves": "^1.9.1",
|
|
62
62
|
"@privy-io/react-auth": "^3.47.0",
|
|
@@ -68,14 +68,14 @@
|
|
|
68
68
|
"viem": "^2.56.3"
|
|
69
69
|
},
|
|
70
70
|
"bin": {
|
|
71
|
-
"westmarch": "
|
|
72
|
-
"westmarch-publish": "
|
|
73
|
-
"westmarch-view": "
|
|
74
|
-
"westmarch-ship": "
|
|
75
|
-
"westmarch-eval": "
|
|
76
|
-
"westmarch-lint": "
|
|
77
|
-
"fangorn-mcp": "
|
|
78
|
-
"fangorn-fx": "
|
|
71
|
+
"westmarch": "src/publish/init.js",
|
|
72
|
+
"westmarch-publish": "src/publish/cli.js",
|
|
73
|
+
"westmarch-view": "src/publish/view-cli.js",
|
|
74
|
+
"westmarch-ship": "src/publish/ship.js",
|
|
75
|
+
"westmarch-eval": "dist/ts/eval.js",
|
|
76
|
+
"westmarch-lint": "src/publish/lint.js",
|
|
77
|
+
"fangorn-mcp": "src/agent/mcp.js",
|
|
78
|
+
"fangorn-fx": "plugin/scripts/fx.mjs"
|
|
79
79
|
},
|
|
80
80
|
"files": [
|
|
81
81
|
"src",
|
package/site/worker.js
CHANGED
|
@@ -35,7 +35,7 @@ import { createPublicClient, http } from "viem";
|
|
|
35
35
|
import { generatePrivateKey } from "viem/accounts";
|
|
36
36
|
import { EMBED_MODEL, DOCUMENT, QUERY, matryoshka } from "../src/core/embed.js";
|
|
37
37
|
import { configure, resetShard } from "../src/core/shard.js";
|
|
38
|
-
import { publishView, r2Store } from "../src/publish/view.js";
|
|
38
|
+
import { ORIGIN, publishView, r2Store } from "../src/publish/view.js";
|
|
39
39
|
import { viewTools } from "../src/agent/view-tools.js";
|
|
40
40
|
|
|
41
41
|
let CONFIG = { paid: null };
|
|
@@ -57,8 +57,18 @@ const encode = (env, prompt) => async (texts) =>
|
|
|
57
57
|
// ── the indexer ───────────────────────────────────────────────────────────────
|
|
58
58
|
|
|
59
59
|
const STATE = "state.json", LOCK = "index.lock";
|
|
60
|
-
// A run
|
|
61
|
-
|
|
60
|
+
// A live run beats its lock every BEAT_MS; one silent past LOCK_MS is presumed dead (killed for CPU
|
|
61
|
+
// or wall time, which skips `finally`) and its lock taken over. Lock: "<last beat ms> <run id>".
|
|
62
|
+
// ponytail: get-then-put, so two runs starting in the same instant can both take it; R2's onlyIf etag when that shows.
|
|
63
|
+
const LOCK_MS = 2 * 60_000, BEAT_MS = 30_000;
|
|
64
|
+
export async function takeLock(bucket, now = Date.now()) {
|
|
65
|
+
const held = await (await bucket.get(LOCK))?.text();
|
|
66
|
+
if (held && now - Number(held.split(" ")[0]) < LOCK_MS) return null;
|
|
67
|
+
const id = crypto.randomUUID();
|
|
68
|
+
const beat = () => bucket.put(LOCK, `${Date.now()} ${id}`);
|
|
69
|
+
await beat();
|
|
70
|
+
return { id, beat, release: async () => { if ((await (await bucket.get(LOCK))?.text())?.endsWith(id)) await bucket.delete(LOCK); } };
|
|
71
|
+
}
|
|
62
72
|
|
|
63
73
|
// CONFIG.network: the SDK's network name ("baseSepolia"); absent, its default.
|
|
64
74
|
const network = () => SupportedNetworks[CONFIG.network] ?? FangornConfig;
|
|
@@ -96,9 +106,9 @@ export async function presented({ fangorn, chain }, state) {
|
|
|
96
106
|
}
|
|
97
107
|
|
|
98
108
|
export async function index(env, { log = console.log } = {}) {
|
|
99
|
-
const lock = await env.VIEW
|
|
100
|
-
if (lock
|
|
101
|
-
|
|
109
|
+
const lock = await takeLock(env.VIEW);
|
|
110
|
+
if (!lock) return log("index: a run is in progress; skipped");
|
|
111
|
+
const beating = setInterval(() => lock.beat().catch(() => {}), BEAT_MS);
|
|
102
112
|
try {
|
|
103
113
|
const state = (await (await env.VIEW.get(STATE))?.json()) ?? { block: null, repos: {} };
|
|
104
114
|
const r = reader(env);
|
|
@@ -113,7 +123,8 @@ export async function index(env, { log = console.log } = {}) {
|
|
|
113
123
|
log(`index: through block ${state.block}, ${Object.keys(report).length} domain(s) changed`);
|
|
114
124
|
return report;
|
|
115
125
|
} finally {
|
|
116
|
-
|
|
126
|
+
clearInterval(beating);
|
|
127
|
+
await lock.release();
|
|
117
128
|
}
|
|
118
129
|
}
|
|
119
130
|
|
|
@@ -455,7 +466,6 @@ async function paidCall(origin, tool, payment, run) {
|
|
|
455
466
|
return { ...result, _meta: { ...result._meta, "x402/payment-response": settled } };
|
|
456
467
|
}
|
|
457
468
|
|
|
458
|
-
export const ORIGIN = "https://origin.westmarch.invalid";
|
|
459
469
|
const BY_ORIGIN = new Set(["/.well-known/agent-card.json", "/openapi.json", "/.well-known/x402"]);
|
|
460
470
|
|
|
461
471
|
const worker = {
|
|
@@ -517,6 +527,15 @@ if (typeof process !== "undefined" && import.meta.url === `file://${process.argv
|
|
|
517
527
|
delimitedPrefixes: [...new Set(ks.filter((k) => rest(k).includes("/")).map((k) => `${prefix + rest(k).split("/")[0]}/`))] };
|
|
518
528
|
},
|
|
519
529
|
};
|
|
530
|
+
const a = await takeLock(VIEW);
|
|
531
|
+
eq([!!a, await takeLock(VIEW)], [true, null], "a held lock skips the next run");
|
|
532
|
+
objs.set(LOCK, { bytes: new TextEncoder().encode(`${Date.now() - LOCK_MS - 1} dead`), at: new Date() });
|
|
533
|
+
const b = await takeLock(VIEW);
|
|
534
|
+
await a.release();
|
|
535
|
+
eq([!!b, objs.has(LOCK)], [true, true], "a silent lock is taken over, and its dead owner can't release the new one");
|
|
536
|
+
await b.release();
|
|
537
|
+
eq(objs.has(LOCK), false, "the owner releases its own lock");
|
|
538
|
+
|
|
520
539
|
// Words → a 768-d vector, so a query shares dimensions with the rows that share its words.
|
|
521
540
|
const calls = [];
|
|
522
541
|
const AI = { run: async (model, { text }) => { calls.push({ model, text });
|
package/src/agent/agent-card.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
// point back at it, so writing someone else's appId here gets you nothing.
|
|
18
18
|
|
|
19
19
|
import { FANGORN_APP_EXTENSION, BaseSepoliaConfig, appId as hashAppId } from "@fangorn-network/sdk";
|
|
20
|
+
import { PLUGIN_MARKETPLACE, PLUGIN_NAME } from "../discover/apps.js";
|
|
20
21
|
|
|
21
22
|
/** Run `register` against a recording `document.modelContext`; return what it
|
|
22
23
|
* registered. `register` is whatever the page calls at load. */
|
|
@@ -48,6 +49,10 @@ const HEX32 = /^0x[0-9a-fA-F]{64}$/;
|
|
|
48
49
|
* tools, as the free tier's Worker does at /mcp.
|
|
49
50
|
* config the deployment; defaults to the SDK's, so the addresses in the
|
|
50
51
|
* card cannot drift from the ones `discoverApp` checks.
|
|
52
|
+
* skill `{url, sha256}`: the app's own agent skill (a SKILL.md), for agents
|
|
53
|
+
* that adopt it, so its behaviour travels with the app and not with a
|
|
54
|
+
* marketplace. The hash pins what the reader saw: an agent adopts it
|
|
55
|
+
* only on its user's yes, and asks again when the hash changes.
|
|
51
56
|
*/
|
|
52
57
|
export function agentCard({ name, description, url, version = "0.0.0", tools = [], tags = [], skills = [], fangorn, ...rest }) {
|
|
53
58
|
if (!name || !url) throw new Error("agentCard: name and url are required");
|
|
@@ -75,7 +80,7 @@ export function agentCard({ name, description, url, version = "0.0.0", tools = [
|
|
|
75
80
|
|
|
76
81
|
/** The params `discoverApp` reads, validated the same way it validates them.
|
|
77
82
|
* A malformed card should fail the build, not the first reader. */
|
|
78
|
-
export function fangornExtension({ app, fromBlock, repos = [], views = [], mcp, paid, access, config = BaseSepoliaConfig }) {
|
|
83
|
+
export function fangornExtension({ app, fromBlock, repos = [], views = [], mcp, paid, access, skill, plugin, config = BaseSepoliaConfig }) {
|
|
79
84
|
if (!app) throw new Error("fangorn.app is required");
|
|
80
85
|
const id = HEX32.test(app) ? app : hashAppId(app);
|
|
81
86
|
const from = String(fromBlock ?? "");
|
|
@@ -96,6 +101,10 @@ export function fangornExtension({ app, fromBlock, repos = [], views = [], mcp,
|
|
|
96
101
|
}
|
|
97
102
|
// `access`: a private app. Its view and tools need a pass (`pass_url`, `pass` in base units, for
|
|
98
103
|
// `days`) or one x402 payment of `call` per tool call; describe and the catalog are free.
|
|
104
|
+
if (skill && !(/^https?:\/\//.test(skill.url ?? "") && /^[0-9a-f]{64}$/.test(skill.sha256 ?? "")))
|
|
105
|
+
throw new Error(`fangorn.skill needs an http(s) url and the sha256 of the file, in hex: ${JSON.stringify(skill)}`);
|
|
106
|
+
if (plugin && !(PLUGIN_MARKETPLACE.test(plugin.marketplace ?? "") && PLUGIN_NAME.test(plugin.name ?? "")))
|
|
107
|
+
throw new Error(`fangorn.plugin needs a marketplace (GitHub owner/repo or https URL) and a plugin name: ${JSON.stringify(plugin)}`);
|
|
99
108
|
if (access && !(/^https?:\/\//.test(access.pass_url ?? "") && /^\d+$/.test(String(access.pass)) && /^\d+$/.test(String(access.call))))
|
|
100
109
|
throw new Error(`fangorn.access needs pass_url, and pass and call in base units: ${JSON.stringify(access)}`);
|
|
101
110
|
return {
|
|
@@ -110,6 +119,8 @@ export function fangornExtension({ app, fromBlock, repos = [], views = [], mcp,
|
|
|
110
119
|
...(paid ? { paid: { url: paid.url, price: String(paid.price), asset: paid.asset, network: paid.network,
|
|
111
120
|
symbol: paid.symbol ?? "USDC", decimals: paid.decimals ?? 6, description: paid.description ?? "" } } : {}),
|
|
112
121
|
...(access ? { access } : {}),
|
|
122
|
+
...(skill ? { skill: { url: skill.url, sha256: skill.sha256 } } : {}),
|
|
123
|
+
...(plugin ? { plugin: { marketplace: plugin.marketplace, name: plugin.name } } : {}),
|
|
113
124
|
},
|
|
114
125
|
};
|
|
115
126
|
}
|
|
@@ -148,6 +159,12 @@ if (typeof process !== "undefined" && import.meta.url === `file://${process.argv
|
|
|
148
159
|
throws(() => fangornExtension({ app: "a" }), /fromBlock/, "missing fromBlock");
|
|
149
160
|
throws(() => fangornExtension({ app: "a", fromBlock: 0, views: ["javascript:alert(1)"] }), /views/, "non-http view");
|
|
150
161
|
throws(() => agentCard({ name: "X" }), /url/, "missing url");
|
|
162
|
+
const sha = "a".repeat(64);
|
|
163
|
+
eq(fangornExtension({ app: "a", fromBlock: 0, skill: { url: "https://x.test/skill/a/SKILL.md", sha256: sha } }).params.skill, { url: "https://x.test/skill/a/SKILL.md", sha256: sha }, "a skill rides in the extension");
|
|
164
|
+
throws(() => fangornExtension({ app: "a", fromBlock: 0, skill: { url: "https://x.test/s.md" } }), /skill/, "a skill without its hash");
|
|
165
|
+
throws(() => fangornExtension({ app: "a", fromBlock: 0, skill: { url: "file:///etc/passwd", sha256: sha } }), /skill/, "a non-http skill");
|
|
166
|
+
eq(fangornExtension({ app: "a", fromBlock: 0, plugin: { marketplace: "o/r", name: "a" } }).params.plugin, { marketplace: "o/r", name: "a" }, "a plugin rides in the extension");
|
|
167
|
+
throws(() => fangornExtension({ app: "a", fromBlock: 0, plugin: { marketplace: "o/r; rm -rf ~", name: "a" } }), /plugin/, "a plugin that would inject into a shell");
|
|
151
168
|
|
|
152
169
|
console.log("agent-card.js self-check ok — tools captured without executing, extension matches the SDK's, bad params fail the build");
|
|
153
170
|
}
|
package/src/agent/mcp.js
CHANGED
|
@@ -24,7 +24,7 @@ import net from "node:net";
|
|
|
24
24
|
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
25
25
|
import { homedir } from "node:os";
|
|
26
26
|
import { createInterface } from "node:readline";
|
|
27
|
-
import { APP_EXTENSION, listApps, toApp } from "../discover/apps.js";
|
|
27
|
+
import { APP_EXTENSION, listApps, pluginOf, skillOf, toApp } from "../discover/apps.js";
|
|
28
28
|
|
|
29
29
|
const log = (...a) => console.error("[fangorn-mcp]", ...a); // stdout is the protocol
|
|
30
30
|
// FANGORN_MCP_TRACE=1: step timings on stderr, for finding where an answer waits.
|
|
@@ -214,8 +214,9 @@ export function handlers(deps) {
|
|
|
214
214
|
if (!mcp) throw new Error(`${card.name ?? cardUrl} has no MCP server (its card has no \`mcp\`)`);
|
|
215
215
|
let s = slug(card.name ?? app);
|
|
216
216
|
while (open.has(s)) s += "-";
|
|
217
|
-
const
|
|
218
|
-
const
|
|
217
|
+
const ext = card.capabilities?.extensions?.find((e) => e.uri === APP_EXTENSION);
|
|
218
|
+
const access = ext?.params?.access ?? null;
|
|
219
|
+
const o = { slug: s, name: card.name, card: cardUrl, appId, skill: skillOf(ext), plugin: pluginOf(ext), ...await deps.remoteTools(mcp, { access }) };
|
|
219
220
|
trace(`open ${app}: ready`);
|
|
220
221
|
open.set(o.slug, o);
|
|
221
222
|
deps.notify?.("notifications/tools/list_changed");
|
|
@@ -249,7 +250,13 @@ export function handlers(deps) {
|
|
|
249
250
|
"open-app": async ({ app }) => {
|
|
250
251
|
const o = await openApp(app);
|
|
251
252
|
return text({ app: o.slug, name: o.name, card: o.card,
|
|
252
|
-
call_as: `${o.slug}__<tool>, or call-app-tool`, tools: o.tools
|
|
253
|
+
call_as: `${o.slug}__<tool>, or call-app-tool`, tools: o.tools,
|
|
254
|
+
// An app's own skill: standing instructions for the reader's agent, so never loaded
|
|
255
|
+
// silently. The fangorn-index skill offers it to the user and pins the hash on a yes.
|
|
256
|
+
...(o.skill ? { skill: { ...o.skill, adopt: "The app ships an agent skill. Offer it to the user (what it would make you do, from its description); adopt it only on their yes, checking sha256, and ask again if the hash changes." } } : {}),
|
|
257
|
+
// Its Claude Code plugin: hooks run code on every matching event, so the same rule, louder.
|
|
258
|
+
...(o.plugin ? { plugin: { ...o.plugin, install: `claude plugin install ${o.plugin.name} --marketplace ${o.plugin.marketplace}`,
|
|
259
|
+
adopt: "The app ships a Claude Code plugin, whose hooks run code on this machine without being called. Offer it to the user once, saying what its hooks trigger on; install only on their yes. It takes effect next session." } } : {}) });
|
|
253
260
|
},
|
|
254
261
|
"call-app-tool": async ({ app, tool, arguments: args }) => call(app, tool, args),
|
|
255
262
|
};
|
|
@@ -298,7 +305,8 @@ if (process.argv[2] === "--selfcheck") {
|
|
|
298
305
|
findApps: async () => ({ apps: [{ name: "Kings Foil", desc: "trials", card: "https://k.test/card", appId: "0xk" },
|
|
299
306
|
{ name: "Bare", desc: "", card: "https://b.test/card", appId: "0xb" }], rejected: [{}] }),
|
|
300
307
|
exploreApps: async (q) => ({ ranked_by: q ? "meaning" : null, apps: [{ app: "kings-foil", name: "Kings Foil", relevant: true }, { app: "b", name: "B", relevant: false }] }),
|
|
301
|
-
resolveCard: async (url) => (url.includes("b.test") ? { card: { name: "Bare" }, mcp: null } : { card: { name: "Kings Foil"
|
|
308
|
+
resolveCard: async (url) => (url.includes("b.test") ? { card: { name: "Bare" }, mcp: null } : { card: { name: "Kings Foil", capabilities: { extensions: [{ uri: APP_EXTENSION,
|
|
309
|
+
params: { skill: { url: "https://k.test/skill/kings-foil/SKILL.md", sha256: "b".repeat(64) }, plugin: { marketplace: "k/kf", name: "kings-foil" } } }] } }, mcp: "https://k.test/mcp" }),
|
|
302
310
|
remoteTools: async () => (opened++, remote),
|
|
303
311
|
};
|
|
304
312
|
deps.notify = serve(handlers(deps), { input, output });
|
|
@@ -321,6 +329,8 @@ if (process.argv[2] === "--selfcheck") {
|
|
|
321
329
|
call(5, "open-app", { app: "Kings Foil" }); await wait();
|
|
322
330
|
call(6, "open-app", { app: "https://k.test/card" }); await wait();
|
|
323
331
|
assert(body(5).tools[0].name === "search" && opened === 1, "open once, by name or by card URL");
|
|
332
|
+
assert(body(5).skill?.url === "https://k.test/skill/kings-foil/SKILL.md" && /user/.test(body(5).skill.adopt), "open-app offers the app's skill, for the user to adopt");
|
|
333
|
+
assert(body(5).plugin?.marketplace === "k/kf" && /user/.test(body(5).plugin.adopt), "open-app offers the app's plugin, for the user to install");
|
|
324
334
|
assert(replies.some((r) => r.method === "notifications/tools/list_changed"), "opening notifies");
|
|
325
335
|
rpc(7, "tools/list"); call(8, "kings-foil__search", { query: "x" }); call(9, "call-app-tool", { app: "kings-foil", tool: "search" });
|
|
326
336
|
call(10, "call-app-tool", { app: "kings-foil", tool: "boom" }); call(11, "open-app", { app: "nope" }); call(13, "open-app", { app: "Bare" }); rpc(12, "nope"); await wait();
|
package/src/discover/apps.js
CHANGED
|
@@ -33,6 +33,20 @@ function safeView(url) {
|
|
|
33
33
|
* src/agent/agent-card.js's self-check fails if the two drift. */
|
|
34
34
|
export const APP_EXTENSION = "https://fangorn.network/a2a/app/v1";
|
|
35
35
|
|
|
36
|
+
/** The app's agent skill, `{url, sha256}`, when its card names one well-formed; else null. */
|
|
37
|
+
export const skillOf = (ext) => {
|
|
38
|
+
const k = ext?.params?.skill;
|
|
39
|
+
return k && safeView(k.url) && /^[0-9a-f]{64}$/.test(k.sha256 ?? "") ? { url: k.url, sha256: k.sha256 } : null;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// The app's Claude Code plugin, for what a skill can't do (hooks). Both fields reach a shell command
|
|
43
|
+
// in the reader's agent, so they are held to a GitHub owner/repo (or https URL) and a plain name.
|
|
44
|
+
export const PLUGIN_MARKETPLACE = /^([\w.-]+\/[\w.-]+|https:\/\/[\w.\/-]+)$/, PLUGIN_NAME = /^[a-z0-9][a-z0-9-]*$/;
|
|
45
|
+
export const pluginOf = (ext) => {
|
|
46
|
+
const p = ext?.params?.plugin;
|
|
47
|
+
return p && PLUGIN_MARKETPLACE.test(p.marketplace ?? "") && PLUGIN_NAME.test(p.name ?? "") ? { marketplace: p.marketplace, name: p.name } : null;
|
|
48
|
+
};
|
|
49
|
+
|
|
36
50
|
/** A verified card → an app entry. `views` is westmarch's param; the SDK does not read it. */
|
|
37
51
|
export function toApp({ card, appId, fromBlock, repos }, cardUrl) {
|
|
38
52
|
const ext = card.capabilities.extensions.find((e) => e.uri === APP_EXTENSION);
|
|
@@ -40,7 +54,7 @@ export function toApp({ card, appId, fromBlock, repos }, cardUrl) {
|
|
|
40
54
|
const p = ext?.params?.paid;
|
|
41
55
|
const paid = p && /^https?:\/\//.test(p.url ?? "") && p.url.includes("{id}") && /^\d+$/.test(String(p.price)) ? p : null;
|
|
42
56
|
return {
|
|
43
|
-
appId, card: cardUrl, fromBlock, repos, views, paid,
|
|
57
|
+
appId, card: cardUrl, fromBlock, repos, views, paid, skill: skillOf(ext), plugin: pluginOf(ext),
|
|
44
58
|
mcp: safeView(ext?.params?.mcp),
|
|
45
59
|
name: card.name ?? appId,
|
|
46
60
|
desc: card.description ?? "",
|
package/src/publish/ship.js
CHANGED
|
@@ -83,6 +83,9 @@ const log = (s) => console.error(`[ship] ${s}`);
|
|
|
83
83
|
// // (pages/intro.html, a fragment, replaces the description on the front page)
|
|
84
84
|
// "nav": [{ "href": "coverage.html", "label": "Coverage" }], // optional: header links to them
|
|
85
85
|
// "examples": ["…"], // optional: questions to start from, on the front page (and a private app's gate)
|
|
86
|
+
// "plugin": {"marketplace": "owner/repo", "name": "…"}, // optional: its Claude Code plugin (hooks), offered by open-app
|
|
87
|
+
// "skill": "skill/SKILL.md", // optional: the app's agent skill, served at skill/<app>/SKILL.md and named
|
|
88
|
+
// // in the card with its sha256; fangorn-index offers it to whoever opens the app
|
|
86
89
|
// "agent": "app/agent.js" }, // optional: the module whose registerAgent the card lists, when
|
|
87
90
|
// // `pages` replaces the stock index.html with a page of its own
|
|
88
91
|
// "types": { "<tag>": { "description": "…", "role_map": {…}, "presentation": {…} } },
|
|
@@ -163,10 +166,13 @@ export function presentedRepos(cfg) {
|
|
|
163
166
|
|
|
164
167
|
/** The Worker's wrangler config: the stock worker, the site as its assets, its bucket, the AI
|
|
165
168
|
* binding, the cron and CONFIG. `worker` is site/worker.js unless a test points elsewhere. */
|
|
166
|
-
export function wranglerConfig({ name, site, account, cron = "*/5 * * * *", config, url, ipfsGateway, worker = join(HERE, "../../site/worker.js") }) {
|
|
169
|
+
export function wranglerConfig({ name, site, account, cron = "*/5 * * * *", cpuMs, config, url, ipfsGateway, worker = join(HERE, "../../site/worker.js") }) {
|
|
167
170
|
return {
|
|
168
171
|
name, main: worker, compatibility_date: "2025-09-15", compatibility_flags: ["nodejs_compat"],
|
|
169
172
|
...(account ? { account_id: account } : {}),
|
|
173
|
+
// site.cpu_ms: the indexer's CPU per run. Reading one big commit (50k records) outlasts the
|
|
174
|
+
// 30 s Workers Paid default; up to 300000. The Free plan refuses the deploy with it set.
|
|
175
|
+
...(cpuMs ? { limits: { cpu_ms: cpuMs } } : {}),
|
|
170
176
|
assets: { directory: site, binding: "ASSETS" },
|
|
171
177
|
r2_buckets: [{ binding: "VIEW", bucket_name: `${name}-view` }],
|
|
172
178
|
ai: { binding: "AI" },
|
|
@@ -270,7 +276,7 @@ export async function buildForDeploy(configPath, wranglerPath = join(dirname(res
|
|
|
270
276
|
log(`the R2 bucket ${w.r2_buckets?.[0]?.bucket_name} doesn't name the Worker; two apps sharing one overwrite each other's view`);
|
|
271
277
|
|
|
272
278
|
process.env.FANGORN_NETWORK = process.env.CHAIN_NAME = cfg.network;
|
|
273
|
-
const [{ createPublicClient, http }, view
|
|
279
|
+
const [{ createPublicClient, http }, view] = await Promise.all([import("viem"), import("./view.js")]);
|
|
274
280
|
const FangornConfig = await view.network(cfg.network);
|
|
275
281
|
const fangorn = await view.readOnlyFangorn();
|
|
276
282
|
fangorn.setAppId(cfg.app);
|
|
@@ -281,7 +287,7 @@ export async function buildForDeploy(configPath, wranglerPath = join(dirname(res
|
|
|
281
287
|
|
|
282
288
|
const base = dirname(resolve(configPath));
|
|
283
289
|
const { site, writeCard } = await buildSite(cfg, base);
|
|
284
|
-
writeCard(ORIGIN, { fromBlock, repos: [] });
|
|
290
|
+
writeCard(view.ORIGIN, { fromBlock, repos: [] });
|
|
285
291
|
const gateway = process.env.FANGORN_IPFS_GATEWAY;
|
|
286
292
|
w.assets = { ...w.assets, directory: relative(dirname(resolve(wranglerPath)), site) };
|
|
287
293
|
w.vars = { ...w.vars, CONFIG: { app: cfg.app, name: cfg.name, description: cfg.description, fromBlock, network: cfg.network,
|
|
@@ -398,7 +404,7 @@ export async function ship(configPath, { crawl = true, deploy = true, dry = fals
|
|
|
398
404
|
const workerConfig = (u) => {
|
|
399
405
|
const path = join(dir, "wrangler.json");
|
|
400
406
|
writeFileSync(path, JSON.stringify(wranglerConfig({
|
|
401
|
-
name: cfg.site.project, site, account: cfg.site.account, cron: cfg.site.cron, url: cfg.site.url, ipfsGateway: view.ipfsGateway(),
|
|
407
|
+
name: cfg.site.project, site, account: cfg.site.account, cron: cfg.site.cron, cpuMs: cfg.site.cpu_ms, url: cfg.site.url, ipfsGateway: view.ipfsGateway(),
|
|
402
408
|
config: { app: cfg.app, name: cfg.name, description: cfg.description, fromBlock: state.fromBlock, network: cfg.network,
|
|
403
409
|
schema: { types: cfg.types, relations: cfg.relations }, repos: register ? [] : repos, paid: sale(u).sale, private: access(u).config },
|
|
404
410
|
}), null, 1));
|
|
@@ -549,6 +555,15 @@ export async function buildSite(cfg, base) {
|
|
|
549
555
|
if (cfg.site.pages) cpSync(resolve(base, cfg.site.pages), site, { recursive: true });
|
|
550
556
|
writeFileSync(join(site, "nav.json"), JSON.stringify(cfg.site.nav ?? []));
|
|
551
557
|
writeFileSync(join(site, "examples.json"), JSON.stringify(cfg.site.examples ?? []));
|
|
558
|
+
// site.skill: the app's agent skill (a SKILL.md), served at skill/<app>/SKILL.md and named in the
|
|
559
|
+
// card with its hash, so fangorn-index can offer it to whoever opens the app.
|
|
560
|
+
let skill = null;
|
|
561
|
+
if (cfg.site.skill) {
|
|
562
|
+
const bytes = readFileSync(resolve(base, cfg.site.skill));
|
|
563
|
+
mkdirSync(join(site, "skill", cfg.app), { recursive: true });
|
|
564
|
+
writeFileSync(join(site, "skill", cfg.app, "SKILL.md"), bytes);
|
|
565
|
+
skill = { path: `skill/${cfg.app}/SKILL.md`, sha256: createHash("sha256").update(bytes).digest("hex") };
|
|
566
|
+
}
|
|
552
567
|
// The card lists the tools the page at `url` registers: the stock page's, or the app's own.
|
|
553
568
|
const card = await import("../agent/agent-card.js");
|
|
554
569
|
const { registerAgent } = await import(cfg.site.agent ? pathToFileURL(resolve(base, cfg.site.agent)).href : "../../site/agent.js");
|
|
@@ -564,7 +579,9 @@ export async function buildSite(cfg, base) {
|
|
|
564
579
|
...(paid ? [{ id: "keys", name: "Keys", tags: [...(cfg.tags ?? []), "x402"],
|
|
565
580
|
description: `The keys to sealed records (POST ${u}/paid), per record.` }] : []),
|
|
566
581
|
],
|
|
567
|
-
fangorn: { app: cfg.app, fromBlock, repos, views: [`${u}/view`], mcp: `${u}/mcp`, config, ...(paid ? { paid } : {}), ...(access ? { access } : {})
|
|
582
|
+
fangorn: { app: cfg.app, fromBlock, repos, views: [`${u}/view`], mcp: `${u}/mcp`, config, ...(paid ? { paid } : {}), ...(access ? { access } : {}),
|
|
583
|
+
...(skill ? { skill: { url: `${u}/${skill.path}`, sha256: skill.sha256 } } : {}),
|
|
584
|
+
...(cfg.site.plugin ? { plugin: cfg.site.plugin } : {}) },
|
|
568
585
|
});
|
|
569
586
|
mkdirSync(join(site, ".well-known"), { recursive: true });
|
|
570
587
|
writeFileSync(join(site, ".well-known/agent-card.json"), JSON.stringify(agentCard, null, 1));
|
|
@@ -703,8 +720,11 @@ export async function indexHere(configPath, { port = 8791 } = {}) {
|
|
|
703
720
|
if (secret) writeFileSync(vars, `PAID_SECRET=${secret}\n`, { mode: 0o600 });
|
|
704
721
|
const url = `http://127.0.0.1:${port}`, start = Math.floor(Date.now() / 1000);
|
|
705
722
|
const wrangler = spawn("npx", ["wrangler", "dev", "--config", wpath, "--port", String(port), "--ip", "127.0.0.1", "--test-scheduled"],
|
|
706
|
-
{ cwd: join(HERE, "../.."), stdio: ["ignore", "
|
|
723
|
+
{ cwd: join(HERE, "../.."), stdio: ["ignore", "pipe", "inherit"],
|
|
707
724
|
env: { ...process.env, ...(cfg.site.account ? { CLOUDFLARE_ACCOUNT_ID: cfg.site.account } : {}) } });
|
|
725
|
+
// A run already holds the lock (the deployed cron's): this one skips, and the catalog would never move.
|
|
726
|
+
let skipped = false;
|
|
727
|
+
wrangler.stdout.on("data", (b) => { process.stdout.write(b); if (String(b).includes("index: a run is in progress; skipped")) skipped = true; });
|
|
708
728
|
try {
|
|
709
729
|
for (;;) {
|
|
710
730
|
if (wrangler.exitCode !== null) throw new Error("wrangler dev exited");
|
|
@@ -716,6 +736,7 @@ export async function indexHere(configPath, { port = 8791 } = {}) {
|
|
|
716
736
|
let catalog = null;
|
|
717
737
|
while (!(catalog?.generated_at >= start)) {
|
|
718
738
|
if (wrangler.exitCode !== null) throw new Error("wrangler dev exited");
|
|
739
|
+
if (skipped) throw new Error("another indexer run holds the lock (the deployed cron's, most likely); it frees within 2 minutes of that run dying. Try again then.");
|
|
719
740
|
await new Promise((ok) => setTimeout(ok, 5000));
|
|
720
741
|
catalog = await fetch(`${url}/view/cdn/catalog`).then((r) => (r.ok ? r.json() : null), () => null);
|
|
721
742
|
}
|