diff --git a/package.json b/package.json index d8282460..97eb8ed7 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "fast-glob": "^3.3.3", "hono": "^4", "ink": "^6.8.0", + "jsonc-parser": "^3.3.1", "open": "^11.0.0", "react": "^19.2.4", "semver": "^7.7.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a4d06e60..bd377807 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,19 +10,19 @@ importers: dependencies: '@anthropic-ai/claude-agent-sdk': specifier: ~0.3.0 - version: 0.3.198(@anthropic-ai/sdk@0.106.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(zod@4.4.3) + version: 0.3.201(@anthropic-ai/sdk@0.106.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(zod@4.4.3) '@anthropic-ai/sdk': specifier: ^0.106.0 version: 0.106.0(zod@4.4.3) '@clack/core': specifier: ^1.0.1 - version: 1.4.2 + version: 1.4.3 '@clack/prompts': specifier: 1.6.0 version: 1.6.0 '@hono/node-server': specifier: ^1 - version: 1.19.14(hono@4.11.4) + version: 1.19.14(hono@4.12.28) '@napi-rs/keyring': specifier: ^1.2.0 version: 1.3.0 @@ -31,7 +31,7 @@ importers: version: 8.13.0 '@workos/migrations': specifier: ^2.4.0 - version: 2.4.0 + version: 2.5.0 '@workos/openapi-spec': specifier: ^0.14.0 version: 0.14.0 @@ -49,10 +49,13 @@ importers: version: 3.3.3 hono: specifier: ^4 - version: 4.11.4 + version: 4.12.28 ink: specifier: ^6.8.0 version: 6.8.0(@types/react@19.2.17)(react@19.2.7) + jsonc-parser: + specifier: ^3.3.1 + version: 3.3.1 open: specifier: ^11.0.0 version: 11.0.0 @@ -67,7 +70,7 @@ importers: version: 13.0.2 xstate: specifier: ^5.28.0 - version: 5.32.2 + version: 5.32.4 yaml: specifier: ^2.8.2 version: 2.9.0 @@ -80,7 +83,7 @@ importers: devDependencies: '@statelyai/inspect': specifier: ^0.7.0 - version: 0.7.2(xstate@5.32.2) + version: 0.7.2(xstate@5.32.4) '@types/node': specifier: ~22.20.0 version: 22.20.0 @@ -98,10 +101,10 @@ importers: version: 17.0.35 '@vitest/coverage-v8': specifier: ^4.0.18 - version: 4.1.9(vitest@4.1.9) + version: 4.1.10(vitest@4.1.10) '@vitest/ui': specifier: ^4.0.18 - version: 4.1.9(vitest@4.1.9) + version: 4.1.10(vitest@4.1.10) dotenv: specifier: ^17.3.1 version: 17.4.2 @@ -110,19 +113,19 @@ importers: version: 0.56.0 oxlint: specifier: ^1.50.0 - version: 1.71.0 + version: 1.72.0 p-limit: specifier: ^7.3.0 version: 7.3.0 tsx: specifier: ^4.20.3 - version: 4.22.4 + version: 4.23.0 typescript: specifier: ^5.9.3 version: 5.9.3 vitest: specifier: ^4.0.18 - version: 4.1.9(@opentelemetry/api@1.9.0)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.9)(@vitest/ui@4.1.9)(msw@2.10.4(@types/node@22.20.0)(typescript@5.9.3))(vite@7.3.1(@types/node@22.20.0)(tsx@4.22.4)(yaml@2.9.0)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.10)(@vitest/ui@4.1.10)(msw@2.10.4(@types/node@22.20.0)(typescript@5.9.3))(vite@8.1.3(@types/node@22.20.0)(esbuild@0.28.1)(tsx@4.23.0)(yaml@2.9.0)) packages: @@ -130,52 +133,52 @@ packages: resolution: {integrity: sha512-3NX/MpTdroi0aKz134A6RC2Gb2iXVECN4QaAXnvCIxxIm3C3AVB1mkUe8NaaiyvOpDfsrqWhYtj+Q6a62RrTsw==} engines: {node: '>=18'} - '@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.198': - resolution: {integrity: sha512-ZmiAybQKIKcP1qEAE/vfXvfxtKxG9CnJn98QTXC5Zxiwuy7Mllx2ALXh9dfmsf0V87CGEodlZQmMgUJotNIsUw==} + '@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.201': + resolution: {integrity: sha512-8Mcb3BDyKUGfJWFFTWwt+at37lbDH3ZwVtUNPWGG1toZ75RDCJry5U4kXRvQ2xokvJQlA0E+eNp6keWe5ZH22Q==} cpu: [arm64] os: [darwin] - '@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.198': - resolution: {integrity: sha512-XwH5vgN46WSwg8aC1OagNofnJpV/G1ciEu118GEKer8ZhVkq/dvK/DqShxMkb6r1jV7u5IJ7zPXu9uKliyNJAw==} + '@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.201': + resolution: {integrity: sha512-TFR2bu0+ml3RHoMrtsgD0qDK5Oknw8kYGBV7qpQHn+IWmE96gnHhogG1LpJwpHtni08XkJIjfWk1DdlsUYtRkQ==} cpu: [x64] os: [darwin] - '@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.198': - resolution: {integrity: sha512-Q7lKVNjIrUQ2B/AR77OvRf0zeOdEjonFVaR9FYrrwtzGeEqum69WSht5nM7Y7el3wjbNi0/eV0QTUM0DlsTEfw==} + '@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.201': + resolution: {integrity: sha512-EiqbpfJIpChfkn+8Uj061Qjyw0eaRcOXtdrvVuHANyj8ZErVOr8HlH6op9PSeIUa9TX0m2+tNgKPQvOGseQckA==} cpu: [arm64] os: [linux] libc: [musl] - '@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.198': - resolution: {integrity: sha512-qmz8dxEtDIlKntU5qYe0R4aWTxTue5S7zIQknatLX7aJ6HN/nq1aCNXWn5smTH2FViBkUPPR+sCIsNwSk6AT6Q==} + '@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.201': + resolution: {integrity: sha512-mShTo3MwF0gkN4dDw78wWJiB6aBDVRkl81cnApvoBofpdyUBYgm9Gw16CCjDTgelMKeBFqN6ErJpwjI3wbP00A==} cpu: [arm64] os: [linux] libc: [glibc] - '@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.198': - resolution: {integrity: sha512-h1SrWVIMjLInYNPlf+TxXuKTOdoiOfJLBSoQG97315Z2Nh0IpBfqWExlqYTtPCgKE7q2iga31U283QfHpIDlSQ==} + '@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.201': + resolution: {integrity: sha512-IbxnzO5UCbqbm2TnzCHkSyJorAFw2isdKdIsFCTxJJjSs3ZC+v3LC1QSUiVCx0qi+CV6w3MKx6mLI11mrvhbbQ==} cpu: [x64] os: [linux] libc: [musl] - '@anthropic-ai/claude-agent-sdk-linux-x64@0.3.198': - resolution: {integrity: sha512-Zqxyz2AT1UM5WlOOoLJhLssZDgZo8rBK5ku6daveK12zp+UTJGZhGsjFghz1/ASxH08KqOTbUePNTORnPhHAEQ==} + '@anthropic-ai/claude-agent-sdk-linux-x64@0.3.201': + resolution: {integrity: sha512-jrJBrRWrSuoFKIgjyqxHqmfd6Pb3Bs5Bvakg0knXCTC4fbUXGnC9Q6u7gdDwgXohUNP6/DD+s8U7bivvvVv0dg==} cpu: [x64] os: [linux] libc: [glibc] - '@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.198': - resolution: {integrity: sha512-mjIHf1HFiRuXefewWTaNZFlTZlCaEt/xsRjc1nSTCEEpFolZayVhrDKz+O2QFVcDtPl8x8GeYSL0kiikg1DZjQ==} + '@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.201': + resolution: {integrity: sha512-UsoytRJ/037uHpb3ATrIoe+AgwTf+PwKuFLGjddHAV/11wERJs0hlrnSmcnp43kf0PFxoSNinngme96YYASmQg==} cpu: [arm64] os: [win32] - '@anthropic-ai/claude-agent-sdk-win32-x64@0.3.198': - resolution: {integrity: sha512-y3HLuCCz1kDwUrhd6OnqO+d5BUpTFSzNUsPT9kf3r1vk9HYKF+eMC9eIlcOhiW2kX491kxEvuEOfqgIkGx15cg==} + '@anthropic-ai/claude-agent-sdk-win32-x64@0.3.201': + resolution: {integrity: sha512-PhalN/0cWcqDfbx7iwoLNR2gurjTiqhBk1G6K+NRScxEcQjWuu5xKXCcdbX8ePVpT+nbEMmFEFpn2y+8V8hIdA==} cpu: [x64] os: [win32] - '@anthropic-ai/claude-agent-sdk@0.3.198': - resolution: {integrity: sha512-xt469sSCyclTPtzpLAg0Aschy665GiRMgZKabSmESbGUA5/H56HcILVOiFxclXswkeMUk2fQxfHJUY9UZfiTnA==} + '@anthropic-ai/claude-agent-sdk@0.3.201': + resolution: {integrity: sha512-InT1XLmf2QpldWdtznKDWEoGJT4p+sXh24yxbeBQ++lMJCzMrI0W27MEmmmDWx0otpa+ubdHCF5YQ6oiNt7cmg==} engines: {node: '>=18.0.0'} peerDependencies: '@anthropic-ai/sdk': '>=0.93.0' @@ -191,133 +194,68 @@ packages: zod: optional: true - '@aws-crypto/crc32@5.2.0': - resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} - engines: {node: '>=16.0.0'} - - '@aws-crypto/sha256-browser@5.2.0': - resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} - - '@aws-crypto/sha256-js@5.2.0': - resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} - engines: {node: '>=16.0.0'} - - '@aws-crypto/supports-web-crypto@5.2.0': - resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} - - '@aws-crypto/util@5.2.0': - resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} - - '@aws-sdk/client-cognito-identity-provider@3.1045.0': - resolution: {integrity: sha512-oc2nj9g24X6MEL+7ys46g2cNpdnRaL9vggOHtFSigX7WPRfQ3opzUnUYd25q+vy5kRcInCdChcWO4wGEK3XfHg==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/core@3.974.8': - resolution: {integrity: sha512-njR2qoG6ZuB0kvAS2FyICsFZJ6gmCcf2X/7JcD14sUvGDm26wiZ5BrA6LOiUxKFEF+IVe7kdroxyE00YlkiYsw==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/credential-provider-env@3.972.34': - resolution: {integrity: sha512-XT0jtf8Fw9JE6ppsQeoNnZRiG+jqRixMT1v1ZR17G60UvVdsQmTG8nbEyHuEPfMxDXEhfdARaM/XiEhca4lGHQ==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/credential-provider-http@3.972.36': - resolution: {integrity: sha512-DPoGWfy7J7RKxvbf5kOKIGQkD2ek3dbKgzKIGrnLuvZBz5myU+Im/H6pmc14QcnFbqHMqxvtWSgRDSJW3qXLQg==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/credential-provider-ini@3.972.38': - resolution: {integrity: sha512-oDzUBu2MGJFgoar05sPMCwSrhw44ASyccrHzj66vO69OZqi7I6hZZxXfuPLC8OCzW7C+sU+bI73XHij41yekgQ==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/credential-provider-login@3.972.38': - resolution: {integrity: sha512-g1NosS8qe4OF++G2UFCM5ovSkgipC7YYor5KCWatG0UoMSO5YFj9C8muePlyVmOBV/WTI16Jo3/s1NUo/o1Bww==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/credential-provider-node@3.972.39': - resolution: {integrity: sha512-HEswDQyxUtadoZ/bJsPPENHg7R0Lzym5LuMksJeHvqhCOpP+rtkDLKI4/ZChH4w3cf5kG8n6bZuI8PzajoiqMg==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/credential-provider-process@3.972.34': - resolution: {integrity: sha512-T3IFs4EVmVi1dVN5RciFnklCANSzvrQd/VuHY9ThHSQmYkTogjcGkoJEr+oNUPQZnso52183088NqysMPji1/Q==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/credential-provider-sso@3.972.38': - resolution: {integrity: sha512-5ZxG+t0+3Q3QPh8KEjX6syskhgNf7I0MN7oGioTf6Lm1NTjfP7sIcYGNsthXC2qR8vcD3edNZwCr2ovfSSWuRA==} + '@aws-sdk/client-cognito-identity-provider@3.1079.0': + resolution: {integrity: sha512-EISFwFAkHGPard4hsPxD+dGYoJFoGpWF2woa2meF0Gs6LiZ4RTeFsxDTQ0mGokBxHxt+iZ1bIlmA6zZlSDOdiQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-web-identity@3.972.38': - resolution: {integrity: sha512-lYHFF30DGI20jZcYX8cm6Ns0V7f1dDN6g/MBDLTyD/5iw+bXs3yBr2iAiHDkx4RFU5JgsnZvCHYKiRVPRdmOgw==} + '@aws-sdk/core@3.974.27': + resolution: {integrity: sha512-WRWEgIq6vx+NU6ot3VrRu4Jovj9MIObitSi6of/GV5THDDPccBhivCRNkWJutMM+m3GvdeI3l/UbGNcoOobxOA==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-host-header@3.972.10': - resolution: {integrity: sha512-IJSsIMeVQ8MMCPbuh1AbltkFhLBLXn7aejzfX5YKT/VLDHn++Dcz8886tXckE+wQssyPUhaXrJhdakO2VilRhg==} + '@aws-sdk/credential-provider-env@3.972.53': + resolution: {integrity: sha512-+KDA3uc/HZ1vIneGu5QMQb0gAXDYrm2vOE60+BJ7lS0YinMQ5i2oV4PR1A16XkF6K1IbSwjEHd1hQIIgMsK48w==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-logger@3.972.10': - resolution: {integrity: sha512-OOuGvvz1Dm20SjZo5oEBePFqxt5nf8AwkNDSyUHvD9/bfNASmstcYxFAHUowy4n6Io7mWUZ04JURZwSBvyQanQ==} + '@aws-sdk/credential-provider-http@3.972.55': + resolution: {integrity: sha512-1gBfkWY3RWeBlCoB9lIJjXMx45/54wxcgfzv6BY9otTmMrZPcNPi1v+MwZxxaCUg441NV3jsr1efnFNCXiW70g==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-recursion-detection@3.972.11': - resolution: {integrity: sha512-+zz6f79Kj9V5qFK2P+D8Ehjnw4AhphAlCAsPjUqEcInA9umtSSKMrHbSagEeOIsDNuvVrH98bjRHcyQukTrhaQ==} + '@aws-sdk/credential-provider-ini@3.972.60': + resolution: {integrity: sha512-CV2md+PXvABwRjApWGhQ0wACy9WSFIhnUGrovLcjnjBCd/46TbuivLADtkF8IWNjtCQmQ+2IagSaxqBYqXBNAQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-sdk-s3@3.972.37': - resolution: {integrity: sha512-Km7M+i8DrLArVzrid1gfxeGhYHBd3uxvE77g0s5a52zPSVosxzQBnJ0gwWb6NIp/DOk8gsBMhi7V+cpJG0ndTA==} + '@aws-sdk/credential-provider-login@3.972.59': + resolution: {integrity: sha512-JG4S9yyA1GFzJdJXqLKrUzZbyK+VDp2QIsJD7YOicJHAhqymfHpDJIok2dLnhOdVB0I37RjdC53uOwCMVS00gw==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-user-agent@3.972.38': - resolution: {integrity: sha512-iz+B29TXcAZsJpwB+AwG/TTGA5l/VnmMZ2UxtiySOZjI6gCdmviXPwdgzcmuazMy16rXoPY4mYCGe7zdNKfx5A==} + '@aws-sdk/credential-provider-node@3.972.62': + resolution: {integrity: sha512-S6Slq3Tx7bvFk5yc34XNADyZYTX2HUXvaFAnowGRQnhjBO8J/mP62Fn7lxvJwjaDyYm/7gh9h6HEHaltRyMFXw==} engines: {node: '>=20.0.0'} - '@aws-sdk/nested-clients@3.997.6': - resolution: {integrity: sha512-WBDnqatJl+kGObpfmfSxqnXeYTu3Me8wx8WCtvoxX3pfWrrTv8I4WTMSSs7PZqcRcVh8WeUKMgGFjMG+52SR1w==} + '@aws-sdk/credential-provider-process@3.972.53': + resolution: {integrity: sha512-EhfH+MQlqOMCkXIVa8MMObPzAQqwTTtxA7KhEJiyPeuNVA8PLOOUpgK7nBrgaDaGiIDLN/9LpGdaHuDjomeRTw==} engines: {node: '>=20.0.0'} - '@aws-sdk/region-config-resolver@3.972.13': - resolution: {integrity: sha512-CvJ2ZIjK/jVD/lbOpowBVElJyC1YxLTIJ13yM0AEo0t2v7swOzGjSA6lJGH+DwZXQhcjUjoYwc8bVYCX5MDr1A==} + '@aws-sdk/credential-provider-sso@3.972.59': + resolution: {integrity: sha512-h8793pOjcImx0SB+VcLONcaQQ57VAvKVuqyewQMRKqqH+CSXsG2dwOeLMUJPMxLdNvL7dXOM0ueTukyNUnu5mA==} engines: {node: '>=20.0.0'} - '@aws-sdk/signature-v4-multi-region@3.996.25': - resolution: {integrity: sha512-+CMIt3e1VzlklAECmG+DtP1sV8iKq25FuA0OKpnJ4KA0kxUtd7CgClY7/RU6VzJBQwbN4EJ9Ue6plvqx1qGadw==} + '@aws-sdk/credential-provider-web-identity@3.972.59': + resolution: {integrity: sha512-VoyO9+vl3XVmpZwn4obskrWIkrA/Jf3lSe1E3ZERlaN9u0D4YZ6+HywC3+L98QOXqZesEfedk67gRER8tK8+8w==} engines: {node: '>=20.0.0'} - '@aws-sdk/token-providers@3.1041.0': - resolution: {integrity: sha512-Th7kPI6YPtvJUcdznooXJMy+9rQWjmEF81LxaJssngBzuysK4a/x+l8kjm1zb7nYsUPbndnBdUnwng/3PLvtGw==} + '@aws-sdk/nested-clients@3.997.27': + resolution: {integrity: sha512-A8PIePF9NIIOJ/4Lg1rl9xm/+QaKkHGetq+Z9wb5B+3Da31YYXRo8n7IDMh5C+HQI5eyEmjrwkGWVdYtnLtbXQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/types@3.973.8': - resolution: {integrity: sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw==} + '@aws-sdk/signature-v4-multi-region@3.996.38': + resolution: {integrity: sha512-C379Sk+MiFZCfWZphKlMyLHKxV22OjoGM5KJjj5IJNJcOCWL4IGIpnEGzv1FQiRwhYXfq55SJMfxlqPE08JJ9g==} engines: {node: '>=20.0.0'} - '@aws-sdk/util-arn-parser@3.972.3': - resolution: {integrity: sha512-HzSD8PMFrvgi2Kserxuff5VitNq2sgf3w9qxmskKDiDTThWfVteJxuCS9JXiPIPtmCrp+7N9asfIaVhBFORllA==} + '@aws-sdk/token-providers@3.1079.0': + resolution: {integrity: sha512-cbietrLlHPhhmbnMPTuDS4Zj/KNGhY+3vVhn6dwjO6Dqzrwothzg2srtcY34T9mlICsTXn34avDoWLHSntP54A==} engines: {node: '>=20.0.0'} - '@aws-sdk/util-endpoints@3.996.8': - resolution: {integrity: sha512-oOZHcRDihk5iEe5V25NVWg45b3qEA8OpHWVdU/XQh8Zj4heVPAJqWvMphQnU7LkufmUo10EpvFPZuQMiFLJK3g==} + '@aws-sdk/types@3.973.15': + resolution: {integrity: sha512-IULn8uBV/SMtmOIANsm4WHXIOtVPBWfOWs3WGL0j/sI+KhaYehvOw0ET+9urnn8MBpiijuU/0JOpuwKOE451PQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/util-locate-window@3.965.5': - resolution: {integrity: sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==} + '@aws-sdk/xml-builder@3.972.33': + resolution: {integrity: sha512-ezbwz9WpuLctm6o7P2t2naDhVVPI5jFGrVefVybhcKGjU57VIyT46pQVO0RI2RYkUdhdj2Z9uSIlAzGZE9NW9A==} engines: {node: '>=20.0.0'} - '@aws-sdk/util-user-agent-browser@3.972.10': - resolution: {integrity: sha512-FAzqXvfEssGdSIz8ejatan0bOdx1qefBWKF/gWmVBXIP1HkS7v/wjjaqrAGGKvyihrXTXW00/2/1nTJtxpXz7g==} - - '@aws-sdk/util-user-agent-node@3.973.24': - resolution: {integrity: sha512-ZWwlkjcIp7cEL8ZfTpTAPNkwx25p7xol0xlKoWVVf22+nsjwmLcHYtTPjIV1cSpmB/b6DaK4cb1fSkvCXHgRdw==} - engines: {node: '>=20.0.0'} - peerDependencies: - aws-crt: '>=1.0.0' - peerDependenciesMeta: - aws-crt: - optional: true - - '@aws-sdk/xml-builder@3.972.22': - resolution: {integrity: sha512-PMYKKtJd70IsSG0yHrdAbxBr+ZWBKLvzFZfD3/urxgf6hXVMzuU5M+3MJ5G67RpOmLBu1fAUN65SbWuKUCOlAA==} - engines: {node: '>=20.0.0'} - - '@aws/lambda-invoke-store@0.2.4': - resolution: {integrity: sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==} + '@aws/lambda-invoke-store@0.3.0': + resolution: {integrity: sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==} engines: {node: '>=18.0.0'} '@babel/helper-string-parser@7.29.7': @@ -333,8 +271,8 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/runtime@7.28.6': - resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} engines: {node: '>=6.9.0'} '@babel/types@7.29.7': @@ -358,15 +296,22 @@ packages: resolution: {integrity: sha512-0Ty/1Gfm+Kb07sXcuESjyKfwEhSy4Ns1AgeEisHb/bDY5fWme0tTeTkU14T1Gmcs17YIjB/teiDe4uaCghbYqQ==} engines: {node: '>= 20.12.0'} + '@clack/core@1.4.3': + resolution: {integrity: sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==} + engines: {node: '>= 20.12.0'} + '@clack/prompts@1.6.0': resolution: {integrity: sha512-EYlRokl8szrP9Z25qT5aepMdBjzBvHF9ZEhzIiUBc9guz/T31EqRgvD0QSgZcpE93xiwrr+OkB4nz0BZyF6fSA==} engines: {node: '>= 20.12.0'} - '@esbuild/aix-ppc64@0.27.7': - resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] + '@emnapi/core@1.11.1': + resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} + + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} '@esbuild/aix-ppc64@0.28.1': resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} @@ -374,300 +319,150 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.27.7': - resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.28.1': resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.27.7': - resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.28.1': resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.27.7': - resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.28.1': resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.27.7': - resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.28.1': resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.27.7': - resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.28.1': resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.27.7': - resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.28.1': resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.7': - resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.28.1': resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.27.7': - resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.28.1': resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.27.7': - resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.28.1': resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.27.7': - resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.28.1': resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.27.7': - resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.28.1': resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.27.7': - resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.28.1': resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.27.7': - resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.28.1': resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.27.7': - resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.28.1': resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.27.7': - resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.28.1': resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.27.7': - resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.28.1': resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.27.7': - resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-arm64@0.28.1': resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.7': - resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.28.1': resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.27.7': - resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-arm64@0.28.1': resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.7': - resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.28.1': resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.27.7': - resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - '@esbuild/openharmony-arm64@0.28.1': resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.27.7': - resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.28.1': resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.27.7': - resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.28.1': resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.27.7': - resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.28.1': resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.27.7': - resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.28.1': resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} engines: {node: '>=18'} @@ -820,8 +615,14 @@ packages: resolution: {integrity: sha512-WrOw/bcXm0f9qHkumlT1QlArXSTWqaY9sunsDpOk+yCCorCKMxvWT/a3xko4EYHVdeZoh00yI2TydXn6eyICDA==} engines: {node: '>= 10'} - '@nodable/entities@2.1.0': - resolution: {integrity: sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==} + '@napi-rs/wasm-runtime@1.1.6': + resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@nodable/entities@2.2.0': + resolution: {integrity: sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg==} '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -848,6 +649,9 @@ packages: resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} + '@oxc-project/types@0.138.0': + resolution: {integrity: sha512-1a7ZKmrRTCoN1XMZ4L0PyyqrMnrNlLyPuOkdSX2MZg7IiIGRUyurNhAm73ptDOraoBcIordsIGKNPKUzy3ZmfA==} + '@oxfmt/binding-android-arm-eabi@0.56.0': resolution: {integrity: sha512-CSCxi7ovYojgfdPOdUb9T508HKeAdDIKeRGg7x8IZwVJrWz9gVgX7MbUnFqtQAE4QvoNo07mj2JlwnOzJw4qqA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -970,124 +774,124 @@ packages: cpu: [x64] os: [win32] - '@oxlint/binding-android-arm-eabi@1.71.0': - resolution: {integrity: sha512-ImGmd1njEg4FEJH03jhRnveEegtO3czCtfptvaHivKAZQIYATbVFBrrzbaYMYv0oJioTnxZAZVSyV+oL7W8S2g==} + '@oxlint/binding-android-arm-eabi@1.72.0': + resolution: {integrity: sha512-zhCmvn+1Mj3UchAc/90i99S0t7jJUsHmFVSPg4UWrjO8b8eaSGwscgO6QAUtvHBstkjQwBttQNswEnAF1mIQdA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxlint/binding-android-arm64@1.71.0': - resolution: {integrity: sha512-4A5BEexBrwY1YFF8Kiq/lp/wQPRG79G3BWIE1FuWaM5MvmpYSd+7ZySVcKkHdwo0UDzdQGddp6pD9mpctMqLnw==} + '@oxlint/binding-android-arm64@1.72.0': + resolution: {integrity: sha512-mtH+aY/ozv1eZoCUC2owjFAtyNBKHpJHygKeEu9zXXnQGW1Q2/qOpvx+I+Lf23+TvTz66F4iiXUbl2cGvoLPCQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxlint/binding-darwin-arm64@1.71.0': - resolution: {integrity: sha512-9wJA9GJulLwS2usU3CEisI/ESDO1n1z9eyTCvApMDrAkbJ1ve0mORgTMjcWWsKxkzkeZ2N/Gpra5IQE7x8tYgQ==} + '@oxlint/binding-darwin-arm64@1.72.0': + resolution: {integrity: sha512-EvnajNPDtfknB3ZieeOOyDTwJn9QXDiwfnF4ZDQqART6RG6hjY4WigQcZdGoK2dkB3e1vrmEzN9aYbQCUkh/gQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxlint/binding-darwin-x64@1.71.0': - resolution: {integrity: sha512-PlLCjS06V0PeJMAJwzjrExw1sYNW9Gch3JtNlcwwZDXGlTYDuwHNN89zYH8LTXFfgkVtsYvs2nv0FqrzyuFDzg==} + '@oxlint/binding-darwin-x64@1.72.0': + resolution: {integrity: sha512-ZkCdEa/G80A7vEHfeCDz/+L3m33DE73v32mDKhgOIgz8Uwf0DFcK7+uu6qC+7LEhmz5fpOe1osWKyjSNMydFIQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxlint/binding-freebsd-x64@1.71.0': - resolution: {integrity: sha512-Lhil7bWre0ncxbUoDoxfS0JzpTz17BRQKW7iwoAUY8GJ66+WwJEfYPCFJ1P0WgVZR5/O/b3Q2pENlHOjeXLOGQ==} + '@oxlint/binding-freebsd-x64@1.72.0': + resolution: {integrity: sha512-NroXv2vh+sxVY1uya/rM5pjhx1hm8BzlYpx9q67QP0Xhw5MH2bf5GJylpvLEC+781p1Xli/317EoV9AlGwViag==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxlint/binding-linux-arm-gnueabihf@1.71.0': - resolution: {integrity: sha512-Oo9/L58PYD3RC0x05d2upAPLllHytTjHQGsnC06P6Ynn7jKkp5mdImQxXdJ3+FnBaKspNpGogzgVsi6g872LiA==} + '@oxlint/binding-linux-arm-gnueabihf@1.72.0': + resolution: {integrity: sha512-0NDywYgfj279Ou/BcQuCYSj7NJwBfmWn5qc5uGO/Ny7fUWmXyIpvawqX/8acQlWG6IXelJsJhj+JAy6sjsKj0A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.71.0': - resolution: {integrity: sha512-mSHfyfgJrEbyIR29ejaeS50BdPk+GoNPlC1dckpDiUZbJAIel68sjSMdOt4WY0/gva+ECC7FNITQkxMJU+vSBw==} + '@oxlint/binding-linux-arm-musleabihf@1.72.0': + resolution: {integrity: sha512-4vpXB06h65Ezsy4hRyrGjGrfa1SkVPii09yaajiYhmVpgsFiLD+KNxIx/BNAY+XiO+i1yqp9HHdwqM8VTqa5XQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm64-gnu@1.71.0': - resolution: {integrity: sha512-n9yY4M2tiy3aij4AqtlnspzpfdpeT5JQfK2/w2d8oyp5W0FRwOb1dIeX99nORNcxGr08iD9bH8N5XFz3I2iy8w==} + '@oxlint/binding-linux-arm64-gnu@1.72.0': + resolution: {integrity: sha512-immaN4g2ZGFiOkKrvRX9LvzZdd2GkQM5wR+UyzYyUuyhUTXGQ4HKUJH18xp4G8OfhCVaVAJfKZxwE1r8+4hhaQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-arm64-musl@1.71.0': - resolution: {integrity: sha512-fJZrs5sDZtTaPIOiemRQQmo82Ezy+vOGXemPc4Ok7iVVsYsFa7SlW6Z5XN819VfsqBHRm3NJ3rTdnR8+bJYJdQ==} + '@oxlint/binding-linux-arm64-musl@1.72.0': + resolution: {integrity: sha512-JGHS9Mnr7iWyyLDxgCv1MhzVpAckgptg00F2gnxt/GD7lQ2SW1BRcxHqhSTaSdDpjWRrBkBxMMh4+Hn3aVtExg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxlint/binding-linux-ppc64-gnu@1.71.0': - resolution: {integrity: sha512-cwl7VKGERIy9p+G+AvZdfy/06q0aHXaTt/mMRReC751iuNYJgqKjB7NydXSS30nBT9vtr2tunciOtrR4fD6FUA==} + '@oxlint/binding-linux-ppc64-gnu@1.72.0': + resolution: {integrity: sha512-AOYgBZqxNshrg83P9v0RYv+m8s10Cqkj4/PxXFDhcS3k7FqsIG5+CxErshZCIN7G8iy4Y+VGfAsuEdar8AcbBg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-gnu@1.71.0': - resolution: {integrity: sha512-eZ8ieVXvzGi8jr7+ybQGPK2STw3mldfxZlgA2738iflfB/rzA69sE6m5rDRpQaxC7dpm745Enlh1Tod0QAk9Gg==} + '@oxlint/binding-linux-riscv64-gnu@1.72.0': + resolution: {integrity: sha512-QMybPS5ij3/vrKG67mqzHwW++91sYxK/PPUVi6SBtNCEzW4niS52fVBdXbQ6nou0wWbUPEpx8Sl/ZjtgE3clXA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-musl@1.71.0': - resolution: {integrity: sha512-puMDbQYe6+NXwfMusojoA7CXGn2b3utukmd23PQqc1E3XhVCwyZ+FueSMzDYeNgDV2dUfIVXAAKZBcFDeCL6sA==} + '@oxlint/binding-linux-riscv64-musl@1.72.0': + resolution: {integrity: sha512-gOc3W7JV0PXRpIL7stUlLe3Wa9Gp0Kdlup87IT3gHDvPKck2xNgMIl/Gs2lldYY2lyXZDC4rWi3hmoLUobkgbQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxlint/binding-linux-s390x-gnu@1.71.0': - resolution: {integrity: sha512-4NJLxBs1ujISCt3L/1FcywLs73PWtJuw+piD6feK2V6h6OS6P7xu9/sWt1DTRLibe6QCzmfZzmM/2HPORoV/Lg==} + '@oxlint/binding-linux-s390x-gnu@1.72.0': + resolution: {integrity: sha512-rpGxph+FjjHcYI5q6uxB3Az+tnfmEnDbSA8+PK9ZE/VzyUAkvBOMeuY7ZQMhu5mpZH7YQDsTdW6Cx4kV/msc6w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-gnu@1.71.0': - resolution: {integrity: sha512-cFDaiR8L3430qp88tfZnvFlt3KotFhR/DlbIL0nHOMMYiG/9Wy4l+6f7t8G8pTa9bd8Lt8+M0y/qjRQ/xcB74g==} + '@oxlint/binding-linux-x64-gnu@1.72.0': + resolution: {integrity: sha512-WND+uhf/Ko13SLqQMWQUgsZuLvYYEvL0ZKgg0tgGYfLqxG7l8Ju123fHDMJyYSDl5E3bUbpFUuii/OvMreFQzw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-musl@1.71.0': - resolution: {integrity: sha512-orfixdt76KlpNly9z0PkWBBNfwjKz+JFVLP/7wnVchlKNU9Dpt9InU/ZggeSej6fC7qwHmHNOGlhLnQXcYoGuA==} + '@oxlint/binding-linux-x64-musl@1.72.0': + resolution: {integrity: sha512-SrpbrUL70nG9vh6zP4/oKHWgLuHquwsr7MW9XOn0olBVgh10Uqr8qscKhQoBGEn6olK/IUpn5GSKcdQ5AjUhGA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxlint/binding-openharmony-arm64@1.71.0': - resolution: {integrity: sha512-9emQu2lAp6yhPB3XuI+++vR+l/o6JR1X+EpxwcumPdQXBWXEPAsquPGL7l158EqU8SebQMXTUa/S5zN98juyHw==} + '@oxlint/binding-openharmony-arm64@1.72.0': + resolution: {integrity: sha512-qkrsEn6NmgFKr7U/QnezQMb+q/vzAy0Dd9Y95gQGQTyjzDLN+HRZMuM5u70iyH4nBLCfKBzhjMsYCehKay2jyg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxlint/binding-win32-arm64-msvc@1.71.0': - resolution: {integrity: sha512-bd5kI8spYwTm3BILDtGhi73zoup5dw8MlPQNT8YB3BD5UIsjNe3K9/4ctrzQMX4SZMoK5HgzVLkLJzacEXB7fA==} + '@oxlint/binding-win32-arm64-msvc@1.72.0': + resolution: {integrity: sha512-LWR6ZlFZph+KPjXv8opgZsXRDCdrdQe8VL8Cg9zxCoBS73h6znzZpydVgmdnwj8mB9AuSM5jxEgDJDpQkjboeg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.71.0': - resolution: {integrity: sha512-W4HvOHGzVLHcrmFu+bMrJlho+/yrlX5ZNdJZqGe8MEldkQG+RHYhxxad9P4jvWAYFmIqUA5i9DQ8QsJqSU9GIw==} + '@oxlint/binding-win32-ia32-msvc@1.72.0': + resolution: {integrity: sha512-yt6HEh7IsHvtjRWtmeZRX134eaXKHq5Gnqlf1xBJdJl1JtdoRUEJw3nAxpZoUDS860cX/foKbztO441anVBtVQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxlint/binding-win32-x64-msvc@1.71.0': - resolution: {integrity: sha512-D2kyEIPHk/G/wiZLnwTVC/sVst+T/lKldVOjAFpgTIBUAOlry72e5OiapDbDBF4LfJLkN5ypJb/8Eu6yJzkveQ==} + '@oxlint/binding-win32-x64-msvc@1.72.0': + resolution: {integrity: sha512-b2eKFD2hX7tIwmo/cyH6TDq8vzWRZ2qNHrzoGntUTmq0h3zQh/uX3eTSHCwI8OB/ADQfJCRelLItK8BsxuucDA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -1101,286 +905,133 @@ packages: '@redocly/ajv@8.18.3': resolution: {integrity: sha512-l42u0of3hY98sN2A+M4qTX1O/KrpgGH32Hu9kP2GtHyD5Dfqq86PKFLe5dwaD8DEnNmlOlll2BAmeEtf0DaySg==} - '@redocly/config@0.49.1': - resolution: {integrity: sha512-Eid8/bDcsf2bpTJ2qZhULflf6Y/TtoUFZt0+a5XZzjZj0uA8L8EQiY/nEdBd6lZQlZsnu8/cAUhTyBebnLi0gA==} + '@redocly/config@0.50.1': + resolution: {integrity: sha512-TrdZUK50baxIjJB/y2ROOqfg35ex+GbkHPoJ40kXQXKMOjrfxfYQ9IliiaLqT5H/Y8qbajPrYQN2DLfvcMaHSw==} - '@redocly/openapi-core@2.36.0': - resolution: {integrity: sha512-u44e3yn0Zj2d59+SzMrHVj0DQZfQJm8C8uaf4MhJDAiHLHyd7adcAoRiqDD+LzkfLvgBepp20Jo6gDEIGl1mDg==} + '@redocly/openapi-core@2.37.0': + resolution: {integrity: sha512-i+q5+3ciI+KjMpcPsec1XO7V3l83g/aX1kZRmuPhJQilKMY2cBDl9M3O9r8httDK9v+V19mF3iIGcjxlJcUlrg==} engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'} - '@rollup/rollup-android-arm-eabi@4.62.2': - resolution: {integrity: sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.62.2': - resolution: {integrity: sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==} + '@rolldown/binding-android-arm64@1.1.4': + resolution: {integrity: sha512-EZLpf/8y7GXkkra90ML47kzik/GMP3EMcE9bPyHmRfxLC6z9+aW5A8poCsoxjrT5GfEcNAAvWwUHjvP1pUQkfw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.62.2': - resolution: {integrity: sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==} + '@rolldown/binding-darwin-arm64@1.1.4': + resolution: {integrity: sha512-aUi+HBvmYb7j8krl1+qJgkG8C17fO79gk3c+jPw4S8glRFc1DTija9S3EyaTSQUm5GJXYKDAsugBEhFHH2vYiQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.62.2': - resolution: {integrity: sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==} + '@rolldown/binding-darwin-x64@1.1.4': + resolution: {integrity: sha512-F7hHC3gwY11+vByKPRWqwGbeXWVgKmL+pTGCinaEhdihzBV2aQ0fvZOch9cXYUOKuKKq429HeYXOqQLc7wFCEg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.62.2': - resolution: {integrity: sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.62.2': - resolution: {integrity: sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==} + '@rolldown/binding-freebsd-x64@1.1.4': + resolution: {integrity: sha512-sI5yw+7s92SK6odiEhD5lKCBlWcpjHS5qyqpVQbZAJ0fIzEUXrmbl3DH2ybR3PZogulNJF+COLtmA8hUfvkCCQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.62.2': - resolution: {integrity: sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==} + '@rolldown/binding-linux-arm-gnueabihf@1.1.4': + resolution: {integrity: sha512-mCi0OKgEieFircrtVYmQAFGszRtMnZ6fpZAXrxanXAu7lqZcsK1E1RAaZNG0uKAnxox3B1f4EyQNnoyMfN1vAA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.62.2': - resolution: {integrity: sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==} - cpu: [arm] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-arm64-gnu@4.62.2': - resolution: {integrity: sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==} + '@rolldown/binding-linux-arm64-gnu@1.1.4': + resolution: {integrity: sha512-B9Ial3Kv5sh0SHnB1g/QWcUQCEvCF6QKGAl4zXypYj65mVI+B4AhFBwPtSN7pDrJeIx8Z7zdy4ntx+wQABom7w==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.62.2': - resolution: {integrity: sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==} + '@rolldown/binding-linux-arm64-musl@1.1.4': + resolution: {integrity: sha512-lZVym0PuHE1KZ22gmFTC15lAkrg9iTszR617oYRB/iPY1A56ywoJzVKOJBKaot5RiikCObmur6pogpse3gRcng==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.62.2': - resolution: {integrity: sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==} - cpu: [loong64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-loong64-musl@4.62.2': - resolution: {integrity: sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==} - cpu: [loong64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-ppc64-gnu@4.62.2': - resolution: {integrity: sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==} + '@rolldown/binding-linux-ppc64-gnu@1.1.4': + resolution: {integrity: sha512-t2DNiLJWNTbnEHyUzTumldML6ET4/g16467LZoDDJ3tSxGvguL5/NyC2lCsNKuyRycg9XeDQF5SSv+TNOhQEXg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.62.2': - resolution: {integrity: sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==} - cpu: [ppc64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-riscv64-gnu@4.62.2': - resolution: {integrity: sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-riscv64-musl@4.62.2': - resolution: {integrity: sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-s390x-gnu@4.62.2': - resolution: {integrity: sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==} + '@rolldown/binding-linux-s390x-gnu@1.1.4': + resolution: {integrity: sha512-0WIRnL1Uw4BvTZRLQt+PVgo6ZKTJadlC2btP+/EOXv2f/DWbY0rEgl+y834mIVwP1FkTlWVTrGGJXf12lru7EQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.62.2': - resolution: {integrity: sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==} + '@rolldown/binding-linux-x64-gnu@1.1.4': + resolution: {integrity: sha512-JWtGshGfX+oENAKonoNkqEJX+7hC8yfhi9GUyPX1VX4mdh1y5r+ZiJLR5XzAB0aoP6s/PcILsGjKq8O0mm24bw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.62.2': - resolution: {integrity: sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==} + '@rolldown/binding-linux-x64-musl@1.1.4': + resolution: {integrity: sha512-rT6yQcxUuXs4CnbofqwHRRV0iem349rLMYpTjkgQGLjrY4ado/eDzwPZPTCgTOlF6Nkp8NEv70yLMTn6qkWxsQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.62.2': - resolution: {integrity: sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.62.2': - resolution: {integrity: sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==} + '@rolldown/binding-openharmony-arm64@1.1.4': + resolution: {integrity: sha512-KXMGoboq5cyaCQjDA4GLuRiOwBQ0EyFnJoVViLeZ45/3rFItRODEr+NdsBcVpll40hhNArlm/speWGRvj08LzA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.62.2': - resolution: {integrity: sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.62.2': - resolution: {integrity: sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==} - cpu: [ia32] - os: [win32] + '@rolldown/binding-wasm32-wasi@1.1.4': + resolution: {integrity: sha512-5K83rb36oJiY7BCyE9zLZtGcPV4g5wvq+xwdO0XPIwDVZI8cyB/AUjkNXGb92/rnmezEkjMOpgY61rtwjQtFwg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] - '@rollup/rollup-win32-x64-gnu@4.62.2': - resolution: {integrity: sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==} - cpu: [x64] + '@rolldown/binding-win32-arm64-msvc@1.1.4': + resolution: {integrity: sha512-PnWBtw3TV5KOg69HQQDR0mnQuyCmSGR2pAB4DC1rPF808fgKeTUMj2EOEyKATpgiuxuR5APQmiDO7PDgEjTFSA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.62.2': - resolution: {integrity: sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==} + '@rolldown/binding-win32-x64-msvc@1.1.4': + resolution: {integrity: sha512-M1lpniBePobTfsa7Ks9a199e1akxsXn+GYBUKsEzv3YFzOm1HJAMNwKI3qr0Zq+mxwx9gOZoTdP1yXRYsZUocQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@smithy/config-resolver@4.5.1': - resolution: {integrity: sha512-abXk3LhODsvRHsk0ZS9ztrg/fZatTa9Z/z4pgx65YSLR+rY6kvUG/1IgcDKEUciR8MfdnkT5oPeHJTy/HhzDIQ==} - engines: {node: '>=18.0.0'} - - '@smithy/core@3.24.1': - resolution: {integrity: sha512-3mT7o4qQyUWttYnVK3A0Z/u3Xha3E81tXn32Tz6vjZiUXhBrkEivpw1hBYfh84iFF9CSzkBU9Y1DJ3Q6RQ231g==} - engines: {node: '>=18.0.0'} - deprecated: Deprecated due to bug in browser bundling instructions https://github.com/smithy-lang/smithy-typescript/issues/2025 - - '@smithy/credential-provider-imds@4.3.1': - resolution: {integrity: sha512-0S/acwHnqX4WrjXzhdiDRxsG2s9SC0cpPIK9nZ1R6UOHd+j7uL28+4bHu22urbLk2TVw3fkp6na/+fkUt/pLNQ==} - engines: {node: '>=18.0.0'} - - '@smithy/fetch-http-handler@5.4.1': - resolution: {integrity: sha512-r7bN6spQ+caZC8AnyvSxkRUb57zt2jhhRw3Z+2Ez8hjq6coIikDBFUUI/+CQ1xx9K6eX1Gx6wUKo4ylU66TIqw==} - engines: {node: '>=18.0.0'} - - '@smithy/hash-node@4.3.1': - resolution: {integrity: sha512-u0/zo11mg7yNneoYgTkH4sXwSmcBpbl49o4UNCtQ7hYsXxynsN25KYHmXzqi7TPk5HQL5klGnpU5koOY0O+9hw==} - engines: {node: '>=18.0.0'} - - '@smithy/invalid-dependency@4.3.1': - resolution: {integrity: sha512-cLmwtDoulyZvRepAfyV+3rx5oMvuh51dbE+6En3vGC09j3uVSRt1U4oguNu32ub3soGX0oYtBs8E7S2Q4SxTqg==} - engines: {node: '>=18.0.0'} - - '@smithy/is-array-buffer@2.2.0': - resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} - engines: {node: '>=14.0.0'} - - '@smithy/middleware-content-length@4.3.1': - resolution: {integrity: sha512-l4BUIP+wljW/Ar+0/QcGdmElI9lalrywfzNijXMBG34Z510FRzPyrDLx/blNTZOAm0C4Mvx5t/bf760CZo1ajg==} - engines: {node: '>=18.0.0'} - - '@smithy/middleware-endpoint@4.5.1': - resolution: {integrity: sha512-qtqu5TS+8Y18ZDkJoiXN5AMW1G4JAg1+xytzpsUvIR5a4EUsgd5HQg12lekEHWpm2TDUmOgg+hBaHK7dvyWdkA==} - engines: {node: '>=18.0.0'} - - '@smithy/middleware-retry@4.6.1': - resolution: {integrity: sha512-eTaQhxs0rfUuAkL2MSKrH8DTO7YCeAgrdN0B2/RAeuHmXQ+x52dk5qUBsi/jtcqe5LxItgq5AG5tI6Cp8c0sow==} - engines: {node: '>=18.0.0'} - - '@smithy/middleware-serde@4.3.1': - resolution: {integrity: sha512-t7YtUe076zWVypVmy1rX91oKi2TFJCkpfFpfMhJFpEIRPP0iL9JxjeSyFQ+1bF45JUfDzOzslUJa150WcSrBug==} - engines: {node: '>=18.0.0'} - - '@smithy/middleware-stack@4.3.1': - resolution: {integrity: sha512-1jKwiKZxCMQNqmp4uVPYA6r+MLGjEtH07gnOUdPgbnjuOIrl/0JY/ICdpQtFgeBsQ/Up01gnSv8GYEL0fb8yvg==} - engines: {node: '>=18.0.0'} - - '@smithy/node-config-provider@4.4.1': - resolution: {integrity: sha512-q7tDJEJXcaSG/8TVpu2f2l9bzxTzDM9geWmltbzsY6Hfh3yiuXXTpLIO8+zwYASPPVFaTJpdKwjSSjdoDoccgw==} - engines: {node: '>=18.0.0'} - - '@smithy/node-http-handler@4.7.1': - resolution: {integrity: sha512-BdEYko85f/ldp68uH8XEyIvo810xFk6eyPH81SRggTOApYHWA+Xu7B2EzLuHbe37WVLaUA7F1fWR3/zBeme2WA==} - engines: {node: '>=18.0.0'} - - '@smithy/property-provider@4.3.1': - resolution: {integrity: sha512-3NHoqVBhzpY2b4YBx9AqyKC4C8nnEjl5FyKuxrCjvnjinG0ODj+yg1xX360nNahT6wghYjSw1SooCt3kIdnqIA==} - engines: {node: '>=18.0.0'} - - '@smithy/protocol-http@5.4.1': - resolution: {integrity: sha512-8irPNCQgYxcSFp1aGcnDNFkTwSA+xPUaFq9V/v1+JXWu8sKr5b3cFmg2kBTkjkvypDmGeNffuNu0x5iqw1NoAw==} - engines: {node: '>=18.0.0'} - - '@smithy/shared-ini-file-loader@4.5.1': - resolution: {integrity: sha512-FKoKxVzdFPhyynFI+SPTWrgOP60fZ4l1UwukWYj4eyhpSmEI7MJ6p58hawIIt9bwp+aek9NEm8Zika7E+GEoeg==} - engines: {node: '>=18.0.0'} - - '@smithy/signature-v4@5.4.1': - resolution: {integrity: sha512-728lZZEWYWubBESrfntNslZQYDKRlJDY4dcDnYbL50+gu35pGPLblu4S0/RH/RDLF6me1M87ECHsHELGL7dA/Q==} - engines: {node: '>=18.0.0'} - - '@smithy/smithy-client@4.13.1': - resolution: {integrity: sha512-IcznNM8Qd9u1X3oflp12tkzyOB4HbT+sfYWlWiyEysgNzSHoWcHUUsTT4y1jjDjtVuuVVQbYks+g1kVd7u1eGQ==} - engines: {node: '>=18.0.0'} - - '@smithy/types@4.14.1': - resolution: {integrity: sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg==} - engines: {node: '>=18.0.0'} - - '@smithy/url-parser@4.3.1': - resolution: {integrity: sha512-tuelFlF2PZR/wogFC58NIrPOv+Zna4N1+3kA161/33D1Gbwvl6Nh4WsAsW05ZyPp0O6CMGsdbb0S2b/qVjRMCw==} - engines: {node: '>=18.0.0'} - - '@smithy/util-base64@4.4.1': - resolution: {integrity: sha512-fTHiwW2xbiRiWzfSk4IGAr3gNZCH4fuRYqt8+IuarsP/YON35576iVdePraZ6yJlFxlCL0eMec3/F7xYqoKzlg==} - engines: {node: '>=18.0.0'} + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - '@smithy/util-body-length-browser@4.3.1': - resolution: {integrity: sha512-1scg5t4nV3hV7CZs996/XHb80aDZ5YotH4NcvkW/w/rHj+cSz0aCIzwz8aUNKB4nCDPSHRCbrKoj+TvycYefmw==} + '@smithy/core@3.29.1': + resolution: {integrity: sha512-qoiY4nrk5OCu1+eIR1VB8l5DmON/oKiqrd5zZFAhXJXjJlLWQusKEW/SkBDAtGDcPaz86m9kfcE1lngU0GlM6A==} engines: {node: '>=18.0.0'} - '@smithy/util-body-length-node@4.3.1': - resolution: {integrity: sha512-VRC8MKVPKrgUYThTA7ughcKMfjW6/X92H0wXGJoda0Apw4O5xbXL0GMLz40DTWlsb5hh2iItk6+XL72uJdxYcw==} + '@smithy/credential-provider-imds@4.4.6': + resolution: {integrity: sha512-B2WQ/PV/H6Jeg3lrIq6bKUfa6Hy01mtK7CGs6lhjzHA6k4aagldH6T6eEjnzKl4HI0cJnAsxfJ19pgb5PV+CVQ==} engines: {node: '>=18.0.0'} - '@smithy/util-buffer-from@2.2.0': - resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} - engines: {node: '>=14.0.0'} - - '@smithy/util-config-provider@4.3.1': - resolution: {integrity: sha512-lw6L5GF5+W19vO6o3fZwRT2cXEG+8b2LH0b9ppjDT6nIxjUgmljEQGninx5XorylwKZZ4XLVABeroJ8oaF9RmQ==} + '@smithy/fetch-http-handler@5.6.3': + resolution: {integrity: sha512-CwCc/7SMTj45y97MUnDTbTaxvtAsiNNRm81z3abROIuMbMsC2Iy5EKfkkVdsKrz8WExQAAMx1EJapq+9j4fFTQ==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-browser@4.4.1': - resolution: {integrity: sha512-1rA7w+LjK1WJClsffC81Z/ZtjFt22QsKhBjUYEnZsGVS2nOTfOENKBzdg4SxhdwFvBCjcbpjscUfXOPwE3UHWQ==} + '@smithy/node-http-handler@4.9.3': + resolution: {integrity: sha512-qZTa4gQFUo8RM02rk6q5UVTDLNrQ1oS20LsepBzqq1QBVc/EHJ03OOUADcqMZiXHArW+Y7+OGY0BpdTwZRq/Yg==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-node@4.3.1': - resolution: {integrity: sha512-1fk1wfQHBenQD5NitVKOFgW0wsISYAFPIXGyStJWAeCtMyRhgHYvtJxBk2rwGWA0L5QX6oM6yeHSLKPFMk59ww==} + '@smithy/signature-v4@5.6.2': + resolution: {integrity: sha512-QgHflghMoPxCJ9axiCVh8KZfbC9fuP6vkXXyK//E3cq7nLaSSyyLj0GAoqVWezYeDQmXIZhmlRvLE16jsqDK6g==} engines: {node: '>=18.0.0'} - '@smithy/util-endpoints@3.5.1': - resolution: {integrity: sha512-yORYzJD5zoGbSDkAACr0dIjDiSEA3X8h8lggDENl1dkKpCG0TQIoItPBqtvuJHzFFjRXumcoH+/09xIuixGyCw==} - engines: {node: '>=18.0.0'} - - '@smithy/util-middleware@4.3.1': - resolution: {integrity: sha512-SRRMDcIgVXVhVbxviBaSZbuWuVW3jD08wv4ESV0V2oiw0Mki8TPVQ5IxwD3MvSTPg52QYsRP+JoMw5WdUdeWAg==} - engines: {node: '>=18.0.0'} - - '@smithy/util-retry@4.4.1': - resolution: {integrity: sha512-qkgWgwn1xw0GoY9Ea/B6FrYSPfHA0zyOtJkokwxZuvucRf2+2lfTut6adi4e4Y7LEAaxsFG7r6i05mtDCxbHKA==} - engines: {node: '>=18.0.0'} - - '@smithy/util-stream@4.6.1': - resolution: {integrity: sha512-GjZfEft0M0V3n2YM/LGkr5LeLd8gxHUIzW0rUz6VtTtlAq245GxHlJghvoPEjJHKTj255iHFAiA4IsIdK40Ueg==} - engines: {node: '>=18.0.0'} - - '@smithy/util-utf8@2.3.0': - resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} - engines: {node: '>=14.0.0'} - - '@smithy/util-utf8@4.3.1': - resolution: {integrity: sha512-FtRrSnriXtOs4+J8/y9SbQ1xmN71hrOsN/YJr5PQQj5nR1l7YNkGS/TEk4gr0WN7gyrUqw8/RFaYVjI18732ZA==} + '@smithy/types@4.15.1': + resolution: {integrity: sha512-x3L0XSACF6UYzKpa9biqiRMgvH5+wnFFew9Tm/grFYqgaupPwx/+ojDPpPJM8dZON3S9tjz5U+PQYsCBd1Mw5Q==} engines: {node: '>=18.0.0'} '@stablelib/base64@1.0.1': @@ -1394,6 +1045,9 @@ packages: peerDependencies: xstate: ^5.5.1 + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} + '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} @@ -1434,20 +1088,20 @@ packages: '@types/yargs@17.0.35': resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - '@vitest/coverage-v8@4.1.9': - resolution: {integrity: sha512-G9/lgqibheLVBDRuya45EbsEXTYcWoSG+TLg7i2axuzx0Eq62eXn+aWXyaVdV5vKvFSWd6ywcX8hA7la9Pvu8g==} + '@vitest/coverage-v8@4.1.10': + resolution: {integrity: sha512-IM49HmthevbgAO4anp1hwtoT9wYe59w0LR00gr+eagHE+ZJ5lK4sLPeO0ubgoJcwLk6dehU3R24N+FbEEKDc8g==} peerDependencies: - '@vitest/browser': 4.1.9 - vitest: 4.1.9 + '@vitest/browser': 4.1.10 + vitest: 4.1.10 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@4.1.9': - resolution: {integrity: sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==} + '@vitest/expect@4.1.10': + resolution: {integrity: sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==} - '@vitest/mocker@4.1.9': - resolution: {integrity: sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==} + '@vitest/mocker@4.1.10': + resolution: {integrity: sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -1457,25 +1111,25 @@ packages: vite: optional: true - '@vitest/pretty-format@4.1.9': - resolution: {integrity: sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==} + '@vitest/pretty-format@4.1.10': + resolution: {integrity: sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==} - '@vitest/runner@4.1.9': - resolution: {integrity: sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==} + '@vitest/runner@4.1.10': + resolution: {integrity: sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==} - '@vitest/snapshot@4.1.9': - resolution: {integrity: sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==} + '@vitest/snapshot@4.1.10': + resolution: {integrity: sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==} - '@vitest/spy@4.1.9': - resolution: {integrity: sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==} + '@vitest/spy@4.1.10': + resolution: {integrity: sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==} - '@vitest/ui@4.1.9': - resolution: {integrity: sha512-U/cRvtqfEPj27FI1n9cyUvi4vXXdcLhjJiI+InYKdk8hP4VrS6RXOjGL7rfFaeBc37iRKANsR6eEzIoC7lmgBQ==} + '@vitest/ui@4.1.10': + resolution: {integrity: sha512-EOUqfXHTXtpSHsyLHH40ts3Ue+hRhSGwzwzMlK0dTEOLSDYyOXLyr5JDGmHQWhN2DYI30gw6dVx3cdgM9FZl+Q==} peerDependencies: - vitest: 4.1.9 + vitest: 4.1.10 - '@vitest/utils@4.1.9': - resolution: {integrity: sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==} + '@vitest/utils@4.1.10': + resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} '@workos-inc/node@10.7.0': resolution: {integrity: sha512-rffa9znZuIv4yo+9JRxGOLTTSxh0XhOT6jlsktgqEi9MuB9V0VFHRzLd3bTpkq+J9sgrPZNGpvX4aWNfMqt5cQ==} @@ -1485,8 +1139,8 @@ packages: resolution: {integrity: sha512-NgQKHpwh8AbT4KvAsW91Y+4f4jja2IvFPQ5atcy5NUxUMVRgXzRFEee3erawfXrTmiCVqJjd9PljHySKBXmHKQ==} engines: {node: '>=20.15.0'} - '@workos/migrations@2.4.0': - resolution: {integrity: sha512-SLK2Dps1yzXY1o9sAHIlIXQfd6jmoI9yZuZQSVA4EtNzdi0Vg5L0mRop36tJqp406Y69s/TuO6evqPzcBak94Q==} + '@workos/migrations@2.5.0': + resolution: {integrity: sha512-2kBiKOf0djjQIThpi43POWy76Dkvx8fFtKvdKtMNiOk5rJqyjsX3Y3oU7JjSx+gZJTfW2YfdDXrQhPnWzdyiUw==} engines: {node: '>=22.11.0'} hasBin: true @@ -1528,10 +1182,6 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} - engines: {node: '>=12'} - ansi-regex@6.2.2: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} @@ -1548,6 +1198,9 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} + anynum@1.0.1: + resolution: {integrity: sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -1701,8 +1354,8 @@ packages: csv-parse@6.2.1: resolution: {integrity: sha512-LRLMV+UCyfMokp8Wb411duBf1gaBKJfOfBWU9eHMJ+b+cJYZsNu3AFmjJf3+yPGd59Exz1TsMjaSFyxnYB9+IQ==} - csv-stringify@6.7.0: - resolution: {integrity: sha512-UdtziYp5HuTz7e5j8Nvq+a/3HQo+2/aJZ9xntNTpmRRIg/3YYqDVgiS9fvAhtNbnyfbv2ZBe0bqCHqzhE7FqWQ==} + csv-stringify@6.8.1: + resolution: {integrity: sha512-tZ6X6TKQyQgCo5OptXcyAbfN1pwmoxEqELPQ7KFazNErx7kiVsDK8o+VYRXhfMl4N9vvOOLXuioquR2MeP847A==} data-uri-to-buffer@4.0.1: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} @@ -1733,6 +1386,10 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + diff@8.0.4: resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} engines: {node: '>=0.3.1'} @@ -1751,8 +1408,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - emoji-regex@10.4.0: - resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1773,8 +1430,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@2.2.0: - resolution: {integrity: sha512-3lGxdTXCLfe1MYfTz1y2ksAAUM4NAOP6rPEjxGJVKO7TZ5+tvHCaQWGpC4Y3IXvW3ece0Cz1cIP4FWBxOnGCTQ==} + es-module-lexer@2.3.0: + resolution: {integrity: sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==} es-object-atoms@1.1.2: resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} @@ -1783,11 +1440,6 @@ packages: es-toolkit@1.44.0: resolution: {integrity: sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==} - esbuild@0.27.7: - resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.28.1: resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} engines: {node: '>=18'} @@ -1868,19 +1520,15 @@ packages: fast-wrap-ansi@0.2.2: resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} - fast-xml-builder@1.2.0: - resolution: {integrity: sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==} - - fast-xml-parser@5.7.2: - resolution: {integrity: sha512-P7oW7tLbYnhOLQk/Gv7cZgzgMPP/XN03K02/Jy6Y/NHzyIAIpxuZIM/YqAkfiXFPxA2CTm7NtCijK9EDu09u2w==} - hasBin: true + fast-xml-builder@1.2.1: + resolution: {integrity: sha512-tPb5TTWfgfVx5BNSi2xV0eLr89POeXXn0dXIsCJ9m1narrWxeIyx6je9d7Rce/3NyXLbvuQmLkxq+RuxMWejvw==} - fast-xml-parser@5.8.0: - resolution: {integrity: sha512-6bIM7fsJxeo3uXv7OncQYsBAMPJ7V16Slahl/6M98C/i2q+vB1+4a0MtrvYwDFEUrwDSbAmeLDRXsOBwrL7yAg==} + fast-xml-parser@5.9.3: + resolution: {integrity: sha512-brCNCeScma/kqa54J4PIDriSSSLssRkuYaUCpvHJulGc3HGI/xxKUCTDcYkAdqJsyb//ydpbxecjC3hB9+tb/g==} hasBin: true - fastq@1.19.0: - resolution: {integrity: sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==} + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} @@ -1929,8 +1577,8 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - gaxios@7.1.5: - resolution: {integrity: sha512-5FZy72Rh8LhtjmvDrKkI+lVhrsQrVKVsItxMoDm5mNQE+xR0WVIIs+jzPSJgBvKVsLi24fZhXJIsNI0bihDzFg==} + gaxios@7.1.6: + resolution: {integrity: sha512-aIQ0QL8Or8vsUhHyXGA6AohOFRrAAiHhrvsAG6myzcSlfhxSXtnwXA/pRuQTilFgjhLe30swK5rg1d7E1f8Izw==} engines: {node: '>=18'} gcp-metadata@8.1.2: @@ -1949,6 +1597,10 @@ packages: resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} engines: {node: '>=18'} + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} + engines: {node: '>=18'} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -1992,12 +1644,8 @@ packages: headers-polyfill@4.0.3: resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} - hono@4.11.4: - resolution: {integrity: sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==} - engines: {node: '>=16.9.0'} - - hono@4.12.27: - resolution: {integrity: sha512-1yrb/+w6HWQJrUCLkJ2IF5jNIPvvFkblV5RNOYl6bV+OA6p9GLcMpHFFGTosSvHvcAUibuUukRqhlYI4z32C7Q==} + hono@4.12.28: + resolution: {integrity: sha512-YwUvVpSF7m1yOblFPrU3Hbo8XhPheBoiyfGuII6z19LnOr6JpDnyyp7LFNrfV56wS8tpvtBFGRISHN02pDdLOA==} engines: {node: '>=16.9.0'} html-escaper@2.0.2: @@ -2011,8 +1659,8 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} engines: {node: '>=0.10.0'} indent-string@5.0.0: @@ -2092,6 +1740,9 @@ packages: is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-unsafe@1.0.1: + resolution: {integrity: sha512-CLK2+VdgERgD96EYm5lUQssZYlRg2tkZnbsxZoacmSiRxiFJ4Nk4SzjCl+Ur+v3kXIY9dTIdb3IH22y1mZ56LA==} + is-what@4.1.16: resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} engines: {node: '>=12.13'} @@ -2155,6 +1806,9 @@ packages: json-schema-typed@8.0.2: resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + jwa@2.0.1: resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} @@ -2165,6 +1819,80 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -2265,6 +1993,9 @@ packages: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + obug@2.1.3: resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} engines: {node: '>=12.20.0'} @@ -2305,8 +2036,8 @@ packages: vite-plus: optional: true - oxlint@1.71.0: - resolution: {integrity: sha512-U1m1X+C0vDj7DC1e13IoZULzEcPczE7UOMTs8VlZGHUEIUaSTZKo5qkPsQEfzpgnQ29Pea/w3Xntk62UCecxZw==} + oxlint@1.72.0: + resolution: {integrity: sha512-1rhdZIP/EvoI91ABIwNU5Q8+bWf8mjrS5UzIOZld4d4bXxJvtlUhlQvaoTogIGin/qdErMOrwaIJvCSIAKTLhA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -2333,8 +2064,8 @@ packages: resolution: {integrity: sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - path-expression-matcher@1.5.0: - resolution: {integrity: sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==} + path-expression-matcher@1.6.1: + resolution: {integrity: sha512-h7bxdzhHk8Knyc4Tj+jMaa7fEEoUJy7p1qtbVgkYg1Uhpe5Np5VuGXCRZnkZvU+Q42M1vStt0ifa3ueykRJPmQ==} engines: {node: '>=14.0.0'} path-key@3.1.1: @@ -2361,6 +2092,10 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} + engines: {node: '>=12'} + pkce-challenge@5.0.1: resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} engines: {node: '>=16.20.0'} @@ -2435,13 +2170,13 @@ packages: resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rollup@4.62.2: - resolution: {integrity: sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} + rolldown@1.1.4: + resolution: {integrity: sha512-IjZYiLxZwpnhwhdBH2ugdTGVSdhCQUmLxLoqyjiL0JxYjyRst+5a0P3xfrTxJ5F638j4Mvvw5FAX5XE6eHpXbA==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true router@2.2.0: @@ -2569,20 +2304,20 @@ packages: resolution: {integrity: sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==} engines: {node: '>=20'} + string-width@8.2.1: + resolution: {integrity: sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==} + engines: {node: '>=20'} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} - strip-ansi@7.2.0: resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} - strnum@2.3.0: - resolution: {integrity: sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==} + strnum@2.4.1: + resolution: {integrity: sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg==} superjson@1.13.3: resolution: {integrity: sha512-mJiVjfd2vokfDxsQPOwJ/PtanO87LhpYY88ubI5dUB1Ab58Txbyje3+jpm+/83R/fevaq/107NNhtYBLuoTrFg==} @@ -2729,8 +2464,8 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsx@4.22.4: - resolution: {integrity: sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==} + tsx@4.23.0: + resolution: {integrity: sha512-eUdUIaCr963q2h5u3+QwvYp0+eqPvn+egeqZUm0hwERCqqx1E3kK5ehbGCvqSE5MQAULr67ww0cA3jKc3YkM1w==} engines: {node: '>=18.0.0'} hasBin: true @@ -2778,15 +2513,16 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + vite@8.1.3: + resolution: {integrity: sha512-Ds+gBRbj0lwRO2Y5hwnUBdxSwlAve9LeRyU4sNnAr0ewW0gWF0n5bgXgUzbgZ49MV9BVUAQUFYVcDUcilUExMA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.3.0 + esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' less: ^4.0.0 - lightningcss: ^1.21.0 sass: ^1.70.0 sass-embedded: ^1.70.0 stylus: '>=0.54.8' @@ -2797,12 +2533,14 @@ packages: peerDependenciesMeta: '@types/node': optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true jiti: optional: true less: optional: true - lightningcss: - optional: true sass: optional: true sass-embedded: @@ -2818,20 +2556,20 @@ packages: yaml: optional: true - vitest@4.1.9: - resolution: {integrity: sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==} + vitest@4.1.10: + resolution: {integrity: sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.9 - '@vitest/browser-preview': 4.1.9 - '@vitest/browser-webdriverio': 4.1.9 - '@vitest/coverage-istanbul': 4.1.9 - '@vitest/coverage-v8': 4.1.9 - '@vitest/ui': 4.1.9 + '@vitest/browser-playwright': 4.1.10 + '@vitest/browser-preview': 4.1.10 + '@vitest/browser-webdriverio': 4.1.10 + '@vitest/coverage-istanbul': 4.1.10 + '@vitest/coverage-v8': 4.1.10 + '@vitest/ui': 4.1.10 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -2889,6 +2627,10 @@ packages: resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} engines: {node: '>=18'} + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -2924,8 +2666,8 @@ packages: resolution: {integrity: sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==} engines: {node: '>=16.0.0'} - xstate@5.32.2: - resolution: {integrity: sha512-uDrojEQYYb4cEeB/SpKDBQlnL2969N5ltmVak4jUMUC6VVRuhi7PCnTBxe4YlQ8YLzdaOEOuVR48CRQPE2o0Uw==} + xstate@5.32.4: + resolution: {integrity: sha512-E5WtDB8DBs2ZWliz2Ry9XfbSZTbBRcK/cwefBot04qQ/L5SLP16xpnTDU4/ZFXuXFhNxi7JP2RhuoGwBnM+S4A==} y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} @@ -2978,419 +2720,199 @@ snapshots: '@alcalzone/ansi-tokenize@0.2.5': dependencies: - ansi-styles: 6.2.1 + ansi-styles: 6.2.3 is-fullwidth-code-point: 5.1.0 - '@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.198': + '@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.201': optional: true - '@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.198': + '@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.201': optional: true - '@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.198': + '@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.201': optional: true - '@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.198': + '@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.201': optional: true - '@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.198': + '@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.201': optional: true - '@anthropic-ai/claude-agent-sdk-linux-x64@0.3.198': + '@anthropic-ai/claude-agent-sdk-linux-x64@0.3.201': optional: true - '@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.198': + '@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.201': optional: true - '@anthropic-ai/claude-agent-sdk-win32-x64@0.3.198': + '@anthropic-ai/claude-agent-sdk-win32-x64@0.3.201': optional: true - '@anthropic-ai/claude-agent-sdk@0.3.198(@anthropic-ai/sdk@0.106.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(zod@4.4.3)': + '@anthropic-ai/claude-agent-sdk@0.3.201(@anthropic-ai/sdk@0.106.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(zod@4.4.3)': dependencies: '@anthropic-ai/sdk': 0.106.0(zod@4.4.3) '@modelcontextprotocol/sdk': 1.29.0(zod@4.4.3) zod: 4.4.3 optionalDependencies: - '@anthropic-ai/claude-agent-sdk-darwin-arm64': 0.3.198 - '@anthropic-ai/claude-agent-sdk-darwin-x64': 0.3.198 - '@anthropic-ai/claude-agent-sdk-linux-arm64': 0.3.198 - '@anthropic-ai/claude-agent-sdk-linux-arm64-musl': 0.3.198 - '@anthropic-ai/claude-agent-sdk-linux-x64': 0.3.198 - '@anthropic-ai/claude-agent-sdk-linux-x64-musl': 0.3.198 - '@anthropic-ai/claude-agent-sdk-win32-arm64': 0.3.198 - '@anthropic-ai/claude-agent-sdk-win32-x64': 0.3.198 + '@anthropic-ai/claude-agent-sdk-darwin-arm64': 0.3.201 + '@anthropic-ai/claude-agent-sdk-darwin-x64': 0.3.201 + '@anthropic-ai/claude-agent-sdk-linux-arm64': 0.3.201 + '@anthropic-ai/claude-agent-sdk-linux-arm64-musl': 0.3.201 + '@anthropic-ai/claude-agent-sdk-linux-x64': 0.3.201 + '@anthropic-ai/claude-agent-sdk-linux-x64-musl': 0.3.201 + '@anthropic-ai/claude-agent-sdk-win32-arm64': 0.3.201 + '@anthropic-ai/claude-agent-sdk-win32-x64': 0.3.201 '@anthropic-ai/sdk@0.106.0(zod@4.4.3)': dependencies: json-schema-to-ts: 3.1.1 standardwebhooks: 1.0.0 - optionalDependencies: - zod: 4.4.3 - - '@aws-crypto/crc32@5.2.0': - dependencies: - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.973.8 - tslib: 2.8.1 - - '@aws-crypto/sha256-browser@5.2.0': - dependencies: - '@aws-crypto/sha256-js': 5.2.0 - '@aws-crypto/supports-web-crypto': 5.2.0 - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.973.8 - '@aws-sdk/util-locate-window': 3.965.5 - '@smithy/util-utf8': 2.3.0 - tslib: 2.8.1 - - '@aws-crypto/sha256-js@5.2.0': - dependencies: - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.973.8 - tslib: 2.8.1 - - '@aws-crypto/supports-web-crypto@5.2.0': - dependencies: - tslib: 2.8.1 - - '@aws-crypto/util@5.2.0': - dependencies: - '@aws-sdk/types': 3.973.8 - '@smithy/util-utf8': 2.3.0 - tslib: 2.8.1 - - '@aws-sdk/client-cognito-identity-provider@3.1045.0': - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.974.8 - '@aws-sdk/credential-provider-node': 3.972.39 - '@aws-sdk/middleware-host-header': 3.972.10 - '@aws-sdk/middleware-logger': 3.972.10 - '@aws-sdk/middleware-recursion-detection': 3.972.11 - '@aws-sdk/middleware-user-agent': 3.972.38 - '@aws-sdk/region-config-resolver': 3.972.13 - '@aws-sdk/types': 3.973.8 - '@aws-sdk/util-endpoints': 3.996.8 - '@aws-sdk/util-user-agent-browser': 3.972.10 - '@aws-sdk/util-user-agent-node': 3.973.24 - '@smithy/config-resolver': 4.5.1 - '@smithy/core': 3.24.1 - '@smithy/fetch-http-handler': 5.4.1 - '@smithy/hash-node': 4.3.1 - '@smithy/invalid-dependency': 4.3.1 - '@smithy/middleware-content-length': 4.3.1 - '@smithy/middleware-endpoint': 4.5.1 - '@smithy/middleware-retry': 4.6.1 - '@smithy/middleware-serde': 4.3.1 - '@smithy/middleware-stack': 4.3.1 - '@smithy/node-config-provider': 4.4.1 - '@smithy/node-http-handler': 4.7.1 - '@smithy/protocol-http': 5.4.1 - '@smithy/smithy-client': 4.13.1 - '@smithy/types': 4.14.1 - '@smithy/url-parser': 4.3.1 - '@smithy/util-base64': 4.4.1 - '@smithy/util-body-length-browser': 4.3.1 - '@smithy/util-body-length-node': 4.3.1 - '@smithy/util-defaults-mode-browser': 4.4.1 - '@smithy/util-defaults-mode-node': 4.3.1 - '@smithy/util-endpoints': 3.5.1 - '@smithy/util-middleware': 4.3.1 - '@smithy/util-retry': 4.4.1 - '@smithy/util-utf8': 4.3.1 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/core@3.974.8': - dependencies: - '@aws-sdk/types': 3.973.8 - '@aws-sdk/xml-builder': 3.972.22 - '@smithy/core': 3.24.1 - '@smithy/node-config-provider': 4.4.1 - '@smithy/property-provider': 4.3.1 - '@smithy/protocol-http': 5.4.1 - '@smithy/signature-v4': 5.4.1 - '@smithy/smithy-client': 4.13.1 - '@smithy/types': 4.14.1 - '@smithy/util-base64': 4.4.1 - '@smithy/util-middleware': 4.3.1 - '@smithy/util-retry': 4.4.1 - '@smithy/util-utf8': 4.3.1 - tslib: 2.8.1 - - '@aws-sdk/credential-provider-env@3.972.34': - dependencies: - '@aws-sdk/core': 3.974.8 - '@aws-sdk/types': 3.973.8 - '@smithy/property-provider': 4.3.1 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - - '@aws-sdk/credential-provider-http@3.972.36': - dependencies: - '@aws-sdk/core': 3.974.8 - '@aws-sdk/types': 3.973.8 - '@smithy/fetch-http-handler': 5.4.1 - '@smithy/node-http-handler': 4.7.1 - '@smithy/property-provider': 4.3.1 - '@smithy/protocol-http': 5.4.1 - '@smithy/smithy-client': 4.13.1 - '@smithy/types': 4.14.1 - '@smithy/util-stream': 4.6.1 - tslib: 2.8.1 - - '@aws-sdk/credential-provider-ini@3.972.38': - dependencies: - '@aws-sdk/core': 3.974.8 - '@aws-sdk/credential-provider-env': 3.972.34 - '@aws-sdk/credential-provider-http': 3.972.36 - '@aws-sdk/credential-provider-login': 3.972.38 - '@aws-sdk/credential-provider-process': 3.972.34 - '@aws-sdk/credential-provider-sso': 3.972.38 - '@aws-sdk/credential-provider-web-identity': 3.972.38 - '@aws-sdk/nested-clients': 3.997.6 - '@aws-sdk/types': 3.973.8 - '@smithy/credential-provider-imds': 4.3.1 - '@smithy/property-provider': 4.3.1 - '@smithy/shared-ini-file-loader': 4.5.1 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/credential-provider-login@3.972.38': - dependencies: - '@aws-sdk/core': 3.974.8 - '@aws-sdk/nested-clients': 3.997.6 - '@aws-sdk/types': 3.973.8 - '@smithy/property-provider': 4.3.1 - '@smithy/protocol-http': 5.4.1 - '@smithy/shared-ini-file-loader': 4.5.1 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/credential-provider-node@3.972.39': - dependencies: - '@aws-sdk/credential-provider-env': 3.972.34 - '@aws-sdk/credential-provider-http': 3.972.36 - '@aws-sdk/credential-provider-ini': 3.972.38 - '@aws-sdk/credential-provider-process': 3.972.34 - '@aws-sdk/credential-provider-sso': 3.972.38 - '@aws-sdk/credential-provider-web-identity': 3.972.38 - '@aws-sdk/types': 3.973.8 - '@smithy/credential-provider-imds': 4.3.1 - '@smithy/property-provider': 4.3.1 - '@smithy/shared-ini-file-loader': 4.5.1 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/credential-provider-process@3.972.34': - dependencies: - '@aws-sdk/core': 3.974.8 - '@aws-sdk/types': 3.973.8 - '@smithy/property-provider': 4.3.1 - '@smithy/shared-ini-file-loader': 4.5.1 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - - '@aws-sdk/credential-provider-sso@3.972.38': - dependencies: - '@aws-sdk/core': 3.974.8 - '@aws-sdk/nested-clients': 3.997.6 - '@aws-sdk/token-providers': 3.1041.0 - '@aws-sdk/types': 3.973.8 - '@smithy/property-provider': 4.3.1 - '@smithy/shared-ini-file-loader': 4.5.1 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/credential-provider-web-identity@3.972.38': - dependencies: - '@aws-sdk/core': 3.974.8 - '@aws-sdk/nested-clients': 3.997.6 - '@aws-sdk/types': 3.973.8 - '@smithy/property-provider': 4.3.1 - '@smithy/shared-ini-file-loader': 4.5.1 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt + optionalDependencies: + zod: 4.4.3 - '@aws-sdk/middleware-host-header@3.972.10': + '@aws-sdk/client-cognito-identity-provider@3.1079.0': dependencies: - '@aws-sdk/types': 3.973.8 - '@smithy/protocol-http': 5.4.1 - '@smithy/types': 4.14.1 + '@aws-sdk/core': 3.974.27 + '@aws-sdk/credential-provider-node': 3.972.62 + '@aws-sdk/types': 3.973.15 + '@smithy/core': 3.29.1 + '@smithy/fetch-http-handler': 5.6.3 + '@smithy/node-http-handler': 4.9.3 + '@smithy/types': 4.15.1 tslib: 2.8.1 - '@aws-sdk/middleware-logger@3.972.10': + '@aws-sdk/core@3.974.27': dependencies: - '@aws-sdk/types': 3.973.8 - '@smithy/types': 4.14.1 + '@aws-sdk/types': 3.973.15 + '@aws-sdk/xml-builder': 3.972.33 + '@aws/lambda-invoke-store': 0.3.0 + '@smithy/core': 3.29.1 + '@smithy/signature-v4': 5.6.2 + '@smithy/types': 4.15.1 + bowser: 2.14.1 tslib: 2.8.1 - '@aws-sdk/middleware-recursion-detection@3.972.11': + '@aws-sdk/credential-provider-env@3.972.53': dependencies: - '@aws-sdk/types': 3.973.8 - '@aws/lambda-invoke-store': 0.2.4 - '@smithy/protocol-http': 5.4.1 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - - '@aws-sdk/middleware-sdk-s3@3.972.37': - dependencies: - '@aws-sdk/core': 3.974.8 - '@aws-sdk/types': 3.973.8 - '@aws-sdk/util-arn-parser': 3.972.3 - '@smithy/core': 3.24.1 - '@smithy/node-config-provider': 4.4.1 - '@smithy/protocol-http': 5.4.1 - '@smithy/signature-v4': 5.4.1 - '@smithy/smithy-client': 4.13.1 - '@smithy/types': 4.14.1 - '@smithy/util-config-provider': 4.3.1 - '@smithy/util-middleware': 4.3.1 - '@smithy/util-stream': 4.6.1 - '@smithy/util-utf8': 4.3.1 + '@aws-sdk/core': 3.974.27 + '@aws-sdk/types': 3.973.15 + '@smithy/core': 3.29.1 + '@smithy/types': 4.15.1 tslib: 2.8.1 - '@aws-sdk/middleware-user-agent@3.972.38': + '@aws-sdk/credential-provider-http@3.972.55': dependencies: - '@aws-sdk/core': 3.974.8 - '@aws-sdk/types': 3.973.8 - '@aws-sdk/util-endpoints': 3.996.8 - '@smithy/core': 3.24.1 - '@smithy/protocol-http': 5.4.1 - '@smithy/types': 4.14.1 - '@smithy/util-retry': 4.4.1 + '@aws-sdk/core': 3.974.27 + '@aws-sdk/types': 3.973.15 + '@smithy/core': 3.29.1 + '@smithy/fetch-http-handler': 5.6.3 + '@smithy/node-http-handler': 4.9.3 + '@smithy/types': 4.15.1 tslib: 2.8.1 - '@aws-sdk/nested-clients@3.997.6': - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.974.8 - '@aws-sdk/middleware-host-header': 3.972.10 - '@aws-sdk/middleware-logger': 3.972.10 - '@aws-sdk/middleware-recursion-detection': 3.972.11 - '@aws-sdk/middleware-user-agent': 3.972.38 - '@aws-sdk/region-config-resolver': 3.972.13 - '@aws-sdk/signature-v4-multi-region': 3.996.25 - '@aws-sdk/types': 3.973.8 - '@aws-sdk/util-endpoints': 3.996.8 - '@aws-sdk/util-user-agent-browser': 3.972.10 - '@aws-sdk/util-user-agent-node': 3.973.24 - '@smithy/config-resolver': 4.5.1 - '@smithy/core': 3.24.1 - '@smithy/fetch-http-handler': 5.4.1 - '@smithy/hash-node': 4.3.1 - '@smithy/invalid-dependency': 4.3.1 - '@smithy/middleware-content-length': 4.3.1 - '@smithy/middleware-endpoint': 4.5.1 - '@smithy/middleware-retry': 4.6.1 - '@smithy/middleware-serde': 4.3.1 - '@smithy/middleware-stack': 4.3.1 - '@smithy/node-config-provider': 4.4.1 - '@smithy/node-http-handler': 4.7.1 - '@smithy/protocol-http': 5.4.1 - '@smithy/smithy-client': 4.13.1 - '@smithy/types': 4.14.1 - '@smithy/url-parser': 4.3.1 - '@smithy/util-base64': 4.4.1 - '@smithy/util-body-length-browser': 4.3.1 - '@smithy/util-body-length-node': 4.3.1 - '@smithy/util-defaults-mode-browser': 4.4.1 - '@smithy/util-defaults-mode-node': 4.3.1 - '@smithy/util-endpoints': 3.5.1 - '@smithy/util-middleware': 4.3.1 - '@smithy/util-retry': 4.4.1 - '@smithy/util-utf8': 4.3.1 + '@aws-sdk/credential-provider-ini@3.972.60': + dependencies: + '@aws-sdk/core': 3.974.27 + '@aws-sdk/credential-provider-env': 3.972.53 + '@aws-sdk/credential-provider-http': 3.972.55 + '@aws-sdk/credential-provider-login': 3.972.59 + '@aws-sdk/credential-provider-process': 3.972.53 + '@aws-sdk/credential-provider-sso': 3.972.59 + '@aws-sdk/credential-provider-web-identity': 3.972.59 + '@aws-sdk/nested-clients': 3.997.27 + '@aws-sdk/types': 3.973.15 + '@smithy/core': 3.29.1 + '@smithy/credential-provider-imds': 4.4.6 + '@smithy/types': 4.15.1 tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/region-config-resolver@3.972.13': + '@aws-sdk/credential-provider-login@3.972.59': dependencies: - '@aws-sdk/types': 3.973.8 - '@smithy/config-resolver': 4.5.1 - '@smithy/node-config-provider': 4.4.1 - '@smithy/types': 4.14.1 + '@aws-sdk/core': 3.974.27 + '@aws-sdk/nested-clients': 3.997.27 + '@aws-sdk/types': 3.973.15 + '@smithy/core': 3.29.1 + '@smithy/types': 4.15.1 tslib: 2.8.1 - '@aws-sdk/signature-v4-multi-region@3.996.25': - dependencies: - '@aws-sdk/middleware-sdk-s3': 3.972.37 - '@aws-sdk/types': 3.973.8 - '@smithy/protocol-http': 5.4.1 - '@smithy/signature-v4': 5.4.1 - '@smithy/types': 4.14.1 + '@aws-sdk/credential-provider-node@3.972.62': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.53 + '@aws-sdk/credential-provider-http': 3.972.55 + '@aws-sdk/credential-provider-ini': 3.972.60 + '@aws-sdk/credential-provider-process': 3.972.53 + '@aws-sdk/credential-provider-sso': 3.972.59 + '@aws-sdk/credential-provider-web-identity': 3.972.59 + '@aws-sdk/types': 3.973.15 + '@smithy/core': 3.29.1 + '@smithy/credential-provider-imds': 4.4.6 + '@smithy/types': 4.15.1 tslib: 2.8.1 - '@aws-sdk/token-providers@3.1041.0': + '@aws-sdk/credential-provider-process@3.972.53': dependencies: - '@aws-sdk/core': 3.974.8 - '@aws-sdk/nested-clients': 3.997.6 - '@aws-sdk/types': 3.973.8 - '@smithy/property-provider': 4.3.1 - '@smithy/shared-ini-file-loader': 4.5.1 - '@smithy/types': 4.14.1 + '@aws-sdk/core': 3.974.27 + '@aws-sdk/types': 3.973.15 + '@smithy/core': 3.29.1 + '@smithy/types': 4.15.1 tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/types@3.973.8': + '@aws-sdk/credential-provider-sso@3.972.59': dependencies: - '@smithy/types': 4.14.1 + '@aws-sdk/core': 3.974.27 + '@aws-sdk/nested-clients': 3.997.27 + '@aws-sdk/token-providers': 3.1079.0 + '@aws-sdk/types': 3.973.15 + '@smithy/core': 3.29.1 + '@smithy/types': 4.15.1 tslib: 2.8.1 - '@aws-sdk/util-arn-parser@3.972.3': + '@aws-sdk/credential-provider-web-identity@3.972.59': dependencies: + '@aws-sdk/core': 3.974.27 + '@aws-sdk/nested-clients': 3.997.27 + '@aws-sdk/types': 3.973.15 + '@smithy/core': 3.29.1 + '@smithy/types': 4.15.1 tslib: 2.8.1 - '@aws-sdk/util-endpoints@3.996.8': + '@aws-sdk/nested-clients@3.997.27': dependencies: - '@aws-sdk/types': 3.973.8 - '@smithy/types': 4.14.1 - '@smithy/url-parser': 4.3.1 - '@smithy/util-endpoints': 3.5.1 + '@aws-sdk/core': 3.974.27 + '@aws-sdk/signature-v4-multi-region': 3.996.38 + '@aws-sdk/types': 3.973.15 + '@smithy/core': 3.29.1 + '@smithy/fetch-http-handler': 5.6.3 + '@smithy/node-http-handler': 4.9.3 + '@smithy/types': 4.15.1 tslib: 2.8.1 - '@aws-sdk/util-locate-window@3.965.5': + '@aws-sdk/signature-v4-multi-region@3.996.38': dependencies: + '@aws-sdk/types': 3.973.15 + '@smithy/signature-v4': 5.6.2 + '@smithy/types': 4.15.1 tslib: 2.8.1 - '@aws-sdk/util-user-agent-browser@3.972.10': + '@aws-sdk/token-providers@3.1079.0': dependencies: - '@aws-sdk/types': 3.973.8 - '@smithy/types': 4.14.1 - bowser: 2.14.1 + '@aws-sdk/core': 3.974.27 + '@aws-sdk/nested-clients': 3.997.27 + '@aws-sdk/types': 3.973.15 + '@smithy/core': 3.29.1 + '@smithy/types': 4.15.1 tslib: 2.8.1 - '@aws-sdk/util-user-agent-node@3.973.24': + '@aws-sdk/types@3.973.15': dependencies: - '@aws-sdk/middleware-user-agent': 3.972.38 - '@aws-sdk/types': 3.973.8 - '@smithy/node-config-provider': 4.4.1 - '@smithy/types': 4.14.1 - '@smithy/util-config-provider': 4.3.1 + '@smithy/types': 4.15.1 tslib: 2.8.1 - '@aws-sdk/xml-builder@3.972.22': + '@aws-sdk/xml-builder@3.972.33': dependencies: - '@nodable/entities': 2.1.0 - '@smithy/types': 4.14.1 - fast-xml-parser: 5.7.2 + '@smithy/types': 4.15.1 tslib: 2.8.1 - '@aws/lambda-invoke-store@0.2.4': {} + '@aws/lambda-invoke-store@0.3.0': {} '@babel/helper-string-parser@7.29.7': {} @@ -3400,7 +2922,7 @@ snapshots: dependencies: '@babel/types': 7.29.7 - '@babel/runtime@7.28.6': {} + '@babel/runtime@7.29.7': {} '@babel/types@7.29.7': dependencies: @@ -3430,6 +2952,11 @@ snapshots: fast-wrap-ansi: 0.2.2 sisteransi: 1.0.5 + '@clack/core@1.4.3': + dependencies: + fast-wrap-ansi: 0.2.2 + sisteransi: 1.0.5 + '@clack/prompts@1.6.0': dependencies: '@clack/core': 1.4.2 @@ -3437,169 +2964,103 @@ snapshots: fast-wrap-ansi: 0.2.2 sisteransi: 1.0.5 - '@esbuild/aix-ppc64@0.27.7': + '@emnapi/core@1.11.1': + dependencies: + '@emnapi/wasi-threads': 1.2.2 + tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.28.1': + '@emnapi/runtime@1.11.1': + dependencies: + tslib: 2.8.1 optional: true - '@esbuild/android-arm64@0.27.7': + '@emnapi/wasi-threads@1.2.2': + dependencies: + tslib: 2.8.1 optional: true - '@esbuild/android-arm64@0.28.1': + '@esbuild/aix-ppc64@0.28.1': optional: true - '@esbuild/android-arm@0.27.7': + '@esbuild/android-arm64@0.28.1': optional: true '@esbuild/android-arm@0.28.1': optional: true - '@esbuild/android-x64@0.27.7': - optional: true - '@esbuild/android-x64@0.28.1': optional: true - '@esbuild/darwin-arm64@0.27.7': - optional: true - '@esbuild/darwin-arm64@0.28.1': optional: true - '@esbuild/darwin-x64@0.27.7': - optional: true - '@esbuild/darwin-x64@0.28.1': optional: true - '@esbuild/freebsd-arm64@0.27.7': - optional: true - '@esbuild/freebsd-arm64@0.28.1': optional: true - '@esbuild/freebsd-x64@0.27.7': - optional: true - '@esbuild/freebsd-x64@0.28.1': optional: true - '@esbuild/linux-arm64@0.27.7': - optional: true - '@esbuild/linux-arm64@0.28.1': optional: true - '@esbuild/linux-arm@0.27.7': - optional: true - '@esbuild/linux-arm@0.28.1': optional: true - '@esbuild/linux-ia32@0.27.7': - optional: true - '@esbuild/linux-ia32@0.28.1': optional: true - '@esbuild/linux-loong64@0.27.7': - optional: true - '@esbuild/linux-loong64@0.28.1': optional: true - '@esbuild/linux-mips64el@0.27.7': - optional: true - '@esbuild/linux-mips64el@0.28.1': optional: true - '@esbuild/linux-ppc64@0.27.7': - optional: true - '@esbuild/linux-ppc64@0.28.1': optional: true - '@esbuild/linux-riscv64@0.27.7': - optional: true - '@esbuild/linux-riscv64@0.28.1': optional: true - '@esbuild/linux-s390x@0.27.7': - optional: true - '@esbuild/linux-s390x@0.28.1': optional: true - '@esbuild/linux-x64@0.27.7': - optional: true - '@esbuild/linux-x64@0.28.1': optional: true - '@esbuild/netbsd-arm64@0.27.7': - optional: true - '@esbuild/netbsd-arm64@0.28.1': optional: true - '@esbuild/netbsd-x64@0.27.7': - optional: true - '@esbuild/netbsd-x64@0.28.1': optional: true - '@esbuild/openbsd-arm64@0.27.7': - optional: true - '@esbuild/openbsd-arm64@0.28.1': optional: true - '@esbuild/openbsd-x64@0.27.7': - optional: true - '@esbuild/openbsd-x64@0.28.1': optional: true - '@esbuild/openharmony-arm64@0.27.7': - optional: true - '@esbuild/openharmony-arm64@0.28.1': optional: true - '@esbuild/sunos-x64@0.27.7': - optional: true - '@esbuild/sunos-x64@0.28.1': optional: true - '@esbuild/win32-arm64@0.27.7': - optional: true - '@esbuild/win32-arm64@0.28.1': optional: true - '@esbuild/win32-ia32@0.27.7': - optional: true - '@esbuild/win32-ia32@0.28.1': optional: true - '@esbuild/win32-x64@0.27.7': - optional: true - '@esbuild/win32-x64@0.28.1': optional: true - '@hono/node-server@1.19.14(hono@4.11.4)': - dependencies: - hono: 4.11.4 - - '@hono/node-server@1.19.14(hono@4.12.27)': + '@hono/node-server@1.19.14(hono@4.12.28)': dependencies: - hono: 4.12.27 + hono: 4.12.28 '@inquirer/ansi@1.0.2': optional: true @@ -3645,7 +3106,7 @@ snapshots: '@modelcontextprotocol/sdk@1.29.0(zod@4.4.3)': dependencies: - '@hono/node-server': 1.19.14(hono@4.12.27) + '@hono/node-server': 1.19.14(hono@4.12.28) ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) content-type: 1.0.5 @@ -3655,7 +3116,7 @@ snapshots: eventsource-parser: 3.1.0 express: 5.2.1 express-rate-limit: 8.5.2(express@5.2.1) - hono: 4.12.27 + hono: 4.12.28 jose: 6.2.3 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 @@ -3726,7 +3187,14 @@ snapshots: '@napi-rs/keyring-win32-ia32-msvc': 1.3.0 '@napi-rs/keyring-win32-x64-msvc': 1.3.0 - '@nodable/entities@2.1.0': {} + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@tybys/wasm-util': 0.10.3 + optional: true + + '@nodable/entities@2.2.0': {} '@nodelib/fs.scandir@2.1.5': dependencies: @@ -3738,7 +3206,7 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.0 + fastq: 1.20.1 '@open-draft/deferred-promise@2.2.0': optional: true @@ -3755,6 +3223,8 @@ snapshots: '@opentelemetry/api@1.9.0': optional: true + '@oxc-project/types@0.138.0': {} + '@oxfmt/binding-android-arm-eabi@0.56.0': optional: true @@ -3812,61 +3282,61 @@ snapshots: '@oxfmt/binding-win32-x64-msvc@0.56.0': optional: true - '@oxlint/binding-android-arm-eabi@1.71.0': + '@oxlint/binding-android-arm-eabi@1.72.0': optional: true - '@oxlint/binding-android-arm64@1.71.0': + '@oxlint/binding-android-arm64@1.72.0': optional: true - '@oxlint/binding-darwin-arm64@1.71.0': + '@oxlint/binding-darwin-arm64@1.72.0': optional: true - '@oxlint/binding-darwin-x64@1.71.0': + '@oxlint/binding-darwin-x64@1.72.0': optional: true - '@oxlint/binding-freebsd-x64@1.71.0': + '@oxlint/binding-freebsd-x64@1.72.0': optional: true - '@oxlint/binding-linux-arm-gnueabihf@1.71.0': + '@oxlint/binding-linux-arm-gnueabihf@1.72.0': optional: true - '@oxlint/binding-linux-arm-musleabihf@1.71.0': + '@oxlint/binding-linux-arm-musleabihf@1.72.0': optional: true - '@oxlint/binding-linux-arm64-gnu@1.71.0': + '@oxlint/binding-linux-arm64-gnu@1.72.0': optional: true - '@oxlint/binding-linux-arm64-musl@1.71.0': + '@oxlint/binding-linux-arm64-musl@1.72.0': optional: true - '@oxlint/binding-linux-ppc64-gnu@1.71.0': + '@oxlint/binding-linux-ppc64-gnu@1.72.0': optional: true - '@oxlint/binding-linux-riscv64-gnu@1.71.0': + '@oxlint/binding-linux-riscv64-gnu@1.72.0': optional: true - '@oxlint/binding-linux-riscv64-musl@1.71.0': + '@oxlint/binding-linux-riscv64-musl@1.72.0': optional: true - '@oxlint/binding-linux-s390x-gnu@1.71.0': + '@oxlint/binding-linux-s390x-gnu@1.72.0': optional: true - '@oxlint/binding-linux-x64-gnu@1.71.0': + '@oxlint/binding-linux-x64-gnu@1.72.0': optional: true - '@oxlint/binding-linux-x64-musl@1.71.0': + '@oxlint/binding-linux-x64-musl@1.72.0': optional: true - '@oxlint/binding-openharmony-arm64@1.71.0': + '@oxlint/binding-openharmony-arm64@1.72.0': optional: true - '@oxlint/binding-win32-arm64-msvc@1.71.0': + '@oxlint/binding-win32-arm64-msvc@1.72.0': optional: true - '@oxlint/binding-win32-ia32-msvc@1.71.0': + '@oxlint/binding-win32-ia32-msvc@1.72.0': optional: true - '@oxlint/binding-win32-x64-msvc@1.71.0': + '@oxlint/binding-win32-x64-msvc@1.72.0': optional: true '@polka/url@1.0.0-next.29': {} @@ -3885,277 +3355,113 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - '@redocly/config@0.49.1': + '@redocly/config@0.50.1': dependencies: json-schema-to-ts: 2.7.2 - '@redocly/openapi-core@2.36.0': + '@redocly/openapi-core@2.37.0': dependencies: '@redocly/ajv': 8.18.3 - '@redocly/config': 0.49.1 + '@redocly/config': 0.50.1 ajv: '@redocly/ajv@8.18.1' ajv-formats: 3.0.1(@redocly/ajv@8.18.1) colorette: 1.4.0 + graphql: 16.14.2 js-levenshtein: 1.1.6 js-yaml: 4.3.0 - picomatch: 4.0.4 + picomatch: 4.0.5 pluralize: 8.0.0 yaml-ast-parser: 0.0.43 - '@rollup/rollup-android-arm-eabi@4.62.2': - optional: true - - '@rollup/rollup-android-arm64@4.62.2': - optional: true - - '@rollup/rollup-darwin-arm64@4.62.2': - optional: true - - '@rollup/rollup-darwin-x64@4.62.2': - optional: true - - '@rollup/rollup-freebsd-arm64@4.62.2': - optional: true - - '@rollup/rollup-freebsd-x64@4.62.2': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.62.2': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.62.2': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.62.2': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.62.2': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.62.2': + '@rolldown/binding-android-arm64@1.1.4': optional: true - '@rollup/rollup-linux-loong64-musl@4.62.2': + '@rolldown/binding-darwin-arm64@1.1.4': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.62.2': + '@rolldown/binding-darwin-x64@1.1.4': optional: true - '@rollup/rollup-linux-ppc64-musl@4.62.2': + '@rolldown/binding-freebsd-x64@1.1.4': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.62.2': + '@rolldown/binding-linux-arm-gnueabihf@1.1.4': optional: true - '@rollup/rollup-linux-riscv64-musl@4.62.2': + '@rolldown/binding-linux-arm64-gnu@1.1.4': optional: true - '@rollup/rollup-linux-s390x-gnu@4.62.2': + '@rolldown/binding-linux-arm64-musl@1.1.4': optional: true - '@rollup/rollup-linux-x64-gnu@4.62.2': + '@rolldown/binding-linux-ppc64-gnu@1.1.4': optional: true - '@rollup/rollup-linux-x64-musl@4.62.2': + '@rolldown/binding-linux-s390x-gnu@1.1.4': optional: true - '@rollup/rollup-openbsd-x64@4.62.2': + '@rolldown/binding-linux-x64-gnu@1.1.4': optional: true - '@rollup/rollup-openharmony-arm64@4.62.2': + '@rolldown/binding-linux-x64-musl@1.1.4': optional: true - '@rollup/rollup-win32-arm64-msvc@4.62.2': + '@rolldown/binding-openharmony-arm64@1.1.4': optional: true - '@rollup/rollup-win32-ia32-msvc@4.62.2': + '@rolldown/binding-wasm32-wasi@1.1.4': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) optional: true - '@rollup/rollup-win32-x64-gnu@4.62.2': + '@rolldown/binding-win32-arm64-msvc@1.1.4': optional: true - '@rollup/rollup-win32-x64-msvc@4.62.2': + '@rolldown/binding-win32-x64-msvc@1.1.4': optional: true - '@smithy/config-resolver@4.5.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/core@3.24.1': - dependencies: - '@aws-crypto/crc32': 5.2.0 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - - '@smithy/credential-provider-imds@4.3.1': - dependencies: - '@smithy/core': 3.24.1 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - - '@smithy/fetch-http-handler@5.4.1': - dependencies: - '@smithy/core': 3.24.1 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - - '@smithy/hash-node@4.3.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/invalid-dependency@4.3.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/is-array-buffer@2.2.0': - dependencies: - tslib: 2.8.1 - - '@smithy/middleware-content-length@4.3.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/middleware-endpoint@4.5.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/middleware-retry@4.6.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/middleware-serde@4.3.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/middleware-stack@4.3.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/node-config-provider@4.4.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/node-http-handler@4.7.1': - dependencies: - '@smithy/core': 3.24.1 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - - '@smithy/property-provider@4.3.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/protocol-http@5.4.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/shared-ini-file-loader@4.5.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/signature-v4@5.4.1': - dependencies: - '@smithy/core': 3.24.1 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - - '@smithy/smithy-client@4.13.1': - dependencies: - '@smithy/core': 3.24.1 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - - '@smithy/types@4.14.1': - dependencies: - tslib: 2.8.1 - - '@smithy/url-parser@4.3.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 + '@rolldown/pluginutils@1.0.1': {} - '@smithy/util-base64@4.4.1': + '@smithy/core@3.29.1': dependencies: - '@smithy/core': 3.24.1 + '@smithy/types': 4.15.1 tslib: 2.8.1 - '@smithy/util-body-length-browser@4.3.1': + '@smithy/credential-provider-imds@4.4.6': dependencies: - '@smithy/core': 3.24.1 + '@smithy/core': 3.29.1 + '@smithy/types': 4.15.1 tslib: 2.8.1 - '@smithy/util-body-length-node@4.3.1': + '@smithy/fetch-http-handler@5.6.3': dependencies: - '@smithy/core': 3.24.1 + '@smithy/core': 3.29.1 + '@smithy/types': 4.15.1 tslib: 2.8.1 - '@smithy/util-buffer-from@2.2.0': + '@smithy/node-http-handler@4.9.3': dependencies: - '@smithy/is-array-buffer': 2.2.0 + '@smithy/core': 3.29.1 + '@smithy/types': 4.15.1 tslib: 2.8.1 - '@smithy/util-config-provider@4.3.1': + '@smithy/signature-v4@5.6.2': dependencies: - '@smithy/core': 3.24.1 + '@smithy/core': 3.29.1 + '@smithy/types': 4.15.1 tslib: 2.8.1 - '@smithy/util-defaults-mode-browser@4.4.1': + '@smithy/types@4.15.1': dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/util-defaults-mode-node@4.3.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/util-endpoints@3.5.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/util-middleware@4.3.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/util-retry@4.4.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/util-stream@4.6.1': - dependencies: - '@smithy/core': 3.24.1 - tslib: 2.8.1 - - '@smithy/util-utf8@2.3.0': - dependencies: - '@smithy/util-buffer-from': 2.2.0 - tslib: 2.8.1 - - '@smithy/util-utf8@4.3.1': - dependencies: - '@smithy/core': 3.24.1 tslib: 2.8.1 '@stablelib/base64@1.0.1': {} '@standard-schema/spec@1.1.0': {} - '@statelyai/inspect@0.7.2(xstate@5.32.2)': + '@statelyai/inspect@0.7.2(xstate@5.32.4)': dependencies: fast-safe-stringify: 2.1.1 isomorphic-ws: 5.0.0(ws@8.21.0) @@ -4163,11 +3469,16 @@ snapshots: safe-stable-stringify: 2.5.0 superjson: 1.13.3 ws: 8.21.0 - xstate: 5.32.2 + xstate: 5.32.4 transitivePeerDependencies: - bufferutil - utf-8-validate + '@tybys/wasm-util@0.10.3': + dependencies: + tslib: 2.8.1 + optional: true + '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 @@ -4208,10 +3519,10 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@vitest/coverage-v8@4.1.9(vitest@4.1.9)': + '@vitest/coverage-v8@4.1.10(vitest@4.1.10)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.1.9 + '@vitest/utils': 4.1.10 ast-v8-to-istanbul: 1.0.4 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 @@ -4220,58 +3531,58 @@ snapshots: obug: 2.1.3 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.9(@opentelemetry/api@1.9.0)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.9)(@vitest/ui@4.1.9)(msw@2.10.4(@types/node@22.20.0)(typescript@5.9.3))(vite@7.3.1(@types/node@22.20.0)(tsx@4.22.4)(yaml@2.9.0)) + vitest: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.10)(@vitest/ui@4.1.10)(msw@2.10.4(@types/node@22.20.0)(typescript@5.9.3))(vite@8.1.3(@types/node@22.20.0)(esbuild@0.28.1)(tsx@4.23.0)(yaml@2.9.0)) - '@vitest/expect@4.1.9': + '@vitest/expect@4.1.10': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.9 - '@vitest/utils': 4.1.9 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.9(msw@2.10.4(@types/node@22.20.0)(typescript@5.9.3))(vite@7.3.1(@types/node@22.20.0)(tsx@4.22.4)(yaml@2.9.0))': + '@vitest/mocker@4.1.10(msw@2.10.4(@types/node@22.20.0)(typescript@5.9.3))(vite@8.1.3(@types/node@22.20.0)(esbuild@0.28.1)(tsx@4.23.0)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.9 + '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.10.4(@types/node@22.20.0)(typescript@5.9.3) - vite: 7.3.1(@types/node@22.20.0)(tsx@4.22.4)(yaml@2.9.0) + vite: 8.1.3(@types/node@22.20.0)(esbuild@0.28.1)(tsx@4.23.0)(yaml@2.9.0) - '@vitest/pretty-format@4.1.9': + '@vitest/pretty-format@4.1.10': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.9': + '@vitest/runner@4.1.10': dependencies: - '@vitest/utils': 4.1.9 + '@vitest/utils': 4.1.10 pathe: 2.0.3 - '@vitest/snapshot@4.1.9': + '@vitest/snapshot@4.1.10': dependencies: - '@vitest/pretty-format': 4.1.9 - '@vitest/utils': 4.1.9 + '@vitest/pretty-format': 4.1.10 + '@vitest/utils': 4.1.10 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.9': {} + '@vitest/spy@4.1.10': {} - '@vitest/ui@4.1.9(vitest@4.1.9)': + '@vitest/ui@4.1.10(vitest@4.1.10)': dependencies: - '@vitest/utils': 4.1.9 + '@vitest/utils': 4.1.10 fflate: 0.8.3 flatted: 3.4.2 pathe: 2.0.3 sirv: 3.0.2 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vitest: 4.1.9(@opentelemetry/api@1.9.0)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.9)(@vitest/ui@4.1.9)(msw@2.10.4(@types/node@22.20.0)(typescript@5.9.3))(vite@7.3.1(@types/node@22.20.0)(tsx@4.22.4)(yaml@2.9.0)) + vitest: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.10)(@vitest/ui@4.1.10)(msw@2.10.4(@types/node@22.20.0)(typescript@5.9.3))(vite@8.1.3(@types/node@22.20.0)(esbuild@0.28.1)(tsx@4.23.0)(yaml@2.9.0)) - '@vitest/utils@4.1.9': + '@vitest/utils@4.1.10': dependencies: - '@vitest/pretty-format': 4.1.9 + '@vitest/pretty-format': 4.1.10 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 @@ -4281,26 +3592,25 @@ snapshots: dependencies: eventemitter3: 5.0.4 - '@workos/migrations@2.4.0': + '@workos/migrations@2.5.0': dependencies: - '@aws-sdk/client-cognito-identity-provider': 3.1045.0 + '@aws-sdk/client-cognito-identity-provider': 3.1079.0 '@workos-inc/node': 10.7.0 chalk: 5.6.2 cli-progress: 3.12.0 commander: 15.0.0 csv-parse: 6.2.1 - csv-stringify: 6.7.0 + csv-stringify: 6.8.1 dotenv: 17.4.2 - fast-xml-parser: 5.8.0 + fast-xml-parser: 5.9.3 google-auth-library: 10.9.0 prompts: 2.4.2 transitivePeerDependencies: - - aws-crt - supports-color '@workos/oagen@0.23.0': dependencies: - '@redocly/openapi-core': 2.36.0 + '@redocly/openapi-core': 2.37.0 commander: 13.1.0 dotenv: 17.4.2 tree-sitter: 0.21.1 @@ -4313,7 +3623,7 @@ snapshots: tree-sitter-ruby: 0.21.0(tree-sitter@0.21.1) tree-sitter-rust: 0.21.0(tree-sitter@0.21.1) tree-sitter-typescript: 0.23.2(tree-sitter@0.21.1) - tsx: 4.22.4 + tsx: 4.23.0 typescript: 6.0.3 transitivePeerDependencies: - tree_sitter @@ -4356,8 +3666,6 @@ snapshots: ansi-regex@5.0.1: {} - ansi-regex@6.1.0: {} - ansi-regex@6.2.2: {} ansi-styles@4.3.0: @@ -4369,6 +3677,8 @@ snapshots: ansi-styles@6.2.3: {} + anynum@1.0.1: {} + argparse@2.0.1: {} assertion-error@2.0.1: {} @@ -4391,7 +3701,7 @@ snapshots: content-type: 2.0.0 debug: 4.4.3 http-errors: 2.0.1 - iconv-lite: 0.7.2 + iconv-lite: 0.7.3 on-finished: 2.4.1 qs: 6.15.3 raw-body: 3.0.2 @@ -4440,7 +3750,7 @@ snapshots: cli-truncate@5.1.1: dependencies: slice-ansi: 7.1.2 - string-width: 8.2.0 + string-width: 8.2.1 cli-width@4.1.0: optional: true @@ -4455,8 +3765,8 @@ snapshots: cliui@9.0.1: dependencies: string-width: 7.2.0 - strip-ansi: 7.1.0 - wrap-ansi: 9.0.0 + strip-ansi: 7.2.0 + wrap-ansi: 9.0.2 code-excerpt@4.0.0: dependencies: @@ -4509,7 +3819,7 @@ snapshots: csv-parse@6.2.1: {} - csv-stringify@6.7.0: {} + csv-stringify@6.8.1: {} data-uri-to-buffer@4.0.1: {} @@ -4528,6 +3838,8 @@ snapshots: depd@2.0.0: {} + detect-libc@2.1.2: {} + diff@8.0.4: {} dotenv@17.4.2: {} @@ -4544,7 +3856,7 @@ snapshots: ee-first@1.1.1: {} - emoji-regex@10.4.0: {} + emoji-regex@10.6.0: {} emoji-regex@8.0.0: {} @@ -4556,7 +3868,7 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@2.2.0: {} + es-module-lexer@2.3.0: {} es-object-atoms@1.1.2: dependencies: @@ -4564,35 +3876,6 @@ snapshots: es-toolkit@1.44.0: {} - esbuild@0.27.7: - optionalDependencies: - '@esbuild/aix-ppc64': 0.27.7 - '@esbuild/android-arm': 0.27.7 - '@esbuild/android-arm64': 0.27.7 - '@esbuild/android-x64': 0.27.7 - '@esbuild/darwin-arm64': 0.27.7 - '@esbuild/darwin-x64': 0.27.7 - '@esbuild/freebsd-arm64': 0.27.7 - '@esbuild/freebsd-x64': 0.27.7 - '@esbuild/linux-arm': 0.27.7 - '@esbuild/linux-arm64': 0.27.7 - '@esbuild/linux-ia32': 0.27.7 - '@esbuild/linux-loong64': 0.27.7 - '@esbuild/linux-mips64el': 0.27.7 - '@esbuild/linux-ppc64': 0.27.7 - '@esbuild/linux-riscv64': 0.27.7 - '@esbuild/linux-s390x': 0.27.7 - '@esbuild/linux-x64': 0.27.7 - '@esbuild/netbsd-arm64': 0.27.7 - '@esbuild/netbsd-x64': 0.27.7 - '@esbuild/openbsd-arm64': 0.27.7 - '@esbuild/openbsd-x64': 0.27.7 - '@esbuild/openharmony-arm64': 0.27.7 - '@esbuild/sunos-x64': 0.27.7 - '@esbuild/win32-arm64': 0.27.7 - '@esbuild/win32-ia32': 0.27.7 - '@esbuild/win32-x64': 0.27.7 - esbuild@0.28.1: optionalDependencies: '@esbuild/aix-ppc64': 0.28.1 @@ -4712,33 +3995,27 @@ snapshots: dependencies: fast-string-width: 3.0.2 - fast-xml-builder@1.2.0: + fast-xml-builder@1.2.1: dependencies: - path-expression-matcher: 1.5.0 + path-expression-matcher: 1.6.1 xml-naming: 0.1.0 - fast-xml-parser@5.7.2: - dependencies: - '@nodable/entities': 2.1.0 - fast-xml-builder: 1.2.0 - path-expression-matcher: 1.5.0 - strnum: 2.3.0 - - fast-xml-parser@5.8.0: + fast-xml-parser@5.9.3: dependencies: - '@nodable/entities': 2.1.0 - fast-xml-builder: 1.2.0 - path-expression-matcher: 1.5.0 - strnum: 2.3.0 + '@nodable/entities': 2.2.0 + fast-xml-builder: 1.2.1 + is-unsafe: 1.0.1 + path-expression-matcher: 1.6.1 + strnum: 2.4.1 xml-naming: 0.1.0 - fastq@1.19.0: + fastq@1.20.1: dependencies: - reusify: 1.0.4 + reusify: 1.1.0 - fdir@6.5.0(picomatch@4.0.4): + fdir@6.5.0(picomatch@4.0.5): optionalDependencies: - picomatch: 4.0.4 + picomatch: 4.0.5 fetch-blob@3.2.0: dependencies: @@ -4777,7 +4054,7 @@ snapshots: function-bind@1.1.2: {} - gaxios@7.1.5: + gaxios@7.1.6: dependencies: extend: 3.0.2 https-proxy-agent: 7.0.6 @@ -4787,7 +4064,7 @@ snapshots: gcp-metadata@8.1.2: dependencies: - gaxios: 7.1.5 + gaxios: 7.1.6 google-logging-utils: 1.1.3 json-bigint: 1.0.0 transitivePeerDependencies: @@ -4799,6 +4076,8 @@ snapshots: get-east-asian-width@1.5.0: {} + get-east-asian-width@1.6.0: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -4825,7 +4104,7 @@ snapshots: dependencies: base64-js: 1.5.1 ecdsa-sig-formatter: 1.0.11 - gaxios: 7.1.5 + gaxios: 7.1.6 gcp-metadata: 8.1.2 google-logging-utils: 1.1.3 jws: 4.0.1 @@ -4836,8 +4115,7 @@ snapshots: gopd@1.2.0: {} - graphql@16.14.2: - optional: true + graphql@16.14.2: {} has-flag@4.0.0: {} @@ -4850,9 +4128,7 @@ snapshots: headers-polyfill@4.0.3: optional: true - hono@4.11.4: {} - - hono@4.12.27: {} + hono@4.12.28: {} html-escaper@2.0.2: {} @@ -4871,7 +4147,7 @@ snapshots: transitivePeerDependencies: - supports-color - iconv-lite@0.7.2: + iconv-lite@0.7.3: dependencies: safer-buffer: 2.1.2 @@ -4929,7 +4205,7 @@ snapshots: is-fullwidth-code-point@5.1.0: dependencies: - get-east-asian-width: 1.5.0 + get-east-asian-width: 1.6.0 is-glob@4.0.3: dependencies: @@ -4950,6 +4226,8 @@ snapshots: is-promise@4.0.0: {} + is-unsafe@1.0.1: {} + is-what@4.1.16: {} is-wsl@1.1.0: {} @@ -4993,19 +4271,21 @@ snapshots: json-schema-to-ts@2.7.2: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.7 '@types/json-schema': 7.0.15 ts-algebra: 1.2.2 json-schema-to-ts@3.1.1: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.7 ts-algebra: 2.0.0 json-schema-traverse@1.0.0: {} json-schema-typed@8.0.2: {} + jsonc-parser@3.3.1: {} + jwa@2.0.1: dependencies: buffer-equal-constant-time: 1.0.1 @@ -5019,6 +4299,55 @@ snapshots: kleur@3.0.3: {} + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -5109,6 +4438,8 @@ snapshots: object-inspect@1.13.4: {} + obug@2.1.1: {} + obug@2.1.3: {} on-finished@2.4.1: @@ -5163,27 +4494,27 @@ snapshots: '@oxfmt/binding-win32-ia32-msvc': 0.56.0 '@oxfmt/binding-win32-x64-msvc': 0.56.0 - oxlint@1.71.0: + oxlint@1.72.0: optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.71.0 - '@oxlint/binding-android-arm64': 1.71.0 - '@oxlint/binding-darwin-arm64': 1.71.0 - '@oxlint/binding-darwin-x64': 1.71.0 - '@oxlint/binding-freebsd-x64': 1.71.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.71.0 - '@oxlint/binding-linux-arm-musleabihf': 1.71.0 - '@oxlint/binding-linux-arm64-gnu': 1.71.0 - '@oxlint/binding-linux-arm64-musl': 1.71.0 - '@oxlint/binding-linux-ppc64-gnu': 1.71.0 - '@oxlint/binding-linux-riscv64-gnu': 1.71.0 - '@oxlint/binding-linux-riscv64-musl': 1.71.0 - '@oxlint/binding-linux-s390x-gnu': 1.71.0 - '@oxlint/binding-linux-x64-gnu': 1.71.0 - '@oxlint/binding-linux-x64-musl': 1.71.0 - '@oxlint/binding-openharmony-arm64': 1.71.0 - '@oxlint/binding-win32-arm64-msvc': 1.71.0 - '@oxlint/binding-win32-ia32-msvc': 1.71.0 - '@oxlint/binding-win32-x64-msvc': 1.71.0 + '@oxlint/binding-android-arm-eabi': 1.72.0 + '@oxlint/binding-android-arm64': 1.72.0 + '@oxlint/binding-darwin-arm64': 1.72.0 + '@oxlint/binding-darwin-x64': 1.72.0 + '@oxlint/binding-freebsd-x64': 1.72.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.72.0 + '@oxlint/binding-linux-arm-musleabihf': 1.72.0 + '@oxlint/binding-linux-arm64-gnu': 1.72.0 + '@oxlint/binding-linux-arm64-musl': 1.72.0 + '@oxlint/binding-linux-ppc64-gnu': 1.72.0 + '@oxlint/binding-linux-riscv64-gnu': 1.72.0 + '@oxlint/binding-linux-riscv64-musl': 1.72.0 + '@oxlint/binding-linux-s390x-gnu': 1.72.0 + '@oxlint/binding-linux-x64-gnu': 1.72.0 + '@oxlint/binding-linux-x64-musl': 1.72.0 + '@oxlint/binding-openharmony-arm64': 1.72.0 + '@oxlint/binding-win32-arm64-msvc': 1.72.0 + '@oxlint/binding-win32-ia32-msvc': 1.72.0 + '@oxlint/binding-win32-x64-msvc': 1.72.0 p-limit@7.3.0: dependencies: @@ -5197,7 +4528,7 @@ snapshots: patch-console@2.0.0: {} - path-expression-matcher@1.5.0: {} + path-expression-matcher@1.6.1: {} path-key@3.1.1: {} @@ -5214,6 +4545,8 @@ snapshots: picomatch@4.0.4: {} + picomatch@4.0.5: {} + pkce-challenge@5.0.1: {} pluralize@8.0.0: {} @@ -5260,7 +4593,7 @@ snapshots: dependencies: bytes: 3.1.2 http-errors: 2.0.1 - iconv-lite: 0.7.2 + iconv-lite: 0.7.3 unpipe: 1.0.0 react-reconciler@0.33.0(react@19.2.7): @@ -5283,38 +4616,28 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 - reusify@1.0.4: {} + reusify@1.1.0: {} - rollup@4.62.2: + rolldown@1.1.4: dependencies: - '@types/estree': 1.0.9 + '@oxc-project/types': 0.138.0 + '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.62.2 - '@rollup/rollup-android-arm64': 4.62.2 - '@rollup/rollup-darwin-arm64': 4.62.2 - '@rollup/rollup-darwin-x64': 4.62.2 - '@rollup/rollup-freebsd-arm64': 4.62.2 - '@rollup/rollup-freebsd-x64': 4.62.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.62.2 - '@rollup/rollup-linux-arm-musleabihf': 4.62.2 - '@rollup/rollup-linux-arm64-gnu': 4.62.2 - '@rollup/rollup-linux-arm64-musl': 4.62.2 - '@rollup/rollup-linux-loong64-gnu': 4.62.2 - '@rollup/rollup-linux-loong64-musl': 4.62.2 - '@rollup/rollup-linux-ppc64-gnu': 4.62.2 - '@rollup/rollup-linux-ppc64-musl': 4.62.2 - '@rollup/rollup-linux-riscv64-gnu': 4.62.2 - '@rollup/rollup-linux-riscv64-musl': 4.62.2 - '@rollup/rollup-linux-s390x-gnu': 4.62.2 - '@rollup/rollup-linux-x64-gnu': 4.62.2 - '@rollup/rollup-linux-x64-musl': 4.62.2 - '@rollup/rollup-openbsd-x64': 4.62.2 - '@rollup/rollup-openharmony-arm64': 4.62.2 - '@rollup/rollup-win32-arm64-msvc': 4.62.2 - '@rollup/rollup-win32-ia32-msvc': 4.62.2 - '@rollup/rollup-win32-x64-gnu': 4.62.2 - '@rollup/rollup-win32-x64-msvc': 4.62.2 - fsevents: 2.3.3 + '@rolldown/binding-android-arm64': 1.1.4 + '@rolldown/binding-darwin-arm64': 1.1.4 + '@rolldown/binding-darwin-x64': 1.1.4 + '@rolldown/binding-freebsd-x64': 1.1.4 + '@rolldown/binding-linux-arm-gnueabihf': 1.1.4 + '@rolldown/binding-linux-arm64-gnu': 1.1.4 + '@rolldown/binding-linux-arm64-musl': 1.1.4 + '@rolldown/binding-linux-ppc64-gnu': 1.1.4 + '@rolldown/binding-linux-s390x-gnu': 1.1.4 + '@rolldown/binding-linux-x64-gnu': 1.1.4 + '@rolldown/binding-linux-x64-musl': 1.1.4 + '@rolldown/binding-openharmony-arm64': 1.1.4 + '@rolldown/binding-wasm32-wasi': 1.1.4 + '@rolldown/binding-win32-arm64-msvc': 1.1.4 + '@rolldown/binding-win32-x64-msvc': 1.1.4 router@2.2.0: dependencies: @@ -5420,7 +4743,7 @@ snapshots: slice-ansi@7.1.2: dependencies: - ansi-styles: 6.2.1 + ansi-styles: 6.2.3 is-fullwidth-code-point: 5.0.0 slice-ansi@8.0.0: @@ -5456,28 +4779,31 @@ snapshots: string-width@7.2.0: dependencies: - emoji-regex: 10.4.0 - get-east-asian-width: 1.3.0 - strip-ansi: 7.1.0 + emoji-regex: 10.6.0 + get-east-asian-width: 1.6.0 + strip-ansi: 7.2.0 string-width@8.2.0: dependencies: get-east-asian-width: 1.5.0 strip-ansi: 7.2.0 - strip-ansi@6.0.1: + string-width@8.2.1: dependencies: - ansi-regex: 5.0.1 + get-east-asian-width: 1.5.0 + strip-ansi: 7.2.0 - strip-ansi@7.1.0: + strip-ansi@6.0.1: dependencies: - ansi-regex: 6.1.0 + ansi-regex: 5.0.1 strip-ansi@7.2.0: dependencies: ansi-regex: 6.2.2 - strnum@2.3.0: {} + strnum@2.4.1: + dependencies: + anynum: 1.0.1 superjson@1.13.3: dependencies: @@ -5497,8 +4823,8 @@ snapshots: tinyglobby@0.2.17: dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 tinypool@2.1.0: {} @@ -5597,7 +4923,7 @@ snapshots: tslib@2.8.1: {} - tsx@4.22.4: + tsx@4.23.0: dependencies: esbuild: 0.28.1 optionalDependencies: @@ -5637,33 +4963,33 @@ snapshots: vary@1.1.2: {} - vite@7.3.1(@types/node@22.20.0)(tsx@4.22.4)(yaml@2.9.0): + vite@8.1.3(@types/node@22.20.0)(esbuild@0.28.1)(tsx@4.23.0)(yaml@2.9.0): dependencies: - esbuild: 0.27.7 - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 + lightningcss: 1.32.0 + picomatch: 4.0.5 postcss: 8.5.16 - rollup: 4.62.2 + rolldown: 1.1.4 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 22.20.0 + esbuild: 0.28.1 fsevents: 2.3.3 - tsx: 4.22.4 + tsx: 4.23.0 yaml: 2.9.0 - vitest@4.1.9(@opentelemetry/api@1.9.0)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.9)(@vitest/ui@4.1.9)(msw@2.10.4(@types/node@22.20.0)(typescript@5.9.3))(vite@7.3.1(@types/node@22.20.0)(tsx@4.22.4)(yaml@2.9.0)): + vitest@4.1.10(@opentelemetry/api@1.9.0)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.10)(@vitest/ui@4.1.10)(msw@2.10.4(@types/node@22.20.0)(typescript@5.9.3))(vite@8.1.3(@types/node@22.20.0)(esbuild@0.28.1)(tsx@4.23.0)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.1.9 - '@vitest/mocker': 4.1.9(msw@2.10.4(@types/node@22.20.0)(typescript@5.9.3))(vite@7.3.1(@types/node@22.20.0)(tsx@4.22.4)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.9 - '@vitest/runner': 4.1.9 - '@vitest/snapshot': 4.1.9 - '@vitest/spy': 4.1.9 - '@vitest/utils': 4.1.9 - es-module-lexer: 2.2.0 + '@vitest/expect': 4.1.10 + '@vitest/mocker': 4.1.10(msw@2.10.4(@types/node@22.20.0)(typescript@5.9.3))(vite@8.1.3(@types/node@22.20.0)(esbuild@0.28.1)(tsx@4.23.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.10 + '@vitest/runner': 4.1.10 + '@vitest/snapshot': 4.1.10 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 + es-module-lexer: 2.3.0 expect-type: 1.4.0 magic-string: 0.30.21 - obug: 2.1.3 + obug: 2.1.1 pathe: 2.0.3 picomatch: 4.0.4 std-env: 4.1.0 @@ -5671,13 +4997,13 @@ snapshots: tinyexec: 1.2.4 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 7.3.1(@types/node@22.20.0)(tsx@4.22.4)(yaml@2.9.0) + vite: 8.1.3(@types/node@22.20.0)(esbuild@0.28.1)(tsx@4.23.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 '@types/node': 22.20.0 - '@vitest/coverage-v8': 4.1.9(vitest@4.1.9) - '@vitest/ui': 4.1.9(vitest@4.1.9) + '@vitest/coverage-v8': 4.1.10(vitest@4.1.10) + '@vitest/ui': 4.1.10(vitest@4.1.10) transitivePeerDependencies: - msw @@ -5694,7 +5020,7 @@ snapshots: widest-line@6.0.0: dependencies: - string-width: 8.2.0 + string-width: 8.2.1 wrap-ansi@6.2.0: dependencies: @@ -5712,9 +5038,15 @@ snapshots: wrap-ansi@9.0.0: dependencies: - ansi-styles: 6.2.1 + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.2.0 + + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.3 string-width: 7.2.0 - strip-ansi: 7.1.0 + strip-ansi: 7.2.0 wrappy@1.0.2: {} @@ -5729,7 +5061,7 @@ snapshots: xml-naming@0.1.0: {} - xstate@5.32.2: {} + xstate@5.32.4: {} y18n@5.0.8: {} diff --git a/src/bin.ts b/src/bin.ts index 6eb01b67..2312ba09 100644 --- a/src/bin.ts +++ b/src/bin.ts @@ -323,6 +323,36 @@ async function runCli(): Promise { await applyInsecureStorage(argv.insecureStorage as boolean | undefined); await maybeWarnUnclaimed(); }) + .middleware(async (argv) => { + // One-time MCP banner (lowest-priority startup notice — runs after the + // telemetry notice + unclaimed warning so they win the one-per-run slot). + // Skip commands that manage MCP/agents directly or where the nudge is + // noise, mirroring + extending maybeWarnUnclaimed's list. Self-guarded and + // never throws. + const command = String(argv._?.[0] ?? ''); + if ( + [ + 'mcp', + 'install', + 'doctor', + 'skills', + 'auth', + 'env', + 'claim', + 'debug', + 'dashboard', + 'emulate', + 'dev', + 'migrations', + 'telemetry', + 'completion', + '', + ].includes(command) + ) + return; + const { maybeShowMcpNotice } = await import('./lib/mcp-notice.js'); + await maybeShowMcpNotice(); + }) .command('auth', 'Manage authentication (login, logout, status)', (yargs) => { yargs.options(insecureStorageOption); registerSubcommand( @@ -466,6 +496,51 @@ async function runCli(): Promise { ); return yargs.demandCommand(1, 'Please specify a skills subcommand').strict(); }) + .command('mcp', 'Manage the WorkOS MCP server in coding agents (Claude Code, Codex, Cursor)', (yargs) => { + registerSubcommand( + yargs, + 'install', + 'Add the WorkOS MCP server to detected coding agents', + (y) => + y.option('agent', { + alias: 'a', + type: 'array', + string: true, + description: 'Target specific agent(s): claude-code, codex, cursor', + }), + async (argv) => { + const { runMcpInstall } = await import('./commands/mcp.js'); + await runMcpInstall({ agent: argv.agent as string[] | undefined }); + }, + ); + registerSubcommand( + yargs, + 'remove', + 'Remove the WorkOS MCP server from coding agents', + (y) => + y.option('agent', { + alias: 'a', + type: 'array', + string: true, + description: 'Target specific agent(s): claude-code, codex, cursor', + }), + async (argv) => { + const { runMcpRemove } = await import('./commands/mcp.js'); + await runMcpRemove({ agent: argv.agent as string[] | undefined }); + }, + ); + registerSubcommand( + yargs, + 'status', + 'Show which coding agents have the WorkOS MCP server configured', + (y) => y, + async () => { + const { runMcpStatus } = await import('./commands/mcp.js'); + await runMcpStatus(); + }, + ); + return yargs.demandCommand(1, 'Please specify an mcp subcommand').strict(); + }) .command( 'doctor', 'Diagnose WorkOS AuthKit integration issues in the current project', diff --git a/src/commands/install.spec.ts b/src/commands/install.spec.ts index 52848383..df19b169 100644 --- a/src/commands/install.spec.ts +++ b/src/commands/install.spec.ts @@ -8,6 +8,10 @@ vi.mock('./install-skill.js', () => ({ autoInstallSkills: vi.fn(), })); +vi.mock('../lib/mcp-notice.js', () => ({ + maybeOfferMcpInstall: vi.fn(), +})); + vi.mock('../utils/clack.js', () => ({ default: { log: { info: vi.fn(), error: vi.fn() }, @@ -25,6 +29,7 @@ vi.mock('../utils/debug.js', () => ({ const { runInstaller } = await import('../run.js'); const { autoInstallSkills } = await import('./install-skill.js'); +const { maybeOfferMcpInstall } = await import('../lib/mcp-notice.js'); const clack = (await import('../utils/clack.js')).default; const { isJsonMode } = await import('../utils/output.js'); const { CliExit } = await import('../utils/cli-exit.js'); @@ -51,6 +56,18 @@ describe('handleInstall', () => { expect(autoInstallOrder).toBeGreaterThan(runInstallerOrder); }); + it('offers the MCP install after skills, on the install-flow entry point', async () => { + vi.mocked(runInstaller).mockResolvedValue(undefined as any); + vi.mocked(autoInstallSkills).mockResolvedValue(null); + + await expect(handleInstall({ _: ['install'], $0: 'workos' } as any)).resolves.toBeUndefined(); + + expect(maybeOfferMcpInstall).toHaveBeenCalledWith({ entryPoint: 'install-flow' }); + const autoInstallOrder = vi.mocked(autoInstallSkills).mock.invocationCallOrder[0]; + const mcpOfferOrder = vi.mocked(maybeOfferMcpInstall).mock.invocationCallOrder[0]; + expect(mcpOfferOrder).toBeGreaterThan(autoInstallOrder); + }); + it('prints an info line when skills were installed in a TTY session', async () => { vi.mocked(runInstaller).mockResolvedValue(undefined as any); vi.mocked(autoInstallSkills).mockResolvedValue({ diff --git a/src/commands/install.ts b/src/commands/install.ts index b04677eb..cc538be6 100644 --- a/src/commands/install.ts +++ b/src/commands/install.ts @@ -5,6 +5,7 @@ import { exitWithError, isJsonMode } from '../utils/output.js'; import { ExitCode, exitWithCode } from '../utils/exit-codes.js'; import type { ArgumentsCamelCase } from 'yargs'; import { autoInstallSkills } from './install-skill.js'; +import { maybeOfferMcpInstall } from '../lib/mcp-notice.js'; /** * Handle install command execution. @@ -37,6 +38,10 @@ export async function handleInstall(argv: ArgumentsCamelCase): Pr `Installed ${skillResult.skills.length} WorkOS ${skillWord} for ${skillResult.agents.join(', ')}. Your coding agent now has up-to-date WorkOS guidance.`, ); } + + // Offer to connect the user's coding agent to WorkOS via MCP. Self-gating + // (human/TTY-only, decline-respecting) and best-effort — never fails install. + await maybeOfferMcpInstall({ entryPoint: 'install-flow' }); } catch (err) { const { getLogFilePath } = await import('../utils/debug.js'); const logPath = getLogFilePath(); diff --git a/src/commands/mcp.spec.ts b/src/commands/mcp.spec.ts new file mode 100644 index 00000000..d3abf6b1 --- /dev/null +++ b/src/commands/mcp.spec.ts @@ -0,0 +1,436 @@ +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; +import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, rmSync } from 'fs'; +import { join } from 'path'; +import { homedir, tmpdir } from 'os'; + +// Mock the shell-out layer so Claude Code / Codex outcomes are scripted. +vi.mock('../utils/exec-file.js', () => ({ + execFileNoThrow: vi.fn(), +})); + +// clack.log writes to the raw stdout/stderr streams (not console.*), so capture +// its human-mode output through a module mock instead of a console spy. +const { clackLogs } = vi.hoisted(() => ({ clackLogs: [] as string[] })); +vi.mock('../utils/clack.js', () => { + const record = (msg: unknown) => { + clackLogs.push(String(msg)); + }; + return { + default: { + log: { info: record, success: record, error: record, warn: record, step: record, message: record }, + }, + }; +}); + +// Point homedir at a real temp dir so Cursor's fs read-modify-write and the +// config-dir detection checks operate on disk without touching the real $HOME. +vi.mock('os', async (importOriginal) => { + const actual = await importOriginal(); + return { ...actual, homedir: vi.fn(actual.homedir) }; +}); + +const { execFileNoThrow } = await import('../utils/exec-file.js'); +const { setOutputMode } = await import('../utils/output.js'); +const { CliExit } = await import('../utils/cli-exit.js'); +const { createMcpClients, detectMcpClients, MCP_AGENT_KEYS } = await import('../lib/mcp-clients.js'); +const { runMcpInstall, runMcpRemove, runMcpStatus } = await import('./mcp.js'); + +type ExecShape = { status: number; stdout?: string; stderr?: string }; + +/** Route exec calls; anything the impl doesn't override defaults to success. */ +function mockExec(impl: (command: string, args: string[]) => ExecShape): void { + vi.mocked(execFileNoThrow).mockImplementation((command: string, args: string[]) => + Promise.resolve({ status: 0, stdout: '', stderr: '', ...impl(command, args) }), + ); +} + +function clientByKey(key: string) { + const target = createMcpClients().find((c) => c.key === key); + if (!target) throw new Error(`no client ${key}`); + return target; +} + +/** Grab a thrown CliExit (handlers exit by throwing, not returning). */ +async function captureExit(fn: () => Promise): Promise | undefined> { + try { + await fn(); + return undefined; + } catch (e) { + if (e instanceof CliExit) return e; + throw e; + } +} + +let testHome: string; +let consoleOutput: string[]; + +beforeEach(() => { + vi.clearAllMocks(); + clackLogs.length = 0; + testHome = mkdtempSync(join(tmpdir(), 'mcp-test-')); + vi.mocked(homedir).mockReturnValue(testHome); + // Default: every shell-out succeeds (overridden per test). + mockExec(() => ({ status: 0 })); + consoleOutput = []; + vi.spyOn(console, 'log').mockImplementation((...args: unknown[]) => { + consoleOutput.push(args.map(String).join(' ')); + }); + vi.spyOn(console, 'error').mockImplementation((...args: unknown[]) => { + consoleOutput.push(args.map(String).join(' ')); + }); +}); + +afterEach(() => { + rmSync(testHome, { recursive: true, force: true }); + setOutputMode('human'); + vi.restoreAllMocks(); +}); + +function makeDir(name: string): void { + mkdirSync(join(testHome, name), { recursive: true }); +} + +function cursorConfigPath(): string { + return join(testHome, '.cursor', 'mcp.json'); +} + +function writeCursorConfig(content: string): void { + makeDir('.cursor'); + writeFileSync(cursorConfigPath(), content, 'utf8'); +} + +describe('createMcpClients', () => { + it('returns the three client targets in a stable order', () => { + const clients = createMcpClients(); + expect(clients.map((c) => c.key)).toEqual(['claude-code', 'codex', 'cursor']); + }); + + it('exposes the known agent keys for validation', () => { + expect(MCP_AGENT_KEYS).toEqual(['claude-code', 'codex', 'cursor']); + }); +}); + +describe('detectMcpClients', () => { + it('reports a CLI client available only when dir AND binary are present', async () => { + makeDir('.claude'); + mockExec((_c, args) => (args[0] === '--version' ? { status: 0 } : { status: 0 })); + expect((await detectMcpClients(['claude-code'])).map((c) => c.key)).toEqual(['claude-code']); + }); + + it('reports a CLI client unavailable when the binary is missing', async () => { + makeDir('.claude'); + mockExec((_c, args) => (args[0] === '--version' ? { status: 1, stderr: 'command not found' } : { status: 0 })); + expect(await detectMcpClients(['claude-code'])).toEqual([]); + }); + + it('reports a CLI client unavailable when the config dir is missing', async () => { + // No ~/.claude dir; binary would run, but the dir gate fails first. + mockExec(() => ({ status: 0 })); + expect(await detectMcpClients(['claude-code'])).toEqual([]); + }); + + it('detects Cursor from its config dir alone (no binary)', async () => { + makeDir('.cursor'); + expect((await detectMcpClients(['cursor'])).map((c) => c.key)).toEqual(['cursor']); + }); + + it('narrows to the requested agent filter', async () => { + makeDir('.claude'); + makeDir('.codex'); + makeDir('.cursor'); + const detected = await detectMcpClients(['cursor']); + expect(detected.map((c) => c.key)).toEqual(['cursor']); + }); + + it('returns nothing for an unknown filter key', async () => { + makeDir('.claude'); + expect(await detectMcpClients(['bogus'])).toEqual([]); + }); +}); + +describe('Claude Code client', () => { + const claude = () => clientByKey('claude-code'); + + it('add maps a clean exit to installed', async () => { + mockExec(() => ({ status: 0 })); + expect((await claude().add()).outcome).toBe('installed'); + }); + + it('add maps an "already exists" collision to already-installed', async () => { + mockExec(() => ({ status: 1, stderr: 'MCP server workos already exists in user scope' })); + expect((await claude().add()).outcome).toBe('already-installed'); + }); + + it('add maps a version gap (unknown --transport) to failed with an excerpt', async () => { + mockExec(() => ({ status: 1, stderr: "error: unknown option '--transport'" })); + const res = await claude().add(); + expect(res.outcome).toBe('failed'); + expect(res.error).toContain('--transport'); + }); + + it('isInstalled matches the workos: list line', async () => { + mockExec(() => ({ + status: 0, + stdout: 'raindrop: https://x (HTTP)\nworkos: https://mcp.workos.com/mcp (HTTP) - Connected', + })); + expect(await claude().isInstalled()).toBe(true); + }); + + it('isInstalled does NOT match a workos-docs substring collision', async () => { + mockExec(() => ({ status: 0, stdout: 'workos-docs: https://docs (HTTP) - Connected' })); + expect(await claude().isInstalled()).toBe(false); + }); + + it('isInstalled is false when list itself fails', async () => { + mockExec(() => ({ status: 1, stderr: 'boom' })); + expect(await claude().isInstalled()).toBe(false); + }); + + it('remove maps a clean exit to removed', async () => { + mockExec(() => ({ status: 0 })); + expect((await claude().remove()).outcome).toBe('removed'); + }); + + it('remove maps "No MCP server named" (exit 1) to not-installed', async () => { + mockExec(() => ({ status: 1, stderr: 'No MCP server named "workos" in user scope' })); + expect((await claude().remove()).outcome).toBe('not-installed'); + }); +}); + +describe('Codex client', () => { + const codex = () => clientByKey('codex'); + + it('add maps a clean exit to installed', async () => { + mockExec(() => ({ status: 0 })); + expect((await codex().add()).outcome).toBe('installed'); + }); + + it('add maps a version gap (unknown --url) to failed', async () => { + mockExec(() => ({ status: 1, stderr: "error: unexpected argument '--url'" })); + const res = await codex().add(); + expect(res.outcome).toBe('failed'); + expect(res.error).toContain('--url'); + }); + + it('add reports installed when a non-zero exit still persisted the server (OAuth-flow timeout)', async () => { + // Codex writes the config, then its post-add OAuth flow blocks and times + // out with a non-zero status — but `mcp list` proves the server landed. + mockExec((_c, args) => { + if (args.includes('add')) return { status: 1, stdout: "Added global MCP server 'workos'." }; + if (args.includes('list')) return { status: 0, stdout: 'workos https://mcp.workos.com/mcp enabled' }; + return { status: 0 }; + }); + expect((await codex().add()).outcome).toBe('installed'); + }); + + it('add stays failed on a non-zero exit when the server did NOT land', async () => { + mockExec((_c, args) => { + if (args.includes('add')) return { status: 1, stderr: 'boom' }; + if (args.includes('list')) return { status: 0, stdout: 'Name Url\ngithub https://x' }; + return { status: 0 }; + }); + expect((await codex().add()).outcome).toBe('failed'); + }); + + it('isInstalled matches the codex table row (name in first column, no colon)', async () => { + mockExec(() => ({ + status: 0, + stdout: 'Name Url\ngithub https://api.github\nworkos https://mcp.workos.com/mcp enabled', + })); + expect(await codex().isInstalled()).toBe(true); + }); + + it('remove maps "No MCP server named" (exit 0) to not-installed', async () => { + mockExec(() => ({ status: 0, stdout: "No MCP server named 'workos' found." })); + expect((await codex().remove()).outcome).toBe('not-installed'); + }); +}); + +describe('Cursor client', () => { + const cursor = () => clientByKey('cursor'); + const val = `{ "url": "https://mcp.workos.com/mcp" }`; + + it('add creates the file when none exists', async () => { + const res = await cursor().add(); + expect(res.outcome).toBe('installed'); + const written = JSON.parse(readFileSync(cursorConfigPath(), 'utf8')); + expect(written.mcpServers.workos.url).toBe('https://mcp.workos.com/mcp'); + }); + + it('add handles an empty file', async () => { + writeCursorConfig(''); + expect((await cursor().add()).outcome).toBe('installed'); + const written = JSON.parse(readFileSync(cursorConfigPath(), 'utf8')); + expect(written.mcpServers.workos.url).toBe('https://mcp.workos.com/mcp'); + }); + + it('add preserves unrelated servers and comments', async () => { + writeCursorConfig('{\n // keep me\n "mcpServers": {\n "other": { "url": "https://other" }\n }\n}'); + expect((await cursor().add()).outcome).toBe('installed'); + const raw = readFileSync(cursorConfigPath(), 'utf8'); + expect(raw).toContain('// keep me'); + expect(raw).toContain('"other"'); + expect(raw).toContain('https://mcp.workos.com/mcp'); + }); + + it('add tolerates a trailing comma (valid JSONC, not malformed)', async () => { + writeCursorConfig('{ "mcpServers": { "other": { "url": "https://other" } }, }'); + expect((await cursor().add()).outcome).toBe('installed'); + }); + + it('add on a malformed file fails WITHOUT overwriting it', async () => { + const malformed = '{ "mcpServers": '; + writeCursorConfig(malformed); + const res = await cursor().add(); + expect(res.outcome).toBe('failed'); + expect(res.error).toContain('fix it manually'); + expect(readFileSync(cursorConfigPath(), 'utf8')).toBe(malformed); + }); + + it('add overwrites an existing workos key with a different URL (idempotent converge)', async () => { + writeCursorConfig('{ "mcpServers": { "workos": { "url": "https://old" } } }'); + expect((await cursor().add()).outcome).toBe('installed'); + const written = JSON.parse(readFileSync(cursorConfigPath(), 'utf8')); + expect(written.mcpServers.workos.url).toBe('https://mcp.workos.com/mcp'); + }); + + it('isInstalled reflects presence of the workos key', async () => { + writeCursorConfig(`{ "mcpServers": { "workos": ${val} } }`); + expect(await cursor().isInstalled()).toBe(true); + writeCursorConfig('{ "mcpServers": { "other": { "url": "x" } } }'); + expect(await cursor().isInstalled()).toBe(false); + }); + + it('remove drops only the workos key, preserving others', async () => { + writeCursorConfig('{ "mcpServers": { "workos": { "url": "https://w" }, "other": { "url": "https://o" } } }'); + expect((await cursor().remove()).outcome).toBe('removed'); + const written = JSON.parse(readFileSync(cursorConfigPath(), 'utf8')); + expect(written.mcpServers.workos).toBeUndefined(); + expect(written.mcpServers.other.url).toBe('https://o'); + }); + + it('remove is a no-op (not-installed) when the file is absent', async () => { + expect((await cursor().remove()).outcome).toBe('not-installed'); + }); + + it('remove is a no-op (not-installed) when the key is absent', async () => { + writeCursorConfig('{ "mcpServers": { "other": { "url": "x" } } }'); + expect((await cursor().remove()).outcome).toBe('not-installed'); + }); +}); + +describe('runMcpInstall / runMcpRemove (human mode)', () => { + it('acts on all detected agents and prints the matrix', async () => { + makeDir('.claude'); + makeDir('.codex'); + makeDir('.cursor'); + mockExec(() => ({ status: 0 })); + await runMcpInstall(); + const joined = clackLogs.join('\n'); + expect(joined).toContain('Claude Code'); + expect(joined).toContain('Codex'); + expect(joined).toContain('Cursor'); + }); + + it('prints the no-agents message and exits 0 when none are detected', async () => { + mockExec((_c, args) => (args[0] === '--version' ? { status: 1 } : { status: 0 })); + const exit = await captureExit(() => runMcpInstall()); + expect(exit).toBeUndefined(); + expect(clackLogs.join('\n')).toContain('No supported coding agents detected'); + }); + + it('exits 1 when any agent fails, after emitting the full matrix', async () => { + makeDir('.claude'); + makeDir('.cursor'); + // Claude add fails hard; Cursor add succeeds. Matrix must include both. + mockExec((_c, args) => { + if (args.includes('add')) return { status: 1, stderr: 'kaboom' }; + return { status: 0 }; + }); + const exit = await captureExit(() => runMcpInstall()); + expect(exit?.exitCode).toBe(1); + const joined = clackLogs.join('\n'); + expect(joined).toContain('Claude Code'); + expect(joined).toContain('Cursor'); + }); + + it('narrows to --agent claude-code', async () => { + makeDir('.claude'); + makeDir('.codex'); + makeDir('.cursor'); + setOutputMode('json'); + await runMcpInstall({ agent: ['claude-code'] }); + const output = JSON.parse(consoleOutput[0]); + expect(output.data.agents).toHaveLength(1); + expect(output.data.agents[0].agent).toBe('claude-code'); + }); + + it('rejects an unknown --agent with a structured error and exit 1', async () => { + const exit = await captureExit(() => runMcpInstall({ agent: ['bogus'] })); + expect(exit?.exitCode).toBe(1); + expect(consoleOutput.join('\n')).toContain('Unknown agent'); + }); +}); + +describe('JSON output mode', () => { + beforeEach(() => { + setOutputMode('json'); + }); + + it('runMcpInstall emits status ok with a per-agent matrix', async () => { + makeDir('.claude'); + makeDir('.cursor'); + mockExec(() => ({ status: 0 })); + await runMcpInstall(); + const output = JSON.parse(consoleOutput[0]); + expect(output.status).toBe('ok'); + expect(output.data.agents.map((a: { agent: string }) => a.agent).sort()).toEqual(['claude-code', 'cursor']); + expect(output.data.agents.every((a: { outcome: string }) => a.outcome === 'installed')).toBe(true); + }); + + it('runMcpInstall with zero agents emits an empty matrix and exits 0', async () => { + mockExec((_c, args) => (args[0] === '--version' ? { status: 1 } : { status: 0 })); + const exit = await captureExit(() => runMcpInstall()); + expect(exit).toBeUndefined(); + const output = JSON.parse(consoleOutput[0]); + expect(output.status).toBe('ok'); + expect(output.data.agents).toEqual([]); + }); + + it('runMcpInstall still emits the full matrix before exiting 1 on failure', async () => { + makeDir('.claude'); + makeDir('.cursor'); + mockExec((_c, args) => + args.includes('add') && args.includes('--transport') ? { status: 1, stderr: 'bad' } : { status: 0 }, + ); + const exit = await captureExit(() => runMcpInstall()); + expect(exit?.exitCode).toBe(1); + const output = JSON.parse(consoleOutput[0]); + const claude = output.data.agents.find((a: { agent: string }) => a.agent === 'claude-code'); + const cursor = output.data.agents.find((a: { agent: string }) => a.agent === 'cursor'); + expect(claude.outcome).toBe('failed'); + expect(cursor.outcome).toBe('installed'); + }); + + it('runMcpRemove emits status ok with outcomes', async () => { + makeDir('.cursor'); + writeCursorConfig('{ "mcpServers": { "workos": { "url": "https://w" } } }'); + await runMcpRemove({ agent: ['cursor'] }); + const output = JSON.parse(consoleOutput[0]); + expect(output.status).toBe('ok'); + expect(output.data.agents[0].outcome).toBe('removed'); + }); + + it('runMcpStatus emits { data: { agents: [...] } } with availability + install flags', async () => { + makeDir('.cursor'); + writeCursorConfig('{ "mcpServers": { "workos": { "url": "https://w" } } }'); + mockExec((_c, args) => (args[0] === '--version' ? { status: 1 } : { status: 0 })); + await runMcpStatus(); + const output = JSON.parse(consoleOutput[0]); + expect(output.data.agents).toHaveLength(3); + const cursor = output.data.agents.find((a: { agent: string }) => a.agent === 'cursor'); + expect(cursor).toMatchObject({ agent: 'cursor', displayName: 'Cursor', available: true, installed: true }); + const claude = output.data.agents.find((a: { agent: string }) => a.agent === 'claude-code'); + expect(claude).toMatchObject({ available: false, installed: false }); + }); +}); diff --git a/src/commands/mcp.ts b/src/commands/mcp.ts new file mode 100644 index 00000000..10ce1170 --- /dev/null +++ b/src/commands/mcp.ts @@ -0,0 +1,136 @@ +import clack from '../utils/clack.js'; +import { outputSuccess, outputJson, outputTable, exitWithError, isJsonMode } from '../utils/output.js'; +import { ExitCode, exitWithCode } from '../utils/exit-codes.js'; +import { + createMcpClients, + detectMcpClients, + MCP_AGENT_KEYS, + type McpAgentKey, + type McpClientResult, +} from '../lib/mcp-clients.js'; + +/** + * `workos mcp install | remove | status` handlers. + * + * Thin callers over `lib/mcp-clients.ts`: detect the clients, run the + * operation, and format the per-agent matrix in both output modes. No prompts + * (non-TTY-safe by construction) and no auth guard — the WorkOS MCP server is + * secret-free, so configuring it never needs an API key. + */ + +export interface McpCommandOptions { + agent?: string[]; +} + +/** Human phrasing for each outcome (JSON mode emits the raw `outcome` value). */ +const OUTCOME_LABEL: Record = { + installed: 'installed', + 'already-installed': 'already installed', + removed: 'removed', + 'not-installed': 'not installed', + skipped: 'skipped', + failed: 'failed', +}; + +/** + * Validate `--agent` values against known keys. Unknown values exit with a + * structured `unknown_agent` error. Returns undefined (no filter) when none + * were passed, so callers act on all detected agents. + */ +function resolveAgentFilter(agent?: string[]): McpAgentKey[] | undefined { + if (!agent || agent.length === 0) return undefined; + const unknown = agent.filter((a) => !MCP_AGENT_KEYS.includes(a as McpAgentKey)); + if (unknown.length > 0) { + exitWithError({ + code: 'unknown_agent', + message: `Unknown agent(s): ${unknown.join(', ')}. Supported: ${MCP_AGENT_KEYS.join(', ')}.`, + }); + } + return agent as McpAgentKey[]; +} + +/** Zero detected agents: same message + exit 0 for both install and remove. */ +function reportNoAgents(): void { + if (isJsonMode()) { + outputSuccess('No supported coding agents detected', { agents: [] }); + } else { + clack.log.info('No supported coding agents detected (looked for Claude Code, Codex, Cursor).'); + } +} + +/** + * Emit the per-agent matrix, then exit non-zero if any agent failed. The full + * matrix is always emitted first so partial success is still fully reported. + */ +function reportResults(message: string, results: McpClientResult[]): void { + if (isJsonMode()) { + outputSuccess(message, { agents: results }); + } else { + for (const r of results) { + const line = `${r.displayName}: ${OUTCOME_LABEL[r.outcome]}`; + if (r.outcome === 'failed') { + clack.log.error(r.error ? `${line} — ${r.error}` : line); + } else if (r.outcome === 'installed' || r.outcome === 'removed' || r.outcome === 'already-installed') { + clack.log.success(line); + } else { + clack.log.info(line); + } + } + } + + if (results.some((r) => r.outcome === 'failed')) { + exitWithCode(ExitCode.GENERAL_ERROR); + } +} + +export async function runMcpInstall(options: McpCommandOptions = {}): Promise { + const filter = resolveAgentFilter(options.agent); + const clients = await detectMcpClients(filter); + if (clients.length === 0) { + reportNoAgents(); + return; + } + const results: McpClientResult[] = []; + for (const client of clients) { + results.push(await client.add()); + } + reportResults('Configured WorkOS MCP server', results); +} + +export async function runMcpRemove(options: McpCommandOptions = {}): Promise { + const filter = resolveAgentFilter(options.agent); + const clients = await detectMcpClients(filter); + if (clients.length === 0) { + reportNoAgents(); + return; + } + const results: McpClientResult[] = []; + for (const client of clients) { + results.push(await client.remove()); + } + reportResults('Removed WorkOS MCP server', results); +} + +export async function runMcpStatus(): Promise { + // Status lists every known agent (not just available ones) with its + // availability + install flags, so `createMcpClients()` — not + // `detectMcpClients()` — is the right source here. + const clients = createMcpClients(); + const agents = await Promise.all( + clients.map(async (client) => { + const available = await client.isAvailable(); + const installed = available ? await client.isInstalled() : false; + return { agent: client.key, displayName: client.displayName, available, installed }; + }), + ); + + if (isJsonMode()) { + outputJson({ data: { agents } }); + return; + } + + outputTable( + [{ header: 'Agent' }, { header: 'Available' }, { header: 'Installed' }], + agents.map((a) => [a.displayName, a.available ? 'yes' : 'no', a.installed ? 'yes' : 'no']), + ); +} diff --git a/src/doctor/checks/mcp.spec.ts b/src/doctor/checks/mcp.spec.ts new file mode 100644 index 00000000..a59d0a1f --- /dev/null +++ b/src/doctor/checks/mcp.spec.ts @@ -0,0 +1,107 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; + +let detectResult: unknown[] = []; +let cursorUrl: string | null = null; + +const detectMcpClientsMock = vi.fn(() => Promise.resolve(detectResult)); +const getCursorConfiguredUrlMock = vi.fn(() => Promise.resolve(cursorUrl)); +vi.mock('../../lib/mcp-clients.js', () => ({ + detectMcpClients: (...a: unknown[]) => detectMcpClientsMock(...(a as [])), + getCursorConfiguredUrl: (...a: unknown[]) => getCursorConfiguredUrlMock(...(a as [])), +})); + +const { MCP_SERVER_URL } = await import('../../lib/constants.js'); +const { checkMcp } = await import('./mcp.js'); + +function fakeClient(key: string, displayName: string, installed: boolean) { + return { + key, + displayName, + isAvailable: vi.fn(() => Promise.resolve(true)), + isInstalled: vi.fn(() => Promise.resolve(installed)), + add: vi.fn(), + remove: vi.fn(), + }; +} + +beforeEach(() => { + vi.clearAllMocks(); + detectResult = []; + cursorUrl = null; + detectMcpClientsMock.mockImplementation(() => Promise.resolve(detectResult)); + getCursorConfiguredUrlMock.mockImplementation(() => Promise.resolve(cursorUrl)); +}); + +describe('checkMcp', () => { + it('returns null when no coding agents are detected', async () => { + detectResult = []; + expect(await checkMcp()).toBeNull(); + }); + + it('reports available + installed per detected agent, with the server URL', async () => { + detectResult = [fakeClient('claude-code', 'Claude Code', true), fakeClient('codex', 'Codex', false)]; + + const result = await checkMcp(); + + expect(result).toEqual({ + serverUrl: MCP_SERVER_URL, + agents: [ + { agent: 'Claude Code', available: true, installed: true }, + { agent: 'Codex', available: true, installed: false }, + ], + }); + }); + + it('flags a Cursor entry with an unexpected URL as misconfigured', async () => { + detectResult = [fakeClient('cursor', 'Cursor', true)]; + cursorUrl = 'https://evil.example.com/mcp'; + + const result = await checkMcp(); + + expect(result!.agents[0]).toEqual({ agent: 'Cursor', available: true, installed: true, misconfigured: true }); + }); + + it('does not flag Cursor when the configured URL matches', async () => { + detectResult = [fakeClient('cursor', 'Cursor', true)]; + cursorUrl = MCP_SERVER_URL; + + const result = await checkMcp(); + + expect(result!.agents[0].misconfigured).toBe(false); + }); + + it('does not flag Cursor when the URL cannot be read (null)', async () => { + detectResult = [fakeClient('cursor', 'Cursor', true)]; + cursorUrl = null; + + const result = await checkMcp(); + + expect(result!.agents[0].misconfigured).toBe(false); + }); + + it('never reads the URL (nor flags) when Cursor lacks the server', async () => { + detectResult = [fakeClient('cursor', 'Cursor', false)]; + + const result = await checkMcp(); + + expect(result!.agents[0].misconfigured).toBeUndefined(); + expect(getCursorConfiguredUrlMock).not.toHaveBeenCalled(); + }); + + it('handles the mixed matrix: one installed, one missing, one misconfigured', async () => { + detectResult = [ + fakeClient('claude-code', 'Claude Code', true), + fakeClient('codex', 'Codex', false), + fakeClient('cursor', 'Cursor', true), + ]; + cursorUrl = 'https://stale.example.com/mcp'; + + const result = await checkMcp(); + + expect(result!.agents).toEqual([ + { agent: 'Claude Code', available: true, installed: true }, + { agent: 'Codex', available: true, installed: false }, + { agent: 'Cursor', available: true, installed: true, misconfigured: true }, + ]); + }); +}); diff --git a/src/doctor/checks/mcp.ts b/src/doctor/checks/mcp.ts new file mode 100644 index 00000000..84f438e2 --- /dev/null +++ b/src/doctor/checks/mcp.ts @@ -0,0 +1,38 @@ +import { detectMcpClients, getCursorConfiguredUrl } from '../../lib/mcp-clients.js'; +import { MCP_SERVER_URL } from '../../lib/constants.js'; +import type { McpInfo, McpAgentMcpStatus } from '../types.js'; + +/** + * Report the WorkOS MCP server status across detected coding agents. + * + * Mirrors checkSkills: per-detected-agent loop, typed `*Info` return, null when + * no agents are detected (so doctor renders no MCP section for users with no + * coding agent installed). Report-only — never mutates config (`--fix` does not + * touch MCP in this phase). + * + * Absent MCP is deliberately NOT an issue: the user may have declined the + * offer. Only Cursor exposes a readable config, so URL drift ("misconfigured") + * is detected for Cursor alone; issues.ts derives a warning from it. Per-agent + * shell-outs carry the 10s timeout from the client library, keeping doctor fast. + */ +export async function checkMcp(): Promise { + const clients = await detectMcpClients(); + if (clients.length === 0) return null; + + const agents = await Promise.all( + clients.map(async (client): Promise => { + const installed = await client.isInstalled(); + const status: McpAgentMcpStatus = { agent: client.displayName, available: true, installed }; + // Cursor is the only client whose config we can read, so it's the only + // one we can flag for URL drift. A missing/unreadable URL (null) is not + // "unexpected" — only a present-but-different URL counts. + if (client.key === 'cursor' && installed) { + const url = await getCursorConfiguredUrl(); + status.misconfigured = url !== null && url !== MCP_SERVER_URL; + } + return status; + }), + ); + + return { serverUrl: MCP_SERVER_URL, agents }; +} diff --git a/src/doctor/index.ts b/src/doctor/index.ts index 5ff26d9a..985d1fa5 100644 --- a/src/doctor/index.ts +++ b/src/doctor/index.ts @@ -9,6 +9,7 @@ import { checkDashboardSettings, compareRedirectUris } from './checks/dashboard. import { checkAuthPatterns } from './checks/auth-patterns.js'; import { checkAiAnalysis } from './checks/ai-analysis.js'; import { checkSkills } from './checks/skills.js'; +import { checkMcp } from './checks/mcp.js'; import { refreshWorkOSSkills } from '../commands/install-skill.js'; import { detectIssues } from './issues.js'; import { formatReport } from './output.js'; @@ -74,14 +75,17 @@ export async function runDoctor(options: DoctorOptions): Promise { const { info: environment, raw: envRaw } = checkEnvironment(options); // Run remaining checks concurrently - const [sdk, framework, runtime, connectivity, language, hostExecution] = await Promise.all([ + const [sdk, framework, runtime, connectivity, language, hostExecution, mcpResult] = await Promise.all([ checkSdk(options), checkFramework(options), checkRuntime(options), checkConnectivity(options, environment.baseUrl ?? 'https://api.workos.com'), checkLanguage(options.installDir), checkHostExecution(), + checkMcp(), ]); + // Normalize the check's null (no agents detected) to undefined for the report. + const mcp = mcpResult ?? undefined; let skills = (await checkSkills()) ?? undefined; @@ -108,6 +112,7 @@ export async function runDoctor(options: DoctorOptions): Promise { hostExecution, connectivity, skills, + mcp, }); const [dashboardResult, authPatterns, aiAnalysis] = await Promise.all([ @@ -156,6 +161,7 @@ export async function runDoctor(options: DoctorOptions): Promise { aiAnalysis, skills, skillsRefresh, + mcp, }; // Detect issues based on (post-refresh) data. diff --git a/src/doctor/issues.spec.ts b/src/doctor/issues.spec.ts index 74c29f1e..f3a9f498 100644 --- a/src/doctor/issues.spec.ts +++ b/src/doctor/issues.spec.ts @@ -61,4 +61,45 @@ describe('detectIssues', () => { }), ); }); + + describe('MCP', () => { + it('adds no issue when MCP is absent or merely not installed', () => { + const report = baseReport(); + // No mcp field at all. + expect(detectIssues(report).some((i) => i.code === 'MCP_MISCONFIGURED')).toBe(false); + + // Detected agents, none misconfigured (some simply lack the server). + report.mcp = { + serverUrl: 'https://mcp.workos.com/mcp', + agents: [ + { agent: 'Claude Code', available: true, installed: false }, + { agent: 'Cursor', available: true, installed: true, misconfigured: false }, + ], + }; + expect(detectIssues(report).some((i) => i.code === 'MCP_MISCONFIGURED')).toBe(false); + }); + + it('adds exactly one warning listing the misconfigured agents', () => { + const report = baseReport(); + report.mcp = { + serverUrl: 'https://mcp.workos.com/mcp', + agents: [ + { agent: 'Claude Code', available: true, installed: true }, + { agent: 'Cursor', available: true, installed: true, misconfigured: true }, + ], + }; + + const mcpIssues = detectIssues(report).filter((i) => i.code === 'MCP_MISCONFIGURED'); + + expect(mcpIssues).toHaveLength(1); + expect(mcpIssues[0]).toEqual( + expect.objectContaining({ + code: 'MCP_MISCONFIGURED', + severity: 'warning', + message: expect.stringContaining('Cursor'), + remediation: 'Run: workos mcp install', + }), + ); + }); + }); }); diff --git a/src/doctor/issues.ts b/src/doctor/issues.ts index d2781e7d..6cce23be 100644 --- a/src/doctor/issues.ts +++ b/src/doctor/issues.ts @@ -178,6 +178,23 @@ export function detectIssues(report: Omit): } } + // MCP server URL drift — warn ONLY when a configured entry points at an + // unexpected URL. Absent MCP is never an issue: the user may have declined + // the offer, and doctor reports state without judging. + if (report.mcp) { + const misconfigured = report.mcp.agents.filter((a) => a.misconfigured); + if (misconfigured.length > 0) { + const agentList = misconfigured.map((a) => a.agent).join(', '); + issues.push({ + code: 'MCP_MISCONFIGURED', + severity: 'warning', + message: `WorkOS MCP server configured with an unexpected URL for ${agentList} — expected ${report.mcp.serverUrl}`, + remediation: 'Run: workos mcp install', + details: { agents: misconfigured.map((a) => a.agent), expectedUrl: report.mcp.serverUrl }, + }); + } + } + return issues; } diff --git a/src/doctor/output.ts b/src/doctor/output.ts index 49532ec3..973b5820 100644 --- a/src/doctor/output.ts +++ b/src/doctor/output.ts @@ -195,6 +195,21 @@ export function formatReport(report: DoctorReport, options?: FormatOptions): voi } } + // MCP Server (per detected coding agent) + if (report.mcp) { + console.log(''); + console.log('MCP Server'); + for (const agent of report.mcp.agents) { + if (agent.misconfigured) { + console.log(` ${Chalk.yellow('!')} ${agent.agent}: configured with an unexpected URL`); + } else if (agent.installed) { + console.log(` ${Chalk.green('✓')} ${agent.agent}: installed`); + } else { + console.log(` ${agent.agent}: ${Chalk.dim('not installed')}`); + } + } + } + // Verbose mode additions if (options?.verbose) { console.log(''); diff --git a/src/doctor/types.ts b/src/doctor/types.ts index c27b267c..07654117 100644 --- a/src/doctor/types.ts +++ b/src/doctor/types.ts @@ -150,6 +150,23 @@ export interface SkillsRefreshResult { skillsInstalled: string[]; } +export interface McpAgentMcpStatus { + /** Display name of the agent (e.g. "Cursor"), mirroring SkillAgentStatus. */ + agent: string; + /** Agent is usable on this machine. */ + available: boolean; + /** The WorkOS MCP server is present in this agent's config. */ + installed: boolean; + /** Cursor only: the entry exists but points at an unexpected URL. */ + misconfigured?: boolean; +} + +export interface McpInfo { + /** The URL the WorkOS MCP server should be configured with. */ + serverUrl: string; + agents: McpAgentMcpStatus[]; +} + export interface DoctorReport { version: string; timestamp: string; @@ -174,6 +191,8 @@ export interface DoctorReport { skills?: SkillsInfo; /** Present only when `--fix` actually performed a refresh. */ skillsRefresh?: SkillsRefreshResult; + /** MCP server status per detected coding agent. Null (absent) when none detected. */ + mcp?: McpInfo; issues: Issue[]; summary: { errors: number; diff --git a/src/emulate/workos/index.ts b/src/emulate/workos/index.ts index a5541c3c..83befa72 100644 --- a/src/emulate/workos/index.ts +++ b/src/emulate/workos/index.ts @@ -1,7 +1,7 @@ import { randomBytes } from 'node:crypto'; import type { ServicePlugin, Store, RouteContext } from '../core/index.js'; import { generateId } from '../core/index.js'; -import { getWorkOSStore, type WorkOSStore } from './store.js'; +import { getWorkOSStore } from './store.js'; import { organizationRoutes } from './routes/organizations.js'; import { organizationDomainRoutes } from './routes/organization-domains.js'; import { membershipRoutes } from './routes/memberships.js'; diff --git a/src/lib/constants.ts b/src/lib/constants.ts index f16189f8..0163dee4 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -36,6 +36,16 @@ export const ANALYTICS_ENABLED = settings.telemetry.enabled; export const INSTALLER_INTERACTION_EVENT_NAME = settings.telemetry.eventName; export const OAUTH_PORT = settings.legacy.oauthPort; +/** + * WorkOS MCP server identity, shared by the `mcp` command group and the + * per-client writers in `lib/mcp-clients.ts`. + * + * The server is secret-free: HTTP transport with OAuth handled by each client + * on first connect, so configuring it never requires CLI auth. + */ +export const MCP_SERVER_NAME = 'workos'; +export const MCP_SERVER_URL = 'https://mcp.workos.com/mcp'; + /** * Common glob patterns to ignore when searching for files. * Used by multiple integrations. diff --git a/src/lib/mcp-clients.ts b/src/lib/mcp-clients.ts new file mode 100644 index 00000000..ab6935df --- /dev/null +++ b/src/lib/mcp-clients.ts @@ -0,0 +1,327 @@ +import { homedir } from 'os'; +import { join } from 'path'; +import { access, mkdir, readFile, writeFile } from 'fs/promises'; +import * as jsonc from 'jsonc-parser'; +import { execFileNoThrow } from '../utils/exec-file.js'; +import { MCP_SERVER_NAME, MCP_SERVER_URL } from './constants.js'; + +/** + * Client-writer library for the WorkOS MCP server. + * + * One `McpClientTarget` interface, three implementations. Claude Code and Codex + * are configured by shelling out to their own CLIs (robust to their config + * format changes); Cursor has no CLI, so we merge `~/.cursor/mcp.json` directly + * with `jsonc-parser` (hand-edited files may contain comments / trailing + * commas). Every operation degrades to a reported outcome — a missing binary, + * an old client without HTTP-transport support, or an unparseable config is a + * `failed`/`skipped`/`not-installed` result, never a thrown error. + * + * The library owns detection and per-client config writing; callers (the `mcp` + * command today; install-flow / doctor in Phase 2) stay thin. Nothing here may + * assume it runs inside the `mcp` command. + */ + +/** 10s ceiling on every CLI shell-out so a hung client can't wedge the caller. */ +const EXEC_TIMEOUT_MS = 10_000; + +/** jsonc parse options: tolerate the comments / trailing commas real users + * hand-edit into `~/.cursor/mcp.json`, and an empty file, so only genuinely + * malformed JSON is flagged. */ +const JSONC_PARSE_OPTIONS: jsonc.ParseOptions = { + allowTrailingComma: true, + allowEmptyContent: true, +}; + +const JSONC_MODIFY_OPTIONS: jsonc.ModificationOptions = { + formattingOptions: { tabSize: 2, insertSpaces: true }, +}; + +export type McpAgentKey = 'claude-code' | 'codex' | 'cursor'; + +export type McpOutcome = 'installed' | 'already-installed' | 'removed' | 'not-installed' | 'skipped' | 'failed'; + +export interface McpClientResult { + agent: McpAgentKey; + displayName: string; + outcome: McpOutcome; + /** stderr/message excerpt when `outcome === 'failed'`. */ + error?: string; +} + +export interface McpClientTarget { + key: McpAgentKey; + displayName: string; + /** Agent is usable on this machine (config dir present AND, for CLI clients, binary runnable). */ + isAvailable(): Promise; + /** The WorkOS server is present in this client's config. */ + isInstalled(): Promise; + add(): Promise; + remove(): Promise; +} + +/** Stable list of known agent keys, for `--agent` validation by callers. */ +export const MCP_AGENT_KEYS: McpAgentKey[] = ['claude-code', 'codex', 'cursor']; + +/** Async existence check — `access` rejects with ENOENT when the path is missing. */ +async function pathExists(p: string): Promise { + try { + await access(p); + return true; + } catch { + return false; + } +} + +/** Trim a shell-out message to a single-line excerpt for the `error` field. */ +function excerpt(raw: string): string { + const text = raw.trim(); + if (!text) return 'Unknown error'; + const firstLine = text.split('\n').find((l) => l.trim().length > 0) ?? text; + return firstLine.trim().slice(0, 300); +} + +/** + * Does a CLI `mcp list` output contain our server? + * + * Matches the first whitespace-delimited token of any line (with an optional + * trailing colon stripped), which covers both list shapes we support: + * - Claude Code: `workos: https://mcp.workos.com/mcp (HTTP) - ✔ Connected` + * - Codex table: `workos https://mcp.workos.com/mcp ...` + * + * First-token matching avoids the substring collision a naive + * `output.includes('workos')` would hit on an unrelated `workos-docs` entry. + */ +function listHasServer(stdout: string, name: string): boolean { + return stdout.split('\n').some((line) => { + const firstToken = line.trim().split(/\s+/)[0] ?? ''; + return firstToken.replace(/:$/, '') === name; + }); +} + +/** + * Shared shell-out client for Claude Code and Codex. The two differ only in + * binary name, config dir, and the `add` arg shape; every outcome-mapping rule + * is identical, so they share one implementation. + */ +function createCliClient(config: { + key: McpAgentKey; + displayName: string; + binary: string; + configDir: string; + addArgs: string[]; + removeArgs: string[]; +}): McpClientTarget { + const { key, displayName, binary, configDir, addArgs, removeArgs } = config; + const result = (outcome: McpOutcome, error?: string): McpClientResult => ({ + agent: key, + displayName, + outcome, + ...(error ? { error } : {}), + }); + + async function checkInstalled(): Promise { + const res = await execFileNoThrow(binary, ['mcp', 'list'], { timeout: EXEC_TIMEOUT_MS }); + if (res.status !== 0) return false; + return listHasServer(res.stdout, MCP_SERVER_NAME); + } + + return { + key, + displayName, + async isAvailable() { + // Two layers: the config dir can exist while the binary isn't on PATH, + // and vice versa — require both before we try to shell out. + if (!(await pathExists(join(homedir(), configDir)))) return false; + const res = await execFileNoThrow(binary, ['--version'], { timeout: EXEC_TIMEOUT_MS }); + return res.status === 0; + }, + isInstalled: checkInstalled, + async add() { + const res = await execFileNoThrow(binary, addArgs, { timeout: EXEC_TIMEOUT_MS }); + if (res.status === 0) return result('installed'); + // Idempotent: an "already exists" collision is a success, not a failure. + const combined = `${res.stdout}\n${res.stderr}`.toLowerCase(); + if (combined.includes('already exists') || combined.includes('already configured')) { + return result('already-installed'); + } + // A non-zero exit doesn't always mean the write failed: Codex persists the + // server config and THEN starts an OAuth flow that blocks (no browser / + // callback available here) until our timeout kills it with a non-zero + // status. Confirm against the actual config before declaring failure — + // more robust than matching each client's success wording. + if (await checkInstalled()) return result('installed'); + // Otherwise a real failure — an old client lacking `--transport http` / + // `--url`, a bad invocation, etc. Reported, never thrown. + return result('failed', excerpt(res.stderr || res.stdout)); + }, + async remove() { + const res = await execFileNoThrow(binary, removeArgs, { timeout: EXEC_TIMEOUT_MS }); + const combined = `${res.stdout}\n${res.stderr}`.toLowerCase(); + // Claude exits 1 and Codex exits 0 when the server is absent; both print + // "No MCP server named ...". Treat either as an idempotent no-op. + if (combined.includes('no mcp server')) return result('not-installed'); + if (res.status === 0) return result('removed'); + return result('failed', excerpt(res.stderr || res.stdout)); + }, + }; +} + +function createClaudeCodeClient(): McpClientTarget { + return createCliClient({ + key: 'claude-code', + displayName: 'Claude Code', + binary: 'claude', + configDir: '.claude', + // User scope: the management MCP is account-level, not per-repo — project + // scope would nag teammates via checked-in config. + addArgs: ['mcp', 'add', '--transport', 'http', '--scope', 'user', MCP_SERVER_NAME, MCP_SERVER_URL], + removeArgs: ['mcp', 'remove', '--scope', 'user', MCP_SERVER_NAME], + }); +} + +function createCodexClient(): McpClientTarget { + return createCliClient({ + key: 'codex', + displayName: 'Codex', + binary: 'codex', + configDir: '.codex', + addArgs: ['mcp', 'add', MCP_SERVER_NAME, '--url', MCP_SERVER_URL], + removeArgs: ['mcp', 'remove', MCP_SERVER_NAME], + }); +} + +/** + * Cursor has no CLI, so we read-modify-write `~/.cursor/mcp.json` directly with + * `jsonc-parser`, preserving existing servers, comments, and formatting. + */ +function createCursorClient(): McpClientTarget { + const key: McpAgentKey = 'cursor'; + const displayName = 'Cursor'; + const cursorDir = () => join(homedir(), '.cursor'); + const configPath = () => join(cursorDir(), 'mcp.json'); + const result = (outcome: McpOutcome, error?: string): McpClientResult => ({ + agent: key, + displayName, + outcome, + ...(error ? { error } : {}), + }); + + /** Read + parse the config. `parseError` is true only for genuinely malformed + * JSON (not comments / trailing commas / empty). */ + async function readConfig(): Promise<{ + content: string; + parsed: Record | undefined; + parseError: boolean; + exists: boolean; + }> { + const path = configPath(); + if (!(await pathExists(path))) { + return { content: '', parsed: undefined, parseError: false, exists: false }; + } + const content = await readFile(path, 'utf8'); + const errors: jsonc.ParseError[] = []; + const parsed = jsonc.parse(content, errors, JSONC_PARSE_OPTIONS) as Record | undefined; + return { content, parsed, parseError: errors.length > 0, exists: true }; + } + + function hasWorkosServer(parsed: Record | undefined): boolean { + const servers = parsed?.mcpServers; + return Boolean(servers && typeof servers === 'object' && MCP_SERVER_NAME in (servers as object)); + } + + return { + key, + displayName, + async isAvailable() { + return pathExists(cursorDir()); + }, + async isInstalled() { + try { + const { parsed, parseError } = await readConfig(); + if (parseError) return false; + return hasWorkosServer(parsed); + } catch { + return false; + } + }, + async add() { + const path = configPath(); + try { + const { content, parseError, exists } = await readConfig(); + // Never overwrite a file we couldn't parse — the user must fix it first. + if (exists && parseError) { + return result('failed', `Could not parse ${path}; fix it manually and retry.`); + } + await mkdir(cursorDir(), { recursive: true }); + // Converge to our URL — an existing `workos` key with a different URL is + // overwritten (reported as `installed`). + const edits = jsonc.modify( + content, + ['mcpServers', MCP_SERVER_NAME], + { url: MCP_SERVER_URL }, + JSONC_MODIFY_OPTIONS, + ); + await writeFile(path, jsonc.applyEdits(content, edits), 'utf8'); + return result('installed'); + } catch (error) { + return result('failed', error instanceof Error ? error.message : 'Unknown error'); + } + }, + async remove() { + const path = configPath(); + try { + const { content, parsed, parseError, exists } = await readConfig(); + if (!exists) return result('not-installed'); + if (parseError) { + return result('failed', `Could not parse ${path}; fix it manually and retry.`); + } + if (!hasWorkosServer(parsed)) return result('not-installed'); + const edits = jsonc.modify(content, ['mcpServers', MCP_SERVER_NAME], undefined, JSONC_MODIFY_OPTIONS); + await writeFile(path, jsonc.applyEdits(content, edits), 'utf8'); + return result('removed'); + } catch (error) { + return result('failed', error instanceof Error ? error.message : 'Unknown error'); + } + }, + }; +} + +/** The three client targets, in a stable order. */ +export function createMcpClients(): McpClientTarget[] { + return [createClaudeCodeClient(), createCodexClient(), createCursorClient()]; +} + +/** + * The URL the WorkOS server is configured with in Cursor's `~/.cursor/mcp.json`, + * or null when the file/entry is absent, unreadable, or unparseable. + * + * Cursor is the only client whose config we read directly (the CLI clients don't + * expose per-entry URLs), so this powers doctor's URL-drift ("misconfigured") + * check without a second jsonc reader duplicating the config schema. Read-only + * and never throws — a problem reading just yields null. + */ +export async function getCursorConfiguredUrl(): Promise { + try { + const path = join(homedir(), '.cursor', 'mcp.json'); + if (!(await pathExists(path))) return null; + const content = await readFile(path, 'utf8'); + const parsed = jsonc.parse(content, [], JSONC_PARSE_OPTIONS) as Record | undefined; + const servers = parsed?.mcpServers as Record | undefined; + const entry = servers?.[MCP_SERVER_NAME] as { url?: unknown } | undefined; + return typeof entry?.url === 'string' ? entry.url : null; + } catch { + return null; + } +} + +/** + * Return only the clients available on this machine, optionally narrowed to + * `agentFilter` keys. Availability is probed in parallel. An unknown filter key + * simply matches nothing here — callers validate keys and surface the error. + */ +export async function detectMcpClients(agentFilter?: string[]): Promise { + const clients = createMcpClients(); + const filtered = agentFilter ? clients.filter((c) => agentFilter.includes(c.key)) : clients; + const availability = await Promise.all(filtered.map((c) => c.isAvailable())); + return filtered.filter((_, i) => availability[i]); +} diff --git a/src/lib/mcp-notice.spec.ts b/src/lib/mcp-notice.spec.ts new file mode 100644 index 00000000..acb40025 --- /dev/null +++ b/src/lib/mcp-notice.spec.ts @@ -0,0 +1,428 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import type { McpClientResult } from './mcp-clients.js'; + +// --- Controllable module state (read lazily inside mock factories) --- +let prefs: Record = {}; +let promptAllowed = true; +let humanMode = true; +let jsonMode = false; +let detectResult: unknown[] = []; + +const loadPreferencesMock = vi.fn(() => Promise.resolve(prefs)); +const savePreferencesMock = vi.fn(); +vi.mock('./preferences.js', () => ({ + loadPreferences: (...a: unknown[]) => loadPreferencesMock(...(a as [])), + savePreferences: (...a: unknown[]) => savePreferencesMock(...(a as [])), +})); + +vi.mock('../utils/interaction-mode.js', () => ({ + isPromptAllowed: () => promptAllowed, + isHumanMode: () => humanMode, +})); + +vi.mock('../utils/output.js', () => ({ isJsonMode: () => jsonMode })); + +const mockRenderStderrBox = vi.fn(); +vi.mock('../utils/box.js', () => ({ + renderStderrBox: (...a: unknown[]) => mockRenderStderrBox(...(a as [])), +})); + +const detectMcpClientsMock = vi.fn(() => Promise.resolve(detectResult)); +vi.mock('./mcp-clients.js', () => ({ + detectMcpClients: (...a: unknown[]) => detectMcpClientsMock(...(a as [])), +})); + +const confirmMock = vi.fn(); +const isCancelMock = vi.fn(() => false); +const clackLog = { success: vi.fn(), error: vi.fn(), info: vi.fn() }; +vi.mock('../utils/clack.js', () => ({ + default: { + confirm: (...a: unknown[]) => confirmMock(...(a as [])), + isCancel: (...a: unknown[]) => isCancelMock(...(a as [])), + log: clackLog, + }, +})); + +const captureMock = vi.fn(); +const emitCommandEventMock = vi.fn(); +vi.mock('../utils/analytics.js', () => ({ + analytics: { + capture: (...a: unknown[]) => captureMock(...(a as [])), + emitCommandEvent: (...a: unknown[]) => emitCommandEventMock(...(a as [])), + }, +})); + +const { + getMcpAskState, + recordMcpDeclined, + recordMcpBannerShown, + isAutoAskEligible, + maybeShowMcpNotice, + maybeOfferMcpInstall, + resetMcpNoticeState, + MCP_OFFER_TIMEOUT_MS, +} = await import('./mcp-notice.js'); +const { markStartupNoticeShown, resetStartupNoticeGate } = await import('./startup-notice-gate.js'); + +interface FakeClientOpts { + installed?: boolean; + add?: McpClientResult; + addThrows?: boolean; +} +function fakeClient(key: string, displayName: string, opts: FakeClientOpts = {}) { + return { + key, + displayName, + isAvailable: vi.fn(() => Promise.resolve(true)), + isInstalled: vi.fn(() => Promise.resolve(opts.installed ?? false)), + add: vi.fn(() => + opts.addThrows + ? Promise.reject(new Error('add exploded')) + : Promise.resolve(opts.add ?? ({ agent: key, displayName, outcome: 'installed' } as McpClientResult)), + ), + remove: vi.fn(), + }; +} + +beforeEach(() => { + vi.clearAllMocks(); + prefs = {}; + promptAllowed = true; + humanMode = true; + jsonMode = false; + detectResult = []; + loadPreferencesMock.mockImplementation(() => Promise.resolve(prefs)); + detectMcpClientsMock.mockImplementation(() => Promise.resolve(detectResult)); + savePreferencesMock.mockReset(); + confirmMock.mockReset(); + isCancelMock.mockReturnValue(false); + resetMcpNoticeState(); + resetStartupNoticeGate(); +}); + +describe('getMcpAskState', () => { + it('reads declined + bannerShown from prefs', async () => { + prefs = { mcp: { promptDeclined: true, bannerShownAt: '2026-01-01T00:00:00.000Z' } }; + expect(await getMcpAskState()).toEqual({ declined: true, bannerShown: true }); + }); + + it('defaults to false when no mcp prefs exist', async () => { + prefs = {}; + expect(await getMcpAskState()).toEqual({ declined: false, bannerShown: false }); + }); + + it('degrades to false/false when loadPreferences throws', async () => { + loadPreferencesMock.mockRejectedValueOnce(new Error('EIO')); + expect(await getMcpAskState()).toEqual({ declined: false, bannerShown: false }); + }); +}); + +describe('markers', () => { + it('recordMcpDeclined persists promptDeclined', async () => { + await recordMcpDeclined(); + expect(savePreferencesMock).toHaveBeenCalledWith({ mcp: { promptDeclined: true } }); + }); + + it('recordMcpBannerShown persists a bannerShownAt timestamp', async () => { + await recordMcpBannerShown(); + expect(savePreferencesMock).toHaveBeenCalledWith({ mcp: { bannerShownAt: expect.any(String) } }); + }); + + it('swallows prefs write failures (degrades to per-run memory)', async () => { + savePreferencesMock.mockImplementation(() => { + throw new Error('EROFS'); + }); + await expect(recordMcpDeclined()).resolves.toBeUndefined(); + await expect(recordMcpBannerShown()).resolves.toBeUndefined(); + }); +}); + +describe('isAutoAskEligible', () => { + it('false when declined — and never shells out to detect clients', async () => { + prefs = { mcp: { promptDeclined: true } }; + detectResult = [fakeClient('cursor', 'Cursor', { installed: false })]; + expect(await isAutoAskEligible()).toBe(false); + expect(detectMcpClientsMock).not.toHaveBeenCalled(); + }); + + it('false when no agents are detected', async () => { + detectResult = []; + expect(await isAutoAskEligible()).toBe(false); + }); + + it('false when every detected agent already has the server', async () => { + detectResult = [fakeClient('cursor', 'Cursor', { installed: true })]; + expect(await isAutoAskEligible()).toBe(false); + }); + + it('true when at least one detected agent lacks the server', async () => { + detectResult = [ + fakeClient('claude-code', 'Claude Code', { installed: true }), + fakeClient('cursor', 'Cursor', { installed: false }), + ]; + expect(await isAutoAskEligible()).toBe(true); + }); +}); + +describe('maybeShowMcpNotice (banner)', () => { + it('renders once and records bannerShown when eligible in human mode', async () => { + detectResult = [fakeClient('cursor', 'Cursor', { installed: false })]; + await maybeShowMcpNotice(); + expect(mockRenderStderrBox).toHaveBeenCalledTimes(1); + expect(savePreferencesMock).toHaveBeenCalledWith({ mcp: { bannerShownAt: expect.any(String) } }); + }); + + it('emits a banner impression event when shown', async () => { + detectResult = [fakeClient('cursor', 'Cursor', { installed: false })]; + await maybeShowMcpNotice(); + expect(emitCommandEventMock).toHaveBeenCalledTimes(1); + expect(emitCommandEventMock).toHaveBeenCalledWith('mcp offer', 0, true, { + extraAttributes: { 'mcp.entry_point': 'banner', 'mcp.shown': true }, + }); + }); + + it('does not render or emit a second time in the same session', async () => { + detectResult = [fakeClient('cursor', 'Cursor', { installed: false })]; + await maybeShowMcpNotice(); + await maybeShowMcpNotice(); + expect(mockRenderStderrBox).toHaveBeenCalledTimes(1); + expect(emitCommandEventMock).toHaveBeenCalledTimes(1); + }); + + it('suppressed outside human mode', async () => { + humanMode = false; + detectResult = [fakeClient('cursor', 'Cursor', { installed: false })]; + await maybeShowMcpNotice(); + expect(mockRenderStderrBox).not.toHaveBeenCalled(); + }); + + it('suppressed in JSON mode', async () => { + jsonMode = true; + detectResult = [fakeClient('cursor', 'Cursor', { installed: false })]; + await maybeShowMcpNotice(); + expect(mockRenderStderrBox).not.toHaveBeenCalled(); + }); + + it('defers when another startup notice already fired this run', async () => { + markStartupNoticeShown(); // e.g. the telemetry notice or unclaimed warning won + detectResult = [fakeClient('cursor', 'Cursor', { installed: false })]; + await maybeShowMcpNotice(); + expect(mockRenderStderrBox).not.toHaveBeenCalled(); + }); + + it('suppressed when the banner was already shown on a previous run', async () => { + prefs = { mcp: { bannerShownAt: '2025-01-01T00:00:00.000Z' } }; + detectResult = [fakeClient('cursor', 'Cursor', { installed: false })]; + await maybeShowMcpNotice(); + expect(mockRenderStderrBox).not.toHaveBeenCalled(); + }); + + it('suppressed for a declined user', async () => { + prefs = { mcp: { promptDeclined: true } }; + detectResult = [fakeClient('cursor', 'Cursor', { installed: false })]; + await maybeShowMcpNotice(); + expect(mockRenderStderrBox).not.toHaveBeenCalled(); + }); + + it('suppressed when nothing is installable (all agents already have it)', async () => { + detectResult = [fakeClient('cursor', 'Cursor', { installed: true })]; + await maybeShowMcpNotice(); + expect(mockRenderStderrBox).not.toHaveBeenCalled(); + }); +}); + +describe('maybeOfferMcpInstall (install-flow prompt)', () => { + it('never prompts when prompting is not allowed (agent/CI/non-TTY)', async () => { + promptAllowed = false; + detectResult = [fakeClient('cursor', 'Cursor', { installed: false })]; + await maybeOfferMcpInstall({ entryPoint: 'install-flow' }); + expect(confirmMock).not.toHaveBeenCalled(); + expect(emitCommandEventMock).not.toHaveBeenCalled(); + expect(savePreferencesMock).not.toHaveBeenCalled(); + }); + + it('never prompts in JSON mode (e.g. `install --json` on a TTY) so output stays clean', async () => { + jsonMode = true; // human interaction mode but machine-readable output + detectResult = [fakeClient('cursor', 'Cursor', { installed: false })]; + await maybeOfferMcpInstall({ entryPoint: 'install-flow' }); + expect(confirmMock).not.toHaveBeenCalled(); + expect(emitCommandEventMock).not.toHaveBeenCalled(); + }); + + it('installs to detected-and-missing agents on accept and captures the outcome', async () => { + const claude = fakeClient('claude-code', 'Claude Code', { installed: false }); + const cursor = fakeClient('cursor', 'Cursor', { installed: true }); // already has it → not a target + detectResult = [claude, cursor]; + confirmMock.mockResolvedValue(true); + + await maybeOfferMcpInstall({ entryPoint: 'install-flow' }); + + // Prompt names only the installable agent. + const message = confirmMock.mock.calls[0][0].message as string; + expect(message).toContain('Claude Code'); + expect(message).not.toContain('Cursor'); + + expect(claude.add).toHaveBeenCalledTimes(1); + expect(cursor.add).not.toHaveBeenCalled(); + expect(emitCommandEventMock).toHaveBeenCalledWith('mcp offer', expect.any(Number), true, { + extraAttributes: { + 'mcp.entry_point': 'install-flow', + 'mcp.accepted': true, + 'mcp.agents_installed': 'claude-code', + 'mcp.agents_failed': '', + }, + }); + }); + + it('records the decline and captures accepted:false on explicit no', async () => { + const cursor = fakeClient('cursor', 'Cursor', { installed: false }); + detectResult = [cursor]; + confirmMock.mockResolvedValue(false); + + await maybeOfferMcpInstall({ entryPoint: 'install-flow' }); + + expect(savePreferencesMock).toHaveBeenCalledWith({ mcp: { promptDeclined: true } }); + expect(cursor.add).not.toHaveBeenCalled(); + // A decline is a completed interaction, not an error: success stays true. + expect(emitCommandEventMock).toHaveBeenCalledWith('mcp offer', expect.any(Number), true, { + extraAttributes: { + 'mcp.entry_point': 'install-flow', + 'mcp.accepted': false, + 'mcp.agents_installed': '', + 'mcp.agents_failed': '', + }, + }); + }); + + it('treats ctrl-C (cancel) as neither a decline nor an install', async () => { + const cursor = fakeClient('cursor', 'Cursor', { installed: false }); + detectResult = [cursor]; + confirmMock.mockResolvedValue(Symbol('cancel')); + isCancelMock.mockReturnValue(true); + + await maybeOfferMcpInstall({ entryPoint: 'install-flow' }); + + expect(savePreferencesMock).not.toHaveBeenCalled(); + expect(emitCommandEventMock).not.toHaveBeenCalled(); + expect(cursor.add).not.toHaveBeenCalled(); + }); + + it('does not prompt a user who already declined', async () => { + prefs = { mcp: { promptDeclined: true } }; + detectResult = [fakeClient('cursor', 'Cursor', { installed: false })]; + await maybeOfferMcpInstall({ entryPoint: 'install-flow' }); + expect(confirmMock).not.toHaveBeenCalled(); + }); + + it('does not prompt when there is nothing to install', async () => { + detectResult = [fakeClient('cursor', 'Cursor', { installed: true })]; + await maybeOfferMcpInstall({ entryPoint: 'install-flow' }); + expect(confirmMock).not.toHaveBeenCalled(); + }); + + it('never throws even if a client install throws (install flow unaffected)', async () => { + detectResult = [fakeClient('cursor', 'Cursor', { installed: false, addThrows: true })]; + confirmMock.mockResolvedValue(true); + await expect(maybeOfferMcpInstall({ entryPoint: 'install-flow' })).resolves.toBeUndefined(); + }); + + it('reports both installed and failed agents in the capture', async () => { + const ok = fakeClient('claude-code', 'Claude Code', { + installed: false, + add: { agent: 'claude-code', displayName: 'Claude Code', outcome: 'installed' }, + }); + const bad = fakeClient('cursor', 'Cursor', { + installed: false, + add: { agent: 'cursor', displayName: 'Cursor', outcome: 'failed', error: 'nope' }, + }); + detectResult = [ok, bad]; + confirmMock.mockResolvedValue(true); + + await maybeOfferMcpInstall({ entryPoint: 'install-flow' }); + + // An accepted offer with a failed agent install is an error span: + // success flips to false while the per-agent lists carry the detail. + expect(emitCommandEventMock).toHaveBeenCalledWith('mcp offer', expect.any(Number), false, { + extraAttributes: { + 'mcp.entry_point': 'install-flow', + 'mcp.accepted': true, + 'mcp.agents_installed': 'claude-code', + 'mcp.agents_failed': 'cursor', + }, + }); + }); + + it('aborts a hung prompt at the deadline: stdin released, nothing recorded', async () => { + const CANCEL = Symbol('clack:cancel'); + const cursor = fakeClient('cursor', 'Cursor', { installed: false }); + detectResult = [cursor]; + // A prompt that never gets an answer: it only resolves (as a cancel, the + // way clack does) when the deadline signal aborts it. + confirmMock.mockImplementation( + (opts: { signal?: AbortSignal }) => + new Promise((resolve) => { + opts.signal?.addEventListener('abort', () => resolve(CANCEL), { once: true }); + }), + ); + isCancelMock.mockImplementation((v: unknown) => v === CANCEL); + + vi.useFakeTimers(); + try { + const offer = maybeOfferMcpInstall({ entryPoint: 'install-flow' }); + await vi.advanceTimersByTimeAsync(MCP_OFFER_TIMEOUT_MS); + await expect(offer).resolves.toBeUndefined(); + } finally { + vi.useRealTimers(); + } + + // The prompt must receive the deadline signal — without it, the race + // resolves but the pending confirm keeps stdin (and the process) alive. + expect(confirmMock.mock.calls[0][0].signal).toBeInstanceOf(AbortSignal); + // A timeout is a cancel, not a decline: nothing persisted, nothing emitted. + expect(savePreferencesMock).not.toHaveBeenCalled(); + expect(emitCommandEventMock).not.toHaveBeenCalled(); + expect(cursor.add).not.toHaveBeenCalled(); + }); + + it('does not start installs when the answer lands at the deadline', async () => { + const cursor = fakeClient('cursor', 'Cursor', { installed: false }); + detectResult = [cursor]; + // Simulate a "yes" submitted in the same tick the deadline fires (submit + // beats cancel inside clack): the signal is already aborted by the time + // the flow sees the answer. + confirmMock.mockImplementation( + (opts: { signal?: AbortSignal }) => + new Promise((resolve) => { + opts.signal?.addEventListener('abort', () => resolve(true), { once: true }); + }), + ); + + vi.useFakeTimers(); + try { + const offer = maybeOfferMcpInstall({ entryPoint: 'install-flow' }); + await vi.advanceTimersByTimeAsync(MCP_OFFER_TIMEOUT_MS); + await expect(offer).resolves.toBeUndefined(); + } finally { + vi.useRealTimers(); + } + + // The outer flow already moved on — no detached install work, no emission. + expect(cursor.add).not.toHaveBeenCalled(); + expect(emitCommandEventMock).not.toHaveBeenCalled(); + }); + + it('counts already-installed agents as installed in the emission', async () => { + const already = fakeClient('codex', 'Codex', { + installed: false, + add: { agent: 'codex', displayName: 'Codex', outcome: 'already-installed' }, + }); + detectResult = [already]; + confirmMock.mockResolvedValue(true); + + await maybeOfferMcpInstall({ entryPoint: 'install-flow' }); + + expect(emitCommandEventMock).toHaveBeenCalledWith('mcp offer', expect.any(Number), true, { + extraAttributes: expect.objectContaining({ 'mcp.agents_installed': 'codex', 'mcp.agents_failed': '' }), + }); + }); +}); diff --git a/src/lib/mcp-notice.ts b/src/lib/mcp-notice.ts new file mode 100644 index 00000000..e8e37f9b --- /dev/null +++ b/src/lib/mcp-notice.ts @@ -0,0 +1,276 @@ +/** + * MCP-install onboarding surfaces + their shared gate state. + * + * One module owns all automatic-ask state so the install-flow prompt and the + * one-time banner can't drift apart. The decline contract is absolute: any + * explicit "no" records `promptDeclined` and no automatic surface ever asks + * again — `workos mcp install` stays available manually. + * + * Mirrors telemetry-notice.ts: persisted shown/declined state in the plain + * prefs store, mode-gated display, and a never-throws contract so a notice can + * never block or fail a command. The mode gate is the CLI's interaction-mode + * system (isPromptAllowed / isHumanMode), which already folds in CI markers, + * agent markers, and TTY state — non-TTY safety comes from using it. + */ + +import chalk from 'chalk'; +import clack from '../utils/clack.js'; +import { isHumanMode, isPromptAllowed } from '../utils/interaction-mode.js'; +import { isJsonMode } from '../utils/output.js'; +import { renderStderrBox } from '../utils/box.js'; +import { formatWorkOSCommand } from '../utils/command-invocation.js'; +import { analytics } from '../utils/analytics.js'; +import { loadPreferences, savePreferences } from './preferences.js'; +import { detectMcpClients, type McpClientResult, type McpClientTarget } from './mcp-clients.js'; +import { hasStartupNoticeShown, markStartupNoticeShown } from './startup-notice-gate.js'; + +export type McpAskState = { declined: boolean; bannerShown: boolean }; + +/** + * Ceiling on the whole install-flow offer so a wedged prompt can never hold up + * `workos install`. The deadline actively aborts the pending clack prompt (via + * AbortSignal) — clack's cancel path releases stdin and restores raw mode, so + * the process can actually exit; a race alone would leave the prompt's stdin + * handle keeping the event loop alive. Mirrors login.ts's + * SKILL_INSTALL_TIMEOUT_MS. + */ +export const MCP_OFFER_TIMEOUT_MS = 30 * 1000; + +let bannerShownThisSession = false; + +/** Human phrasing for each install outcome shown in the accept matrix. */ +const OUTCOME_LABEL: Record = { + installed: 'installed', + 'already-installed': 'already installed', + removed: 'removed', + 'not-installed': 'not installed', + skipped: 'skipped', + failed: 'failed', +}; + +/** + * Read the persisted automatic-ask state. Never throws — a missing/corrupt + * prefs file degrades to "nothing recorded" so gating still works in-memory. + */ +export async function getMcpAskState(): Promise { + try { + const prefs = await loadPreferences(); + return { + declined: prefs.mcp?.promptDeclined === true, + bannerShown: Boolean(prefs.mcp?.bannerShownAt), + }; + } catch { + return { declined: false, bannerShown: false }; + } +} + +/** + * Record an explicit decline. Absolute and permanent for automatic surfaces. + * Write failures are swallowed: gating degrades to per-run memory, never + * crashes a command. + */ +export async function recordMcpDeclined(): Promise { + try { + savePreferences({ mcp: { promptDeclined: true } }); + } catch { + // Swallow — a read-only prefs file must never break a command. + } +} + +/** Record that the one-time banner was shown, stamping the current time. */ +export async function recordMcpBannerShown(): Promise { + try { + savePreferences({ mcp: { bannerShownAt: new Date().toISOString() } }); + } catch { + // Swallow — see recordMcpDeclined. + } +} + +/** + * The detected agents that would actually receive an install: available on this + * machine AND missing the WorkOS server. Empty when there is nothing to offer. + * Never throws — detection failure yields an empty set. + */ +async function detectInstallTargets(): Promise { + try { + const clients = await detectMcpClients(); + if (clients.length === 0) return []; + const installed = await Promise.all(clients.map((c) => c.isInstalled())); + return clients.filter((_, i) => !installed[i]); + } catch { + return []; + } +} + +/** + * Would an automatic ask be appropriate right now? True only when the user has + * not declined AND at least one detected agent lacks the server. Does NOT gate + * on interaction mode — callers add that (isPromptAllowed for the prompt, + * isHumanMode for the banner). Checks `declined` first so declined machines + * never pay for the client shell-outs. + */ +export async function isAutoAskEligible(): Promise { + const { declined } = await getMcpAskState(); + if (declined) return false; + const targets = await detectInstallTargets(); + return targets.length > 0; +} + +/** + * One-time stderr banner nudging the user toward `workos mcp install`. Shown at + * most once per machine, only on a normal human-mode run, and never when an + * earlier startup notice already fired this run (telemetry notice and unclaimed + * warning take precedence). Records `bannerShownAt` before printing — + * shown-once beats seen-once (a lost banner is fine; a nag loop is not). Never + * throws. + */ +export async function maybeShowMcpNotice(): Promise { + try { + if (bannerShownThisSession) return; + if (!isHumanMode()) return; // suppress in agent / CI / non-TTY + if (isJsonMode()) return; // never on the machine-readable path + if (hasStartupNoticeShown()) return; // one-notice-per-run cap; telemetry/unclaimed win + const { bannerShown } = await getMcpAskState(); + if (bannerShown) return; // already shown once, ever + if (!(await isAutoAskEligible())) return; // declined, or nothing to offer + + // Claim the slot + persist BEFORE printing: a lost banner beats a nag loop. + bannerShownThisSession = true; + markStartupNoticeShown(); + await recordMcpBannerShown(); + + // Impression event. Queued (not capture()d) so it rides the CLI's final + // flush; capture() only folds session tags and no session exists here. + analytics.emitCommandEvent('mcp offer', 0, true, { + extraAttributes: { 'mcp.entry_point': 'banner', 'mcp.shown': true }, + }); + + const cmd = chalk.cyan(formatWorkOSCommand('mcp install')); + const inner = ` ${chalk.cyan('ℹ')} New: connect your coding agent to WorkOS. Run ${cmd} to add the WorkOS MCP server (Claude Code, Codex, Cursor). `; + renderStderrBox(inner, chalk.cyan); + } catch { + // Never block command startup. + } +} + +/** Emit the per-agent install matrix (human mode) without ever exiting. */ +function printInstallMatrix(results: McpClientResult[]): void { + for (const r of results) { + const line = `${r.displayName}: ${OUTCOME_LABEL[r.outcome]}`; + if (r.outcome === 'failed') { + clack.log.error(r.error ? `${line} — ${r.error}` : line); + } else { + clack.log.success(line); + } + } +} + +/** + * The real install-flow offer. Self-gating: renders nothing unless prompting is + * allowed, the user hasn't declined, and there is at least one agent to install + * to. On yes: install + print the matrix + emit the adoption event. On explicit + * no: record the decline + emit (a decline is an adoption signal). On cancel + * (ctrl-C): skip silently without recording — a cancel is not a decline. + */ +async function offerMcpInstall(signal: AbortSignal): Promise { + if (!isPromptAllowed()) return; // the entire mode gate (CI / agent / non-TTY) + if (isJsonMode()) return; // never prompt on the machine-readable path (e.g. `install --json` on a TTY) + const { declined } = await getMcpAskState(); + if (declined) return; // decline is absolute + const targets = await detectInstallTargets(); + if (targets.length === 0) return; // nothing to offer + + const names = targets.map((t) => t.displayName).join(', '); + const offerStartedAt = Date.now(); + // The deadline signal aborts a hung/unanswered prompt: clack resolves it as + // a cancel and releases stdin so the process can exit. + const answer = await clack.confirm({ + message: `Add the WorkOS MCP server to ${names}? Your coding agent gets tools to manage WorkOS resources (you'll authorize via OAuth on first use).`, + signal, + }); + + // Cancel (ctrl-C or deadline abort) is not a decline — skip silently, ask + // again next time. + if (clack.isCancel(answer)) return; + + // Adoption events are queued command events, NOT capture(): the installer + // session has already shut down by the time this offer runs (run-with-core + // fires session.end in its finally), so folded tags would never ship. A + // queued event rides the CLI's unconditional final flush (bin.ts) and the + // store-forward exit handler covers anything the flush misses. + if (!answer) { + // Record the decline BEFORE anything else so a later crash can't re-ask. + await recordMcpDeclined(); + // A decline is a completed interaction, not an error: success stays true. + analytics.emitCommandEvent('mcp offer', Date.now() - offerStartedAt, true, { + extraAttributes: { + 'mcp.entry_point': 'install-flow', + 'mcp.accepted': false, + 'mcp.agents_installed': '', + 'mcp.agents_failed': '', + }, + }); + return; + } + + // The user submitted right as the deadline fired: the outer flow has already + // moved on, so don't start install work it will never report on. + if (signal.aborted) return; + + const results: McpClientResult[] = []; + for (const target of targets) { + results.push(await target.add()); + } + printInstallMatrix(results); + + const installed = results + .filter((r) => r.outcome === 'installed' || r.outcome === 'already-installed') + .map((r) => r.agent); + const failed = results.filter((r) => r.outcome === 'failed').map((r) => r.agent); + // success=false when any agent failed, so the offer surfaces as an error + // span while mcp.agents_failed carries which ones. + analytics.emitCommandEvent('mcp offer', Date.now() - offerStartedAt, failed.length === 0, { + extraAttributes: { + 'mcp.entry_point': 'install-flow', + 'mcp.accepted': true, + 'mcp.agents_installed': installed.join(','), + 'mcp.agents_failed': failed.join(','), + }, + }); +} + +/** + * Offer to install the WorkOS MCP server at the end of `workos install`. + * + * Wraps offerMcpInstall best-effort: a try/catch AND a 30s deadline so the + * offer can never throw into, wedge, or fail the install flow. The deadline + * aborts the pending prompt (AbortSignal → clack cancel, which releases stdin); + * the race is a backstop in case the flow is wedged somewhere that can't be + * aborted (client shell-outs are separately bounded by their exec timeouts). + * `workos install` has already succeeded by the time this runs. + */ +export async function maybeOfferMcpInstall(_opts: { entryPoint: 'install-flow' }): Promise { + let timeoutHandle: ReturnType | undefined; + const deadline = new AbortController(); + try { + const timeout = new Promise((resolve) => { + timeoutHandle = setTimeout(() => { + deadline.abort(); + resolve(); + }, MCP_OFFER_TIMEOUT_MS); + // Don't keep the event loop alive on this timer — the process should exit + // as soon as everything else settles. + timeoutHandle.unref?.(); + }); + await Promise.race([offerMcpInstall(deadline.signal), timeout]); + } catch { + // The MCP offer must never fail or block `workos install`. + } finally { + if (timeoutHandle) clearTimeout(timeoutHandle); + } +} + +/** Reset per-session banner state (for testing). */ +export function resetMcpNoticeState(): void { + bannerShownThisSession = false; +} diff --git a/src/lib/preferences.ts b/src/lib/preferences.ts index 159df931..5b9c5490 100644 --- a/src/lib/preferences.ts +++ b/src/lib/preferences.ts @@ -24,6 +24,20 @@ export interface CliPreferences { /** ISO timestamp the first-run notice was shown — written in Phase 2 only. */ noticeShownAt?: string; }; + /** + * MCP-install onboarding state. Owned semantically by lib/mcp-notice.ts; the + * shape lives here so it rides the same plain-JSON prefs store as telemetry. + */ + mcp?: { + /** + * true => the user explicitly declined an automatic MCP install offer. The + * decline is absolute: no automatic surface (prompt or banner) asks again; + * `workos mcp install` stays available manually. + */ + promptDeclined?: boolean; + /** ISO timestamp the one-time MCP banner was shown. */ + bannerShownAt?: string; + }; } /** Effective source of the resolved telemetry-enabled decision. */ @@ -117,6 +131,9 @@ export function savePreferences(next: CliPreferences): void { ...current, ...next, ...(current.telemetry || next.telemetry ? { telemetry: { ...current.telemetry, ...next.telemetry } } : {}), + // Deep-merge mcp too so writing one marker (e.g. bannerShownAt) never + // clobbers the other (promptDeclined), which are written at different times. + ...(current.mcp || next.mcp ? { mcp: { ...current.mcp, ...next.mcp } } : {}), }; fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 }); diff --git a/src/lib/startup-notice-gate.ts b/src/lib/startup-notice-gate.ts new file mode 100644 index 00000000..d87e344b --- /dev/null +++ b/src/lib/startup-notice-gate.ts @@ -0,0 +1,32 @@ +/** + * One-notice-per-run coordinator for the startup stderr notices. + * + * Three middlewares can each want to print a one-line stderr notice at startup: + * the first-run telemetry notice, the unclaimed-environment warning, and the + * MCP banner. Stacking two or three boxes on a single command is noise, so this + * module is the shared latch — whichever fires first calls + * markStartupNoticeShown(), and the lower-priority MCP banner checks + * hasStartupNoticeShown() and defers. + * + * Ordering IS priority: bin.ts runs the telemetry + unclaimed middlewares before + * the MCP banner middleware, so those two always win a contested run. In-memory + * only (a run is a single CLI process); the per-machine "already shown" state is + * persisted separately by each notice. + */ + +let shown = false; + +/** Record that a startup notice has displayed this run. */ +export function markStartupNoticeShown(): void { + shown = true; +} + +/** Whether any startup notice has already displayed this run. */ +export function hasStartupNoticeShown(): boolean { + return shown; +} + +/** Reset the latch (for testing). */ +export function resetStartupNoticeGate(): void { + shown = false; +} diff --git a/src/lib/telemetry-notice.ts b/src/lib/telemetry-notice.ts index 17e44e45..74e5981b 100644 --- a/src/lib/telemetry-notice.ts +++ b/src/lib/telemetry-notice.ts @@ -18,6 +18,7 @@ import { isJsonMode } from '../utils/output.js'; import { renderStderrBox } from '../utils/box.js'; import { formatWorkOSCommand } from '../utils/command-invocation.js'; import { isNoticeShown, markNoticeShown, isTelemetryOptedOut } from './preferences.js'; +import { markStartupNoticeShown } from './startup-notice-gate.js'; let shownThisSession = false; @@ -44,6 +45,8 @@ export function maybeShowTelemetryNotice(): void { // rather than silently suppressing the notice for the rest of the session. shownThisSession = true; markNoticeShown(); + // Claim the one-notice-per-run slot so the lower-priority MCP banner defers. + markStartupNoticeShown(); } catch { // Never block command execution. } diff --git a/src/lib/unclaimed-warning.ts b/src/lib/unclaimed-warning.ts index 198fa125..9ce9c033 100644 --- a/src/lib/unclaimed-warning.ts +++ b/src/lib/unclaimed-warning.ts @@ -13,6 +13,7 @@ import { createClaimNonce, UnclaimedEnvApiError } from './unclaimed-env-api.js'; import { logError, logInfo } from '../utils/debug.js'; import { isJsonMode } from '../utils/output.js'; import { renderStderrBox } from '../utils/box.js'; +import { markStartupNoticeShown } from './startup-notice-gate.js'; let warningShownThisSession = false; let claimCheckDoneThisSession = false; @@ -61,6 +62,8 @@ export async function warnIfUnclaimed(): Promise { if (!isJsonMode()) { const inner = ` ${chalk.yellow('⚠ Unclaimed environment')} — Run ${chalk.cyan('workos env claim')} to keep your data. `; renderStderrBox(inner, chalk.yellow); + // Claim the one-notice-per-run slot so the lower-priority MCP banner defers. + markStartupNoticeShown(); } } catch (error) { // Never block command execution, but log for diagnostics diff --git a/src/utils/analytics.spec.ts b/src/utils/analytics.spec.ts index af8c8d52..44f682ee 100644 --- a/src/utils/analytics.spec.ts +++ b/src/utils/analytics.spec.ts @@ -596,6 +596,28 @@ describe('Analytics', () => { expect(event.attributes['termination.reason']).toBeUndefined(); expect(event.attributes['api.status']).toBeUndefined(); }); + + it('merges extraAttributes into the event attributes', () => { + analytics.emitCommandEvent('mcp offer', 0, true, { + extraAttributes: { 'mcp.entry_point': 'banner', 'mcp.shown': true }, + }); + + const event = mockQueueEvent.mock.calls.find((c: any) => c[0].type === 'command')[0]; + expect(event.attributes['mcp.entry_point']).toBe('banner'); + expect(event.attributes['mcp.shown']).toBe(true); + expect(event.attributes['command.name']).toBe('mcp offer'); + }); + + it('extraAttributes cannot override standard command fields', () => { + analytics.emitCommandEvent('mcp offer', 5, true, { + extraAttributes: { 'command.name': 'evil', 'command.success': false, 'device.id': 'spoofed' }, + }); + + const event = mockQueueEvent.mock.calls.find((c: any) => c[0].type === 'command')[0]; + expect(event.attributes['command.name']).toBe('mcp offer'); + expect(event.attributes['command.success']).toBe(true); + expect(event.attributes['device.id']).toBe(TEST_DEVICE_ID); + }); }); describe('captureUnhandledCrash', () => { diff --git a/src/utils/analytics.ts b/src/utils/analytics.ts index 1f529375..070ee3a0 100644 --- a/src/utils/analytics.ts +++ b/src/utils/analytics.ts @@ -295,6 +295,7 @@ export class Analytics { reason?: TerminationReason; errorCode?: string; apiContext?: { status?: number; code?: string; resource?: string }; + extraAttributes?: Record; }, ) { if (!this.isEnabled()) return; @@ -306,6 +307,9 @@ export class Analytics { sessionId: this.sessionId, timestamp: new Date().toISOString(), attributes: { + // Extras first: standard fields below win on key collision, so callers + // can never override command.name, error fields, or the fingerprint. + ...options?.extraAttributes, 'command.name': name, 'command.duration_ms': durationMs, 'command.success': success, diff --git a/src/utils/help-json.ts b/src/utils/help-json.ts index b85e54a2..b377a912 100644 --- a/src/utils/help-json.ts +++ b/src/utils/help-json.ts @@ -184,6 +184,44 @@ const commands: CommandSchema[] = [ }, ], }, + { + name: 'mcp', + description: 'Manage the WorkOS MCP server in coding agents (Claude Code, Codex, Cursor)', + commands: [ + { + name: 'install', + description: 'Add the WorkOS MCP server to detected coding agents', + options: [ + { + name: 'agent', + type: 'array', + description: 'Target specific agent(s): claude-code, codex, cursor', + required: false, + alias: 'a', + hidden: false, + }, + ], + }, + { + name: 'remove', + description: 'Remove the WorkOS MCP server from coding agents', + options: [ + { + name: 'agent', + type: 'array', + description: 'Target specific agent(s): claude-code, codex, cursor', + required: false, + alias: 'a', + hidden: false, + }, + ], + }, + { + name: 'status', + description: 'Show which coding agents have the WorkOS MCP server configured', + }, + ], + }, { name: 'doctor', description: 'Diagnose WorkOS AuthKit integration issues in the current project', diff --git a/src/utils/telemetry-types.ts b/src/utils/telemetry-types.ts index 82a067ed..4ea58839 100644 --- a/src/utils/telemetry-types.ts +++ b/src/utils/telemetry-types.ts @@ -91,7 +91,10 @@ export interface CommandEvent extends BaseTelemetryEvent { 'api.resource'?: string; 'cli.version': string; 'workos.user_id'?: string; - } & EnvFingerprint; + // Open for caller-supplied dimensions (e.g. mcp.*) — the gateway schema is + // passthrough and flattens unknown attributes onto the command span. + } & EnvFingerprint & + Record; } export interface CrashEvent extends BaseTelemetryEvent {