Unified · Split
| @@ -1,8 +1,17 @@ | ||
| 1 | 1 | # Changesets |
| 2 | 2 | |
| 3 | −Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works | |
| 4 | −with multi-package repos, or single-package repos to help you version and publish your code. You can | |
| 5 | −find the full documentation for it [in our repository](https://github.com/changesets/changesets). | |
| 3 | +This repo uses Changesets to drive releases for the published `executor` CLI. | |
| 6 | 4 | |
| 7 | −We have a quick list of common questions to get you started engaging with this project in | |
| 8 | −[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md). | |
| 5 | +## What to put in a changeset | |
| 6 | + | |
| 7 | +Only `executor` is managed directly by Changesets. | |
| 8 | + | |
| 9 | +After `changeset version` runs, `scripts/release/sync-versions.mjs` copies that version to the rest of the repo manifests so the workspace stays aligned without making every internal package independently releasable. | |
| 10 | + | |
| 11 | +## Beta releases | |
| 12 | + | |
| 13 | +Use prerelease mode for beta trains: | |
| 14 | + | |
| 15 | +- `bun run release:beta:start` | |
| 16 | +- merge release PRs while prerelease mode is active | |
| 17 | +- `bun run release:beta:stop` when you want to return to stable releases | |
| @@ -7,5 +7,27 @@ · 6 unmodified lines | ||
| 7 | 7 | "access": "public", |
| 8 | 8 | "baseBranch": "main", |
| 9 | 9 | "updateInternalDependencies": "patch", |
| 10 | − "ignore": [] | |
| 10 | + "ignore": [ | |
| 11 | + "@executor/server", | |
| 12 | + "@executor/web", | |
| 13 | + "@executor/react", | |
| 14 | + "@executor/api", | |
| 15 | + "@executor/config", | |
| 16 | + "@executor/execution", | |
| 17 | + "@executor/sdk", | |
| 18 | + "@executor/storage-file", | |
| 19 | + "@executor/host-mcp", | |
| 20 | + "@executor/codemode-core", | |
| 21 | + "@executor/ir", | |
| 22 | + "@executor/runtime-deno-subprocess", | |
| 23 | + "@executor/runtime-quickjs", | |
| 24 | + "@executor/plugin-file-secrets", | |
| 25 | + "@executor/plugin-google-discovery", | |
| 26 | + "@executor/plugin-graphql", | |
| 27 | + "@executor/plugin-keychain", | |
| 28 | + "@executor/plugin-mcp", | |
| 29 | + "@executor/plugin-onepassword", | |
| 30 | + "@executor/plugin-openapi", | |
| 31 | + "@executor/ui" | |
| 32 | + ] | |
| 11 | 33 | } |
| @@ -1,5 +0,0 @@ | ||
| 1 | −--- | |
| 2 | −"executor": minor | |
| 3 | −--- | |
| 4 | − | |
| 5 | −Prepare the next executor beta minor release. | |
| @@ -1,5 +0,0 @@ | ||
| 1 | −--- | |
| 2 | −"executor": patch | |
| 3 | −--- | |
| 4 | − | |
| 5 | −Fix the packaged beta so the bundled 1Password SDK can load its wasm asset after install. | |
| @@ -2,59 +2,28 @@ · 1 unmodified line | ||
| 2 | 2 | "mode": "pre", |
| 3 | 3 | "tag": "beta", |
| 4 | 4 | "initialVersions": { |
| 5 | − "@executor/docs": "0.0.0", | |
| 6 | − "executor": "1.2.6", | |
| 7 | − "@executor/web": "0.0.0", | |
| 8 | − "@executor/mcp-elicitation-demo": "0.0.0", | |
| 9 | − "@executor/serve-skills-via-mcp-demo": "0.0.0", | |
| 10 | − "@executor/sqlite-sdk-consumer-example": "0.0.0", | |
| 11 | − "@executor/react": "0.0.0", | |
| 12 | − "@executor/effect-test-utils": "0.0.0", | |
| 13 | − "@executor/kitchen-sink": "0.0.0", | |
| 14 | − "@executor/ai-sdk-adapter": "0.0.0", | |
| 15 | − "@executor/executor-mcp": "0.0.0", | |
| 16 | − "@executor/codemode-core": "0.0.0", | |
| 17 | − "@executor/ir": "0.0.0", | |
| 5 | + "executor": "1.4.0-beta.0", | |
| 6 | + "@executor/server": "1.4.0-beta.0", | |
| 7 | + "@executor/web": "1.4.0-beta.0", | |
| 8 | + "@executor/react": "1.4.0-beta.0", | |
| 9 | + "@executor/api": "1.4.0-beta.0", | |
| 10 | + "@executor/config": "1.4.0-beta.0", | |
| 11 | + "@executor/execution": "1.4.0-beta.0", | |
| 12 | + "@executor/sdk": "1.4.0-beta.0", | |
| 13 | + "@executor/storage-file": "1.4.0-beta.0", | |
| 14 | + "@executor/host-mcp": "1.4.0-beta.0", | |
| 15 | + "@executor/codemode-core": "1.4.0-beta.0", | |
| 16 | + "@executor/ir": "1.4.0-beta.0", | |
| 18 | 17 | "@executor/runtime-deno-subprocess": "0.0.0", |
| 19 | − "@executor/runtime-quickjs": "0.0.0", | |
| 20 | − "@executor/runtime-ses": "0.0.0", | |
| 21 | − "@executor/platform-api": "0.0.0", | |
| 22 | − "@executor/platform-sdk": "0.0.0", | |
| 23 | − "@executor/platform-sdk-file": "0.0.0", | |
| 24 | − "@executor/server": "0.0.0", | |
| 25 | − "@executor/source-core": "0.0.0", | |
| 26 | − "@executor/plugin-execution-history-react": "0.0.0", | |
| 27 | − "@executor/plugin-google-discovery-http": "0.0.0", | |
| 28 | − "@executor/plugin-google-discovery-react": "0.0.0", | |
| 29 | − "@executor/plugin-google-discovery-sdk": "0.0.0", | |
| 30 | − "@executor/plugin-google-discovery-shared": "0.0.0", | |
| 31 | − "@executor/plugin-graphql-http": "0.0.0", | |
| 32 | − "@executor/plugin-graphql-react": "0.0.0", | |
| 33 | − "@executor/plugin-graphql-sdk": "0.0.0", | |
| 34 | − "@executor/plugin-graphql-shared": "0.0.0", | |
| 35 | − "@executor/plugin-keychain-secret-store-sdk": "0.0.0", | |
| 36 | − "@executor/plugin-local-secret-store-sdk": "0.0.0", | |
| 37 | − "@executor/plugin-local-tools-react": "0.0.0", | |
| 38 | − "@executor/plugin-local-tools-sdk": "0.0.0", | |
| 39 | − "@executor/plugin-mcp-http": "0.0.0", | |
| 40 | − "@executor/plugin-mcp-react": "0.0.0", | |
| 41 | − "@executor/plugin-mcp-sdk": "0.0.0", | |
| 42 | − "@executor/plugin-mcp-shared": "0.0.0", | |
| 43 | − "@executor/plugin-onepassword-http": "0.0.0", | |
| 44 | − "@executor/plugin-onepassword-react": "0.0.0", | |
| 45 | − "@executor/plugin-onepassword-sdk": "0.0.0", | |
| 46 | − "@executor/plugin-onepassword-shared": "0.0.0", | |
| 47 | − "@executor/plugin-openapi-http": "0.0.0", | |
| 48 | − "@executor/plugin-openapi-react": "0.0.0", | |
| 49 | − "@executor/plugin-openapi-sdk": "0.0.0", | |
| 50 | − "@executor/plugin-openapi-shared": "0.0.0" | |
| 18 | + "@executor/runtime-quickjs": "1.4.0-beta.0", | |
| 19 | + "@executor/plugin-file-secrets": "1.4.0-beta.0", | |
| 20 | + "@executor/plugin-google-discovery": "1.4.0-beta.0", | |
| 21 | + "@executor/plugin-graphql": "1.4.0-beta.0", | |
| 22 | + "@executor/plugin-keychain": "1.4.0-beta.0", | |
| 23 | + "@executor/plugin-mcp": "1.4.0-beta.0", | |
| 24 | + "@executor/plugin-onepassword": "1.4.0-beta.0", | |
| 25 | + "@executor/plugin-openapi": "1.4.0-beta.0", | |
| 26 | + "@executor/ui": "1.4.0-beta.0" | |
| 51 | 27 | }, |
| 52 | − "changesets": [ | |
| 53 | − "cute-steaks-sink", | |
| 54 | − "funny-forks-listen", | |
| 55 | − "fuzzy-camels-cheer", | |
| 56 | − "quick-cars-approve", | |
| 57 | − "tame-trains-confess", | |
| 58 | − "tasty-geese-cough" | |
| 59 | − ] | |
| 28 | + "changesets": [] | |
| 60 | 29 | } |
| @@ -1,5 +0,0 @@ | ||
| 1 | −--- | |
| 2 | −"executor": patch | |
| 3 | −--- | |
| 4 | − | |
| 5 | −Improve MCP source setup by auto-detecting OAuth requirements, showing a loading state during discovery, and allowing creation without signing in. | |
| @@ -2,4 +2,4 @@ · 1 unmodified line | ||
| 2 | 2 | "executor": patch |
| 3 | 3 | --- |
| 4 | 4 | |
| 5 | −Compact openapi sources | |
| 5 | +Release 1.4 | |
| @@ -1,5 +0,0 @@ | ||
| 1 | −--- | |
| 2 | −"executor": patch | |
| 3 | −--- | |
| 4 | − | |
| 5 | −Fix the beta distribution packaging flow so the prerelease publish passes again. | |
| @@ -1,5 +0,0 @@ | ||
| 1 | −--- | |
| 2 | −"executor": patch | |
| 3 | −--- | |
| 4 | − | |
| 5 | −Improve Google Discovery sources view | |
| @@ -1,347 +0,0 @@ | ||
| 1 | −{ | |
| 2 | − "sources": { | |
| 3 | − "vercel": { | |
| 4 | − "name": "Vercel API", | |
| 5 | − "config": { | |
| 6 | − "specUrl": "https://openapi.vercel.sh/", | |
| 7 | − "baseUrl": "https://api.vercel.com/", | |
| 8 | − "auth": { | |
| 9 | − "kind": "none" | |
| 10 | − }, | |
| 11 | − "defaultHeaders": null | |
| 12 | − }, | |
| 13 | − "kind": "openapi" | |
| 14 | − }, | |
| 15 | − "deepwiki-mcp": { | |
| 16 | − "name": "DeepWiki MCP", | |
| 17 | − "namespace": "deepwiki.mcp", | |
| 18 | − "config": { | |
| 19 | − "endpoint": "https://mcp.deepwiki.com/mcp", | |
| 20 | − "transport": "auto", | |
| 21 | − "queryParams": null, | |
| 22 | − "headers": null, | |
| 23 | − "command": null, | |
| 24 | − "args": null, | |
| 25 | − "env": null, | |
| 26 | − "cwd": null, | |
| 27 | − "auth": { | |
| 28 | − "kind": "none" | |
| 29 | − } | |
| 30 | − }, | |
| 31 | − "kind": "mcp" | |
| 32 | − }, | |
| 33 | − "linear-graphql": { | |
| 34 | − "name": "Linear GraphQL", | |
| 35 | − "namespace": "linear.graphql", | |
| 36 | − "config": { | |
| 37 | − "endpoint": "https://api.linear.app/graphql", | |
| 38 | − "defaultHeaders": null, | |
| 39 | − "auth": { | |
| 40 | − "kind": "none" | |
| 41 | − } | |
| 42 | − }, | |
| 43 | − "kind": "graphql" | |
| 44 | − }, | |
| 45 | − "axiom-mcp": { | |
| 46 | − "name": "Axiom MCP", | |
| 47 | − "namespace": "axiom.mcp", | |
| 48 | − "config": { | |
| 49 | − "endpoint": "https://mcp.axiom.co/mcp", | |
| 50 | − "transport": "auto", | |
| 51 | − "queryParams": null, | |
| 52 | − "headers": null, | |
| 53 | − "command": null, | |
| 54 | − "args": null, | |
| 55 | − "env": null, | |
| 56 | − "cwd": null, | |
| 57 | − "auth": { | |
| 58 | − "kind": "oauth2", | |
| 59 | − "redirectUri": "http://localhost:8788/v1/plugins/mcp/oauth/callback", | |
| 60 | − "accessTokenRef": { | |
| 61 | − "secretId": "sec_534bd6a9-0bd3-4f66-97ac-ddf22ea2ae82" | |
| 62 | − }, | |
| 63 | − "refreshTokenRef": { | |
| 64 | − "secretId": "sec_3e665cbc-2ba9-4d5b-97a4-db811248574f" | |
| 65 | − }, | |
| 66 | − "tokenType": "bearer", | |
| 67 | − "expiresAt": 1806390691402, | |
| 68 | − "scope": "", | |
| 69 | − "resourceMetadataUrl": null, | |
| 70 | − "authorizationServerUrl": "https://mcp.axiom.co/", | |
| 71 | − "resourceMetadata": null, | |
| 72 | − "authorizationServerMetadata": { | |
| 73 | − "issuer": "https://mcp.axiom.co", | |
| 74 | − "authorization_endpoint": "https://mcp.axiom.co/authorize", | |
| 75 | − "token_endpoint": "https://mcp.axiom.co/token", | |
| 76 | − "registration_endpoint": "https://mcp.axiom.co/register", | |
| 77 | − "response_types_supported": [ | |
| 78 | − "code" | |
| 79 | − ], | |
| 80 | − "response_modes_supported": [ | |
| 81 | − "query" | |
| 82 | − ], | |
| 83 | − "grant_types_supported": [ | |
| 84 | − "authorization_code", | |
| 85 | − "refresh_token" | |
| 86 | − ], | |
| 87 | − "token_endpoint_auth_methods_supported": [ | |
| 88 | − "client_secret_basic", | |
| 89 | − "client_secret_post", | |
| 90 | − "none" | |
| 91 | − ], | |
| 92 | − "revocation_endpoint": "https://mcp.axiom.co/token", | |
| 93 | − "code_challenge_methods_supported": [ | |
| 94 | − "plain", | |
| 95 | − "S256" | |
| 96 | − ] | |
| 97 | − }, | |
| 98 | − "clientInformation": { | |
| 99 | − "redirect_uris": [ | |
| 100 | − "http://localhost:8788/v1/plugins/mcp/oauth/callback" | |
| 101 | − ], | |
| 102 | − "token_endpoint_auth_method": "none", | |
| 103 | − "grant_types": [ | |
| 104 | − "authorization_code", | |
| 105 | − "refresh_token" | |
| 106 | − ], | |
| 107 | − "response_types": [ | |
| 108 | − "code" | |
| 109 | − ], | |
| 110 | − "client_name": "Executor Local", | |
| 111 | − "client_id": "PgIDrWWSMRBtHHsg", | |
| 112 | − "client_id_issued_at": 1774854684 | |
| 113 | − } | |
| 114 | − } | |
| 115 | − }, | |
| 116 | − "kind": "mcp" | |
| 117 | − }, | |
| 118 | − "mcp-mcp": { | |
| 119 | − "name": "Mcp MCP", | |
| 120 | − "namespace": "mcp.mcp", | |
| 121 | − "config": { | |
| 122 | − "endpoint": "https://mcp.linear.app/mcp", | |
| 123 | − "transport": "auto", | |
| 124 | − "queryParams": null, | |
| 125 | − "headers": null, | |
| 126 | − "command": null, | |
| 127 | − "args": null, | |
| 128 | − "env": null, | |
| 129 | − "cwd": null, | |
| 130 | − "auth": { | |
| 131 | − "kind": "oauth2", | |
| 132 | − "redirectUri": "http://localhost:8788/v1/plugins/mcp/oauth/callback", | |
| 133 | − "accessTokenRef": { | |
| 134 | − "secretId": "sec_ae3503a2-f813-4fe4-8882-1ee7b0e86cab" | |
| 135 | − }, | |
| 136 | − "refreshTokenRef": { | |
| 137 | − "secretId": "sec_3e453bf7-9343-41e4-a00e-1b81448591f7" | |
| 138 | − }, | |
| 139 | − "tokenType": "bearer", | |
| 140 | − "expiresAt": 1775459747141, | |
| 141 | − "scope": "", | |
| 142 | − "resourceMetadataUrl": null, | |
| 143 | − "authorizationServerUrl": "https://mcp.linear.app", | |
| 144 | − "resourceMetadata": { | |
| 145 | − "resource": "https://mcp.linear.app", | |
| 146 | − "authorization_servers": [ | |
| 147 | − "https://mcp.linear.app" | |
| 148 | − ], | |
| 149 | − "bearer_methods_supported": [ | |
| 150 | − "header" | |
| 151 | − ] | |
| 152 | − }, | |
| 153 | − "authorizationServerMetadata": { | |
| 154 | − "issuer": "https://mcp.linear.app", | |
| 155 | − "authorization_endpoint": "https://mcp.linear.app/authorize", | |
| 156 | − "token_endpoint": "https://mcp.linear.app/token", | |
| 157 | − "registration_endpoint": "https://mcp.linear.app/register", | |
| 158 | − "response_types_supported": [ | |
| 159 | − "code" | |
| 160 | − ], | |
| 161 | − "response_modes_supported": [ | |
| 162 | − "query" | |
| 163 | − ], | |
| 164 | − "grant_types_supported": [ | |
| 165 | − "authorization_code", | |
| 166 | − "refresh_token" | |
| 167 | − ], | |
| 168 | − "token_endpoint_auth_methods_supported": [ | |
| 169 | − "client_secret_basic", | |
| 170 | − "client_secret_post", | |
| 171 | − "none" | |
| 172 | − ], | |
| 173 | − "revocation_endpoint": "https://mcp.linear.app/token", | |
| 174 | − "code_challenge_methods_supported": [ | |
| 175 | − "plain", | |
| 176 | − "S256" | |
| 177 | − ], | |
| 178 | − "client_id_metadata_document_supported": false | |
| 179 | − }, | |
| 180 | − "clientInformation": { | |
| 181 | − "redirect_uris": [ | |
| 182 | − "http://localhost:8788/v1/plugins/mcp/oauth/callback" | |
| 183 | − ], | |
| 184 | − "token_endpoint_auth_method": "none", | |
| 185 | − "grant_types": [ | |
| 186 | − "authorization_code", | |
| 187 | − "refresh_token" | |
| 188 | − ], | |
| 189 | − "response_types": [ | |
| 190 | − "code" | |
| 191 | − ], | |
| 192 | − "client_name": "Executor Local", | |
| 193 | − "client_id": "xYJ-DOv7vWmXjAsi", | |
| 194 | − "client_id_issued_at": 1774854942 | |
| 195 | − } | |
| 196 | − } | |
| 197 | − }, | |
| 198 | − "kind": "mcp" | |
| 199 | − }, | |
| 200 | − "google-calendar": { | |
| 201 | − "name": "Google Calendar", | |
| 202 | − "namespace": "google.calendar", | |
| 203 | − "config": { | |
| 204 | − "service": "calendar", | |
| 205 | − "version": "v3", | |
| 206 | − "discoveryUrl": "https://calendar-json.googleapis.com/$discovery/rest?version=v3", | |
| 207 | − "defaultHeaders": null, | |
| 208 | − "scopes": [ | |
| 209 | − "https://www.googleapis.com/auth/calendar" | |
| 210 | − ], | |
| 211 | − "auth": { | |
| 212 | − "kind": "oauth2", | |
| 213 | − "clientId": "171149749557-apegmds63qp2h2u2s55p6rom1j6m3m5k.apps.googleusercontent.com", | |
| 214 | − "clientSecretRef": { | |
| 215 | − "secretId": "sec_f2c1f3ce-97c5-429b-a7bf-22fcd6007de3" | |
| 216 | − }, | |
| 217 | − "clientAuthentication": "client_secret_post", | |
| 218 | − "authorizationEndpoint": "https://accounts.google.com/o/oauth2/v2/auth", | |
| 219 | − "tokenEndpoint": "https://oauth2.googleapis.com/token", | |
| 220 | − "scopes": [ | |
| 221 | − "https://www.googleapis.com/auth/calendar" | |
| 222 | − ], | |
| 223 | − "accessTokenRef": { | |
| 224 | − "secretId": "sec_023e64bd-8e6b-49cc-b33c-950c31612846" | |
| 225 | − }, | |
| 226 | − "refreshTokenRef": { | |
| 227 | − "secretId": "sec_e4c2e96c-b809-4d72-873c-a8ba7d595610" | |
| 228 | − }, | |
| 229 | − "expiresAt": 1774859675319 | |
| 230 | − } | |
| 231 | − }, | |
| 232 | − "kind": "google_discovery" | |
| 233 | − }, | |
| 234 | − "google-drive": { | |
| 235 | − "name": "Google Drive", | |
| 236 | − "namespace": "google.drive", | |
| 237 | − "config": { | |
| 238 | − "service": "drive", | |
| 239 | − "version": "v3", | |
| 240 | − "discoveryUrl": "https://www.googleapis.com/discovery/v1/apis/drive/v3/rest", | |
| 241 | − "defaultHeaders": null, | |
| 242 | − "scopes": [ | |
| 243 | − "https://www.googleapis.com/auth/drive", | |
| 244 | − "https://www.googleapis.com/auth/drive.apps.readonly" | |
| 245 | − ], | |
| 246 | − "auth": { | |
| 247 | − "kind": "oauth2", | |
| 248 | − "clientId": "171149749557-apegmds63qp2h2u2s55p6rom1j6m3m5k.apps.googleusercontent.com", | |
| 249 | − "clientSecretRef": { | |
| 250 | − "secretId": "sec_f2c1f3ce-97c5-429b-a7bf-22fcd6007de3" | |
| 251 | − }, | |
| 252 | − "clientAuthentication": "client_secret_post", | |
| 253 | − "authorizationEndpoint": "https://accounts.google.com/o/oauth2/v2/auth", | |
| 254 | − "tokenEndpoint": "https://oauth2.googleapis.com/token", | |
| 255 | − "scopes": [ | |
| 256 | − "https://www.googleapis.com/auth/drive", | |
| 257 | − "https://www.googleapis.com/auth/drive.apps.readonly" | |
| 258 | − ], | |
| 259 | − "accessTokenRef": { | |
| 260 | − "secretId": "sec_39d48e40-634c-4673-8038-8fc7c027c698" | |
| 261 | − }, | |
| 262 | − "refreshTokenRef": { | |
| 263 | − "secretId": "sec_ec05b35f-c0ff-4529-b80e-a5638589a6eb" | |
| 264 | − }, | |
| 265 | − "expiresAt": 1774859675319 | |
| 266 | − } | |
| 267 | − }, | |
| 268 | − "kind": "google_discovery" | |
| 269 | − }, | |
| 270 | − "google-gmail": { | |
| 271 | − "name": "Gmail", | |
| 272 | − "namespace": "google.gmail", | |
| 273 | − "kind": "google_discovery", | |
| 274 | − "config": { | |
| 275 | − "service": "gmail", | |
| 276 | − "version": "v1", | |
| 277 | − "discoveryUrl": "https://gmail.googleapis.com/$discovery/rest?version=v1", | |
| 278 | − "defaultHeaders": null, | |
| 279 | − "scopes": [ | |
| 280 | − "https://mail.google.com/", | |
| 281 | − "https://www.googleapis.com/auth/gmail.settings.basic", | |
| 282 | − "https://www.googleapis.com/auth/gmail.settings.sharing" | |
| 283 | − ], | |
| 284 | − "auth": { | |
| 285 | − "kind": "oauth2", | |
| 286 | − "clientId": "171149749557-apegmds63qp2h2u2s55p6rom1j6m3m5k.apps.googleusercontent.com", | |
| 287 | − "clientSecretRef": { | |
| 288 | − "secretId": "sec_f2c1f3ce-97c5-429b-a7bf-22fcd6007de3" | |
| 289 | − }, | |
| 290 | − "clientAuthentication": "client_secret_post", | |
| 291 | − "authorizationEndpoint": "https://accounts.google.com/o/oauth2/v2/auth", | |
| 292 | − "tokenEndpoint": "https://oauth2.googleapis.com/token", | |
| 293 | − "scopes": [ | |
| 294 | − "https://mail.google.com/", | |
| 295 | − "https://www.googleapis.com/auth/gmail.settings.basic", | |
| 296 | − "https://www.googleapis.com/auth/gmail.settings.sharing" | |
| 297 | − ], | |
| 298 | − "accessTokenRef": { | |
| 299 | − "secretId": "sec_379eee62-86fe-49fe-93dc-8af40fa04dc3" | |
| 300 | − }, | |
| 301 | − "refreshTokenRef": { | |
| 302 | − "secretId": "sec_c58e7cb5-296b-4024-8f22-8b49ef7a7f38" | |
| 303 | − }, | |
| 304 | − "expiresAt": 1774859675319 | |
| 305 | − } | |
| 306 | − } | |
| 307 | − } | |
| 308 | − }, | |
| 309 | − "policies": { | |
| 310 | − "linear.graphql.agentActivities": { | |
| 311 | − "match": "linear.graphql.agentActivities", | |
| 312 | − "action": "allow", | |
| 313 | − "approval": "auto", | |
| 314 | − "priority": 10 | |
| 315 | − }, | |
| 316 | − "vercel.accessGroups.createAccessGroup": { | |
| 317 | − "match": "vercel.accessGroups.createAccessGroup", | |
| 318 | − "action": "deny", | |
| 319 | − "approval": "auto", | |
| 320 | − "priority": 10 | |
| 321 | − }, | |
| 322 | − "vercel.dns.createRecord": { | |
| 323 | − "match": "vercel.dns.createRecord", | |
| 324 | − "action": "deny", | |
| 325 | − "approval": "auto", | |
| 326 | − "priority": 10 | |
| 327 | − }, | |
| 328 | − "vercel.dns.getRecords": { | |
| 329 | − "match": "vercel.dns.getRecords", | |
| 330 | − "action": "deny", | |
| 331 | − "approval": "auto", | |
| 332 | − "priority": 10 | |
| 333 | − }, | |
| 334 | − "vercel.dns.removeRecord": { | |
| 335 | − "match": "vercel.dns.removeRecord", | |
| 336 | − "action": "deny", | |
| 337 | − "approval": "auto", | |
| 338 | − "priority": 10 | |
| 339 | − }, | |
| 340 | − "vercel.dns.updateRecord": { | |
| 341 | − "match": "vercel.dns.updateRecord", | |
| 342 | − "action": "allow", | |
| 343 | − "approval": "auto", | |
| 344 | − "priority": 10 | |
| 345 | − } | |
| 346 | − } | |
| 347 | −} | |
| @@ -33,6 +33,8 @@ jobs: · 32 unmodified lines | ||
| 33 | 33 | |
| 34 | 34 | - name: Setup Bun |
| 35 | 35 | uses: oven-sh/setup-bun@v2 |
| 36 | + with: | |
| 37 | + bun-version: 1.2.22 | |
| 36 | 38 | |
| 37 | 39 | - name: Setup Node |
| 38 | 40 | uses: actions/setup-node@v4 |
| @@ -48,21 +50,17 @@ jobs: · 9 unmodified lines | ||
| 48 | 50 | - name: Install dependencies |
| 49 | 51 | run: bun install --frozen-lockfile |
| 50 | 52 | |
| 51 | − - name: Run executor checks | |
| 52 | − run: | | |
| 53 | − bun run --cwd apps/executor typecheck | |
| 54 | − bun run --cwd apps/executor test | |
| 53 | + - name: Run release checks | |
| 54 | + run: bun run release:check | |
| 55 | 55 | |
| 56 | 56 | - name: Publish package and create release |
| 57 | 57 | env: |
| 58 | 58 | GH_TOKEN: ${{ github.token }} |
| 59 | 59 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} |
| 60 | + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| 60 | 61 | RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }} |
| 61 | 62 | run: | |
| 62 | 63 | export GITHUB_REF_TYPE=tag |
| 63 | 64 | export GITHUB_REF_NAME="$RELEASE_TAG" |
| 64 | 65 | export GITHUB_REF="refs/tags/$RELEASE_TAG" |
| 65 | − if [ -n "${NPM_TOKEN:-}" ]; then | |
| 66 | − export NODE_AUTH_TOKEN="$NPM_TOKEN" | |
| 67 | − fi | |
| 68 | − bun run --cwd apps/executor release:publish | |
| 66 | + bun run release:publish | |
| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | name: Release |
| 2 | −run-name: "prepare release" | |
| 2 | +run-name: prepare release | |
| 3 | 3 | |
| 4 | 4 | on: |
| 5 | 5 | push: |
| @@ -28,6 +28,8 @@ jobs: · 22 unmodified lines | ||
| 28 | 28 | |
| 29 | 29 | - name: Setup Bun |
| 30 | 30 | uses: oven-sh/setup-bun@v2 |
| 31 | + with: | |
| 32 | + bun-version: 1.2.22 | |
| 31 | 33 | |
| 32 | 34 | - name: Setup Node |
| 33 | 35 | uses: actions/setup-node@v4 |
| @@ -57,9 +59,9 @@ jobs: · 23 unmodified lines | ||
| 57 | 59 | before="$(git rev-list --max-count=1 HEAD^ 2>/dev/null || true)" |
| 58 | 60 | fi |
| 59 | 61 | |
| 60 | − version="$(node -e "console.log(JSON.parse(require('fs').readFileSync('apps/executor/package.json', 'utf8')).version)")" | |
| 61 | − if [ -n "$before" ] && git cat-file -e "$before:apps/executor/package.json" 2>/dev/null; then | |
| 62 | − previous_version="$(git show "$before:apps/executor/package.json" | node -e "let data = ''; process.stdin.setEncoding('utf8'); process.stdin.on('data', (chunk) => { data += chunk; }); process.stdin.on('end', () => { console.log(JSON.parse(data).version ?? ''); });")" | |
| 62 | + version="$(node -e "console.log(JSON.parse(require('fs').readFileSync('apps/cli/package.json', 'utf8')).version)")" | |
| 63 | + if [ -n "$before" ] && git cat-file -e "$before:apps/cli/package.json" 2>/dev/null; then | |
| 64 | + previous_version="$(git show "$before:apps/cli/package.json" | node -e "let data = ''; process.stdin.setEncoding('utf8'); process.stdin.on('data', (chunk) => { data += chunk; }); process.stdin.on('end', () => { console.log(JSON.parse(data).version ?? ''); });")" | |
| 63 | 65 | else |
| 64 | 66 | previous_version="" |
| 65 | 67 | fi |
| @@ -1,90 +1,39 @@ | ||
| 1 | −# Environment variables | |
| 2 | −.env | |
| 3 | −.env.* | |
| 4 | −!.env.example | |
| 5 | −.env*.local | |
| 6 | − | |
| 7 | −# Vercel | |
| 8 | −.vercel | |
| 9 | − | |
| 10 | −# Next.js | |
| 11 | −.next/ | |
| 12 | − | |
| 13 | −# Turbo | |
| 14 | −.turbo/ | |
| 15 | −.turbo-prune-check/ | |
| 16 | − | |
| 17 | −# Executor | |
| 18 | −.executor-v2/ | |
| 19 | −.executor/* | |
| 20 | −!.executor/executor.json | |
| 21 | −!.executor/executor.jsonc | |
| 22 | −!.executor/tools/ | |
| 23 | −!.executor/tools/** | |
| 24 | −.executor/artifacts/ | |
| 25 | −.executor/state/ | |
| 26 | −.executor/types/ | |
| 27 | − | |
| 28 | −# Cloudflare Workers local state | |
| 29 | −**/.wrangler/ | |
| 30 | −**/.dev.vars | |
| 31 | − | |
| 32 | −# Dependencies | |
| 33 | −**/node_modules/ | |
| 34 | − | |
| 35 | −# TypeScript build info | |
| 36 | −*.tsbuildinfo | |
| 1 | +# dependencies (bun install) | |
| 2 | +node_modules | |
| 37 | 3 | |
| 38 | −# Output / build artifacts | |
| 4 | +# output | |
| 39 | 5 | out |
| 40 | 6 | dist |
| 41 | 7 | *.tgz |
| 42 | 8 | |
| 43 | −# Rust / Cargo build artifacts | |
| 44 | −**/target/ | |
| 45 | −tools/openapi-extractor-rs/pkg-*/ | |
| 46 | − | |
| 47 | −# Code coverage | |
| 9 | +# code coverage | |
| 48 | 10 | coverage |
| 49 | 11 | *.lcov |
| 50 | 12 | |
| 51 | −# Logs | |
| 13 | +# logs | |
| 52 | 14 | logs |
| 53 | −*.log | |
| 54 | −report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json | |
| 15 | +_.log | |
| 16 | +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json | |
| 17 | + | |
| 18 | +# dotenv environment variable files | |
| 19 | +.env | |
| 20 | +.env.development.local | |
| 21 | +.env.test.local | |
| 22 | +.env.production.local | |
| 23 | +.env.local | |
| 55 | 24 | |
| 56 | −# Caches | |
| 25 | +# caches | |
| 57 | 26 | .eslintcache |
| 58 | 27 | .cache |
| 28 | +*.tsbuildinfo | |
| 29 | +.turbo | |
| 59 | 30 | |
| 60 | 31 | # IntelliJ based IDEs |
| 61 | 32 | .idea |
| 62 | 33 | |
| 63 | −# Finder (macOS) | |
| 34 | +# Finder (MacOS) folder config | |
| 64 | 35 | .DS_Store |
| 65 | − | |
| 66 | −# Convex local backend state | |
| 67 | −convex_local_backend.sqlite3 | |
| 68 | −convex_local_storage/ | |
| 69 | − | |
| 70 | −# Local OpenAPI sources service state | |
| 71 | −sources/data/*.sqlite | |
| 72 | −sources/data/*.sqlite-shm | |
| 73 | −sources/data/*.sqlite-wal | |
| 74 | −packages/platform/server/:memory:/ | |
| 75 | − | |
| 76 | −# Composio toolkit scrape outputs | |
| 77 | −sources/composio-scrape/data/ | |
| 78 | − | |
| 79 | −# Dev runner PID file | |
| 80 | −.dev.pids | |
| 81 | − | |
| 82 | −# Misc | |
| 83 | −*.har | |
| 84 | −.chat-links.json | |
| 85 | −.reference/ | |
| 86 | 36 | personal-notes/ |
| 87 | −.tmp/ | |
| 88 | −executor/.env.executor-push | |
| 89 | −ignored/ | |
| 90 | −agent-notes/ | |
| 37 | +*.har.executor | |
| 38 | +executor.har | |
| 39 | +.executor/ | |
| @@ -1,20 +1,12 @@ | ||
| 1 | 1 | { |
| 2 | 2 | "mcpServers": { |
| 3 | − "executor-stdio": { | |
| 3 | + "executor": { | |
| 4 | 4 | "command": "bun", |
| 5 | 5 | "args": [ |
| 6 | 6 | "run", |
| 7 | − "executor", | |
| 8 | − "mcp", | |
| 9 | − "--stdio" | |
| 10 | − ] | |
| 11 | − }, | |
| 12 | − "executor-stdio-prod": { | |
| 13 | − "command": "executor", | |
| 14 | − "args": [ | |
| 15 | − "mcp", | |
| 16 | − "--stdio" | |
| 7 | + "/Users/rhyssullivan/src/v4-executor/apps/cli/src/main.ts", | |
| 8 | + "mcp" | |
| 17 | 9 | ] |
| 18 | 10 | } |
| 19 | 11 | } |
| 20 | −} | |
| 12 | +} | |
| @@ -1,87 +1,5 @@ | ||
| 1 | 1 | { |
| 2 | − "$schema": "./node_modules/oxlint/configuration_schema.json", | |
| 3 | − | |
| 4 | − // Keep the built-in default plugin set explicit so monorepo lint behavior | |
| 5 | − // does not drift when oxlint changes its defaults. | |
| 6 | − "plugins": ["typescript", "oxc", "unicorn"], | |
| 7 | − | |
| 8 | − "categories": { | |
| 9 | − "correctness": "warn", | |
| 10 | − }, | |
| 11 | − | |
| 12 | − "ignorePatterns": [ | |
| 13 | − "**/node_modules/**", | |
| 14 | − "**/.turbo/**", | |
| 15 | − "**/dist/**", | |
| 16 | − "**/coverage/**", | |
| 17 | − "**/.next/**", | |
| 18 | − "**/.mint/**", | |
| 19 | − ], | |
| 20 | − | |
| 21 | − "settings": { | |
| 22 | − "executorMonorepo": { | |
| 23 | − "packageScopes": ["@executor/"], | |
| 24 | − }, | |
| 25 | − }, | |
| 26 | − | |
| 27 | − "jsPlugins": [ | |
| 28 | − { | |
| 29 | − "name": "executor-monorepo", | |
| 30 | − "specifier": "./tools/oxlint/plugin.mjs", | |
| 31 | − }, | |
| 32 | − ], | |
| 33 | − | |
| 34 | 2 | "rules": { |
| 35 | − // This repo uses Effect.gen heavily. The underlying generator syntax is an | |
| 36 | − // implementation detail, so "no yield" is not a useful signal here. | |
| 37 | − "require-yield": "off", | |
| 38 | − | |
| 39 | − "no-unused-vars": "warn", | |
| 40 | − | |
| 41 | − // Monorepo-specific rules. | |
| 42 | − "executor-monorepo/no-async-effect-vitest-tests": "error", | |
| 43 | − "executor-monorepo/no-cross-workspace-relative-imports": "error", | |
| 44 | − "executor-monorepo/no-direct-effect-tag-read": "error", | |
| 45 | − "executor-monorepo/no-effect-env-any": "error", | |
| 46 | − "executor-monorepo/no-effect-never-cast": "error", | |
| 47 | − "executor-monorepo/no-effect-run-in-effect-vitest-tests": "error", | |
| 48 | − "executor-monorepo/no-manual-httpapi-openapi-bridge": "error", | |
| 49 | − "executor-monorepo/no-manual-openapi-documents": "error", | |
| 50 | − "executor-monorepo/no-node-fs-with-effect-imports": "error", | |
| 51 | − "executor-monorepo/no-raw-effect-fail-errors": "error", | |
| 52 | − "executor-monorepo/no-yield-effect-fail": "error", | |
| 53 | − "executor-monorepo/no-workspace-src-imports": "warn", | |
| 54 | − }, | |
| 55 | − | |
| 56 | − "overrides": [ | |
| 57 | − { | |
| 58 | − // SDK tests still use relative workspace imports to avoid introducing | |
| 59 | − // package-graph cycles from test-only dependencies. | |
| 60 | − "files": [ | |
| 61 | − "packages/platform/sdk/src/executor.test.ts", | |
| 62 | − "packages/platform/sdk/src/runtime/executor-runtime.test.ts", | |
| 63 | − "packages/platform/server/src/index.test.ts", | |
| 64 | − "packages/clients/react/src/index.test.tsx" | |
| 65 | − ], | |
| 66 | − "rules": { | |
| 67 | − "executor-monorepo/no-cross-workspace-relative-imports": "off" | |
| 68 | − } | |
| 69 | − }, | |
| 70 | − { | |
| 71 | − // JSON Schema conditionals legitimately use a `then` key. | |
| 72 | − "files": [ | |
| 73 | − "packages/platform/control-plane/src/runtime/catalog/source/runtime.ts", | |
| 74 | − ], | |
| 75 | − "rules": { | |
| 76 | − "unicorn/no-thenable": "off", | |
| 77 | − }, | |
| 78 | − }, | |
| 79 | − { | |
| 80 | − // This stack-integrity check intentionally prefers invariant failures in cleanup. | |
| 81 | − "files": ["packages/sources/core/src/catalog-json-schema.ts"], | |
| 82 | − "rules": { | |
| 83 | − "no-unsafe-finally": "off", | |
| 84 | − }, | |
| 85 | − }, | |
| 86 | − ], | |
| 3 | + "typescript/no-explicit-any": "error" | |
| 4 | + } | |
| 87 | 5 | } |
| @@ -0,0 +1 @@ | ||
| 1 | +Subproject commit ec5c50507b1a2f5ad712c148a7da0fadb8cb9f52 | |
| @@ -0,0 +1 @@ | ||
| 1 | +Subproject commit 957095fdfc930eae666f78d65f7af8584959bffd | |
| @@ -0,0 +1 @@ | ||
| 1 | +Subproject commit 2d532f8322368eedc835fa09dc9223a9ddef9e1d | |
| @@ -0,0 +1,205 @@ | ||
| 1 | +--- | |
| 2 | +name: effect-http-testing | |
| 3 | +description: Testing Effect HttpApi services end-to-end. Use when writing tests that involve Effect's HttpApi, HttpApiBuilder, HttpClient, HttpServer, or when testing any HTTP service/plugin built with @effect/platform. Covers proper layer composition, test server setup, HttpClient injection, and common pitfalls. | |
| 4 | +--- | |
| 5 | + | |
| 6 | +# Effect HTTP Testing | |
| 7 | + | |
| 8 | +## Core Pattern | |
| 9 | + | |
| 10 | +Define an API with `HttpApi`, implement handlers with `HttpApiBuilder.group`, serve it with `HttpApiBuilder.serve()`, and use `NodeHttpServer.layerTest` to get an in-process test server + `HttpClient` pointed at it. | |
| 11 | + | |
| 12 | +```ts | |
| 13 | +import { expect, layer } from "@effect/vitest" | |
| 14 | +import { Effect, Layer, Schema } from "effect" | |
| 15 | +import { | |
| 16 | + HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, | |
| 17 | + HttpClient, OpenApi | |
| 18 | +} from "@effect/platform" | |
| 19 | +import { NodeHttpServer } from "@effect/platform-node" | |
| 20 | + | |
| 21 | +// 1. Define the API | |
| 22 | +class Item extends Schema.Class<Item>("Item")({ | |
| 23 | + id: Schema.Number, | |
| 24 | + name: Schema.String, | |
| 25 | +}) {} | |
| 26 | + | |
| 27 | +const ItemsGroup = HttpApiGroup.make("items") | |
| 28 | + .add(HttpApiEndpoint.get("listItems", "/items").addSuccess(Schema.Array(Item))) | |
| 29 | + .add( | |
| 30 | + HttpApiEndpoint.get("getItem", "/items/:itemId") | |
| 31 | + .setPath(Schema.Struct({ itemId: Schema.NumberFromString })) | |
| 32 | + .addSuccess(Item) | |
| 33 | + ) | |
| 34 | + | |
| 35 | +const MyApi = HttpApi.make("myApi").add(ItemsGroup) | |
| 36 | + | |
| 37 | +// 2. Implement handlers | |
| 38 | +const ItemsLive = HttpApiBuilder.group(MyApi, "items", (handlers) => | |
| 39 | + handlers | |
| 40 | + .handle("listItems", () => Effect.succeed([{ id: 1, name: "Widget" }])) | |
| 41 | + .handle("getItem", (req) => Effect.succeed({ id: req.path.itemId, name: "Widget" })) | |
| 42 | +) | |
| 43 | + | |
| 44 | +// 3. Build test layer | |
| 45 | +const ApiLive = HttpApiBuilder.api(MyApi).pipe(Layer.provide(ItemsLive)) | |
| 46 | + | |
| 47 | +const TestLayer = HttpApiBuilder.serve().pipe( | |
| 48 | + Layer.provide(ApiLive), | |
| 49 | + Layer.provideMerge(NodeHttpServer.layerTest), | |
| 50 | +) | |
| 51 | + | |
| 52 | +// 4. Use layer() to share across tests | |
| 53 | +layer(TestLayer)("My API", (it) => { | |
| 54 | + it.effect("works", () => | |
| 55 | + Effect.gen(function* () { | |
| 56 | + const client = yield* HttpClient.HttpClient | |
| 57 | + // client is already pointed at the test server | |
| 58 | + const response = yield* client.get("/items") | |
| 59 | + // ... | |
| 60 | + }) | |
| 61 | + ) | |
| 62 | +}) | |
| 63 | +``` | |
| 64 | + | |
| 65 | +## Critical Rules | |
| 66 | + | |
| 67 | +### Layer composition order matters | |
| 68 | + | |
| 69 | +`HttpApiBuilder.serve()` consumes `HttpApi.Api`. The API layer must be provided to it, not the other way around: | |
| 70 | + | |
| 71 | +```ts | |
| 72 | +// CORRECT | |
| 73 | +HttpApiBuilder.serve().pipe( | |
| 74 | + Layer.provide(ApiLive), | |
| 75 | + Layer.provideMerge(NodeHttpServer.layerTest), | |
| 76 | +) | |
| 77 | + | |
| 78 | +// WRONG — "Service not found: HttpApi.Api" | |
| 79 | +ApiLive.pipe( | |
| 80 | + Layer.provide(HttpApiBuilder.serve()), | |
| 81 | + Layer.provideMerge(NodeHttpServer.layerTest), | |
| 82 | +) | |
| 83 | +``` | |
| 84 | + | |
| 85 | +### layerTestClient prepends the server URL | |
| 86 | + | |
| 87 | +`NodeHttpServer.layerTest` (and `HttpServer.layerTestClient`) produce an `HttpClient` that automatically prepends the test server's `http://127.0.0.1:<port>` to every request URL. | |
| 88 | + | |
| 89 | +- Use **paths only** (`/items`, `/items/2`) in requests — not full URLs | |
| 90 | +- If your code builds full URLs (e.g. `http://localhost/items`), the client will produce `http://127.0.0.1:PORThttp://localhost/items` — an invalid URL | |
| 91 | +- When injecting the test client into code that normally uses a `baseUrl`, pass `baseUrl: ""` or skip the base URL entirely | |
| 92 | + | |
| 93 | +### Path parameters need setPath() | |
| 94 | + | |
| 95 | +Effect's `HttpApiEndpoint` with `:param` syntax does NOT automatically populate `req.path`. You must call `.setPath()` with a schema: | |
| 96 | + | |
| 97 | +```ts | |
| 98 | +// WRONG — req.path is undefined | |
| 99 | +HttpApiEndpoint.get("getItem", "/items/:itemId").addSuccess(Item) | |
| 100 | + | |
| 101 | +// CORRECT — req.path.itemId is typed and populated | |
| 102 | +HttpApiEndpoint.get("getItem", "/items/:itemId") | |
| 103 | + .setPath(Schema.Struct({ itemId: Schema.NumberFromString })) | |
| 104 | + .addSuccess(Item) | |
| 105 | +``` | |
| 106 | + | |
| 107 | +### OpenApi.fromApi generates the spec | |
| 108 | + | |
| 109 | +Use `OpenApi.fromApi(api)` to generate an OpenAPI spec from an `HttpApi` definition. The generated spec: | |
| 110 | +- Uses `"Api"` as the default title (not the api id) | |
| 111 | +- Converts `:param` to `{param}` in paths | |
| 112 | +- Does NOT list path parameters in the `parameters` array — they're implicit in the path template | |
| 113 | +- Uses `group.endpoint` format for operationIds (e.g. `items.listItems`) | |
| 114 | + | |
| 115 | +### Grab the test HttpClient from context | |
| 116 | + | |
| 117 | +Inside `layer()` tests, the `HttpClient` is available in the Effect context: | |
| 118 | + | |
| 119 | +```ts | |
| 120 | +layer(TestLayer)("tests", (it) => { | |
| 121 | + it.effect("test", () => | |
| 122 | + Effect.gen(function* () { | |
| 123 | + const httpClient = yield* HttpClient.HttpClient | |
| 124 | + // Use it directly or wrap in a Layer for injection | |
| 125 | + const clientLayer = Layer.succeed(HttpClient.HttpClient, httpClient) | |
| 126 | + }) | |
| 127 | + ) | |
| 128 | +}) | |
| 129 | +``` | |
| 130 | + | |
| 131 | +### Use HttpClient for HTTP calls, not fetch | |
| 132 | + | |
| 133 | +Production code should use `HttpClient` from `@effect/platform`, not raw `fetch`: | |
| 134 | + | |
| 135 | +```ts | |
| 136 | +import { HttpClient, HttpClientRequest } from "@effect/platform" | |
| 137 | + | |
| 138 | +// Build request | |
| 139 | +let request = HttpClientRequest.get("/items") | |
| 140 | +request = HttpClientRequest.setHeader(request, "accept", "application/json") | |
| 141 | +request = HttpClientRequest.setUrlParam(request, "limit", "10") | |
| 142 | + | |
| 143 | +// Execute — requires HttpClient in context | |
| 144 | +const response = yield* client.execute(request) | |
| 145 | + | |
| 146 | +// Read body | |
| 147 | +const data = yield* response.json // Effect<unknown> | |
| 148 | +const text = yield* response.text // Effect<string> | |
| 149 | +``` | |
| 150 | + | |
| 151 | +This makes testing clean — swap in a test client layer, no monkey-patching needed. | |
| 152 | + | |
| 153 | +### Response headers are Record<string, string> | |
| 154 | + | |
| 155 | +Effect's `HttpClientResponse.headers` is a plain `Record<string, string>`, not a Web `Headers` object. Don't call `.forEach()` or `.get()` on it: | |
| 156 | + | |
| 157 | +```ts | |
| 158 | +// WRONG | |
| 159 | +response.headers.forEach((v, k) => ...) | |
| 160 | +response.headers.get("content-type") | |
| 161 | + | |
| 162 | +// CORRECT | |
| 163 | +const ct = response.headers["content-type"] | |
| 164 | +const copy = { ...response.headers } | |
| 165 | +``` | |
| 166 | + | |
| 167 | +### HttpClientRequest.make takes uppercase methods | |
| 168 | + | |
| 169 | +```ts | |
| 170 | +// The method parameter to make() must be uppercase | |
| 171 | +HttpClientRequest.make("GET")("/items") | |
| 172 | + | |
| 173 | +// Or use the convenience methods | |
| 174 | +HttpClientRequest.get("/items") | |
| 175 | +HttpClientRequest.post("/items") | |
| 176 | +``` | |
| 177 | + | |
| 178 | +### Prepending base URLs to a client | |
| 179 | + | |
| 180 | +Use `HttpClient.mapRequest` with `HttpClientRequest.prependUrl`: | |
| 181 | + | |
| 182 | +```ts | |
| 183 | +const clientWithBase = Layer.effect( | |
| 184 | + HttpClient.HttpClient, | |
| 185 | + Effect.map( | |
| 186 | + HttpClient.HttpClient, | |
| 187 | + HttpClient.mapRequest(HttpClientRequest.prependUrl("https://api.example.com")), | |
| 188 | + ), | |
| 189 | +).pipe(Layer.provide(baseClientLayer)) | |
| 190 | +``` | |
| 191 | + | |
| 192 | +### Error assertions | |
| 193 | + | |
| 194 | +Use `Effect.flip` to turn errors into values for assertion: | |
| 195 | + | |
| 196 | +```ts | |
| 197 | +const error = yield* Effect.flip(someFailingEffect) | |
| 198 | +expect(error._tag).toBe("MyError") | |
| 199 | +``` | |
| 200 | + | |
| 201 | +### Dependencies | |
| 202 | + | |
| 203 | +- `@effect/platform` — HttpApi, HttpClient, HttpServer, OpenApi | |
| 204 | +- `@effect/platform-node` — NodeHttpServer.layerTest (for Node/vitest) | |
| 205 | +- `@effect/vitest` — `layer()`, `it.effect()`, `expect` | |
| @@ -0,0 +1,210 @@ | ||
| 1 | +--- | |
| 2 | +name: effect-client-wrapper | |
| 3 | +description: Pattern for wrapping third-party SDK clients (Stripe, Resend, AWS, etc.) with Effect. Use when creating Effect services that wrap external libraries with Promise-based APIs. Provides type-safe error handling, automatic tracing, and clean dependency injection via the "use" pattern. | |
| 4 | +--- | |
| 5 | + | |
| 6 | +# Effect Client Wrapper Pattern | |
| 7 | + | |
| 8 | +Wrap third-party SDK clients with Effect using the "use" pattern for consistent error handling, tracing, and dependency injection. | |
| 9 | + | |
| 10 | +## Pattern Structure | |
| 11 | + | |
| 12 | +```typescript | |
| 13 | +import { Context, Data, Effect, Layer, Config, Redacted } from "effect"; | |
| 14 | + | |
| 15 | +// 1. Define tagged errors | |
| 16 | +export class MyClientError extends Data.TaggedError("MyClientError")<{ | |
| 17 | + cause: unknown; | |
| 18 | +}> {} | |
| 19 | + | |
| 20 | +export class MyClientInstantiationError extends Data.TaggedError( | |
| 21 | + "MyClientInstantiationError", | |
| 22 | +)<{ | |
| 23 | + cause: unknown; | |
| 24 | +}> {} | |
| 25 | + | |
| 26 | +// 2. Define service interface with `use` method | |
| 27 | +export type IMyClient = Readonly<{ | |
| 28 | + client: ThirdPartyClient; | |
| 29 | + use: <A>( | |
| 30 | + fn: (client: ThirdPartyClient) => Promise<A>, | |
| 31 | + ) => Effect.Effect<A, MyClientError, never>; | |
| 32 | +}>; | |
| 33 | + | |
| 34 | +// 3. Create the service implementation | |
| 35 | +const make = Effect.gen(function* () { | |
| 36 | + const apiKey = yield* Config.redacted("MY_CLIENT_API_KEY"); | |
| 37 | + | |
| 38 | + const client = yield* Effect.try({ | |
| 39 | + try: () => new ThirdPartyClient(Redacted.value(apiKey)), | |
| 40 | + catch: (cause) => new MyClientInstantiationError({ cause }), | |
| 41 | + }); | |
| 42 | + | |
| 43 | + const use = <A>(fn: (client: ThirdPartyClient) => Promise<A>) => | |
| 44 | + Effect.tryPromise({ | |
| 45 | + try: () => fn(client), | |
| 46 | + catch: (cause) => new MyClientError({ cause }), | |
| 47 | + }).pipe(Effect.withSpan(`my_client.${fn.name ?? "use"}`)); | |
| 48 | + | |
| 49 | + return { client, use }; | |
| 50 | +}); | |
| 51 | + | |
| 52 | +// 4. Export as Context.Tag with Default layer | |
| 53 | +export class MyClient extends Context.Tag("MyClient")<MyClient, IMyClient>() { | |
| 54 | + static Default = Layer.effect(this, make).pipe( | |
| 55 | + Layer.annotateSpans({ module: "MyClient" }), | |
| 56 | + ); | |
| 57 | +} | |
| 58 | +``` | |
| 59 | + | |
| 60 | +## Usage | |
| 61 | + | |
| 62 | +```typescript | |
| 63 | +const program = Effect.gen(function* () { | |
| 64 | + const myClient = yield* MyClient; | |
| 65 | + | |
| 66 | + const result = yield* myClient.use((client) => | |
| 67 | + client.someMethod({ param: "value" }), | |
| 68 | + ); | |
| 69 | + | |
| 70 | + return result; | |
| 71 | +}); | |
| 72 | + | |
| 73 | +// Run with layer | |
| 74 | +program.pipe(Effect.provide(MyClient.Default)); | |
| 75 | +``` | |
| 76 | + | |
| 77 | +## Key Benefits | |
| 78 | + | |
| 79 | +1. **Centralized error handling** - All client errors wrapped in typed `MyClientError` | |
| 80 | +2. **Automatic tracing** - Every `use` call creates a span with function name | |
| 81 | +3. **Config-based secrets** - API keys loaded via `Config.redacted` | |
| 82 | +4. **Clean DI** - Consumers inject via `yield* MyClient` | |
| 83 | +5. **Encapsulation** - Raw client hidden behind `use` interface | |
| 84 | + | |
| 85 | +## Variations | |
| 86 | + | |
| 87 | +### Multiple Error Types | |
| 88 | + | |
| 89 | +```typescript | |
| 90 | +export class MyClientNetworkError extends Data.TaggedError( | |
| 91 | + "MyClientNetworkError", | |
| 92 | +)<{ | |
| 93 | + cause: unknown; | |
| 94 | +}> {} | |
| 95 | + | |
| 96 | +export class MyClientValidationError extends Data.TaggedError( | |
| 97 | + "MyClientValidationError", | |
| 98 | +)<{ | |
| 99 | + message: string; | |
| 100 | +}> {} | |
| 101 | + | |
| 102 | +const use = <A>(fn: (client: ThirdPartyClient) => Promise<A>) => | |
| 103 | + Effect.tryPromise({ | |
| 104 | + try: () => fn(client), | |
| 105 | + catch: (cause) => { | |
| 106 | + if (cause instanceof NetworkError) { | |
| 107 | + return new MyClientNetworkError({ cause }); | |
| 108 | + } | |
| 109 | + return new MyClientError({ cause }); | |
| 110 | + }, | |
| 111 | + }).pipe(Effect.withSpan(`my_client.${fn.name ?? "use"}`)); | |
| 112 | +``` | |
| 113 | + | |
| 114 | +### Named Operations | |
| 115 | + | |
| 116 | +Expose specific methods instead of generic `use`: | |
| 117 | + | |
| 118 | +```typescript | |
| 119 | +export type IEmailClient = Readonly<{ | |
| 120 | + sendEmail: ( | |
| 121 | + params: SendEmailParams, | |
| 122 | + ) => Effect.Effect<EmailResult, EmailError>; | |
| 123 | + getEmail: (id: string) => Effect.Effect<Email, EmailError>; | |
| 124 | +}>; | |
| 125 | + | |
| 126 | +const make = Effect.gen(function* () { | |
| 127 | + const resend = yield* ResendClient; | |
| 128 | + | |
| 129 | + return { | |
| 130 | + sendEmail: (params) => | |
| 131 | + resend | |
| 132 | + .use((client) => client.emails.send(params)) | |
| 133 | + .pipe(Effect.withSpan("email_client.send")), | |
| 134 | + | |
| 135 | + getEmail: (id) => | |
| 136 | + resend | |
| 137 | + .use((client) => client.emails.get(id)) | |
| 138 | + .pipe(Effect.withSpan("email_client.get")), | |
| 139 | + }; | |
| 140 | +}); | |
| 141 | +``` | |
| 142 | + | |
| 143 | +### With Retry Policy | |
| 144 | + | |
| 145 | +```typescript | |
| 146 | +import { Schedule } from "effect"; | |
| 147 | + | |
| 148 | +const retryPolicy = Schedule.exponential(100).pipe( | |
| 149 | + Schedule.intersect(Schedule.recurs(3)), | |
| 150 | + Schedule.jittered, | |
| 151 | +); | |
| 152 | + | |
| 153 | +const use = <A>(fn: (client: ThirdPartyClient) => Promise<A>) => | |
| 154 | + Effect.tryPromise({ | |
| 155 | + try: () => fn(client), | |
| 156 | + catch: (cause) => new MyClientError({ cause }), | |
| 157 | + }).pipe( | |
| 158 | + Effect.retry(retryPolicy), | |
| 159 | + Effect.withSpan(`my_client.${fn.name ?? "use"}`), | |
| 160 | + ); | |
| 161 | +``` | |
| 162 | + | |
| 163 | +## Real-World Example: Stripe | |
| 164 | + | |
| 165 | +```typescript | |
| 166 | +import Stripe from "stripe"; | |
| 167 | +import { Context, Data, Effect, Layer, Config, Redacted } from "effect"; | |
| 168 | + | |
| 169 | +export class StripeError extends Data.TaggedError("StripeError")<{ | |
| 170 | + cause: unknown; | |
| 171 | +}> {} | |
| 172 | + | |
| 173 | +export type IStripeClient = Readonly<{ | |
| 174 | + use: <A>(fn: (stripe: Stripe) => Promise<A>) => Effect.Effect<A, StripeError>; | |
| 175 | +}>; | |
| 176 | + | |
| 177 | +const make = Effect.gen(function* () { | |
| 178 | + const secretKey = yield* Config.redacted("STRIPE_SECRET_KEY"); | |
| 179 | + | |
| 180 | + const client = new Stripe(Redacted.value(secretKey)); | |
| 181 | + | |
| 182 | + const use = <A>(fn: (stripe: Stripe) => Promise<A>) => | |
| 183 | + Effect.tryPromise({ | |
| 184 | + try: () => fn(client), | |
| 185 | + catch: (cause) => new StripeError({ cause }), | |
| 186 | + }).pipe(Effect.withSpan(`stripe.${fn.name ?? "use"}`)); | |
| 187 | + | |
| 188 | + return { use }; | |
| 189 | +}); | |
| 190 | + | |
| 191 | +export class StripeClient extends Context.Tag("StripeClient")< | |
| 192 | + StripeClient, | |
| 193 | + IStripeClient | |
| 194 | +>() { | |
| 195 | + static Default = Layer.effect(this, make).pipe( | |
| 196 | + Layer.annotateSpans({ module: "StripeClient" }), | |
| 197 | + ); | |
| 198 | +} | |
| 199 | + | |
| 200 | +// Usage | |
| 201 | +const createCustomer = Effect.gen(function* () { | |
| 202 | + const stripe = yield* StripeClient; | |
| 203 | + | |
| 204 | + const customer = yield* stripe.use((client) => | |
| 205 | + client.customers.create({ email: "user@example.com" }), | |
| 206 | + ); | |
| 207 | + | |
| 208 | + return customer; | |
| 209 | +}); | |
| 210 | +``` | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "typescript.tsdk": "./node_modules/typescript/lib", | |
| 3 | + "typescript.enablePromptUseWorkspaceTsdk": true | |
| 4 | +} | |
| @@ -0,0 +1 @@ | ||
| 1 | +use effect vitest and run tests via vitest not bun test | |
| @@ -0,0 +1 @@ | ||
| 1 | +use effect vitest and run tests via vitest not bun test | |
| @@ -1,21 +0,0 @@ | ||
| 1 | −MIT License | |
| 2 | − | |
| 3 | −Copyright (c) 2026 Rhys Sullivan | |
| 4 | − | |
| 5 | −Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 6 | −of this software and associated documentation files (the "Software"), to deal | |
| 7 | −in the Software without restriction, including without limitation the rights | |
| 8 | −to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 9 | −copies of the Software, and to permit persons to whom the Software is | |
| 10 | −furnished to do so, subject to the following conditions: | |
| 11 | − | |
| 12 | −The above copyright notice and this permission notice shall be included in all | |
| 13 | −copies or substantial portions of the Software. | |
| 14 | − | |
| 15 | −THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 16 | −IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 17 | −FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 18 | −AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 19 | −LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 20 | −OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 21 | −SOFTWARE. | |
| @@ -1,395 +0,0 @@ | ||
| 1 | −# executor | |
| 2 | − | |
| 3 | − | |
| 4 | −https://github.com/user-attachments/assets/11225f83-e848-42ba-99b2-a993bcc88dad | |
| 5 | − | |
| 6 | − | |
| 7 | −`executor` is a local-first execution environment for AI agents. | |
| 8 | − | |
| 9 | −It gives an agent a TypeScript runtime, a discoverable tool catalog, and a single local place to connect external systems such as MCP servers, OpenAPI APIs, and GraphQL APIs. Instead of pasting large MCP manifests into every chat or giving an agent broad shell access, you run code inside `executor` and let it call typed `tools.*` functions. | |
| 10 | − | |
| 11 | −[](https://deepwiki.com/RhysSullivan/executor) | |
| 12 | − | |
| 13 | −## Community | |
| 14 | − | |
| 15 | −Join the Discord community: https://discord.gg/eF29HBHwM6 | |
| 16 | − | |
| 17 | −At runtime, `executor` behaves like one local product: | |
| 18 | − | |
| 19 | −- a CLI for starting the runtime and executing code | |
| 20 | −- a local API server | |
| 21 | −- a local web UI for connecting sources, inspecting tools, and managing secrets | |
| 22 | −- an MCP endpoint for hosts that want to drive `executor` through MCP | |
| 23 | − | |
| 24 | −The current codebase lives in `apps/` and `packages/`. Older experiments stay in `legacy/` and `legacy2/`. | |
| 25 | − | |
| 26 | −## Attribution | |
| 27 | − | |
| 28 | −- [Crystian](https://www.linkedin.com/in/crystian/) provided the npm package name `executor`. | |
| 29 | −- The `codemode` concept in this project is inspired by Cloudflare's [Code Mode announcement](https://blog.cloudflare.com/code-mode/). | |
| 30 | − | |
| 31 | −## Why this exists | |
| 32 | − | |
| 33 | −`executor` is built around a simple idea: agents should work against a structured tool environment instead of guessing at raw HTTP calls, carrying huge MCP definitions in context, or running arbitrary local commands with broad permissions. | |
| 34 | − | |
| 35 | −In practice that means: | |
| 36 | − | |
| 37 | −- sources are connected once and turned into a reusable workspace tool catalog | |
| 38 | −- the agent discovers tools by intent, inspects schemas, and then calls typed functions | |
| 39 | −- secrets and OAuth flows stay in the local runtime and web UI instead of being pasted into chat | |
| 40 | −- human interaction can pause an execution and resume it cleanly | |
| 41 | − | |
| 42 | −## Mental model | |
| 43 | − | |
| 44 | −Think of `executor` as a local control plane for agent tool use. | |
| 45 | − | |
| 46 | −1. You start a local `executor` daemon. | |
| 47 | −2. You connect sources such as an MCP server, an OpenAPI document, or a GraphQL endpoint. | |
| 48 | −3. `executor` indexes those sources into a workspace tool catalog. | |
| 49 | −4. An agent runs TypeScript against that catalog through `executor call` or through the MCP bridge. | |
| 50 | −5. If a tool needs credentials or user input, execution pauses, opens a local flow, and then resumes. | |
| 51 | − | |
| 52 | −## What it does today | |
| 53 | − | |
| 54 | −### Connect external tool sources | |
| 55 | − | |
| 56 | −`executor` currently supports these source types: | |
| 57 | − | |
| 58 | −- `mcp`: remote MCP servers, including transport selection for streamable HTTP or SSE | |
| 59 | −- `openapi`: REST APIs described by an OpenAPI document | |
| 60 | −- `graphql`: GraphQL endpoints that can be introspected into callable tools | |
| 61 | − | |
| 62 | −The add-source flow can: | |
| 63 | − | |
| 64 | −- probe a URL and infer what kind of source it is | |
| 65 | −- infer likely authentication requirements | |
| 66 | −- prompt for credentials when discovery or connection needs them | |
| 67 | −- start OAuth when a source requires it | |
| 68 | −- persist the source and its indexed tool metadata in the local workspace | |
| 69 | − | |
| 70 | −The web app also includes templates for common providers so you can start from real examples instead of filling every field by hand. | |
| 71 | − | |
| 72 | −### Run agent code against tools | |
| 73 | − | |
| 74 | −The main CLI workflow is `executor call`. | |
| 75 | − | |
| 76 | −The runtime expects the agent to use the built-in discovery workflow: | |
| 77 | − | |
| 78 | −```ts | |
| 79 | −const matches = await tools.discover({ query: "github issues", limit: 5 }); | |
| 80 | −const path = matches.bestPath; | |
| 81 | −const detail = await tools.describe.tool({ path, includeSchemas: true }); | |
| 82 | − | |
| 83 | −return await tools.github.issues.list({ | |
| 84 | − owner: "vercel", | |
| 85 | − repo: "next.js", | |
| 86 | −}); | |
| 87 | −``` | |
| 88 | − | |
| 89 | −A few important rules shape the execution model: | |
| 90 | − | |
| 91 | −- write TypeScript, not raw shell pipelines | |
| 92 | −- use `tools.*`, not direct `fetch` | |
| 93 | −- discover first when the exact tool path is not known | |
| 94 | −- inspect schemas before calling complex tools | |
| 95 | − | |
| 96 | −### Handle credentials and user interaction | |
| 97 | − | |
| 98 | −When a source or tool needs human input, `executor` can pause the execution and create an interaction record. | |
| 99 | − | |
| 100 | −That interaction may ask you to: | |
| 101 | − | |
| 102 | −- open a secure local credential page | |
| 103 | −- complete an OAuth flow in the browser | |
| 104 | −- respond to a structured elicitation from a tool host | |
| 105 | −- resume a paused execution from the CLI | |
| 106 | − | |
| 107 | −This is the core human-in-the-loop behavior that lets `executor` keep secrets and approvals outside the agent's raw context. | |
| 108 | − | |
| 109 | −### Inspect the connected tool model | |
| 110 | − | |
| 111 | −The web UI is not just a setup surface. It is also where you can inspect what `executor` learned from a source. | |
| 112 | − | |
| 113 | −For each source you can: | |
| 114 | − | |
| 115 | −- browse its tool tree | |
| 116 | −- search for tools by intent | |
| 117 | −- inspect input and output schemas | |
| 118 | −- view generated manifests, definitions, and raw source documents when available | |
| 119 | −- edit source settings and authentication details | |
| 120 | − | |
| 121 | −## Quick start | |
| 122 | − | |
| 123 | −If you want to use this a package distribution, install it via npm: | |
| 124 | − | |
| 125 | −```bash | |
| 126 | −npm install -g executor | |
| 127 | −executor web | |
| 128 | −``` | |
| 129 | − | |
| 130 | −That starts a foreground local session, prints the local web URL, and keeps it alive until you press `Ctrl+C`. | |
| 131 | − | |
| 132 | −If you want the MCP endpoint instead, run: | |
| 133 | − | |
| 134 | −```bash | |
| 135 | −executor mcp | |
| 136 | −``` | |
| 137 | − | |
| 138 | −That prints the local MCP URL and keeps the session alive until you press `Ctrl+C`. | |
| 139 | − | |
| 140 | −If you want a local stdio MCP server for agent configs such as Codex or OpenCode, run: | |
| 141 | − | |
| 142 | −```bash | |
| 143 | −executor mcp --stdio | |
| 144 | −``` | |
| 145 | − | |
| 146 | −Then you can run the CLI as `executor`. | |
| 147 | − | |
| 148 | −If you are working from this repository locally, the easiest path is: | |
| 149 | − | |
| 150 | −```bash | |
| 151 | −bun install | |
| 152 | −bun dev | |
| 153 | −``` | |
| 154 | − | |
| 155 | −That starts the local runtime. The default base URL is: | |
| 156 | − | |
| 157 | −```text | |
| 158 | −http://127.0.0.1:8788 | |
| 159 | −``` | |
| 160 | − | |
| 161 | −From there: | |
| 162 | − | |
| 163 | −1. Open the web UI in your browser. | |
| 164 | −2. Add a source from `/sources/add`. | |
| 165 | −3. If needed, store credentials in `/secrets`. | |
| 166 | −4. Run TypeScript with `bun run executor call ...`. | |
| 167 | − | |
| 168 | −If you are using a packaged distribution, the command name is simply `executor` instead of `bun run executor`. | |
| 169 | − | |
| 170 | −## Core CLI commands | |
| 171 | − | |
| 172 | −```bash | |
| 173 | −executor web | |
| 174 | −executor mcp | |
| 175 | −executor mcp --stdio | |
| 176 | −executor call --file script.ts | |
| 177 | −executor resume --execution-id exec_123 | |
| 178 | −``` | |
| 179 | − | |
| 180 | −Compatibility commands for the detached daemon are still available: | |
| 181 | − | |
| 182 | −```bash | |
| 183 | −executor up | |
| 184 | −executor down | |
| 185 | −executor status --json | |
| 186 | −executor doctor --json | |
| 187 | −``` | |
| 188 | − | |
| 189 | −`executor call` accepts code in three ways: | |
| 190 | − | |
| 191 | −- inline as a positional argument | |
| 192 | −- from `--file` | |
| 193 | −- from standard input with `--stdin` | |
| 194 | − | |
| 195 | −Examples: | |
| 196 | − | |
| 197 | −```bash | |
| 198 | −executor call 'const matches = await tools.discover({ query: "repo details", limit: 1 }); return matches;' | |
| 199 | −executor call --file script.ts | |
| 200 | −cat script.ts | executor call --stdin | |
| 201 | −executor call --no-open --file script.ts | |
| 202 | −``` | |
| 203 | − | |
| 204 | −If an execution pauses, resume it with: | |
| 205 | − | |
| 206 | −```bash | |
| 207 | −executor resume --execution-id exec_123 | |
| 208 | −``` | |
| 209 | − | |
| 210 | −## Adding a source | |
| 211 | − | |
| 212 | −There are two main ways to add a source. | |
| 213 | − | |
| 214 | −### In the web UI | |
| 215 | − | |
| 216 | −Use the Add Source flow to: | |
| 217 | − | |
| 218 | −- paste a URL | |
| 219 | −- run discovery | |
| 220 | −- review the inferred kind, namespace, transport, and auth | |
| 221 | −- connect the source | |
| 222 | −- complete credential or OAuth setup if required | |
| 223 | − | |
| 224 | −This is the easiest path for most users. | |
| 225 | − | |
| 226 | −### From inside an execution | |
| 227 | − | |
| 228 | −The runtime also exposes `tools.executor.sources.add(...)`, which lets an agent add a source from code. | |
| 229 | − | |
| 230 | −Examples: | |
| 231 | − | |
| 232 | −```ts | |
| 233 | −return await tools.executor.sources.add({ | |
| 234 | − kind: "mcp", | |
| 235 | − name: "Example", | |
| 236 | − endpoint: "https://example.com/mcp", | |
| 237 | − transport: "auto", | |
| 238 | − queryParams: null, | |
| 239 | − headers: null, | |
| 240 | − command: null, | |
| 241 | − args: null, | |
| 242 | − env: null, | |
| 243 | − cwd: null, | |
| 244 | − auth: { kind: "none" }, | |
| 245 | −}); | |
| 246 | −``` | |
| 247 | − | |
| 248 | −```ts | |
| 249 | −return await tools.executor.sources.add({ | |
| 250 | − kind: "openapi", | |
| 251 | − name: "GitHub", | |
| 252 | − specUrl: | |
| 253 | − "https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json", | |
| 254 | − baseUrl: null, | |
| 255 | − auth: { kind: "none" }, | |
| 256 | −}); | |
| 257 | −``` | |
| 258 | − | |
| 259 | −`executor.sources.add(...)` accepts the final plugin-specific source config. | |
| 260 | −Browser OAuth and popup-driven auth flows live on the plugin-owned HTTP and web surfaces. | |
| 261 | − | |
| 262 | −## How execution works | |
| 263 | − | |
| 264 | −At a high level, every execution follows the same loop: | |
| 265 | − | |
| 266 | −1. `executor` resolves the current local installation and workspace. | |
| 267 | −2. It builds a tool catalog from built-in tools plus all connected workspace sources. | |
| 268 | −3. It runs your TypeScript inside the configured sandbox runtime. QuickJS is the default, and `.executor/executor.jsonc` can set `"runtime": "quickjs" | "ses" | "deno"`. | |
| 269 | −4. Tool calls are dispatched through `executor` rather than directly from your code. | |
| 270 | −5. If a tool needs interaction, the run pauses and records a pending interaction. | |
| 271 | −6. Once the interaction is resolved, the execution continues and eventually completes or fails. | |
| 272 | − | |
| 273 | −Example: | |
| 274 | − | |
| 275 | −```jsonc | |
| 276 | −{ | |
| 277 | − "runtime": "ses", | |
| 278 | − "sources": {} | |
| 279 | −} | |
| 280 | −``` | |
| 281 | − | |
| 282 | −This gives you a stable surface for agent automation: | |
| 283 | − | |
| 284 | −- the agent sees a coherent catalog | |
| 285 | −- connected sources become reusable namespace-based tools | |
| 286 | −- auth stays attached to sources and secret material | |
| 287 | −- the runtime can track execution state instead of losing it inside a one-shot prompt | |
| 288 | − | |
| 289 | −## Web UI overview | |
| 290 | − | |
| 291 | −The React web app is served from the same local server as the API. | |
| 292 | − | |
| 293 | −Main screens: | |
| 294 | − | |
| 295 | −- `/`: list connected sources in the current local workspace | |
| 296 | −- `/sources/add`: discover and connect new sources | |
| 297 | −- `/sources/:sourceId`: inspect tools, search tools, and browse source artifacts | |
| 298 | −- `/sources/:sourceId/edit`: edit source settings and auth | |
| 299 | −- `/secrets`: create, update, and delete locally stored secrets | |
| 300 | − | |
| 301 | −The UI uses the same control-plane API as the CLI, so both surfaces are operating on the same local runtime state. | |
| 302 | − | |
| 303 | −## Local-first runtime behavior | |
| 304 | − | |
| 305 | −By default `executor` runs as a single local daemon process. | |
| 306 | − | |
| 307 | −It serves: | |
| 308 | − | |
| 309 | −- `/v1` for the local control-plane API | |
| 310 | −- `/mcp` for the `executor` MCP endpoint | |
| 311 | −- the web UI for normal browser routes | |
| 312 | − | |
| 313 | −Default network location: | |
| 314 | − | |
| 315 | −- host: `127.0.0.1` | |
| 316 | −- port: `8788` | |
| 317 | − | |
| 318 | −Default data locations are OS-aware: | |
| 319 | − | |
| 320 | −- Linux data: `~/.local/share/executor` | |
| 321 | −- Linux runtime state: `~/.local/state/executor/run` | |
| 322 | −- macOS: `~/Library/Application Support/Executor` | |
| 323 | −- Windows: `%LOCALAPPDATA%\Executor` | |
| 324 | − | |
| 325 | −The server also maintains local PID and log files in its runtime directory. | |
| 326 | − | |
| 327 | −## Persistence and data | |
| 328 | − | |
| 329 | −`executor` persists the local control plane to local files. | |
| 330 | − | |
| 331 | −Persisted concepts include: | |
| 332 | − | |
| 333 | −- local installation identity | |
| 334 | −- connected sources | |
| 335 | −- indexed tool artifacts and related metadata | |
| 336 | −- credentials and secret material bindings | |
| 337 | −- source auth sessions | |
| 338 | −- execution and interaction state | |
| 339 | −- executions and execution interactions | |
| 340 | −- policies | |
| 341 | − | |
| 342 | −On first start, `executor` provisions a local account, a personal organization, and a default workspace automatically. | |
| 343 | − | |
| 344 | −## Security and trust model | |
| 345 | − | |
| 346 | −`executor` is designed to narrow how agents interact with external systems. | |
| 347 | − | |
| 348 | −Compared with direct shell or raw API usage, the model is intentionally more structured: | |
| 349 | − | |
| 350 | −- tool calls are routed through a controlled runtime | |
| 351 | −- secrets are stored separately from prompt text | |
| 352 | −- OAuth and credential capture happen through local flows | |
| 353 | −- executions can pause for interaction instead of guessing or failing silently | |
| 354 | −- source auth and tool metadata live with the workspace rather than inside each prompt | |
| 355 | − | |
| 356 | −This does not make the system magically risk-free, but it gives the runtime places to enforce policy, collect approvals, and keep sensitive material out of the agent's immediate context. | |
| 357 | − | |
| 358 | −## Repository layout | |
| 359 | − | |
| 360 | −If you are exploring the repo, these are the directories that matter most: | |
| 361 | − | |
| 362 | −- `apps/executor`: packaged CLI entrypoint and daemon lifecycle commands | |
| 363 | −- `apps/web`: local React web UI | |
| 364 | −- `packages/platform/server`: local HTTP server that serves API, MCP, and UI | |
| 365 | −- `packages/platform/sdk`: source management, secrets, persistence, execution, and inspection | |
| 366 | −- `packages/platform/api`: thin HTTP adapter over the platform SDK | |
| 367 | −- `packages/platform/internal`: thin internal tool adapter over the platform SDK | |
| 368 | −- `packages/kernel/runtime-deno-subprocess`: optional Deno subprocess runtime for TypeScript execution | |
| 369 | −- `packages/kernel/runtime-quickjs`: default QuickJS sandbox runtime for TypeScript execution | |
| 370 | −- `packages/kernel/runtime-ses`: optional SES sandbox runtime for TypeScript execution | |
| 371 | −- `packages/hosts/mcp`: MCP bridge for `execute` and `resume` | |
| 372 | −- `packages/kernel/core` plus `packages/sources/*`: core tool abstractions and first-party source integrations | |
| 373 | − | |
| 374 | −## Releasing | |
| 375 | − | |
| 376 | −- Add a changeset in any PR that should release: `bun run changeset`. | |
| 377 | −- Merge that PR to `main`. `.github/workflows/release.yml` opens or updates a `Version Packages` release PR for version bumps and changelog updates. | |
| 378 | −- Merge the `Version Packages` PR. The release workflow pushes the matching git tag and dispatches `.github/workflows/publish-executor-package.yml`, which publishes to npm and creates the GitHub release. | |
| 379 | −- Do not edit `apps/executor/package.json` by hand for normal releases. Changesets owns the version. | |
| 380 | −- For a beta train, enter prerelease mode with `bun run release:beta:start`, commit `.changeset/pre.json`, and merge it. Release PRs will then use `-beta.x` versions until you exit with `bun run release:beta:stop`. | |
| 381 | −- `bun run --cwd apps/executor release:publish` remains the publish implementation used by CI. | |
| 382 | −- To build and pack the publish artifact locally without publishing, run `bun run --cwd apps/executor release:publish:dry-run`. | |
| 383 | −- `.github/workflows/publish-executor-package.yml` can also be run manually with a tag input if a publish needs to be retried for an already-created version tag. | |
| 384 | −- One-time npm setup: either configure npm trusted publishing for `RhysSullivan/executor` with the workflow file `.github/workflows/publish-executor-package.yml`, or add a GitHub Actions secret named `NPM_TOKEN` that can publish the `executor` package. | |
| 385 | −- Stable releases use a normal semver like `1.2.3` and publish to npm under `latest`. | |
| 386 | −- Beta releases use a prerelease semver like `1.3.0-beta.1` and publish to npm under `beta`. | |
| 387 | −- When a release should become an upgrade test fixture, capture a real workspace snapshot with `bun run fixture:release:capture -- ...` and commit it under [`packages/platform/sdk/src/runtime/__fixtures__`](./packages/platform/sdk/src/runtime/__fixtures__/README.md). | |
| 388 | − | |
| 389 | −## Project status | |
| 390 | − | |
| 391 | −This repository is explicitly on its third major architecture iteration. | |
| 392 | − | |
| 393 | −- `apps/` and `packages/` are the active implementation | |
| 394 | −- `legacy/` is the original codebase | |
| 395 | −- `legacy2/` is the second generation | |
| @@ -0,0 +1,50 @@ | ||
| 1 | +# Releasing | |
| 2 | + | |
| 3 | +This repo uses Changesets for version orchestration and a custom publish script for the generated `executor` npm package plus its platform packages. | |
| 4 | + | |
| 5 | +## Normal release flow | |
| 6 | + | |
| 7 | +1. Add a changeset in the PR that should ship: | |
| 8 | + - `bun run changeset` | |
| 9 | +2. Merge that PR to `main`. | |
| 10 | +3. `.github/workflows/release.yml` opens or updates a `Version Packages` PR. | |
| 11 | +4. Merge the `Version Packages` PR. | |
| 12 | +5. The release workflow tags the commit and dispatches `.github/workflows/publish-executor-package.yml`. | |
| 13 | +6. The publish workflow: | |
| 14 | + - runs `bun run release:check` | |
| 15 | + - performs a full dry-run release build before publish | |
| 16 | + - publishes npm packages under the correct dist-tag | |
| 17 | + - creates or updates the GitHub release with build artifacts | |
| 18 | + | |
| 19 | +## Beta releases | |
| 20 | + | |
| 21 | +Enter prerelease mode before starting a beta train: | |
| 22 | + | |
| 23 | +- `bun run release:beta:start` | |
| 24 | + | |
| 25 | +That commits `.changeset/pre.json` into the repo and causes future release PRs to produce versions like `1.5.0-beta.0`, `1.5.0-beta.1`, and so on. | |
| 26 | + | |
| 27 | +When the beta train is done: | |
| 28 | + | |
| 29 | +- `bun run release:beta:stop` | |
| 30 | + | |
| 31 | +Stable versions publish to npm under `latest`. | |
| 32 | +Beta versions publish to npm under `beta`. | |
| 33 | + | |
| 34 | +## Local dry run | |
| 35 | + | |
| 36 | +To build the full release payload without publishing to npm or GitHub: | |
| 37 | + | |
| 38 | +- `bun run release:publish:dry-run` | |
| 39 | + | |
| 40 | +That produces: | |
| 41 | + | |
| 42 | +- platform archives in `apps/cli/dist` | |
| 43 | +- the packed wrapper tarball in `apps/cli/dist/release` | |
| 44 | + | |
| 45 | +## Notes | |
| 46 | + | |
| 47 | +- Changesets owns the published CLI version via `apps/cli/package.json`. | |
| 48 | +- `scripts/release/sync-versions.mjs` propagates that version across the rest of the repo manifests after `changeset version` runs. | |
| 49 | +- The publish workflow supports either npm trusted publishing or an `NPM_TOKEN` secret. | |
| 50 | +- Re-running the publish workflow for the same tag is safe for packages that are already on npm; existing versions are skipped. | |
| @@ -0,0 +1,2 @@ | ||
| 1 | +#!/usr/bin/env bun | |
| 2 | +import "../src/main.ts"; | |
| @@ -0,0 +1,35 @@ | ||
| 1 | +{ | |
| 2 | + "name": "executor", | |
| 3 | + "version": "1.4.0-beta.0", | |
| 4 | + "private": true, | |
| 5 | + "type": "module", | |
| 6 | + "bin": { | |
| 7 | + "executor": "./bin/executor.ts" | |
| 8 | + }, | |
| 9 | + "exports": { | |
| 10 | + ".": "./src/main.ts" | |
| 11 | + }, | |
| 12 | + "scripts": { | |
| 13 | + "build": "bun run src/build.ts binary --single", | |
| 14 | + "build:all": "bun run src/build.ts binary", | |
| 15 | + "build:publish": "bun run src/build.ts publish", | |
| 16 | + "release:publish:dry-run": "bun run src/release.ts --dry-run", | |
| 17 | + "release:publish": "bun run src/release.ts", | |
| 18 | + "typecheck": "tsc --noEmit" | |
| 19 | + }, | |
| 20 | + "dependencies": { | |
| 21 | + "@effect/cli": "catalog:", | |
| 22 | + "@effect/platform": "catalog:", | |
| 23 | + "@effect/platform-bun": "catalog:", | |
| 24 | + "@executor/api": "workspace:*", | |
| 25 | + "@executor/runtime-quickjs": "workspace:*", | |
| 26 | + "@executor/server": "workspace:*", | |
| 27 | + "@jitl/quickjs-wasmfile-release-sync": "*", | |
| 28 | + "quickjs-emscripten": "*", | |
| 29 | + "effect": "catalog:" | |
| 30 | + }, | |
| 31 | + "devDependencies": { | |
| 32 | + "bun-types": "catalog:", | |
| 33 | + "typescript": "^5.9.3" | |
| 34 | + } | |
| 35 | +} | |
| @@ -0,0 +1,465 @@ | ||
| 1 | +import { cp, mkdir, rm, writeFile, chmod } from "node:fs/promises"; | |
| 2 | +import { existsSync } from "node:fs"; | |
| 3 | +import { createRequire } from "node:module"; | |
| 4 | +import { resolve, join, dirname } from "node:path"; | |
| 5 | +import { fileURLToPath } from "node:url"; | |
| 6 | +import { $ } from "bun"; | |
| 7 | + | |
| 8 | +const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../../.."); | |
| 9 | +const cliRoot = resolve(repoRoot, "apps/cli"); | |
| 10 | +const webRoot = resolve(repoRoot, "apps/web"); | |
| 11 | +const distDir = resolve(cliRoot, "dist"); | |
| 12 | + | |
| 13 | +const resolveQuickJsWasmPath = (): string => { | |
| 14 | + const req = createRequire(join(repoRoot, "packages/kernel/runtime-quickjs/package.json")); | |
| 15 | + const quickJsPkg = req.resolve("quickjs-emscripten/package.json"); | |
| 16 | + const wasmPath = resolve( | |
| 17 | + dirname(quickJsPkg), | |
| 18 | + "../@jitl/quickjs-wasmfile-release-sync/dist/emscripten-module.wasm", | |
| 19 | + ); | |
| 20 | + if (!existsSync(wasmPath)) throw new Error(`QuickJS WASM not found at ${wasmPath}`); | |
| 21 | + return wasmPath; | |
| 22 | +}; | |
| 23 | + | |
| 24 | +// --------------------------------------------------------------------------- | |
| 25 | +// Metadata | |
| 26 | +// --------------------------------------------------------------------------- | |
| 27 | + | |
| 28 | +const readMetadata = async () => { | |
| 29 | + const rootPkg = await Bun.file(join(repoRoot, "package.json")).json(); | |
| 30 | + const cliPkg = await Bun.file(join(cliRoot, "package.json")).json(); | |
| 31 | + return { | |
| 32 | + name: "executor", | |
| 33 | + version: process.env.EXECUTOR_VERSION ?? cliPkg.version ?? rootPkg.version ?? "0.0.0", | |
| 34 | + description: rootPkg.description ?? "Local AI executor with a CLI, local API server, and web UI.", | |
| 35 | + keywords: rootPkg.keywords ?? [], | |
| 36 | + homepage: rootPkg.homepage, | |
| 37 | + bugs: rootPkg.bugs, | |
| 38 | + repository: rootPkg.repository, | |
| 39 | + license: rootPkg.license ?? "MIT", | |
| 40 | + }; | |
| 41 | +}; | |
| 42 | + | |
| 43 | +// --------------------------------------------------------------------------- | |
| 44 | +// Targets | |
| 45 | +// --------------------------------------------------------------------------- | |
| 46 | + | |
| 47 | +type Target = { | |
| 48 | + os: "linux" | "darwin" | "win32"; | |
| 49 | + arch: "x64" | "arm64"; | |
| 50 | + abi?: "musl"; | |
| 51 | +}; | |
| 52 | + | |
| 53 | +const ALL_TARGETS: Target[] = [ | |
| 54 | + { os: "linux", arch: "x64" }, | |
| 55 | + { os: "linux", arch: "arm64" }, | |
| 56 | + { os: "linux", arch: "x64", abi: "musl" }, | |
| 57 | + { os: "linux", arch: "arm64", abi: "musl" }, | |
| 58 | + { os: "darwin", arch: "x64" }, | |
| 59 | + { os: "darwin", arch: "arm64" }, | |
| 60 | + { os: "win32", arch: "x64" }, | |
| 61 | + { os: "win32", arch: "arm64" }, | |
| 62 | +]; | |
| 63 | + | |
| 64 | +const platformName = (t: Target) => | |
| 65 | + t.os === "win32" ? "windows" : t.os; | |
| 66 | + | |
| 67 | +const targetPackageName = (t: Target) => | |
| 68 | + ["executor", platformName(t), t.arch, t.abi].filter(Boolean).join("-"); | |
| 69 | + | |
| 70 | +const bunTarget = (t: Target) => | |
| 71 | + ["bun", platformName(t), t.arch, t.abi].filter(Boolean).join("-"); | |
| 72 | + | |
| 73 | +const binaryName = (t: Target) => | |
| 74 | + t.os === "win32" ? "executor.exe" : "executor"; | |
| 75 | + | |
| 76 | +const isCurrentPlatform = (t: Target) => | |
| 77 | + t.os === process.platform && t.arch === process.arch && !t.abi; | |
| 78 | + | |
| 79 | +// --------------------------------------------------------------------------- | |
| 80 | +// Build web app | |
| 81 | +// --------------------------------------------------------------------------- | |
| 82 | + | |
| 83 | +const buildWeb = async () => { | |
| 84 | + const webDist = join(webRoot, "dist"); | |
| 85 | + if (existsSync(webDist)) return webDist; | |
| 86 | + | |
| 87 | + console.log("Building web app..."); | |
| 88 | + const proc = Bun.spawn(["bun", "run", "build"], { cwd: webRoot, stdio: ["ignore", "inherit", "inherit"] }); | |
| 89 | + if ((await proc.exited) !== 0) throw new Error("Web build failed"); | |
| 90 | + return webDist; | |
| 91 | +}; | |
| 92 | + | |
| 93 | +// --------------------------------------------------------------------------- | |
| 94 | +// Embedded web UI — generates a virtual module that imports all web assets | |
| 95 | +// using `with { type: "file" }` so Bun bakes them into the compiled binary. | |
| 96 | +// --------------------------------------------------------------------------- | |
| 97 | + | |
| 98 | +const createEmbeddedWebUISource = async () => { | |
| 99 | + const webDist = await buildWeb(); | |
| 100 | + const files = (await Array.fromAsync(new Bun.Glob("**/*").scan({ cwd: webDist }))) | |
| 101 | + .map((f) => f.replaceAll("\\", "/")) | |
| 102 | + .sort(); | |
| 103 | + | |
| 104 | + const imports = files.map((file, i) => { | |
| 105 | + const spec = join(webDist, file).replaceAll("\\", "/"); | |
| 106 | + return `import file_${i} from ${JSON.stringify(spec)} with { type: "file" };`; | |
| 107 | + }); | |
| 108 | + | |
| 109 | + const entries = files.map((file, i) => ` ${JSON.stringify(file)}: file_${i},`); | |
| 110 | + | |
| 111 | + return [ | |
| 112 | + "// Auto-generated — maps web UI paths to embedded file references", | |
| 113 | + ...imports, | |
| 114 | + "export default {", | |
| 115 | + ...entries, | |
| 116 | + "} as Record<string, string>;", | |
| 117 | + ].join("\n"); | |
| 118 | +}; | |
| 119 | + | |
| 120 | +// --------------------------------------------------------------------------- | |
| 121 | +// Build platform binaries | |
| 122 | +// --------------------------------------------------------------------------- | |
| 123 | + | |
| 124 | +const buildBinaries = async (targets: Target[]) => { | |
| 125 | + const meta = await readMetadata(); | |
| 126 | + const binaries: Record<string, string> = {}; | |
| 127 | + | |
| 128 | + await rm(distDir, { recursive: true, force: true }); | |
| 129 | + | |
| 130 | + console.log("Generating embedded web UI bundle..."); | |
| 131 | + const embeddedWebUI = await createEmbeddedWebUISource(); | |
| 132 | + const quickJsWasmPath = resolveQuickJsWasmPath(); | |
| 133 | + | |
| 134 | + for (const target of targets) { | |
| 135 | + const name = targetPackageName(target); | |
| 136 | + const outDir = join(distDir, name); | |
| 137 | + const binDir = join(outDir, "bin"); | |
| 138 | + await mkdir(binDir, { recursive: true }); | |
| 139 | + | |
| 140 | + console.log(`Building ${name}...`); | |
| 141 | + | |
| 142 | + await Bun.build({ | |
| 143 | + entrypoints: [join(cliRoot, "src/main.ts"), "embedded-web-ui.gen.ts"], | |
| 144 | + minify: true, | |
| 145 | + files: { | |
| 146 | + "embedded-web-ui.gen.ts": embeddedWebUI, | |
| 147 | + }, | |
| 148 | + compile: { | |
| 149 | + target: bunTarget(target) as any, | |
| 150 | + outfile: join(binDir, binaryName(target)), | |
| 151 | + }, | |
| 152 | + }); | |
| 153 | + | |
| 154 | + // Copy QuickJS WASM next to binary — loaded at runtime by the server | |
| 155 | + await cp(quickJsWasmPath, join(binDir, "emscripten-module.wasm")); | |
| 156 | + | |
| 157 | + // Smoke test on current platform | |
| 158 | + if (isCurrentPlatform(target)) { | |
| 159 | + const bin = join(binDir, binaryName(target)); | |
| 160 | + console.log(` Smoke test: ${bin} --version`); | |
| 161 | + const version = await $`${bin} --version`.text(); | |
| 162 | + console.log(` OK: ${version.trim()}`); | |
| 163 | + } | |
| 164 | + | |
| 165 | + // Platform package.json | |
| 166 | + await writeFile( | |
| 167 | + join(outDir, "package.json"), | |
| 168 | + JSON.stringify( | |
| 169 | + { | |
| 170 | + name, | |
| 171 | + version: meta.version, | |
| 172 | + os: [target.os], | |
| 173 | + cpu: [target.arch], | |
| 174 | + bin: { executor: `bin/${binaryName(target)}` }, | |
| 175 | + }, | |
| 176 | + null, | |
| 177 | + 2, | |
| 178 | + ) + "\n", | |
| 179 | + ); | |
| 180 | + | |
| 181 | + binaries[name] = meta.version; | |
| 182 | + } | |
| 183 | + | |
| 184 | + return binaries; | |
| 185 | +}; | |
| 186 | + | |
| 187 | +// --------------------------------------------------------------------------- | |
| 188 | +// Build wrapper npm package | |
| 189 | +// --------------------------------------------------------------------------- | |
| 190 | + | |
| 191 | +const buildWrapperPackage = async (binaries: Record<string, string>) => { | |
| 192 | + const meta = await readMetadata(); | |
| 193 | + const wrapperDir = join(distDir, meta.name); | |
| 194 | + const binDir = join(wrapperDir, "bin"); | |
| 195 | + | |
| 196 | + await mkdir(binDir, { recursive: true }); | |
| 197 | + | |
| 198 | + // Node.js shim that finds + spawns the right platform binary | |
| 199 | + await writeFile(join(binDir, "executor"), NODE_SHIM); | |
| 200 | + await chmod(join(binDir, "executor"), 0o755); | |
| 201 | + | |
| 202 | + // Postinstall: hardlink the platform binary for faster startup | |
| 203 | + await writeFile(join(wrapperDir, "postinstall.mjs"), POSTINSTALL_SCRIPT); | |
| 204 | + | |
| 205 | + // Package.json | |
| 206 | + await writeFile( | |
| 207 | + join(wrapperDir, "package.json"), | |
| 208 | + JSON.stringify( | |
| 209 | + { | |
| 210 | + name: meta.name, | |
| 211 | + version: meta.version, | |
| 212 | + description: meta.description, | |
| 213 | + keywords: meta.keywords, | |
| 214 | + homepage: meta.homepage, | |
| 215 | + bugs: meta.bugs, | |
| 216 | + repository: meta.repository, | |
| 217 | + license: meta.license, | |
| 218 | + bin: { executor: "bin/executor" }, | |
| 219 | + scripts: { | |
| 220 | + postinstall: "node ./postinstall.mjs", | |
| 221 | + }, | |
| 222 | + optionalDependencies: binaries, | |
| 223 | + }, | |
| 224 | + null, | |
| 225 | + 2, | |
| 226 | + ) + "\n", | |
| 227 | + ); | |
| 228 | + | |
| 229 | + // README | |
| 230 | + const readmePath = join(repoRoot, "README.md"); | |
| 231 | + if (existsSync(readmePath)) { | |
| 232 | + await cp(readmePath, join(wrapperDir, "README.md")); | |
| 233 | + } | |
| 234 | + | |
| 235 | + console.log(`\nWrapper package: ${wrapperDir}`); | |
| 236 | + console.log(` ${meta.name}@${meta.version}`); | |
| 237 | + console.log(` optionalDependencies: ${Object.keys(binaries).join(", ")}`); | |
| 238 | +}; | |
| 239 | + | |
| 240 | +// --------------------------------------------------------------------------- | |
| 241 | +// Publish | |
| 242 | +// --------------------------------------------------------------------------- | |
| 243 | + | |
| 244 | +const packageAlreadyPublished = async (pkgDir: string) => { | |
| 245 | + const pkg = await Bun.file(join(pkgDir, "package.json")).json() as { | |
| 246 | + name?: string; | |
| 247 | + version?: string; | |
| 248 | + }; | |
| 249 | + | |
| 250 | + if (!pkg.name || !pkg.version) { | |
| 251 | + throw new Error(`Missing name/version in ${join(pkgDir, "package.json")}`); | |
| 252 | + } | |
| 253 | + | |
| 254 | + const proc = Bun.spawn(["npm", "view", `${pkg.name}@${pkg.version}`, "version"], { | |
| 255 | + cwd: pkgDir, | |
| 256 | + stdio: ["ignore", "ignore", "ignore"], | |
| 257 | + }); | |
| 258 | + | |
| 259 | + return (await proc.exited) === 0; | |
| 260 | +}; | |
| 261 | + | |
| 262 | +const publishPackedPackage = async (pkgDir: string, channel: string) => { | |
| 263 | + if (await packageAlreadyPublished(pkgDir)) { | |
| 264 | + console.log(`Skipping ${pkgDir}; package version already exists on npm.`); | |
| 265 | + return; | |
| 266 | + } | |
| 267 | + | |
| 268 | + await $`bun pm pack`.cwd(pkgDir); | |
| 269 | + | |
| 270 | + if (process.env.GITHUB_ACTIONS === "true") { | |
| 271 | + await $`npm publish *.tgz --access public --tag ${channel} --provenance`.cwd(pkgDir); | |
| 272 | + } else { | |
| 273 | + await $`npm publish *.tgz --access public --tag ${channel}`.cwd(pkgDir); | |
| 274 | + } | |
| 275 | +}; | |
| 276 | + | |
| 277 | +const publish = async (channel: string) => { | |
| 278 | + const meta = await readMetadata(); | |
| 279 | + | |
| 280 | + // Publish platform packages | |
| 281 | + for (const entry of new Bun.Glob("executor-*/package.json").scanSync({ cwd: distDir })) { | |
| 282 | + const pkgDir = join(distDir, dirname(entry)); | |
| 283 | + console.log(`Publishing ${pkgDir}...`); | |
| 284 | + await publishPackedPackage(pkgDir, channel); | |
| 285 | + } | |
| 286 | + | |
| 287 | + // Publish wrapper package | |
| 288 | + const wrapperDir = join(distDir, meta.name); | |
| 289 | + console.log(`Publishing ${wrapperDir}...`); | |
| 290 | + await publishPackedPackage(wrapperDir, channel); | |
| 291 | +}; | |
| 292 | + | |
| 293 | +// --------------------------------------------------------------------------- | |
| 294 | +// GitHub release assets | |
| 295 | +// --------------------------------------------------------------------------- | |
| 296 | + | |
| 297 | +const ZIP_ASSET_SCRIPT = [ | |
| 298 | + "import pathlib, sys, zipfile", | |
| 299 | + "output = pathlib.Path(sys.argv[1])", | |
| 300 | + "with zipfile.ZipFile(output, 'w', compression=zipfile.ZIP_DEFLATED) as archive:", | |
| 301 | + " for path in pathlib.Path('.').rglob('*'):", | |
| 302 | + " if path.is_file():", | |
| 303 | + " archive.write(path, path.as_posix())", | |
| 304 | +].join("\n"); | |
| 305 | + | |
| 306 | +const createReleaseAssets = async () => { | |
| 307 | + for (const entry of new Bun.Glob("executor-*/package.json").scanSync({ cwd: distDir })) { | |
| 308 | + const pkgDir = join(distDir, dirname(entry)); | |
| 309 | + const pkg = await Bun.file(join(pkgDir, "package.json")).json(); | |
| 310 | + const name = pkg.name as string; | |
| 311 | + | |
| 312 | + if (name.includes("linux")) { | |
| 313 | + await $`tar -czf ${join(distDir, `${name}.tar.gz`)} *`.cwd(join(pkgDir, "bin")); | |
| 314 | + } else { | |
| 315 | + await $`python3 -c ${ZIP_ASSET_SCRIPT} ${join(distDir, `${name}.zip`)}`.cwd(join(pkgDir, "bin")); | |
| 316 | + } | |
| 317 | + | |
| 318 | + console.log(`Created release asset: ${name}`); | |
| 319 | + } | |
| 320 | +}; | |
| 321 | + | |
| 322 | +// --------------------------------------------------------------------------- | |
| 323 | +// Node.js shim — finds the right platform binary and spawns it | |
| 324 | +// --------------------------------------------------------------------------- | |
| 325 | + | |
| 326 | +const NODE_SHIM = `#!/usr/bin/env node | |
| 327 | +const childProcess = require("child_process"); | |
| 328 | +const fs = require("fs"); | |
| 329 | +const path = require("path"); | |
| 330 | +const os = require("os"); | |
| 331 | + | |
| 332 | +function run(target) { | |
| 333 | + const result = childProcess.spawnSync(target, process.argv.slice(2), { stdio: "inherit" }); | |
| 334 | + if (result.error) { console.error(result.error.message); process.exit(1); } | |
| 335 | + process.exit(typeof result.status === "number" ? result.status : 0); | |
| 336 | +} | |
| 337 | + | |
| 338 | +// Check env override | |
| 339 | +if (process.env.EXECUTOR_BIN_PATH) run(process.env.EXECUTOR_BIN_PATH); | |
| 340 | + | |
| 341 | +// Check cached binary from postinstall | |
| 342 | +const scriptDir = path.dirname(fs.realpathSync(__filename)); | |
| 343 | +const cached = path.join(scriptDir, ".executor"); | |
| 344 | +if (fs.existsSync(cached)) run(cached); | |
| 345 | + | |
| 346 | +// Resolve platform | |
| 347 | +const platformMap = { darwin: "darwin", linux: "linux", win32: "windows" }; | |
| 348 | +const platform = platformMap[os.platform()] || os.platform(); | |
| 349 | +const arch = os.arch() === "arm64" ? "arm64" : "x64"; | |
| 350 | +const binary = platform === "windows" ? "executor.exe" : "executor"; | |
| 351 | + | |
| 352 | +// Detect musl | |
| 353 | +const isMusl = (() => { | |
| 354 | + if (platform !== "linux") return false; | |
| 355 | + try { if (fs.existsSync("/etc/alpine-release")) return true; } catch {} | |
| 356 | + try { | |
| 357 | + const r = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" }); | |
| 358 | + if (((r.stdout || "") + (r.stderr || "")).toLowerCase().includes("musl")) return true; | |
| 359 | + } catch {} | |
| 360 | + return false; | |
| 361 | +})(); | |
| 362 | + | |
| 363 | +// Build candidate list | |
| 364 | +const base = "executor-" + platform + "-" + arch; | |
| 365 | +const names = (() => { | |
| 366 | + if (platform === "linux" && isMusl) { | |
| 367 | + return [base + "-musl", base]; | |
| 368 | + } | |
| 369 | + if (platform === "linux") { | |
| 370 | + return [base, base + "-musl"]; | |
| 371 | + } | |
| 372 | + return [base]; | |
| 373 | +})(); | |
| 374 | + | |
| 375 | +// Walk up to find node_modules | |
| 376 | +function findBinary(startDir) { | |
| 377 | + let current = startDir; | |
| 378 | + for (;;) { | |
| 379 | + const modules = path.join(current, "node_modules"); | |
| 380 | + if (fs.existsSync(modules)) { | |
| 381 | + for (const name of names) { | |
| 382 | + const candidate = path.join(modules, name, "bin", binary); | |
| 383 | + if (fs.existsSync(candidate)) return candidate; | |
| 384 | + } | |
| 385 | + } | |
| 386 | + const parent = path.dirname(current); | |
| 387 | + if (parent === current) return; | |
| 388 | + current = parent; | |
| 389 | + } | |
| 390 | +} | |
| 391 | + | |
| 392 | +const resolved = findBinary(scriptDir); | |
| 393 | +if (!resolved) { | |
| 394 | + console.error("Could not find executor binary for your platform. Try installing " + names.map(n => '"' + n + '"').join(" or ")); | |
| 395 | + process.exit(1); | |
| 396 | +} | |
| 397 | +run(resolved); | |
| 398 | +`; | |
| 399 | + | |
| 400 | +// --------------------------------------------------------------------------- | |
| 401 | +// Postinstall — hardlink/copy the platform binary for fast startup | |
| 402 | +// --------------------------------------------------------------------------- | |
| 403 | + | |
| 404 | +const POSTINSTALL_SCRIPT = `#!/usr/bin/env node | |
| 405 | +const fs = require("fs"); | |
| 406 | +const path = require("path"); | |
| 407 | +const os = require("os"); | |
| 408 | +const { createRequire } = require("module"); | |
| 409 | + | |
| 410 | +const __dirname_resolved = path.dirname(fs.realpathSync(__filename)); | |
| 411 | +const require_ = createRequire(__filename); | |
| 412 | + | |
| 413 | +const platformMap = { darwin: "darwin", linux: "linux", win32: "windows" }; | |
| 414 | +const platform = platformMap[os.platform()] || os.platform(); | |
| 415 | +const arch = os.arch() === "arm64" ? "arm64" : "x64"; | |
| 416 | +const binary = platform === "windows" ? "executor.exe" : "executor"; | |
| 417 | +const base = "executor-" + platform + "-" + arch; | |
| 418 | + | |
| 419 | +const names = platform === "linux" ? [base, base + "-musl"] : [base]; | |
| 420 | + | |
| 421 | +for (const name of names) { | |
| 422 | + try { | |
| 423 | + const pkgJson = require_.resolve(name + "/package.json"); | |
| 424 | + const binaryPath = path.join(path.dirname(pkgJson), "bin", binary); | |
| 425 | + if (!fs.existsSync(binaryPath)) continue; | |
| 426 | + | |
| 427 | + const target = path.join(__dirname_resolved, "bin", ".executor"); | |
| 428 | + const binDir = path.join(__dirname_resolved, "bin"); | |
| 429 | + if (!fs.existsSync(binDir)) fs.mkdirSync(binDir, { recursive: true }); | |
| 430 | + if (fs.existsSync(target)) fs.unlinkSync(target); | |
| 431 | + | |
| 432 | + try { fs.linkSync(binaryPath, target); } | |
| 433 | + catch { fs.copyFileSync(binaryPath, target); } | |
| 434 | + fs.chmodSync(target, 0o755); | |
| 435 | + console.log("executor: binary linked for " + name); | |
| 436 | + break; | |
| 437 | + } catch {} | |
| 438 | +} | |
| 439 | +`; | |
| 440 | + | |
| 441 | +// --------------------------------------------------------------------------- | |
| 442 | +// CLI | |
| 443 | +// --------------------------------------------------------------------------- | |
| 444 | + | |
| 445 | +const command = process.argv[2]; | |
| 446 | +const singleFlag = process.argv.includes("--single"); | |
| 447 | + | |
| 448 | +if (command === "binary") { | |
| 449 | + const targets = singleFlag | |
| 450 | + ? ALL_TARGETS.filter(isCurrentPlatform) | |
| 451 | + : ALL_TARGETS; | |
| 452 | + const binaries = await buildBinaries(targets); | |
| 453 | + await buildWrapperPackage(binaries); | |
| 454 | +} else if (command === "release-assets") { | |
| 455 | + await createReleaseAssets(); | |
| 456 | +} else if (command === "publish") { | |
| 457 | + const channel = process.argv[3] ?? "latest"; | |
| 458 | + await publish(channel); | |
| 459 | +} else { | |
| 460 | + console.log(`Usage: | |
| 461 | + bun run build.ts binary [--single] Build platform binaries + wrapper package | |
| 462 | + bun run build.ts release-assets Create .tar.gz/.zip from built binaries | |
| 463 | + bun run build.ts publish [channel] Publish all packages to npm`); | |
| 464 | + process.exit(1); | |
| 465 | +} | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +declare module "embedded-web-ui.gen.ts" { | |
| 2 | + const files: Record<string, string>; | |
| 3 | + export default files; | |
| 4 | +} | |
| @@ -0,0 +1,388 @@ | ||
| 1 | +// Pre-load QuickJS WASM for compiled binaries — must run before server imports | |
| 2 | +import { dirname, join } from "node:path"; | |
| 3 | +const wasmOnDisk = join(dirname(process.execPath), "emscripten-module.wasm"); | |
| 4 | +if (typeof Bun !== "undefined" && await Bun.file(wasmOnDisk).exists()) { | |
| 5 | + const { setQuickJSModule } = await import("@executor/runtime-quickjs"); | |
| 6 | + const { newQuickJSWASMModule } = await import("quickjs-emscripten"); | |
| 7 | + const wasmBinary = await Bun.file(wasmOnDisk).arrayBuffer(); | |
| 8 | + const variant = { | |
| 9 | + type: "sync" as const, | |
| 10 | + importFFI: () => import("@jitl/quickjs-wasmfile-release-sync/ffi").then((m: any) => m.QuickJSFFI), | |
| 11 | + importModuleLoader: () => | |
| 12 | + import("@jitl/quickjs-wasmfile-release-sync/emscripten-module").then((m: any) => { | |
| 13 | + const original = m.default; | |
| 14 | + return (moduleArg: any = {}) => original({ ...moduleArg, wasmBinary }); | |
| 15 | + }), | |
| 16 | + }; | |
| 17 | + const mod = await newQuickJSWASMModule(variant as any); | |
| 18 | + setQuickJSModule(mod); | |
| 19 | +} | |
| 20 | + | |
| 21 | +import { spawn } from "node:child_process"; | |
| 22 | +import { resolve } from "node:path"; | |
| 23 | +import { Command, Options, Args } from "@effect/cli"; | |
| 24 | +import { BunRuntime } from "@effect/platform-bun"; | |
| 25 | +import { FetchHttpClient, HttpApiClient } from "@effect/platform"; | |
| 26 | +import * as Effect from "effect/Effect"; | |
| 27 | +import * as Option from "effect/Option"; | |
| 28 | +import * as Cause from "effect/Cause"; | |
| 29 | + | |
| 30 | +import { ExecutorApi } from "@executor/api"; | |
| 31 | +import { createServerHandlers, runMcpStdioServer, getExecutor } from "@executor/server"; | |
| 32 | + | |
| 33 | +// --------------------------------------------------------------------------- | |
| 34 | +// Constants | |
| 35 | +// --------------------------------------------------------------------------- | |
| 36 | + | |
| 37 | +const CLI_NAME = "executor"; | |
| 38 | +const { version: CLI_VERSION } = await import("../package.json"); | |
| 39 | +const DEFAULT_PORT = 8788; | |
| 40 | +const DEFAULT_BASE_URL = `http://localhost:${DEFAULT_PORT}`; | |
| 41 | + | |
| 42 | +// Embedded web UI — baked into compiled binaries via `with { type: "file" }` | |
| 43 | +const embeddedWebUI: Record<string, string> | null = | |
| 44 | + await import("embedded-web-ui.gen.ts") | |
| 45 | + .then((m) => m.default as Record<string, string>) | |
| 46 | + .catch(() => null); | |
| 47 | + | |
| 48 | +// --------------------------------------------------------------------------- | |
| 49 | +// Helpers | |
| 50 | +// --------------------------------------------------------------------------- | |
| 51 | + | |
| 52 | +const waitForShutdownSignal = () => | |
| 53 | + Effect.async<void, never>((resume) => { | |
| 54 | + const shutdown = () => resume(Effect.void); | |
| 55 | + process.once("SIGINT", shutdown); | |
| 56 | + process.once("SIGTERM", shutdown); | |
| 57 | + return Effect.sync(() => { | |
| 58 | + process.off("SIGINT", shutdown); | |
| 59 | + process.off("SIGTERM", shutdown); | |
| 60 | + }); | |
| 61 | + }); | |
| 62 | + | |
| 63 | +const appendUrlPath = (baseUrl: string, pathname: string): string => | |
| 64 | + new URL(pathname, baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`).toString(); | |
| 65 | + | |
| 66 | +const renderSessionSummary = (kind: "web" | "mcp", baseUrl: string): string => { | |
| 67 | + const displayKind = kind === "mcp" ? "MCP" : "web"; | |
| 68 | + const primaryLabel = kind === "web" ? "Web" : "MCP"; | |
| 69 | + const primaryUrl = kind === "web" ? baseUrl : appendUrlPath(baseUrl, "mcp"); | |
| 70 | + const secondaryLabel = kind === "web" ? "MCP" : "Web"; | |
| 71 | + const secondaryUrl = kind === "web" ? appendUrlPath(baseUrl, "mcp") : baseUrl; | |
| 72 | + const guidance = | |
| 73 | + kind === "web" | |
| 74 | + ? "Keep this process running while you use the browser session." | |
| 75 | + : "Use this MCP URL in your client and keep this process running."; | |
| 76 | + | |
| 77 | + return [ | |
| 78 | + `Executor ${displayKind} session is ready.`, | |
| 79 | + `${primaryLabel}: ${primaryUrl}`, | |
| 80 | + `${secondaryLabel}: ${secondaryUrl}`, | |
| 81 | + `OpenAPI: ${appendUrlPath(baseUrl, "docs")}`, | |
| 82 | + "", | |
| 83 | + guidance, | |
| 84 | + "Press Ctrl+C to stop.", | |
| 85 | + ].join("\n"); | |
| 86 | +}; | |
| 87 | + | |
| 88 | +// --------------------------------------------------------------------------- | |
| 89 | +// Background server management | |
| 90 | +// --------------------------------------------------------------------------- | |
| 91 | + | |
| 92 | +const isServerReachable = async (baseUrl: string): Promise<boolean> => { | |
| 93 | + try { | |
| 94 | + const res = await fetch(`${baseUrl}/docs`, { signal: AbortSignal.timeout(2000) }); | |
| 95 | + return res.ok; | |
| 96 | + } catch { | |
| 97 | + return false; | |
| 98 | + } | |
| 99 | +}; | |
| 100 | + | |
| 101 | +const script = process.argv[1]; | |
| 102 | +const isDevMode = script?.endsWith(".ts") || script?.endsWith(".js"); | |
| 103 | +const cliPrefix = isDevMode ? `bun run ${script}` : "executor"; | |
| 104 | + | |
| 105 | +const startBackgroundServer = (port: number): void => { | |
| 106 | + const args = isDevMode | |
| 107 | + ? ["run", script, "web", "--port", String(port)] | |
| 108 | + : ["web", "--port", String(port)]; | |
| 109 | + const child = spawn(process.execPath, args, { | |
| 110 | + detached: true, | |
| 111 | + stdio: "ignore", | |
| 112 | + }); | |
| 113 | + child.unref(); | |
| 114 | +}; | |
| 115 | + | |
| 116 | +const ensureServer = (baseUrl: string) => | |
| 117 | + Effect.gen(function* () { | |
| 118 | + if (yield* Effect.promise(() => isServerReachable(baseUrl))) return; | |
| 119 | + | |
| 120 | + const url = new URL(baseUrl); | |
| 121 | + const port = Number(url.port) || DEFAULT_PORT; | |
| 122 | + console.error(`Starting background server on port ${port}...`); | |
| 123 | + startBackgroundServer(port); | |
| 124 | + | |
| 125 | + const deadline = Date.now() + 30_000; | |
| 126 | + while (Date.now() < deadline) { | |
| 127 | + yield* Effect.promise(() => new Promise((r) => setTimeout(r, 200))); | |
| 128 | + if (yield* Effect.promise(() => isServerReachable(baseUrl))) return; | |
| 129 | + } | |
| 130 | + | |
| 131 | + return yield* Effect.fail(new Error(`Server failed to start within 30s at ${baseUrl}`)); | |
| 132 | + }); | |
| 133 | + | |
| 134 | +// --------------------------------------------------------------------------- | |
| 135 | +// Typed API client | |
| 136 | +// --------------------------------------------------------------------------- | |
| 137 | + | |
| 138 | +const makeApiClient = (baseUrl: string) => | |
| 139 | + HttpApiClient.make(ExecutorApi, { baseUrl }).pipe( | |
| 140 | + Effect.provide(FetchHttpClient.layer), | |
| 141 | + ); | |
| 142 | + | |
| 143 | +// --------------------------------------------------------------------------- | |
| 144 | +// Static file serving from embedded web UI | |
| 145 | +// --------------------------------------------------------------------------- | |
| 146 | + | |
| 147 | +const WEB_DIST_DIR = resolve(import.meta.dirname, "../../web/dist"); | |
| 148 | + | |
| 149 | +const serveStatic = async (pathname: string): Promise<Response | null> => { | |
| 150 | + const key = pathname.replace(/^\//, ""); | |
| 151 | + | |
| 152 | + // Compiled binary: serve from embedded bunfs | |
| 153 | + if (embeddedWebUI) { | |
| 154 | + const match = embeddedWebUI[key] ?? embeddedWebUI["index.html"] ?? null; | |
| 155 | + if (!match) return null; | |
| 156 | + const file = Bun.file(match); | |
| 157 | + if (await file.exists()) { | |
| 158 | + return new Response(file, { | |
| 159 | + headers: { "content-type": file.type || "application/octet-stream" }, | |
| 160 | + }); | |
| 161 | + } | |
| 162 | + return null; | |
| 163 | + } | |
| 164 | + | |
| 165 | + // Dev mode: serve from apps/web/dist on disk | |
| 166 | + const filePath = resolve(WEB_DIST_DIR, key); | |
| 167 | + if (!filePath.startsWith(WEB_DIST_DIR)) return null; | |
| 168 | + | |
| 169 | + const file = Bun.file(filePath); | |
| 170 | + if (await file.exists()) { | |
| 171 | + return new Response(file, { | |
| 172 | + headers: { "content-type": file.type || "application/octet-stream" }, | |
| 173 | + }); | |
| 174 | + } | |
| 175 | + | |
| 176 | + // SPA fallback | |
| 177 | + const index = Bun.file(resolve(WEB_DIST_DIR, "index.html")); | |
| 178 | + if (await index.exists()) { | |
| 179 | + return new Response(index, { headers: { "content-type": "text/html" } }); | |
| 180 | + } | |
| 181 | + | |
| 182 | + return null; | |
| 183 | +}; | |
| 184 | + | |
| 185 | +// --------------------------------------------------------------------------- | |
| 186 | +// Foreground session — API + MCP + Web UI on one Bun.serve() | |
| 187 | +// --------------------------------------------------------------------------- | |
| 188 | + | |
| 189 | +const runForegroundSession = (input: { kind: "web" | "mcp"; port: number }) => | |
| 190 | + Effect.gen(function* () { | |
| 191 | + const handlers = yield* Effect.promise(() => createServerHandlers()); | |
| 192 | + | |
| 193 | + const server = Bun.serve({ | |
| 194 | + port: input.port, | |
| 195 | + async fetch(request) { | |
| 196 | + const url = new URL(request.url); | |
| 197 | + | |
| 198 | + if (url.pathname.startsWith("/mcp")) { | |
| 199 | + return handlers.mcp.handleRequest(request); | |
| 200 | + } | |
| 201 | + | |
| 202 | + if ( | |
| 203 | + url.pathname.startsWith("/v1/") || | |
| 204 | + url.pathname.startsWith("/docs") || | |
| 205 | + url.pathname === "/openapi.json" | |
| 206 | + ) { | |
| 207 | + return handlers.api.handler(request); | |
| 208 | + } | |
| 209 | + | |
| 210 | + const staticResponse = await serveStatic(url.pathname); | |
| 211 | + if (staticResponse) return staticResponse; | |
| 212 | + | |
| 213 | + return new Response("Not Found", { status: 404 }); | |
| 214 | + }, | |
| 215 | + }); | |
| 216 | + | |
| 217 | + const baseUrl = `http://localhost:${server.port}`; | |
| 218 | + console.log(renderSessionSummary(input.kind, baseUrl)); | |
| 219 | + | |
| 220 | + yield* waitForShutdownSignal(); | |
| 221 | + | |
| 222 | + server.stop(true); | |
| 223 | + yield* Effect.promise(() => handlers.mcp.close()); | |
| 224 | + yield* Effect.promise(() => handlers.api.dispose()); | |
| 225 | + }); | |
| 226 | + | |
| 227 | +// --------------------------------------------------------------------------- | |
| 228 | +// Stdio MCP session | |
| 229 | +// --------------------------------------------------------------------------- | |
| 230 | + | |
| 231 | +const runStdioMcpSession = () => | |
| 232 | + Effect.gen(function* () { | |
| 233 | + const executor = yield* Effect.promise(() => getExecutor()); | |
| 234 | + yield* Effect.promise(() => runMcpStdioServer({ executor })); | |
| 235 | + }); | |
| 236 | + | |
| 237 | +// --------------------------------------------------------------------------- | |
| 238 | +// Code resolution — positional arg > --file > stdin | |
| 239 | +// --------------------------------------------------------------------------- | |
| 240 | + | |
| 241 | +const readCode = (input: { | |
| 242 | + code: Option.Option<string>; | |
| 243 | + file: Option.Option<string>; | |
| 244 | + stdin: boolean; | |
| 245 | +}): Effect.Effect<string, Error> => | |
| 246 | + Effect.gen(function* () { | |
| 247 | + const code = Option.getOrUndefined(input.code); | |
| 248 | + if (code && code.trim().length > 0) return code; | |
| 249 | + | |
| 250 | + const file = Option.getOrUndefined(input.file); | |
| 251 | + if (file && file.trim().length > 0) { | |
| 252 | + const contents = yield* Effect.tryPromise({ | |
| 253 | + try: () => Bun.file(file).text(), | |
| 254 | + catch: (e) => new Error(`Failed to read file: ${e}`), | |
| 255 | + }); | |
| 256 | + if (contents.trim().length > 0) return contents; | |
| 257 | + } | |
| 258 | + | |
| 259 | + if (input.stdin || !process.stdin.isTTY) { | |
| 260 | + const chunks: string[] = []; | |
| 261 | + process.stdin.setEncoding("utf8"); | |
| 262 | + const contents = yield* Effect.tryPromise({ | |
| 263 | + try: async () => { | |
| 264 | + for await (const chunk of process.stdin) chunks.push(chunk as string); | |
| 265 | + return chunks.join(""); | |
| 266 | + }, | |
| 267 | + catch: (e) => new Error(`Failed to read stdin: ${e}`), | |
| 268 | + }); | |
| 269 | + if (contents.trim().length > 0) return contents; | |
| 270 | + } | |
| 271 | + | |
| 272 | + return yield* Effect.fail( | |
| 273 | + new Error("No code provided. Pass code as an argument, --file, or pipe to stdin."), | |
| 274 | + ); | |
| 275 | + }); | |
| 276 | + | |
| 277 | +// --------------------------------------------------------------------------- | |
| 278 | +// Commands | |
| 279 | +// --------------------------------------------------------------------------- | |
| 280 | + | |
| 281 | +const callCommand = Command.make( | |
| 282 | + "call", | |
| 283 | + { | |
| 284 | + code: Args.text({ name: "code" }).pipe(Args.optional), | |
| 285 | + file: Options.text("file").pipe(Options.optional), | |
| 286 | + stdin: Options.boolean("stdin").pipe(Options.withDefault(false)), | |
| 287 | + baseUrl: Options.text("base-url").pipe(Options.withDefault(DEFAULT_BASE_URL)), | |
| 288 | + }, | |
| 289 | + ({ code, file, stdin, baseUrl }) => | |
| 290 | + Effect.gen(function* () { | |
| 291 | + const resolvedCode = yield* readCode({ code, file, stdin }); | |
| 292 | + yield* ensureServer(baseUrl); | |
| 293 | + | |
| 294 | + const client = yield* makeApiClient(baseUrl); | |
| 295 | + const result = yield* client.executions.execute({ payload: { code: resolvedCode } }); | |
| 296 | + | |
| 297 | + if (result.status === "completed") { | |
| 298 | + if (result.isError) { | |
| 299 | + console.error(result.text); | |
| 300 | + process.exitCode = 1; | |
| 301 | + } else { | |
| 302 | + console.log(result.text); | |
| 303 | + } | |
| 304 | + } else { | |
| 305 | + console.log(result.text); | |
| 306 | + const executionId = (result.structured as any)?.executionId; | |
| 307 | + if (executionId) { | |
| 308 | + console.log( | |
| 309 | + `\nTo resume:\n ${cliPrefix} resume --execution-id ${executionId} --action accept`, | |
| 310 | + ); | |
| 311 | + } | |
| 312 | + } | |
| 313 | + }), | |
| 314 | +).pipe(Command.withDescription("Execute code against the local executor")); | |
| 315 | + | |
| 316 | +const resumeCommand = Command.make( | |
| 317 | + "resume", | |
| 318 | + { | |
| 319 | + executionId: Options.text("execution-id"), | |
| 320 | + action: Options.text("action").pipe(Options.withDefault("accept")), | |
| 321 | + content: Options.text("content").pipe(Options.optional), | |
| 322 | + baseUrl: Options.text("base-url").pipe(Options.withDefault(DEFAULT_BASE_URL)), | |
| 323 | + }, | |
| 324 | + ({ executionId, action, content, baseUrl }) => | |
| 325 | + Effect.gen(function* () { | |
| 326 | + yield* ensureServer(baseUrl); | |
| 327 | + | |
| 328 | + const parsedContent = Option.getOrUndefined(content); | |
| 329 | + const contentObj = parsedContent ? JSON.parse(parsedContent) : undefined; | |
| 330 | + | |
| 331 | + const client = yield* makeApiClient(baseUrl); | |
| 332 | + const result = yield* client.executions.resume({ | |
| 333 | + path: { executionId }, | |
| 334 | + payload: { action: action as "accept" | "decline" | "cancel", content: contentObj }, | |
| 335 | + }); | |
| 336 | + | |
| 337 | + if (result.isError) { | |
| 338 | + console.error(result.text); | |
| 339 | + process.exitCode = 1; | |
| 340 | + } else { | |
| 341 | + console.log(result.text); | |
| 342 | + } | |
| 343 | + }), | |
| 344 | +).pipe(Command.withDescription("Resume a paused execution")); | |
| 345 | + | |
| 346 | +const webCommand = Command.make( | |
| 347 | + "web", | |
| 348 | + { | |
| 349 | + port: Options.integer("port").pipe(Options.withDefault(DEFAULT_PORT)), | |
| 350 | + }, | |
| 351 | + ({ port }) => runForegroundSession({ kind: "web", port }), | |
| 352 | +).pipe(Command.withDescription("Start a foreground web session")); | |
| 353 | + | |
| 354 | +const mcpCommand = Command.make( | |
| 355 | + "mcp", | |
| 356 | + {}, | |
| 357 | + () => runStdioMcpSession(), | |
| 358 | +).pipe(Command.withDescription("Start an MCP server over stdio")); | |
| 359 | + | |
| 360 | +// --------------------------------------------------------------------------- | |
| 361 | +// Root command | |
| 362 | +// --------------------------------------------------------------------------- | |
| 363 | + | |
| 364 | +const root = Command.make("executor").pipe( | |
| 365 | + Command.withSubcommands([callCommand, resumeCommand, webCommand, mcpCommand] as const), | |
| 366 | + Command.withDescription("Executor local CLI"), | |
| 367 | +); | |
| 368 | + | |
| 369 | +// --------------------------------------------------------------------------- | |
| 370 | +// Run | |
| 371 | +// --------------------------------------------------------------------------- | |
| 372 | + | |
| 373 | +const runCli = Command.run(root, { | |
| 374 | + name: CLI_NAME, | |
| 375 | + version: CLI_VERSION, | |
| 376 | + executable: CLI_NAME, | |
| 377 | +}); | |
| 378 | + | |
| 379 | +const program = runCli(process.argv).pipe( | |
| 380 | + Effect.catchAllCause((cause) => | |
| 381 | + Effect.sync(() => { | |
| 382 | + console.error(Cause.pretty(cause)); | |
| 383 | + process.exitCode = 1; | |
| 384 | + }), | |
| 385 | + ), | |
| 386 | +); | |
| 387 | + | |
| 388 | +BunRuntime.runMain(program as Effect.Effect<void, never, never>); | |
| @@ -0,0 +1,270 @@ | ||
| 1 | +import { existsSync } from "node:fs"; | |
| 2 | +import { mkdir, readdir, rename, rm } from "node:fs/promises"; | |
| 3 | +import { dirname, join, resolve } from "node:path"; | |
| 4 | +import { fileURLToPath } from "node:url"; | |
| 5 | + | |
| 6 | +type ReleaseChannel = "latest" | "beta"; | |
| 7 | + | |
| 8 | +type ReleaseCliOptions = { | |
| 9 | + readonly dryRun: boolean; | |
| 10 | +}; | |
| 11 | + | |
| 12 | +type CommandInput = { | |
| 13 | + readonly command: string; | |
| 14 | + readonly args: ReadonlyArray<string>; | |
| 15 | + readonly cwd: string; | |
| 16 | + readonly captureOutput?: boolean; | |
| 17 | +}; | |
| 18 | + | |
| 19 | +type CommandOutput = { | |
| 20 | + readonly stdout: string; | |
| 21 | + readonly stderr: string; | |
| 22 | +}; | |
| 23 | + | |
| 24 | +const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../../.."); | |
| 25 | +const cliRoot = resolve(repoRoot, "apps/cli"); | |
| 26 | +const distDir = resolve(cliRoot, "dist"); | |
| 27 | +const releaseDir = resolve(distDir, "release"); | |
| 28 | +const wrapperDir = resolve(distDir, "executor"); | |
| 29 | +const versionPackagePath = resolve(cliRoot, "package.json"); | |
| 30 | +const semverPattern = | |
| 31 | + /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/; | |
| 32 | + | |
| 33 | +const parseArgs = (argv: ReadonlyArray<string>): ReleaseCliOptions => { | |
| 34 | + let dryRun = false; | |
| 35 | + | |
| 36 | + for (const arg of argv) { | |
| 37 | + if (arg === "--dry-run") { | |
| 38 | + dryRun = true; | |
| 39 | + continue; | |
| 40 | + } | |
| 41 | + | |
| 42 | + throw new Error(`Unknown argument: ${arg}`); | |
| 43 | + } | |
| 44 | + | |
| 45 | + return { dryRun }; | |
| 46 | +}; | |
| 47 | + | |
| 48 | +const runCommand = async (input: CommandInput): Promise<CommandOutput> => { | |
| 49 | + const proc = Bun.spawn([input.command, ...input.args], { | |
| 50 | + cwd: input.cwd, | |
| 51 | + env: process.env, | |
| 52 | + stdio: input.captureOutput ? ["ignore", "pipe", "pipe"] : ["ignore", "inherit", "inherit"], | |
| 53 | + }); | |
| 54 | + | |
| 55 | + const exitCode = await proc.exited; | |
| 56 | + const stdout = input.captureOutput && proc.stdout ? await new Response(proc.stdout).text() : ""; | |
| 57 | + const stderr = input.captureOutput && proc.stderr ? await new Response(proc.stderr).text() : ""; | |
| 58 | + | |
| 59 | + if (exitCode !== 0) { | |
| 60 | + throw new Error( | |
| 61 | + [ | |
| 62 | + `${input.command} ${input.args.join(" ")} exited with code ${exitCode}`, | |
| 63 | + stdout.trim().length > 0 ? `stdout:\n${stdout.trim()}` : null, | |
| 64 | + stderr.trim().length > 0 ? `stderr:\n${stderr.trim()}` : null, | |
| 65 | + ] | |
| 66 | + .filter((part) => part !== null) | |
| 67 | + .join("\n\n"), | |
| 68 | + ); | |
| 69 | + } | |
| 70 | + | |
| 71 | + return { | |
| 72 | + stdout: stdout.trim(), | |
| 73 | + stderr: stderr.trim(), | |
| 74 | + }; | |
| 75 | +}; | |
| 76 | + | |
| 77 | +const readVersion = async (): Promise<string> => { | |
| 78 | + const pkg = await Bun.file(versionPackagePath).json() as { version?: string }; | |
| 79 | + const version = pkg.version?.trim(); | |
| 80 | + | |
| 81 | + if (!version) { | |
| 82 | + throw new Error(`Missing version in ${versionPackagePath}`); | |
| 83 | + } | |
| 84 | + | |
| 85 | + return version; | |
| 86 | +}; | |
| 87 | + | |
| 88 | +const validateVersion = (version: string): void => { | |
| 89 | + if (!semverPattern.test(version)) { | |
| 90 | + throw new Error(`${versionPackagePath} version is not valid semver: ${version}`); | |
| 91 | + } | |
| 92 | +}; | |
| 93 | + | |
| 94 | +const resolveChannel = (version: string): ReleaseChannel => | |
| 95 | + version.includes("-") ? "beta" : "latest"; | |
| 96 | + | |
| 97 | +const resolveTagFromEnvironment = (): string | undefined => { | |
| 98 | + const refName = process.env.GITHUB_REF_NAME?.trim(); | |
| 99 | + if (process.env.GITHUB_REF_TYPE === "tag" && refName) { | |
| 100 | + return refName; | |
| 101 | + } | |
| 102 | + | |
| 103 | + const ref = process.env.GITHUB_REF?.trim(); | |
| 104 | + if (ref?.startsWith("refs/tags/")) { | |
| 105 | + return ref.slice("refs/tags/".length); | |
| 106 | + } | |
| 107 | + | |
| 108 | + return undefined; | |
| 109 | +}; | |
| 110 | + | |
| 111 | +const resolveGitHubRepository = (): string => { | |
| 112 | + const repository = process.env.GH_REPO?.trim() || process.env.GITHUB_REPOSITORY?.trim(); | |
| 113 | + if (!repository) { | |
| 114 | + throw new Error("Set GH_REPO or GITHUB_REPOSITORY before creating a GitHub release."); | |
| 115 | + } | |
| 116 | + | |
| 117 | + return repository; | |
| 118 | +}; | |
| 119 | + | |
| 120 | +const packWrapperPackage = async (): Promise<string> => { | |
| 121 | + if (!existsSync(wrapperDir)) { | |
| 122 | + throw new Error(`Wrapper package directory not found: ${wrapperDir}`); | |
| 123 | + } | |
| 124 | + | |
| 125 | + await mkdir(releaseDir, { recursive: true }); | |
| 126 | + | |
| 127 | + const before = new Set((await readdir(wrapperDir)).filter((entry) => entry.endsWith(".tgz"))); | |
| 128 | + await runCommand({ | |
| 129 | + command: "bun", | |
| 130 | + args: ["pm", "pack"], | |
| 131 | + cwd: wrapperDir, | |
| 132 | + }); | |
| 133 | + | |
| 134 | + const after = (await readdir(wrapperDir)).filter((entry) => entry.endsWith(".tgz")); | |
| 135 | + const archiveName = after.find((entry) => !before.has(entry)) ?? after[0]; | |
| 136 | + | |
| 137 | + if (!archiveName) { | |
| 138 | + throw new Error(`bun pm pack did not create a .tgz archive in ${wrapperDir}`); | |
| 139 | + } | |
| 140 | + | |
| 141 | + const sourcePath = join(wrapperDir, archiveName); | |
| 142 | + const destinationPath = join(releaseDir, archiveName); | |
| 143 | + | |
| 144 | + await rm(destinationPath, { force: true }); | |
| 145 | + await rename(sourcePath, destinationPath); | |
| 146 | + | |
| 147 | + return destinationPath; | |
| 148 | +}; | |
| 149 | + | |
| 150 | +const collectReleaseAssetPaths = async (wrapperArchivePath: string): Promise<ReadonlyArray<string>> => { | |
| 151 | + const assetNames = (await readdir(distDir)) | |
| 152 | + .filter((entry) => /^executor-.*\.(?:tar\.gz|zip)$/.test(entry)) | |
| 153 | + .sort(); | |
| 154 | + | |
| 155 | + return [ | |
| 156 | + wrapperArchivePath, | |
| 157 | + ...assetNames.map((entry) => join(distDir, entry)), | |
| 158 | + ]; | |
| 159 | +}; | |
| 160 | + | |
| 161 | +const githubReleaseExists = async (tag: string, repository: string): Promise<boolean> => { | |
| 162 | + const proc = Bun.spawn(["gh", "release", "view", tag, "--repo", repository], { | |
| 163 | + cwd: repoRoot, | |
| 164 | + env: process.env, | |
| 165 | + stdio: ["ignore", "ignore", "ignore"], | |
| 166 | + }); | |
| 167 | + | |
| 168 | + return (await proc.exited) === 0; | |
| 169 | +}; | |
| 170 | + | |
| 171 | +const syncGitHubRelease = async (input: { | |
| 172 | + readonly tag: string; | |
| 173 | + readonly channel: ReleaseChannel; | |
| 174 | + readonly assetPaths: ReadonlyArray<string>; | |
| 175 | +}): Promise<void> => { | |
| 176 | + if (!process.env.GH_TOKEN?.trim()) { | |
| 177 | + throw new Error("GH_TOKEN is required to create or update a GitHub release."); | |
| 178 | + } | |
| 179 | + | |
| 180 | + const repository = resolveGitHubRepository(); | |
| 181 | + | |
| 182 | + if (await githubReleaseExists(input.tag, repository)) { | |
| 183 | + await runCommand({ | |
| 184 | + command: "gh", | |
| 185 | + args: ["release", "upload", input.tag, ...input.assetPaths, "--repo", repository, "--clobber"], | |
| 186 | + cwd: repoRoot, | |
| 187 | + }); | |
| 188 | + return; | |
| 189 | + } | |
| 190 | + | |
| 191 | + const args = [ | |
| 192 | + "release", | |
| 193 | + "create", | |
| 194 | + input.tag, | |
| 195 | + ...input.assetPaths, | |
| 196 | + "--repo", | |
| 197 | + repository, | |
| 198 | + "--title", | |
| 199 | + input.tag, | |
| 200 | + "--generate-notes", | |
| 201 | + "--verify-tag", | |
| 202 | + ]; | |
| 203 | + | |
| 204 | + if (input.channel === "beta") { | |
| 205 | + args.push("--prerelease"); | |
| 206 | + } else { | |
| 207 | + args.push("--latest"); | |
| 208 | + } | |
| 209 | + | |
| 210 | + await runCommand({ | |
| 211 | + command: "gh", | |
| 212 | + args, | |
| 213 | + cwd: repoRoot, | |
| 214 | + }); | |
| 215 | +}; | |
| 216 | + | |
| 217 | +const main = async () => { | |
| 218 | + const options = parseArgs(process.argv.slice(2)); | |
| 219 | + const version = await readVersion(); | |
| 220 | + const tag = `v${version}`; | |
| 221 | + const refTag = resolveTagFromEnvironment(); | |
| 222 | + const channel = resolveChannel(version); | |
| 223 | + | |
| 224 | + validateVersion(version); | |
| 225 | + | |
| 226 | + if (refTag && refTag !== tag) { | |
| 227 | + throw new Error(`GitHub tag ${refTag} does not match ${versionPackagePath} version ${version}`); | |
| 228 | + } | |
| 229 | + | |
| 230 | + await rm(releaseDir, { recursive: true, force: true }); | |
| 231 | + await mkdir(releaseDir, { recursive: true }); | |
| 232 | + | |
| 233 | + await runCommand({ | |
| 234 | + command: "bun", | |
| 235 | + args: ["run", "src/build.ts", "binary"], | |
| 236 | + cwd: cliRoot, | |
| 237 | + }); | |
| 238 | + | |
| 239 | + await runCommand({ | |
| 240 | + command: "bun", | |
| 241 | + args: ["run", "src/build.ts", "release-assets"], | |
| 242 | + cwd: cliRoot, | |
| 243 | + }); | |
| 244 | + | |
| 245 | + const wrapperArchivePath = await packWrapperPackage(); | |
| 246 | + const assetPaths = await collectReleaseAssetPaths(wrapperArchivePath); | |
| 247 | + | |
| 248 | + console.log(`Prepared executor@${version} for ${channel}`); | |
| 249 | + for (const assetPath of assetPaths) { | |
| 250 | + console.log(`- ${assetPath}`); | |
| 251 | + } | |
| 252 | + | |
| 253 | + if (options.dryRun) { | |
| 254 | + return; | |
| 255 | + } | |
| 256 | + | |
| 257 | + await runCommand({ | |
| 258 | + command: "bun", | |
| 259 | + args: ["run", "src/build.ts", "publish", channel], | |
| 260 | + cwd: cliRoot, | |
| 261 | + }); | |
| 262 | + | |
| 263 | + await syncGitHubRelease({ | |
| 264 | + tag, | |
| 265 | + channel, | |
| 266 | + assetPaths, | |
| 267 | + }); | |
| 268 | +}; | |
| 269 | + | |
| 270 | +await main(); | |
| @@ -0,0 +1,14 @@ | ||
| 1 | +{ | |
| 2 | + "compilerOptions": { | |
| 3 | + "strict": true, | |
| 4 | + "target": "ESNext", | |
| 5 | + "module": "ESNext", | |
| 6 | + "moduleResolution": "bundler", | |
| 7 | + "esModuleInterop": true, | |
| 8 | + "skipLibCheck": true, | |
| 9 | + "noEmit": true, | |
| 10 | + "declaration": true, | |
| 11 | + "types": ["bun-types"] | |
| 12 | + }, | |
| 13 | + "include": ["src", "bin"] | |
| 14 | +} | |
| @@ -1,3 +0,0 @@ | ||
| 1 | −# @executor/docs | |
| 2 | − | |
| 3 | −## null | |
| @@ -1,32 +0,0 @@ | ||
| 1 | −{ | |
| 2 | − "$schema": "https://mintlify.com/docs.json", | |
| 3 | − "theme": "mint", | |
| 4 | − "name": "Executor", | |
| 5 | − "description": "A local-first execution environment for AI agents.", | |
| 6 | − "colors": { | |
| 7 | − "primary": "#0D9373", | |
| 8 | − "light": "#07C983", | |
| 9 | − "dark": "#0D9373" | |
| 10 | − }, | |
| 11 | − "navigation": { | |
| 12 | − "tabs": [ | |
| 13 | − { | |
| 14 | − "tab": "Docs", | |
| 15 | − "groups": [ | |
| 16 | − { | |
| 17 | − "group": "Status", | |
| 18 | − "pages": [ | |
| 19 | − "introduction" | |
| 20 | − ] | |
| 21 | − } | |
| 22 | − ] | |
| 23 | − } | |
| 24 | − ] | |
| 25 | − }, | |
| 26 | − "footer": { | |
| 27 | − "socials": { | |
| 28 | − "github": "https://github.com/anomalyco/executor", | |
| 29 | − "discord": "https://discord.gg/eF29HBHwM6" | |
| 30 | − } | |
| 31 | − } | |
| 32 | −} | |
| @@ -1,10 +0,0 @@ | ||
| 1 | −--- | |
| 2 | −title: "Introduction" | |
| 3 | −description: "A local-first execution environment for AI agents." | |
| 4 | −--- | |
| 5 | − | |
| 6 | −`executor` is a local-first execution environment for AI agents. It gives an agent a TypeScript runtime, a discoverable tool catalog, and a single local place to connect external systems such as MCP servers, OpenAPI APIs, and GraphQL APIs. | |
| 7 | − | |
| 8 | −The docs set has been intentionally removed for now while the plugin architecture is still shifting. | |
| 9 | − | |
| 10 | −Use the repository source directly if you need current implementation details. | |
| @@ -1,11 +0,0 @@ | ||
| 1 | −{ | |
| 2 | − "name": "@executor/docs", | |
| 3 | − "private": true, | |
| 4 | − "type": "module", | |
| 5 | − "scripts": { | |
| 6 | − "dev": "bunx --bun mint dev --no-open --port 3337", | |
| 7 | − "typecheck": "echo 'No typecheck for @executor/docs'", | |
| 8 | − "validate": "bunx --bun mint validate" | |
| 9 | − }, | |
| 10 | − "version": "0.0.0" | |
| 11 | −} | |
| @@ -1,175 +0,0 @@ | ||
| 1 | −# executor | |
| 2 | − | |
| 3 | −## 1.3.0-beta.5 | |
| 4 | − | |
| 5 | −### Patch Changes | |
| 6 | − | |
| 7 | −- 0316b25: Compact openapi sources | |
| 8 | − | |
| 9 | −## 1.3.0-beta.4 | |
| 10 | − | |
| 11 | −### Patch Changes | |
| 12 | − | |
| 13 | −- 787dd66: Improve Google Discovery sources view | |
| 14 | − | |
| 15 | −## 1.3.0-beta.3 | |
| 16 | − | |
| 17 | −### Patch Changes | |
| 18 | − | |
| 19 | −- Improve MCP source setup by auto-detecting OAuth requirements, showing a loading state during discovery, and allowing creation without signing in. | |
| 20 | − | |
| 21 | −## 1.3.0-beta.2 | |
| 22 | − | |
| 23 | −### Patch Changes | |
| 24 | − | |
| 25 | −- Fix the packaged beta so the bundled 1Password SDK can load its wasm asset after install. | |
| 26 | − | |
| 27 | −## 1.3.0-beta.1 | |
| 28 | − | |
| 29 | −### Patch Changes | |
| 30 | − | |
| 31 | −- Fix the beta distribution packaging flow so the prerelease publish passes again. | |
| 32 | − | |
| 33 | −## 1.3.0-beta.0 | |
| 34 | − | |
| 35 | −### Minor Changes | |
| 36 | − | |
| 37 | −- e4b1359: Prepare the next executor beta minor release. | |
| 38 | − | |
| 39 | −## 1.2.6 | |
| 40 | − | |
| 41 | −### Patch Changes | |
| 42 | − | |
| 43 | −- 54d39e4: Disable executor injected tools | |
| 44 | − | |
| 45 | −## 1.2.5 | |
| 46 | − | |
| 47 | −### Patch Changes | |
| 48 | − | |
| 49 | −- d95a087: Add stdio MCP support via `executor mcp --stdio`, make foreground `web` and `mcp` sessions first-class CLI entrypoints, and update the dashboard MCP install card to default to the stdio install flow with an HTTP toggle. | |
| 50 | − | |
| 51 | −## 1.2.5-beta.0 | |
| 52 | − | |
| 53 | −### Patch Changes | |
| 54 | − | |
| 55 | −- d95a087: Add stdio MCP support via `executor mcp --stdio`, make foreground `web` and `mcp` sessions first-class CLI entrypoints, and update the dashboard MCP install card to default to the stdio install flow with an HTTP toggle. | |
| 56 | − | |
| 57 | −## 1.2.4 | |
| 58 | − | |
| 59 | −### Patch Changes | |
| 60 | − | |
| 61 | −- 5617247: Prewarm the lean workspace source index at startup and reuse it across discovery requests so the first tool search no longer pays the full catalog hydration cost. | |
| 62 | −- dc94998: Auto migrate sources on startup | |
| 63 | −- 74185a9: Move execution to adapters rather than IR model | |
| 64 | −- 1f82a22: Avoid generating source tool type previews when building namespace metadata, and cap MCP execute help examples to five tools per source. | |
| 65 | −- 5e3cb3e: Add GitHub source support, migrate legacy executor state on load, and fix execute-path runtime regressions. | |
| 66 | −- f0a3802: Fix legacy format parsing | |
| 67 | −- 44ce032: Avoid ever building a full schema workspace catalog during tool description, and resolve schemaful tool details through direct one-tool lookup instead. | |
| 68 | −- ec5e3a3: Fix Google Discovery tool execution for sources stored with discovery document endpoints | |
| 69 | −- 839dcb6: Make `executor up` output more helpful and less debug-oriented. | |
| 70 | −- 5869ddb: Fix build | |
| 71 | − | |
| 72 | −## 1.2.4-beta.9 | |
| 73 | − | |
| 74 | −### Patch Changes | |
| 75 | − | |
| 76 | −- 44ce032: Avoid ever building a full schema workspace catalog during tool description, and resolve schemaful tool details through direct one-tool lookup instead. | |
| 77 | − | |
| 78 | −## 1.2.4-beta.8 | |
| 79 | − | |
| 80 | −### Patch Changes | |
| 81 | − | |
| 82 | −- 5617247: Prewarm the lean workspace source index at startup and reuse it across discovery requests so the first tool search no longer pays the full catalog hydration cost. | |
| 83 | − | |
| 84 | −## 1.2.4-beta.7 | |
| 85 | − | |
| 86 | −### Patch Changes | |
| 87 | − | |
| 88 | −- 1f82a22: Avoid generating source tool type previews when building namespace metadata, and cap MCP execute help examples to five tools per source. | |
| 89 | − | |
| 90 | −## 1.2.4-beta.6 | |
| 91 | − | |
| 92 | −### Patch Changes | |
| 93 | − | |
| 94 | −- 839dcb6: Make `executor up` output more helpful and less debug-oriented. | |
| 95 | − | |
| 96 | −## 1.2.4-beta.5 | |
| 97 | − | |
| 98 | −### Patch Changes | |
| 99 | − | |
| 100 | −- 5e3cb3e: Add GitHub source support, migrate legacy executor state on load, and fix execute-path runtime regressions. | |
| 101 | − | |
| 102 | −## 1.2.4-beta.4 | |
| 103 | − | |
| 104 | −### Patch Changes | |
| 105 | − | |
| 106 | −- ec5e3a3: Fix Google Discovery tool execution for sources stored with discovery document endpoints | |
| 107 | − | |
| 108 | −## 1.2.4-beta.3 | |
| 109 | − | |
| 110 | −### Patch Changes | |
| 111 | − | |
| 112 | −- dc94998: Auto migrate sources on startup | |
| 113 | − | |
| 114 | −## 1.2.4-beta.2 | |
| 115 | − | |
| 116 | −### Patch Changes | |
| 117 | − | |
| 118 | −- f0a3802: Fix legacy format parsing | |
| 119 | − | |
| 120 | −## 1.2.4-beta.1 | |
| 121 | − | |
| 122 | −### Patch Changes | |
| 123 | − | |
| 124 | −- 5869ddb: Fix build | |
| 125 | − | |
| 126 | −## 1.2.4-beta.0 | |
| 127 | − | |
| 128 | −### Patch Changes | |
| 129 | − | |
| 130 | −- 74185a9: Move execution to adapters rather than IR model | |
| 131 | − | |
| 132 | −## 1.2.3 | |
| 133 | − | |
| 134 | −### Patch Changes | |
| 135 | − | |
| 136 | −- eda1217: Always request maximal scope for Google Apis | |
| 137 | − | |
| 138 | −## 1.2.2 | |
| 139 | − | |
| 140 | −### Patch Changes | |
| 141 | − | |
| 142 | −- 661ed29: Support selecting runtime | |
| 143 | − | |
| 144 | −## 1.2.1 | |
| 145 | − | |
| 146 | −### Patch Changes | |
| 147 | − | |
| 148 | −- 329cc41: fix migration | |
| 149 | −- 86d4d4d: package the PGlite runtime assets in the published CLI bundle | |
| 150 | − | |
| 151 | −## 1.2.0 | |
| 152 | − | |
| 153 | −### Minor Changes | |
| 154 | − | |
| 155 | −- 7574535: add multiple sources at same time | |
| 156 | − | |
| 157 | −### Patch Changes | |
| 158 | − | |
| 159 | −- a2ada62: Google workspace support, folder based config | |
| 160 | − - @executor/codemode-core@null | |
| 161 | − - @executor/control-plane@null | |
| 162 | − - @executor/executor-mcp@null | |
| 163 | − - @executor/server@null | |
| 164 | − | |
| 165 | −## 1.2.0-beta.7 | |
| 166 | − | |
| 167 | −### Minor Changes | |
| 168 | − | |
| 169 | −- 7574535: add multiple sources at same time | |
| 170 | − | |
| 171 | −## 1.1.10-beta.6 | |
| 172 | − | |
| 173 | −### Patch Changes | |
| 174 | − | |
| 175 | −- a2ada62: Google workspace support, folder based config | |
| @@ -1,10 +0,0 @@ | ||
| 1 | −#!/usr/bin/env bash | |
| 2 | −set -euo pipefail | |
| 3 | −SOURCE="$0" | |
| 4 | −while [ -L "$SOURCE" ]; do | |
| 5 | − DIR="$(cd "$(dirname "$SOURCE")" && pwd)" | |
| 6 | − SOURCE="$(readlink "$SOURCE")" | |
| 7 | − [[ "$SOURCE" != /* ]] && SOURCE="$DIR/$SOURCE" | |
| 8 | −done | |
| 9 | −SCRIPT_DIR="$(cd "$(dirname "$SOURCE")" && pwd)" | |
| 10 | −exec bun "$SCRIPT_DIR/../src/cli/main.ts" "$@" | |
| @@ -1,65 +0,0 @@ | ||
| 1 | −{ | |
| 2 | − "name": "executor", | |
| 3 | − "version": "1.3.0-beta.5", | |
| 4 | − "description": "Local AI executor with a CLI, local API server, and web UI.", | |
| 5 | − "keywords": [ | |
| 6 | − "executor", | |
| 7 | − "ai", | |
| 8 | − "agent", | |
| 9 | − "cli", | |
| 10 | − "automation", | |
| 11 | − "local-first" | |
| 12 | − ], | |
| 13 | − "homepage": "https://github.com/RhysSullivan/executor", | |
| 14 | − "bugs": { | |
| 15 | − "url": "https://github.com/RhysSullivan/executor/issues" | |
| 16 | − }, | |
| 17 | − "repository": { | |
| 18 | − "type": "git", | |
| 19 | − "url": "git+https://github.com/RhysSullivan/executor.git" | |
| 20 | − }, | |
| 21 | − "license": "MIT", | |
| 22 | − "private": true, | |
| 23 | − "type": "module", | |
| 24 | − "bin": { | |
| 25 | − "executor": "bin/executor" | |
| 26 | − }, | |
| 27 | − "scripts": { | |
| 28 | − "typecheck": "bunx tsc --noEmit -p tsconfig.json", | |
| 29 | − "test": "vitest run", | |
| 30 | − "test:watch": "vitest", | |
| 31 | − "start": "bun src/cli/main.ts", | |
| 32 | − "release:publish:dry-run": "bun src/distribution/publish.ts --dry-run", | |
| 33 | − "release:publish": "bun src/distribution/publish.ts" | |
| 34 | − }, | |
| 35 | − "dependencies": { | |
| 36 | − "@effect/cli": "catalog:", | |
| 37 | − "@effect/platform": "catalog:", | |
| 38 | − "@effect/platform-node": "catalog:", | |
| 39 | − "@executor/codemode-core": "workspace:*", | |
| 40 | − "@executor/executor-mcp": "workspace:*", | |
| 41 | − "@executor/plugin-google-discovery-sdk": "workspace:*", | |
| 42 | − "@executor/plugin-graphql-sdk": "workspace:*", | |
| 43 | − "@executor/plugin-keychain-secret-store-sdk": "workspace:*", | |
| 44 | − "@executor/plugin-local-secret-store-sdk": "workspace:*", | |
| 45 | − "@executor/plugin-local-tools-sdk": "workspace:*", | |
| 46 | − "@executor/plugin-mcp-sdk": "workspace:*", | |
| 47 | − "@executor/plugin-openapi-sdk": "workspace:*", | |
| 48 | − "@executor/platform-api": "workspace:*", | |
| 49 | − "@executor/platform-sdk": "workspace:*", | |
| 50 | − "@executor/platform-sdk-file": "workspace:*", | |
| 51 | − "@executor/server": "workspace:*", | |
| 52 | − "effect": "catalog:" | |
| 53 | − }, | |
| 54 | − "devDependencies": { | |
| 55 | − "@executor/effect-test-utils": "workspace:*", | |
| 56 | − "@executor/mcp-elicitation-demo": "workspace:*", | |
| 57 | − "@executor/runtime-ses": "workspace:*", | |
| 58 | − "@effect/vitest": "catalog:", | |
| 59 | − "@modelcontextprotocol/sdk": "^1.26.0", | |
| 60 | − "@types/node": "catalog:", | |
| 61 | − "bun-types": "catalog:", | |
| 62 | − "vitest": "catalog:", | |
| 63 | − "zod": "catalog:" | |
| 64 | − } | |
| 65 | −} | |
| @@ -1,37 +0,0 @@ | ||
| 1 | −import { describe, expect, it } from "@effect/vitest"; | |
| 2 | − | |
| 3 | −import { decideInteractionHandling } from "./interaction-handling"; | |
| 4 | − | |
| 5 | −describe("interaction-handling", () => { | |
| 6 | − it("keeps URL interactions distinct even when the terminal is non-interactive", () => { | |
| 7 | − expect(decideInteractionHandling({ | |
| 8 | − parsed: { | |
| 9 | − mode: "url", | |
| 10 | − message: "Connect Axiom", | |
| 11 | − url: "https://mcp.axiom.co/authorize", | |
| 12 | − }, | |
| 13 | − isInteractiveTerminal: false, | |
| 14 | − })).toBe("url_paused"); | |
| 15 | − }); | |
| 16 | − | |
| 17 | − it("waits on URL interactions in an interactive terminal", () => { | |
| 18 | − expect(decideInteractionHandling({ | |
| 19 | − parsed: { | |
| 20 | − mode: "url", | |
| 21 | − message: "Connect Axiom", | |
| 22 | − url: "https://mcp.axiom.co/authorize", | |
| 23 | − }, | |
| 24 | − isInteractiveTerminal: true, | |
| 25 | − })).toBe("url_interactive"); | |
| 26 | − }); | |
| 27 | − | |
| 28 | − it("falls back to form pause handling for non-interactive prompts", () => { | |
| 29 | − expect(decideInteractionHandling({ | |
| 30 | − parsed: { | |
| 31 | − mode: "form", | |
| 32 | − message: "Approve tool call", | |
| 33 | − }, | |
| 34 | − isInteractiveTerminal: false, | |
| 35 | − })).toBe("form_paused"); | |
| 36 | − }); | |
| 37 | −}); | |
| @@ -1,18 +0,0 @@ | ||
| 1 | −import type { ParsedInteractionPayload } from "./pending-interaction-output"; | |
| 2 | − | |
| 3 | −export type InteractionHandling = | |
| 4 | − | "url_interactive" | |
| 5 | − | "url_paused" | |
| 6 | − | "form_interactive" | |
| 7 | − | "form_paused"; | |
| 8 | − | |
| 9 | −export const decideInteractionHandling = (input: { | |
| 10 | − parsed: ParsedInteractionPayload | null; | |
| 11 | − isInteractiveTerminal: boolean; | |
| 12 | −}): InteractionHandling => { | |
| 13 | − if (input.parsed?.mode === "url") { | |
| 14 | − return input.isInteractiveTerminal ? "url_interactive" : "url_paused"; | |
| 15 | − } | |
| 16 | − | |
| 17 | − return input.isInteractiveTerminal ? "form_interactive" : "form_paused"; | |
| 18 | −}; | |
| @@ -1,1196 +0,0 @@ | ||
| 1 | −import { spawn } from "node:child_process"; | |
| 2 | −import { createRequire } from "node:module"; | |
| 3 | −import { dirname } from "node:path"; | |
| 4 | −import { createInterface } from "node:readline/promises"; | |
| 5 | −import { FileSystem } from "@effect/platform"; | |
| 6 | −import { Args, Command, Options } from "@effect/cli"; | |
| 7 | −import { | |
| 8 | − NodeFileSystem, | |
| 9 | − NodePath, | |
| 10 | − NodeRuntime, | |
| 11 | −} from "@effect/platform-node"; | |
| 12 | −import { | |
| 13 | − createExecutorApiEffectClient as createExecutorApiClient, | |
| 14 | − type ExecutorApiEffectClient as ExecutorApiClient, | |
| 15 | −} from "@executor/platform-api/effect"; | |
| 16 | −import { runExecutorMcpStdioServer } from "@executor/executor-mcp"; | |
| 17 | −import { | |
| 18 | − googleDiscoverySdkPlugin, | |
| 19 | −} from "@executor/plugin-google-discovery-sdk"; | |
| 20 | −import { | |
| 21 | − graphqlSdkPlugin, | |
| 22 | −} from "@executor/plugin-graphql-sdk"; | |
| 23 | −import { | |
| 24 | − keychainSecretStoreSdkPlugin, | |
| 25 | −} from "@executor/plugin-keychain-secret-store-sdk"; | |
| 26 | −import { | |
| 27 | − localSecretStoreSdkPlugin, | |
| 28 | −} from "@executor/plugin-local-secret-store-sdk"; | |
| 29 | −import { | |
| 30 | − localToolsSdkPlugin, | |
| 31 | −} from "@executor/plugin-local-tools-sdk"; | |
| 32 | −import { | |
| 33 | − mcpSdkPlugin, | |
| 34 | −} from "@executor/plugin-mcp-sdk"; | |
| 35 | −import { | |
| 36 | − openApiSdkPlugin, | |
| 37 | −} from "@executor/plugin-openapi-sdk"; | |
| 38 | −import { | |
| 39 | − getExecutorInternalToolHelpLines, | |
| 40 | − RuntimeExecutionResolverService, | |
| 41 | −} from "@executor/platform-sdk/runtime"; | |
| 42 | −import type { | |
| 43 | − ExecutorSdkPluginRegistry, | |
| 44 | −} from "@executor/platform-sdk/plugins"; | |
| 45 | −import { | |
| 46 | − createExecutorEffect, | |
| 47 | − type ExecutorEffect as Executor, | |
| 48 | −} from "@executor/platform-sdk/effect"; | |
| 49 | −import { | |
| 50 | − createLocalExecutorBackend, | |
| 51 | −} from "@executor/platform-sdk-file"; | |
| 52 | −import { | |
| 53 | − ExecutionIdSchema, | |
| 54 | − type ExecutionEnvelope, | |
| 55 | − type ExecutionInteraction, | |
| 56 | −} from "@executor/platform-sdk/schema"; | |
| 57 | −import type { ToolCatalog } from "@executor/codemode-core"; | |
| 58 | − | |
| 59 | −import * as Effect from "effect/Effect"; | |
| 60 | −import * as Schema from "effect/Schema"; | |
| 61 | −import * as Option from "effect/Option"; | |
| 62 | −import * as Cause from "effect/Cause"; | |
| 63 | − | |
| 64 | −import { | |
| 65 | − createFileGoogleDiscoveryOAuthSessionStorage, | |
| 66 | − createFileGoogleDiscoverySourceStorage, | |
| 67 | − createFileGraphqlSourceStorage, | |
| 68 | − createFileMcpOAuthSessionStorage, | |
| 69 | − createFileMcpSourceStorage, | |
| 70 | − createFileOpenApiSourceStorage, | |
| 71 | − createLocalExecutorServer, | |
| 72 | − DEFAULT_SERVER_BASE_URL, | |
| 73 | − DEFAULT_SERVER_HOST, | |
| 74 | − DEFAULT_SERVER_LOG_FILE, | |
| 75 | − DEFAULT_SERVER_PID_FILE, | |
| 76 | − DEFAULT_SERVER_PORT, | |
| 77 | − SERVER_POLL_INTERVAL_MS, | |
| 78 | − SERVER_START_TIMEOUT_MS, | |
| 79 | − runLocalExecutorServer, | |
| 80 | −} from "@executor/server"; | |
| 81 | −import { | |
| 82 | − resolveCliLocalDataDir, | |
| 83 | − resolveRuntimeWebAssetsDir, | |
| 84 | − resolveSelfCommand, | |
| 85 | −} from "./runtime-paths"; | |
| 86 | −import { | |
| 87 | − buildPausedExecutionOutput, | |
| 88 | − parseInteractionPayload, | |
| 89 | −} from "./pending-interaction-output"; | |
| 90 | −import { decideInteractionHandling } from "./interaction-handling"; | |
| 91 | −import { | |
| 92 | − renderMcpSessionSummary, | |
| 93 | − renderWebSessionSummary, | |
| 94 | −} from "./session-summary"; | |
| 95 | −import { | |
| 96 | − executorAppEffectError, | |
| 97 | − type LocalServerReachabilityTimeoutError, | |
| 98 | − localServerReachabilityTimeoutError, | |
| 99 | −} from "../effect-errors"; | |
| 100 | − | |
| 101 | −const toError = (cause: unknown): Error => | |
| 102 | − cause instanceof Error ? cause : new Error(String(cause)); | |
| 103 | −const sleep = (ms: number) => | |
| 104 | − Effect.promise(() => new Promise<void>((resolve) => setTimeout(resolve, ms))); | |
| 105 | − | |
| 106 | −const openUrlInBrowser = (url: string): Effect.Effect<void, never, never> => | |
| 107 | − Effect.sync(() => { | |
| 108 | − const cmd = | |
| 109 | − process.platform === "darwin" | |
| 110 | − ? ["open", url] | |
| 111 | − : process.platform === "win32" | |
| 112 | − ? ["cmd", "/c", "start", "", url] | |
| 113 | − : ["xdg-open", url]; | |
| 114 | − | |
| 115 | − try { | |
| 116 | − const child = spawn(cmd[0]!, cmd.slice(1), { | |
| 117 | − detached: true, | |
| 118 | − stdio: "ignore", | |
| 119 | − }); | |
| 120 | − child.on("error", () => undefined); | |
| 121 | − child.unref(); | |
| 122 | − } catch { | |
| 123 | − // Best-effort browser launch only; always leave the URL in stdout. | |
| 124 | − } | |
| 125 | − }).pipe(Effect.catchAll(() => Effect.void)); | |
| 126 | − | |
| 127 | −const promptLine = (prompt: string): Effect.Effect<string, Error, never> => | |
| 128 | − Effect.tryPromise({ | |
| 129 | − try: async () => { | |
| 130 | − const rl = createInterface({ | |
| 131 | − input: process.stdin, | |
| 132 | − output: process.stdout, | |
| 133 | − }); | |
| 134 | − | |
| 135 | − try { | |
| 136 | − return await rl.question(prompt); | |
| 137 | − } finally { | |
| 138 | − rl.close(); | |
| 139 | − } | |
| 140 | − }, | |
| 141 | − catch: toError, | |
| 142 | − }); | |
| 143 | − | |
| 144 | −const readStdin = (): Effect.Effect<string, Error, never> => | |
| 145 | − Effect.tryPromise({ | |
| 146 | − try: async () => { | |
| 147 | − let contents = ""; | |
| 148 | − process.stdin.setEncoding("utf8"); | |
| 149 | − for await (const chunk of process.stdin) { | |
| 150 | − contents += chunk; | |
| 151 | − } | |
| 152 | − return contents; | |
| 153 | − }, | |
| 154 | − catch: toError, | |
| 155 | − }); | |
| 156 | − | |
| 157 | −const readCode = (input: { | |
| 158 | − code?: string; | |
| 159 | − file?: string; | |
| 160 | − stdin?: boolean; | |
| 161 | −}): Effect.Effect<string, Error, FileSystem.FileSystem> => | |
| 162 | − Effect.gen(function* () { | |
| 163 | − if (input.code && input.code.trim().length > 0) { | |
| 164 | − return input.code; | |
| 165 | − } | |
| 166 | − | |
| 167 | − if (input.file && input.file.trim().length > 0) { | |
| 168 | − const fs = yield* FileSystem.FileSystem; | |
| 169 | − const contents = yield* fs.readFileString(input.file!, "utf8").pipe( | |
| 170 | − Effect.mapError(toError), | |
| 171 | − ); | |
| 172 | − if (contents.trim().length > 0) { | |
| 173 | − return contents; | |
| 174 | − } | |
| 175 | − } | |
| 176 | − | |
| 177 | − const shouldReadStdin = input.stdin === true || !process.stdin.isTTY; | |
| 178 | − if (shouldReadStdin) { | |
| 179 | − const contents = yield* readStdin(); | |
| 180 | − if (contents.trim().length > 0) { | |
| 181 | − return contents; | |
| 182 | − } | |
| 183 | − } | |
| 184 | − | |
| 185 | − return yield* executorAppEffectError("cli/main", "Provide code as a positional argument, use --file, or pipe code over stdin."); | |
| 186 | − }); | |
| 187 | − | |
| 188 | −const getBootstrapClient = (baseUrl: string = DEFAULT_SERVER_BASE_URL) => | |
| 189 | − createExecutorApiClient({ baseUrl }); | |
| 190 | − | |
| 191 | −const decodeExecutionId = Schema.decodeUnknown(ExecutionIdSchema); | |
| 192 | −const require = createRequire(import.meta.url); | |
| 193 | −const CLI_NAME = "executor"; | |
| 194 | −const CLI_LOCAL_DATA_DIR = resolveCliLocalDataDir(); | |
| 195 | −const CLI_VERSION = (() => { | |
| 196 | − const candidatePaths = [ | |
| 197 | − "../package.json", | |
| 198 | − "../../package.json", | |
| 199 | − ]; | |
| 200 | − | |
| 201 | − for (const candidatePath of candidatePaths) { | |
| 202 | − try { | |
| 203 | − const metadata = require(candidatePath) as { version?: string }; | |
| 204 | − if (metadata.version && metadata.version.trim().length > 0) { | |
| 205 | − return metadata.version; | |
| 206 | − } | |
| 207 | − } catch { | |
| 208 | − // Fall through to the default version below. | |
| 209 | − } | |
| 210 | − } | |
| 211 | − | |
| 212 | − return "0.0.0-local"; | |
| 213 | −})(); | |
| 214 | −const HELP_TOKENS = ["--help", "-h", "help"] as const; | |
| 215 | − | |
| 216 | −const isHelpToken = (value: string | undefined): boolean => | |
| 217 | − value !== undefined && HELP_TOKENS.includes(value as (typeof HELP_TOKENS)[number]); | |
| 218 | − | |
| 219 | −const normalizeCliArgs = (rawArgs: readonly string[]): string[] => { | |
| 220 | − return rawArgs[0] === "run" | |
| 221 | − ? ["call", ...rawArgs.slice(1)] | |
| 222 | − : [...rawArgs]; | |
| 223 | −}; | |
| 224 | − | |
| 225 | −const getCliArgs = (): string[] => normalizeCliArgs(process.argv.slice(2)); | |
| 226 | − | |
| 227 | −const toEffectCliArgv = (args: readonly string[]): string[] => [ | |
| 228 | − process.execPath || CLI_NAME, | |
| 229 | − CLI_NAME, | |
| 230 | − ...args, | |
| 231 | −]; | |
| 232 | − | |
| 233 | −const buildWorkflowText = ( | |
| 234 | − namespaces: readonly string[] = [], | |
| 235 | − pluginRegistry?: ExecutorSdkPluginRegistry, | |
| 236 | −): string => | |
| 237 | − [ | |
| 238 | − "Execute TypeScript in sandbox; call tools via discovery workflow.", | |
| 239 | − ...(namespaces.length > 0 | |
| 240 | − ? [ | |
| 241 | − "Available namespaces:", | |
| 242 | − ...namespaces.map((namespace) => `- ${namespace}`), | |
| 243 | − ] | |
| 244 | − : []), | |
| 245 | − "Workflow:", | |
| 246 | − '1) const { results, bestPath } = await tools.discover({ query: "<intent>", limit: 12 });', | |
| 247 | − '2) const path = bestPath ?? results[0]?.path; if (!path) return "No matching tools found.";', | |
| 248 | − "3) const details = await tools.describe.tool({ path, includeSchemas: true });", | |
| 249 | − "4) Call selected tools.<path>(input).", | |
| 250 | − "5) Use source plugins to inspect or add API sources.", | |
| 251 | − ...(pluginRegistry | |
| 252 | − ? getExecutorInternalToolHelpLines(pluginRegistry) | |
| 253 | − : ["Use executor.* tools to inspect or manage API sources."]), | |
| 254 | − "6) If execution pauses for interaction, resume it with `executor resume --execution-id ...`.", | |
| 255 | − "The tools object is a lazy proxy, so Object.keys(tools) is not a useful way to discover capabilities.", | |
| 256 | − "Do not use fetch; use tools.* only.", | |
| 257 | − ].join("\n"); | |
| 258 | − | |
| 259 | −const getDefaultRunWorkflow = (pluginRegistry?: ExecutorSdkPluginRegistry) => | |
| 260 | − buildWorkflowText([], pluginRegistry); | |
| 261 | − | |
| 262 | −const indentBlock = (value: string, prefix: string = " "): string => | |
| 263 | − value | |
| 264 | − .split("\n") | |
| 265 | − .map((line) => (line.length > 0 ? `${prefix}${line}` : "")) | |
| 266 | − .join("\n"); | |
| 267 | − | |
| 268 | −const formatCauseMessage = (cause: Cause.Cause<unknown>): string => { | |
| 269 | − const failure = Option.getOrUndefined(Cause.failureOption(cause)); | |
| 270 | − if (failure instanceof Error && failure.message.length > 0) { | |
| 271 | − return failure.message; | |
| 272 | − } | |
| 273 | − if (typeof failure === "string" && failure.length > 0) { | |
| 274 | − return failure; | |
| 275 | − } | |
| 276 | − | |
| 277 | − const defect = Option.getOrUndefined(Cause.dieOption(cause)); | |
| 278 | − if (defect instanceof Error && defect.message.length > 0) { | |
| 279 | − return defect.message; | |
| 280 | − } | |
| 281 | − if (typeof defect === "string" && defect.length > 0) { | |
| 282 | − return defect; | |
| 283 | − } | |
| 284 | − | |
| 285 | − return Cause.pretty(cause).split("\n").find((line) => line.trim().length > 0) ?? "unknown error"; | |
| 286 | −}; | |
| 287 | − | |
| 288 | −const formatCatalogUnavailableMessage = (cause: Cause.Cause<unknown>): string => { | |
| 289 | − const message = formatCauseMessage(cause); | |
| 290 | − return message === "Error: An error has occurred" | |
| 291 | − ? "Current workspace catalog unavailable." | |
| 292 | − : `Current workspace catalog unavailable: ${message}`; | |
| 293 | −}; | |
| 294 | − | |
| 295 | −const closeExecutor = (executor: Executor) => | |
| 296 | − Effect.tryPromise({ | |
| 297 | − try: () => executor.close(), | |
| 298 | − catch: toError, | |
| 299 | − }).pipe(Effect.catchAll(() => Effect.void)); | |
| 300 | − | |
| 301 | −const buildRunWorkflowText = ( | |
| 302 | − catalog?: ToolCatalog, | |
| 303 | − pluginRegistry?: ExecutorSdkPluginRegistry, | |
| 304 | −): Effect.Effect<string, Error, never> => { | |
| 305 | − if (!catalog) { | |
| 306 | − return Effect.succeed(getDefaultRunWorkflow(pluginRegistry)); | |
| 307 | − } | |
| 308 | − | |
| 309 | − return catalog.listNamespaces({ limit: 200 }).pipe( | |
| 310 | − Effect.map((namespaces) => | |
| 311 | − buildWorkflowText( | |
| 312 | − namespaces.length > 0 | |
| 313 | − ? namespaces.map((namespace) => namespace.displayName ?? namespace.namespace) | |
| 314 | − : ["none discovered yet"], | |
| 315 | − pluginRegistry, | |
| 316 | − ) | |
| 317 | − ), | |
| 318 | − Effect.mapError(toError), | |
| 319 | − ); | |
| 320 | −}; | |
| 321 | − | |
| 322 | −const loadRunWorkflowText = (): Effect.Effect<string, Error, never> => | |
| 323 | − Effect.acquireUseRelease( | |
| 324 | − createExecutorEffect({ | |
| 325 | − backend: createLocalExecutorBackend({ | |
| 326 | − cwd: process.cwd(), | |
| 327 | − localDataDir: CLI_LOCAL_DATA_DIR, | |
| 328 | − }), | |
| 329 | − plugins: [ | |
| 330 | − localSecretStoreSdkPlugin, | |
| 331 | − keychainSecretStoreSdkPlugin, | |
| 332 | − localToolsSdkPlugin(), | |
| 333 | − graphqlSdkPlugin({ | |
| 334 | − storage: createFileGraphqlSourceStorage({ | |
| 335 | − rootDir: `${CLI_LOCAL_DATA_DIR}/plugins/graphql/sources`, | |
| 336 | − }), | |
| 337 | − }), | |
| 338 | − googleDiscoverySdkPlugin({ | |
| 339 | − storage: createFileGoogleDiscoverySourceStorage({ | |
| 340 | − rootDir: `${CLI_LOCAL_DATA_DIR}/plugins/google-discovery/sources`, | |
| 341 | − }), | |
| 342 | − oauthSessions: createFileGoogleDiscoveryOAuthSessionStorage({ | |
| 343 | − rootDir: `${CLI_LOCAL_DATA_DIR}/plugins/google-discovery/oauth-sessions`, | |
| 344 | − }), | |
| 345 | − }), | |
| 346 | − mcpSdkPlugin({ | |
| 347 | − storage: createFileMcpSourceStorage({ | |
| 348 | − rootDir: `${CLI_LOCAL_DATA_DIR}/plugins/mcp/sources`, | |
| 349 | − }), | |
| 350 | − oauthSessions: createFileMcpOAuthSessionStorage({ | |
| 351 | − rootDir: `${CLI_LOCAL_DATA_DIR}/plugins/mcp/oauth-sessions`, | |
| 352 | − }), | |
| 353 | − }), | |
| 354 | − openApiSdkPlugin({ | |
| 355 | − storage: createFileOpenApiSourceStorage({ | |
| 356 | − rootDir: `${CLI_LOCAL_DATA_DIR}/plugins/openapi/sources`, | |
| 357 | − }), | |
| 358 | − }), | |
| 359 | − ] as const, | |
| 360 | − }).pipe(Effect.mapError(toError)), | |
| 361 | − (executor) => | |
| 362 | − Effect.gen(function* () { | |
| 363 | − const environment = yield* Effect.gen(function* () { | |
| 364 | − const resolveExecutionEnvironment = yield* RuntimeExecutionResolverService; | |
| 365 | − return yield* resolveExecutionEnvironment({ | |
| 366 | − scopeId: executor.scopeId, | |
| 367 | − actorScopeId: executor.actorScopeId, | |
| 368 | − executionId: ExecutionIdSchema.make("exec_help"), | |
| 369 | − }); | |
| 370 | − }).pipe( | |
| 371 | − Effect.provide(executor.runtime.runtimeLayer), | |
| 372 | − Effect.mapError(toError), | |
| 373 | − ); | |
| 374 | − | |
| 375 | − return yield* buildRunWorkflowText( | |
| 376 | − environment.catalog, | |
| 377 | − executor.runtime.pluginRegistry, | |
| 378 | − ); | |
| 379 | − }), | |
| 380 | − closeExecutor, | |
| 381 | − ).pipe( | |
| 382 | − Effect.catchAllCause((cause) => | |
| 383 | − Effect.succeed( | |
| 384 | − [ | |
| 385 | − getDefaultRunWorkflow(), | |
| 386 | − "", | |
| 387 | − formatCatalogUnavailableMessage(cause), | |
| 388 | − ].join("\n"), | |
| 389 | − ) | |
| 390 | − ), | |
| 391 | − ); | |
| 392 | − | |
| 393 | −const printRootHelp = (workflow: string) => | |
| 394 | − Effect.sync(() => { | |
| 395 | − console.log([ | |
| 396 | − `${CLI_NAME} ${CLI_VERSION}`, | |
| 397 | − "", | |
| 398 | − "USAGE", | |
| 399 | − "", | |
| 400 | − " executor web [--port integer]", | |
| 401 | − " executor mcp [--port integer] [--stdio] [--web-port integer]", | |
| 402 | − " executor call [code] [--file text] [--stdin] [--base-url text] [--no-open]", | |
| 403 | − " executor resume --execution-id text [--base-url text] [--no-open]", | |
| 404 | − "", | |
| 405 | − "CALL WORKFLOW", | |
| 406 | − "", | |
| 407 | − indentBlock(workflow), | |
| 408 | − "", | |
| 409 | − "COMMANDS", | |
| 410 | − "", | |
| 411 | − " web", | |
| 412 | − " Start a foreground web session and print the local URL.", | |
| 413 | − " mcp", | |
| 414 | − " Start a foreground MCP session, or run stdio MCP with --stdio.", | |
| 415 | − " call", | |
| 416 | − " Execute code against the local executor server.", | |
| 417 | − " resume", | |
| 418 | − " Resume a paused execution.", | |
| 419 | − "", | |
| 420 | − "TIP", | |
| 421 | − "", | |
| 422 | − " Run `executor web` for the browser UI, `executor mcp` for HTTP MCP, or `executor mcp --stdio` for local stdio MCP.", | |
| 423 | − ].join("\n")); | |
| 424 | − }); | |
| 425 | − | |
| 426 | −const printCallHelp = (workflow: string) => | |
| 427 | − Effect.sync(() => { | |
| 428 | − console.log([ | |
| 429 | − "executor call", | |
| 430 | − "", | |
| 431 | − "USAGE", | |
| 432 | − "", | |
| 433 | − " executor call [code] [--file text] [--stdin] [--base-url text] [--no-open]", | |
| 434 | − "", | |
| 435 | − "DESCRIPTION", | |
| 436 | − "", | |
| 437 | − " Execute code against the local executor server.", | |
| 438 | − "", | |
| 439 | − "WORKFLOW", | |
| 440 | − "", | |
| 441 | − indentBlock(workflow), | |
| 442 | − "", | |
| 443 | − "OPTIONS", | |
| 444 | − "", | |
| 445 | − " [code]", | |
| 446 | − " Inline code to execute.", | |
| 447 | − " --file text", | |
| 448 | − " Read code from a file.", | |
| 449 | − " --stdin", | |
| 450 | − " Read code from stdin.", | |
| 451 | − " --base-url text", | |
| 452 | − " Override the executor server base URL.", | |
| 453 | − " --no-open", | |
| 454 | − " Print interaction URLs without opening a browser.", | |
| 455 | − "", | |
| 456 | − "EXAMPLES", | |
| 457 | − "", | |
| 458 | − ' executor call \'const { results } = await tools.discover({ query: "github issues", limit: 5 }); return results.map((match) => match.path);\'', | |
| 459 | − ' executor call \'const { results, bestPath } = await tools.discover({ query: "repo details", limit: 1 }); const path = bestPath ?? results[0]?.path; return path ? await tools.describe.tool({ path, includeSchemas: true }) : null;\'', | |
| 460 | − " cat script.ts | executor call --stdin", | |
| 461 | − " executor call --file script.ts", | |
| 462 | − " executor call --no-open --file script.ts", | |
| 463 | − " executor resume --execution-id exec_123", | |
| 464 | − ].join("\n")); | |
| 465 | − }); | |
| 466 | − | |
| 467 | −const helpOverride = (): Effect.Effect<void, Error, never> | null => { | |
| 468 | − const args = getCliArgs(); | |
| 469 | − | |
| 470 | − if (args.length === 0 || (args.length === 1 && isHelpToken(args[0]))) { | |
| 471 | − return loadRunWorkflowText().pipe(Effect.flatMap(printRootHelp)); | |
| 472 | − } | |
| 473 | − | |
| 474 | − if (args[0] === "call" && args.length === 2 && isHelpToken(args[1])) { | |
| 475 | − return loadRunWorkflowText().pipe(Effect.flatMap(printCallHelp)); | |
| 476 | − } | |
| 477 | − | |
| 478 | − return null; | |
| 479 | −}; | |
| 480 | − | |
| 481 | −const getLocalAuthedClient = (baseUrl: string = DEFAULT_SERVER_BASE_URL) => | |
| 482 | − Effect.gen(function* () { | |
| 483 | − const bootstrapClient = yield* getBootstrapClient(baseUrl); | |
| 484 | − const installation = yield* bootstrapClient.local.installation({}); | |
| 485 | − const client = yield* createExecutorApiClient({ | |
| 486 | − baseUrl, | |
| 487 | − }); | |
| 488 | − | |
| 489 | − return { | |
| 490 | − installation, | |
| 491 | − client, | |
| 492 | − } as const; | |
| 493 | − }); | |
| 494 | − | |
| 495 | −const isServerReachable = (baseUrl: string) => | |
| 496 | − getBootstrapClient(baseUrl).pipe( | |
| 497 | − Effect.flatMap((client) => client.local.installation({})), | |
| 498 | − Effect.as(true), | |
| 499 | − Effect.catchAll(() => Effect.succeed(false)), | |
| 500 | − ); | |
| 501 | − | |
| 502 | −const getDefaultServerOptions = (port: number = DEFAULT_SERVER_PORT) => { | |
| 503 | − const assetsDir = resolveRuntimeWebAssetsDir(); | |
| 504 | − | |
| 505 | − return { | |
| 506 | − host: DEFAULT_SERVER_HOST, | |
| 507 | − port, | |
| 508 | − localDataDir: CLI_LOCAL_DATA_DIR, | |
| 509 | − pidFile: DEFAULT_SERVER_PID_FILE, | |
| 510 | − ui: assetsDir ? { assetsDir } : undefined, | |
| 511 | − }; | |
| 512 | −}; | |
| 513 | − | |
| 514 | −const startServerInBackground = (port: number) => | |
| 515 | − Effect.scoped( | |
| 516 | − Effect.gen(function* () { | |
| 517 | − const fs = yield* FileSystem.FileSystem; | |
| 518 | − const command = resolveSelfCommand(["__local-server", "--port", String(port)]); | |
| 519 | − yield* fs.makeDirectory(dirname(DEFAULT_SERVER_LOG_FILE), { | |
| 520 | − recursive: true, | |
| 521 | − }).pipe(Effect.mapError(toError)); | |
| 522 | − const logHandle = yield* fs.open(DEFAULT_SERVER_LOG_FILE, { | |
| 523 | − flag: "a", | |
| 524 | − }).pipe(Effect.mapError(toError)); | |
| 525 | − | |
| 526 | − yield* Effect.try({ | |
| 527 | − try: () => { | |
| 528 | − const fd = Number(logHandle.fd); | |
| 529 | − const child = spawn(command[0]!, command.slice(1), { | |
| 530 | − detached: true, | |
| 531 | − stdio: ["ignore", fd, fd], | |
| 532 | − }); | |
| 533 | − child.unref(); | |
| 534 | − }, | |
| 535 | − catch: toError, | |
| 536 | − }); | |
| 537 | − }), | |
| 538 | − ); | |
| 539 | − | |
| 540 | −const readServerLogTail = ( | |
| 541 | − logFile: string = DEFAULT_SERVER_LOG_FILE, | |
| 542 | − maxLines: number = 40, | |
| 543 | − maxChars: number = 6000, | |
| 544 | −): Effect.Effect<string | null, never, FileSystem.FileSystem> => | |
| 545 | − Effect.gen(function* () { | |
| 546 | − const fs = yield* FileSystem.FileSystem; | |
| 547 | − const contents = yield* fs.readFileString(logFile, "utf8").pipe( | |
| 548 | − Effect.catchAll(() => Effect.succeed<string | null>(null)), | |
| 549 | − ); | |
| 550 | − | |
| 551 | − if (contents === null) { | |
| 552 | − return null; | |
| 553 | − } | |
| 554 | − | |
| 555 | − const lines = contents.split(/\r?\n/u).filter((line) => line.length > 0); | |
| 556 | − const tail = lines.slice(-maxLines).join("\n"); | |
| 557 | − return tail.length > maxChars ? tail.slice(-maxChars) : tail; | |
| 558 | − }); | |
| 559 | − | |
| 560 | −const failReachabilityTimeout = (input: { | |
| 561 | − baseUrl: string; | |
| 562 | − expected: boolean; | |
| 563 | − logFile?: string; | |
| 564 | −}): Effect.Effect<never, LocalServerReachabilityTimeoutError, FileSystem.FileSystem> => | |
| 565 | − Effect.gen(function* () { | |
| 566 | − const logFile = input.logFile ?? DEFAULT_SERVER_LOG_FILE; | |
| 567 | − const logTail = yield* readServerLogTail(logFile); | |
| 568 | − | |
| 569 | − return yield* localServerReachabilityTimeoutError({ | |
| 570 | − baseUrl: input.baseUrl, | |
| 571 | − expected: input.expected, | |
| 572 | − logFile, | |
| 573 | − logTail, | |
| 574 | − }); | |
| 575 | − }); | |
| 576 | − | |
| 577 | −const waitForReachability = (baseUrl: string, expected: boolean) => | |
| 578 | − Effect.gen(function* () { | |
| 579 | − const startedAt = Date.now(); | |
| 580 | − while (Date.now() - startedAt < SERVER_START_TIMEOUT_MS) { | |
| 581 | − const reachable = yield* isServerReachable(baseUrl); | |
| 582 | − if (reachable === expected) { | |
| 583 | − return; | |
| 584 | − } | |
| 585 | − yield* sleep(SERVER_POLL_INTERVAL_MS); | |
| 586 | − } | |
| 587 | − | |
| 588 | − return yield* failReachabilityTimeout({ baseUrl, expected }); | |
| 589 | − }); | |
| 590 | − | |
| 591 | −const printText = (value: string) => | |
| 592 | − Effect.sync(() => { | |
| 593 | − console.log(value); | |
| 594 | − }); | |
| 595 | − | |
| 596 | −const ensureServer = (baseUrl: string = DEFAULT_SERVER_BASE_URL) => | |
| 597 | − Effect.gen(function* () { | |
| 598 | − const reachable = yield* isServerReachable(baseUrl); | |
| 599 | − if (reachable) { | |
| 600 | − return { | |
| 601 | − started: false, | |
| 602 | − } as const; | |
| 603 | − } | |
| 604 | − | |
| 605 | − const url = new URL(baseUrl); | |
| 606 | − const port = Number(url.port || DEFAULT_SERVER_PORT); | |
| 607 | − yield* startServerInBackground(port); | |
| 608 | − | |
| 609 | − yield* waitForReachability(baseUrl, true); | |
| 610 | − | |
| 611 | − return { | |
| 612 | − started: true, | |
| 613 | − } as const; | |
| 614 | − }); | |
| 615 | − | |
| 616 | −const waitForShutdownSignal = () => | |
| 617 | − Effect.async<void, never>((resume) => { | |
| 618 | − const shutdown = () => resume(Effect.void); | |
| 619 | − process.once("SIGINT", shutdown); | |
| 620 | − process.once("SIGTERM", shutdown); | |
| 621 | − | |
| 622 | − return Effect.sync(() => { | |
| 623 | − process.off("SIGINT", shutdown); | |
| 624 | − process.off("SIGTERM", shutdown); | |
| 625 | − }); | |
| 626 | − }); | |
| 627 | − | |
| 628 | −const runForegroundSession = (input: { | |
| 629 | − kind: "web" | "mcp"; | |
| 630 | − port: number; | |
| 631 | −}) => | |
| 632 | − Effect.scoped( | |
| 633 | − Effect.gen(function* () { | |
| 634 | − const server = yield* createLocalExecutorServer(getDefaultServerOptions(input.port)); | |
| 635 | − const workspaceId = server.runtime.localInstallation.scopeId; | |
| 636 | − const summary = input.kind === "web" | |
| 637 | − ? renderWebSessionSummary({ | |
| 638 | − baseUrl: server.baseUrl, | |
| 639 | − workspaceId, | |
| 640 | − }) | |
| 641 | − : renderMcpSessionSummary({ | |
| 642 | − baseUrl: server.baseUrl, | |
| 643 | − workspaceId, | |
| 644 | − }); | |
| 645 | − | |
| 646 | − yield* printText(summary); | |
| 647 | − yield* waitForShutdownSignal(); | |
| 648 | − }), | |
| 649 | − ); | |
| 650 | − | |
| 651 | −const runStdioMcpSession = (webPort?: number) => | |
| 652 | − Effect.scoped( | |
| 653 | − Effect.gen(function* () { | |
| 654 | − const server = yield* createLocalExecutorServer( | |
| 655 | − getDefaultServerOptions(webPort ?? 0), | |
| 656 | − ); | |
| 657 | − yield* Effect.tryPromise({ | |
| 658 | − try: () => runExecutorMcpStdioServer(server.runtime), | |
| 659 | − catch: toError, | |
| 660 | − }); | |
| 661 | − }), | |
| 662 | − ); | |
| 663 | − | |
| 664 | − | |
| 665 | − | |
| 666 | −const isRecord = (value: unknown): value is Record<string, unknown> => | |
| 667 | − typeof value === "object" && value !== null && !Array.isArray(value); | |
| 668 | − | |
| 669 | −type PromptField = { | |
| 670 | − name: string; | |
| 671 | − label: string; | |
| 672 | − description?: string; | |
| 673 | − type: string; | |
| 674 | − required: boolean; | |
| 675 | − enumValues?: readonly unknown[]; | |
| 676 | −}; | |
| 677 | − | |
| 678 | −const getPromptFields = (requestedSchema: Record<string, unknown> | undefined): PromptField[] => { | |
| 679 | − if (!requestedSchema || !isRecord(requestedSchema.properties)) { | |
| 680 | − return []; | |
| 681 | − } | |
| 682 | − | |
| 683 | − const required = new Set( | |
| 684 | − Array.isArray(requestedSchema.required) | |
| 685 | − ? requestedSchema.required.filter((value): value is string => typeof value === "string") | |
| 686 | − : [], | |
| 687 | − ); | |
| 688 | − | |
| 689 | − return Object.entries(requestedSchema.properties).flatMap(([name, property]) => { | |
| 690 | − if (!isRecord(property)) { | |
| 691 | − return []; | |
| 692 | − } | |
| 693 | − | |
| 694 | − return [{ | |
| 695 | − name, | |
| 696 | − label: | |
| 697 | − typeof property.title === "string" && property.title.trim().length > 0 | |
| 698 | − ? property.title.trim() | |
| 699 | − : name, | |
| 700 | − description: | |
| 701 | − typeof property.description === "string" && property.description.trim().length > 0 | |
| 702 | − ? property.description.trim() | |
| 703 | − : undefined, | |
| 704 | − type: typeof property.type === "string" ? property.type : "string", | |
| 705 | − required: required.has(name), | |
| 706 | − enumValues: Array.isArray(property.enum) ? property.enum : undefined, | |
| 707 | − }]; | |
| 708 | − }); | |
| 709 | −}; | |
| 710 | − | |
| 711 | −const parsePromptValue = (field: PromptField, raw: string): | |
| 712 | − | { ok: true; value: unknown } | |
| 713 | − | { ok: false; message: string } => { | |
| 714 | − if (field.enumValues && field.enumValues.length > 0) { | |
| 715 | − const normalized = field.enumValues.map((value) => String(value)); | |
| 716 | − if (!normalized.includes(raw)) { | |
| 717 | − return { | |
| 718 | − ok: false, | |
| 719 | − message: `Enter one of: ${normalized.join(", ")}`, | |
| 720 | − }; | |
| 721 | − } | |
| 722 | − } | |
| 723 | − | |
| 724 | − if (field.type === "boolean") { | |
| 725 | − const normalized = raw.trim().toLowerCase(); | |
| 726 | − if (["y", "yes", "true"].includes(normalized)) { | |
| 727 | − return { ok: true, value: true }; | |
| 728 | − } | |
| 729 | − if (["n", "no", "false"].includes(normalized)) { | |
| 730 | − return { ok: true, value: false }; | |
| 731 | − } | |
| 732 | − return { ok: false, message: "Enter yes or no" }; | |
| 733 | − } | |
| 734 | − | |
| 735 | − if (field.type === "number" || field.type === "integer") { | |
| 736 | − const value = Number(raw); | |
| 737 | − if (!Number.isFinite(value)) { | |
| 738 | − return { ok: false, message: "Enter a number" }; | |
| 739 | − } | |
| 740 | − if (field.type === "integer" && !Number.isInteger(value)) { | |
| 741 | − return { ok: false, message: "Enter an integer" }; | |
| 742 | − } | |
| 743 | − return { ok: true, value }; | |
| 744 | − } | |
| 745 | − | |
| 746 | − if (field.type === "object" || field.type === "array") { | |
| 747 | − try { | |
| 748 | − return { ok: true, value: JSON.parse(raw) }; | |
| 749 | − } catch { | |
| 750 | − return { ok: false, message: "Enter valid JSON" }; | |
| 751 | − } | |
| 752 | − } | |
| 753 | − | |
| 754 | − return { ok: true, value: raw }; | |
| 755 | −}; | |
| 756 | − | |
| 757 | −const promptStructuredInteraction = (parsed: { | |
| 758 | − message: string; | |
| 759 | − requestedSchema?: Record<string, unknown>; | |
| 760 | −}) => | |
| 761 | − Effect.gen(function* () { | |
| 762 | − const fields = getPromptFields(parsed.requestedSchema); | |
| 763 | − if (fields.length === 0) { | |
| 764 | − return null as Record<string, unknown> | null; | |
| 765 | − } | |
| 766 | − | |
| 767 | − yield* Effect.sync(() => { | |
| 768 | − process.stdout.write(`${parsed.message}\n`); | |
| 769 | − }); | |
| 770 | − | |
| 771 | − const content: Record<string, unknown> = {}; | |
| 772 | − for (const field of fields) { | |
| 773 | − if (field.description) { | |
| 774 | − yield* Effect.sync(() => { | |
| 775 | − process.stdout.write(`${field.description}\n`); | |
| 776 | − }); | |
| 777 | − } | |
| 778 | − | |
| 779 | − while (true) { | |
| 780 | − const raw = yield* promptLine( | |
| 781 | − `${field.label}${field.required ? "" : " (optional)"}: `, | |
| 782 | − ); | |
| 783 | − const trimmed = raw.trim(); | |
| 784 | − if (trimmed.length === 0) { | |
| 785 | − if (field.required) { | |
| 786 | − return null; | |
| 787 | − } | |
| 788 | − break; | |
| 789 | − } | |
| 790 | − | |
| 791 | − const parsedValue = parsePromptValue(field, trimmed); | |
| 792 | − if (parsedValue.ok) { | |
| 793 | − content[field.name] = parsedValue.value; | |
| 794 | − break; | |
| 795 | − } | |
| 796 | − | |
| 797 | − yield* Effect.sync(() => { | |
| 798 | − process.stdout.write(`${parsedValue.message}\n`); | |
| 799 | − }); | |
| 800 | − } | |
| 801 | − } | |
| 802 | − | |
| 803 | − return content; | |
| 804 | − }); | |
| 805 | − | |
| 806 | −const printUrlInteraction = (input: { | |
| 807 | − message: string; | |
| 808 | − url: string | null; | |
| 809 | − shouldOpen: boolean; | |
| 810 | −}) => | |
| 811 | − Effect.gen(function* () { | |
| 812 | − yield* Effect.sync(() => { | |
| 813 | − process.stdout.write(`${input.message}\n${input.url ?? ""}\n`); | |
| 814 | − }); | |
| 815 | − | |
| 816 | − if (input.shouldOpen && input.url) { | |
| 817 | − yield* openUrlInBrowser(input.url); | |
| 818 | − } | |
| 819 | − }); | |
| 820 | − | |
| 821 | −const executionInteractionMode = (): "live_form" | "detach" => | |
| 822 | − process.stdin.isTTY && process.stdout.isTTY ? "live_form" : "detach"; | |
| 823 | − | |
| 824 | −const promptInteraction = (input: { | |
| 825 | − interaction: ExecutionInteraction; | |
| 826 | − shouldOpenUrls: boolean; | |
| 827 | −}) => | |
| 828 | − Effect.gen(function* () { | |
| 829 | − const parsed = parseInteractionPayload(input.interaction); | |
| 830 | − | |
| 831 | − if (!process.stdin.isTTY || !process.stdout.isTTY || parsed === null) { | |
| 832 | − return null; | |
| 833 | − } | |
| 834 | − | |
| 835 | − if (parsed.mode === "url") { | |
| 836 | − yield* printUrlInteraction({ | |
| 837 | − message: parsed.message, | |
| 838 | − url: parsed.url ?? null, | |
| 839 | − shouldOpen: input.shouldOpenUrls, | |
| 840 | − }); | |
| 841 | − return null; | |
| 842 | − } | |
| 843 | − | |
| 844 | − const structured = yield* promptStructuredInteraction(parsed); | |
| 845 | − if (structured !== null) { | |
| 846 | − return JSON.stringify({ | |
| 847 | − action: "accept", | |
| 848 | − content: structured, | |
| 849 | − }); | |
| 850 | − } | |
| 851 | − | |
| 852 | − const line = yield* promptLine(`${parsed.message} [y/N] `); | |
| 853 | − const normalized = line.trim().toLowerCase(); | |
| 854 | − if (normalized.length === 0) { | |
| 855 | − return null; | |
| 856 | − } | |
| 857 | − if (normalized !== "y" && normalized !== "yes" && normalized !== "n" && normalized !== "no") { | |
| 858 | − return null; | |
| 859 | − } | |
| 860 | − const accepted = normalized === "y" || normalized === "yes"; | |
| 861 | − | |
| 862 | − return JSON.stringify({ | |
| 863 | − action: accepted ? "accept" : "decline", | |
| 864 | − content: { | |
| 865 | − approve: accepted, | |
| 866 | − }, | |
| 867 | − }); | |
| 868 | − }); | |
| 869 | − | |
| 870 | −const waitForExecutionProgress = (input: { | |
| 871 | − client: ExecutorApiClient; | |
| 872 | − workspaceId: ExecutionEnvelope["execution"]["scopeId"]; | |
| 873 | − executionId: ExecutionEnvelope["execution"]["id"]; | |
| 874 | − pendingInteractionId: ExecutionInteraction["id"]; | |
| 875 | −}) => | |
| 876 | − Effect.gen(function* () { | |
| 877 | − while (true) { | |
| 878 | − yield* sleep(SERVER_POLL_INTERVAL_MS); | |
| 879 | − | |
| 880 | − const next = yield* input.client.executions.get({ | |
| 881 | − path: { | |
| 882 | − workspaceId: input.workspaceId, | |
| 883 | − executionId: input.executionId, | |
| 884 | − }, | |
| 885 | − }); | |
| 886 | − | |
| 887 | − if ( | |
| 888 | − next.execution.status !== "waiting_for_interaction" | |
| 889 | − || next.pendingInteraction === null | |
| 890 | − || next.pendingInteraction.id !== input.pendingInteractionId | |
| 891 | − ) { | |
| 892 | − return next; | |
| 893 | − } | |
| 894 | − } | |
| 895 | − }); | |
| 896 | − | |
| 897 | −const printExecution = (envelope: ExecutionEnvelope) => | |
| 898 | − Effect.sync(() => { | |
| 899 | − const execution = envelope.execution; | |
| 900 | − if (execution.status === "completed") { | |
| 901 | − if (execution.resultJson) { | |
| 902 | − console.log(execution.resultJson); | |
| 903 | − } else { | |
| 904 | − console.log("completed"); | |
| 905 | − } | |
| 906 | − return; | |
| 907 | − } | |
| 908 | − | |
| 909 | − if (execution.status === "failed") { | |
| 910 | − console.error(execution.errorText ?? "Execution failed"); | |
| 911 | − process.exitCode = 1; | |
| 912 | − return; | |
| 913 | − } | |
| 914 | − if (execution.status === "waiting_for_interaction" && envelope.pendingInteraction !== null) { | |
| 915 | − return; | |
| 916 | − } | |
| 917 | − | |
| 918 | − | |
| 919 | − console.log(JSON.stringify({ | |
| 920 | − id: execution.id, | |
| 921 | − status: execution.status, | |
| 922 | − })); | |
| 923 | − }); | |
| 924 | − | |
| 925 | −const driveExecution = (input: { | |
| 926 | − client: ExecutorApiClient; | |
| 927 | − workspaceId: ExecutionEnvelope["execution"]["scopeId"]; | |
| 928 | − envelope: ExecutionEnvelope; | |
| 929 | − baseUrl: string; | |
| 930 | − shouldOpenUrls: boolean; | |
| 931 | −}) => | |
| 932 | − Effect.gen(function* () { | |
| 933 | − let current = input.envelope; | |
| 934 | − | |
| 935 | − while (current.execution.status === "waiting_for_interaction") { | |
| 936 | − const pending = current.pendingInteraction; | |
| 937 | − | |
| 938 | − if (pending === null) { | |
| 939 | − return current; | |
| 940 | − } | |
| 941 | − | |
| 942 | − const parsed = parseInteractionPayload(pending); | |
| 943 | − const handling = decideInteractionHandling({ | |
| 944 | − parsed, | |
| 945 | − isInteractiveTerminal: process.stdin.isTTY && process.stdout.isTTY, | |
| 946 | − }); | |
| 947 | − | |
| 948 | − if (handling === "url_interactive" && parsed?.mode === "url") { | |
| 949 | − yield* printUrlInteraction({ | |
| 950 | − message: parsed.message, | |
| 951 | − url: parsed.url ?? null, | |
| 952 | − shouldOpen: input.shouldOpenUrls, | |
| 953 | − }); | |
| 954 | − | |
| 955 | − current = yield* waitForExecutionProgress({ | |
| 956 | − client: input.client, | |
| 957 | − workspaceId: input.workspaceId, | |
| 958 | − executionId: current.execution.id, | |
| 959 | − pendingInteractionId: pending.id, | |
| 960 | − }); | |
| 961 | − continue; | |
| 962 | − } | |
| 963 | − | |
| 964 | − if (handling === "url_paused") { | |
| 965 | − if (input.shouldOpenUrls && parsed?.mode === "url" && parsed.url) { | |
| 966 | − yield* openUrlInBrowser(parsed.url); | |
| 967 | − } | |
| 968 | − | |
| 969 | − const paused = buildPausedExecutionOutput({ | |
| 970 | − executionId: current.execution.id, | |
| 971 | − interaction: pending, | |
| 972 | − baseUrl: input.baseUrl, | |
| 973 | − shouldOpenUrls: input.shouldOpenUrls, | |
| 974 | − cliName: CLI_NAME, | |
| 975 | − }); | |
| 976 | − yield* Effect.sync(() => { | |
| 977 | − console.log(JSON.stringify(paused)); | |
| 978 | − process.exitCode = 20; | |
| 979 | − }); | |
| 980 | − return current; | |
| 981 | − } | |
| 982 | − | |
| 983 | − if (handling === "form_paused") { | |
| 984 | − const paused = buildPausedExecutionOutput({ | |
| 985 | − executionId: current.execution.id, | |
| 986 | − interaction: pending, | |
| 987 | − baseUrl: input.baseUrl, | |
| 988 | − shouldOpenUrls: input.shouldOpenUrls, | |
| 989 | − cliName: CLI_NAME, | |
| 990 | − }); | |
| 991 | − yield* Effect.sync(() => { | |
| 992 | − console.log(JSON.stringify(paused)); | |
| 993 | − process.exitCode = 20; | |
| 994 | − }); | |
| 995 | − return current; | |
| 996 | − } | |
| 997 | − | |
| 998 | − const responseJson = yield* promptInteraction({ | |
| 999 | − interaction: pending, | |
| 1000 | − shouldOpenUrls: input.shouldOpenUrls, | |
| 1001 | − }); | |
| 1002 | − if (responseJson === null) { | |
| 1003 | − const paused = buildPausedExecutionOutput({ | |
| 1004 | − executionId: current.execution.id, | |
| 1005 | − interaction: pending, | |
| 1006 | − baseUrl: input.baseUrl, | |
| 1007 | − shouldOpenUrls: input.shouldOpenUrls, | |
| 1008 | − cliName: CLI_NAME, | |
| 1009 | − }); | |
| 1010 | − yield* Effect.sync(() => { | |
| 1011 | − console.log(JSON.stringify(paused)); | |
| 1012 | − process.exitCode = 20; | |
| 1013 | − }); | |
| 1014 | − return current; | |
| 1015 | − } | |
| 1016 | − | |
| 1017 | − current = yield* input.client.executions.resume({ | |
| 1018 | − path: { | |
| 1019 | − workspaceId: input.workspaceId, | |
| 1020 | − executionId: current.execution.id, | |
| 1021 | − }, | |
| 1022 | − payload: { | |
| 1023 | − responseJson, | |
| 1024 | − interactionMode: executionInteractionMode(), | |
| 1025 | − }, | |
| 1026 | − }); | |
| 1027 | − } | |
| 1028 | − | |
| 1029 | − return current; | |
| 1030 | − }); | |
| 1031 | − | |
| 1032 | −const serverStartCommand = Command.make( | |
| 1033 | − "start", | |
| 1034 | − { | |
| 1035 | − port: Options.integer("port").pipe(Options.withDefault(DEFAULT_SERVER_PORT)), | |
| 1036 | − }, | |
| 1037 | − ({ port }) => runLocalExecutorServer(getDefaultServerOptions(port)), | |
| 1038 | −).pipe(Command.withDescription("Start the local executor server")); | |
| 1039 | − | |
| 1040 | −const serverCommand = Command.make("server").pipe( | |
| 1041 | − Command.withSubcommands([serverStartCommand] as const), | |
| 1042 | − Command.withDescription("Local server commands"), | |
| 1043 | −); | |
| 1044 | − | |
| 1045 | −const webCommand = Command.make( | |
| 1046 | − "web", | |
| 1047 | − { | |
| 1048 | − port: Options.integer("port").pipe(Options.withDefault(DEFAULT_SERVER_PORT)), | |
| 1049 | − }, | |
| 1050 | − ({ port }) => runForegroundSession({ kind: "web", port }), | |
| 1051 | −).pipe(Command.withDescription("Start a foreground web session and print the local URL")); | |
| 1052 | − | |
| 1053 | −const mcpCommand = Command.make( | |
| 1054 | − "mcp", | |
| 1055 | − { | |
| 1056 | − port: Options.integer("port").pipe(Options.withDefault(DEFAULT_SERVER_PORT)), | |
| 1057 | − stdio: Options.boolean("stdio").pipe(Options.withDefault(false)), | |
| 1058 | − webPort: Options.integer("web-port").pipe(Options.optional), | |
| 1059 | − }, | |
| 1060 | − ({ port, stdio, webPort }) => | |
| 1061 | − stdio | |
| 1062 | − ? runStdioMcpSession(Option.getOrUndefined(webPort)) | |
| 1063 | − : runForegroundSession({ kind: "mcp", port }), | |
| 1064 | −).pipe(Command.withDescription("Start a foreground MCP session, or run stdio MCP with --stdio")); | |
| 1065 | − | |
| 1066 | −const callCommand = Command.make( | |
| 1067 | − "call", | |
| 1068 | − { | |
| 1069 | − code: Args.text({ name: "code" }).pipe( | |
| 1070 | − Args.withDescription("Inline code to execute."), | |
| 1071 | − Args.optional, | |
| 1072 | − ), | |
| 1073 | − file: Options.text("file").pipe(Options.optional), | |
| 1074 | − stdin: Options.boolean("stdin").pipe(Options.withDefault(false)), | |
| 1075 | − baseUrl: Options.text("base-url").pipe(Options.withDefault(DEFAULT_SERVER_BASE_URL)), | |
| 1076 | − noOpen: Options.boolean("no-open").pipe(Options.withDefault(false)), | |
| 1077 | − }, | |
| 1078 | − ({ code, file, stdin, baseUrl, noOpen }) => | |
| 1079 | − Effect.gen(function* () { | |
| 1080 | − const resolvedCode = yield* readCode({ | |
| 1081 | − code: Option.getOrUndefined(code), | |
| 1082 | − file: Option.getOrUndefined(file), | |
| 1083 | − stdin, | |
| 1084 | − }); | |
| 1085 | − | |
| 1086 | − yield* ensureServer(baseUrl); | |
| 1087 | − const { installation, client } = yield* getLocalAuthedClient(baseUrl); | |
| 1088 | − const created = yield* client.executions.create({ | |
| 1089 | − path: { | |
| 1090 | − workspaceId: installation.scopeId, | |
| 1091 | − }, | |
| 1092 | − payload: { | |
| 1093 | − code: resolvedCode, | |
| 1094 | − interactionMode: executionInteractionMode(), | |
| 1095 | − }, | |
| 1096 | − }); | |
| 1097 | − | |
| 1098 | − const settled = yield* driveExecution({ | |
| 1099 | − client, | |
| 1100 | − workspaceId: installation.scopeId, | |
| 1101 | − envelope: created, | |
| 1102 | − baseUrl, | |
| 1103 | − shouldOpenUrls: !noOpen, | |
| 1104 | − }); | |
| 1105 | − | |
| 1106 | − yield* printExecution(settled); | |
| 1107 | − }), | |
| 1108 | −).pipe(Command.withDescription("Execute code against the local executor server")); | |
| 1109 | − | |
| 1110 | −const resumeCommand = Command.make( | |
| 1111 | − "resume", | |
| 1112 | − { | |
| 1113 | − executionId: Options.text("execution-id"), | |
| 1114 | − baseUrl: Options.text("base-url").pipe(Options.withDefault(DEFAULT_SERVER_BASE_URL)), | |
| 1115 | − noOpen: Options.boolean("no-open").pipe(Options.withDefault(false)), | |
| 1116 | − }, | |
| 1117 | − ({ executionId, baseUrl, noOpen }) => | |
| 1118 | − Effect.gen(function* () { | |
| 1119 | − yield* ensureServer(baseUrl); | |
| 1120 | − const { installation, client } = yield* getLocalAuthedClient(baseUrl); | |
| 1121 | − const decodedExecutionId = yield* decodeExecutionId(executionId).pipe( | |
| 1122 | − Effect.mapError((cause) => toError(cause)), | |
| 1123 | − ); | |
| 1124 | − const execution = yield* client.executions.get({ | |
| 1125 | − path: { | |
| 1126 | − workspaceId: installation.scopeId, | |
| 1127 | − executionId: decodedExecutionId, | |
| 1128 | − }, | |
| 1129 | − }); | |
| 1130 | − | |
| 1131 | − const settled = yield* driveExecution({ | |
| 1132 | − client, | |
| 1133 | − workspaceId: installation.scopeId, | |
| 1134 | − envelope: execution, | |
| 1135 | − baseUrl, | |
| 1136 | − shouldOpenUrls: !noOpen, | |
| 1137 | − }); | |
| 1138 | − | |
| 1139 | − yield* printExecution(settled); | |
| 1140 | − }), | |
| 1141 | −).pipe(Command.withDescription("Resume a paused execution")); | |
| 1142 | − | |
| 1143 | −const devCommand = Command.make("dev").pipe( | |
| 1144 | − Command.withDescription("Development helpers"), | |
| 1145 | −); | |
| 1146 | − | |
| 1147 | −const root = Command.make("executor").pipe( | |
| 1148 | − Command.withSubcommands([ | |
| 1149 | − serverCommand, | |
| 1150 | − webCommand, | |
| 1151 | − mcpCommand, | |
| 1152 | − callCommand, | |
| 1153 | − resumeCommand, | |
| 1154 | − devCommand, | |
| 1155 | − ] as const), | |
| 1156 | − Command.withDescription("Executor local CLI"), | |
| 1157 | −); | |
| 1158 | − | |
| 1159 | −const runCli = Command.run(root, { | |
| 1160 | − name: CLI_NAME, | |
| 1161 | − version: CLI_VERSION, | |
| 1162 | − executable: CLI_NAME, | |
| 1163 | −}); | |
| 1164 | − | |
| 1165 | −const hiddenServer = (): Effect.Effect<void, Error, never> | null => { | |
| 1166 | − const args = getCliArgs(); | |
| 1167 | − if (args[0] !== "__local-server") { | |
| 1168 | − return null; | |
| 1169 | − } | |
| 1170 | − | |
| 1171 | − const portFlagIndex = args.findIndex((arg) => arg === "--port"); | |
| 1172 | − const port = portFlagIndex >= 0 ? Number(args[portFlagIndex + 1]) : DEFAULT_SERVER_PORT; | |
| 1173 | − | |
| 1174 | − return runLocalExecutorServer({ | |
| 1175 | − ...getDefaultServerOptions( | |
| 1176 | − Number.isInteger(port) && port > 0 ? port : DEFAULT_SERVER_PORT, | |
| 1177 | − ), | |
| 1178 | − }); | |
| 1179 | −}; | |
| 1180 | − | |
| 1181 | −const program = (hiddenServer() | |
| 1182 | − ?? helpOverride() | |
| 1183 | − ?? runCli(toEffectCliArgv(getCliArgs())).pipe(Effect.mapError(toError))) | |
| 1184 | − .pipe(Effect.provide(NodeFileSystem.layer)) | |
| 1185 | − .pipe(Effect.provide(NodePath.layer)) | |
| 1186 | − .pipe( | |
| 1187 | − Effect.catchAllCause((cause) => | |
| 1188 | − Effect.sync(() => { | |
| 1189 | − console.error(Cause.pretty(cause)); | |
| 1190 | − process.exitCode = 1; | |
| 1191 | − }), | |
| 1192 | − ), | |
| 1193 | − ); | |
| 1194 | − | |
| 1195 | −// Effect CLI's environment does not fully narrow at the process boundary. | |
| 1196 | −NodeRuntime.runMain(program as Effect.Effect<void, never, never>); | |
| @@ -1,125 +0,0 @@ | ||
| 1 | −import type { ExecutionInteraction } from "@executor/platform-sdk/schema"; | |
| 2 | − | |
| 3 | −const isRecord = (value: unknown): value is Record<string, unknown> => | |
| 4 | − typeof value === "object" && value !== null && !Array.isArray(value); | |
| 5 | − | |
| 6 | −export type ParsedInteractionPayload = { | |
| 7 | − message: string; | |
| 8 | − mode: "form" | "url"; | |
| 9 | − url?: string; | |
| 10 | − requestedSchema?: Record<string, unknown>; | |
| 11 | −}; | |
| 12 | − | |
| 13 | −export const parseInteractionPayload = ( | |
| 14 | − interaction: ExecutionInteraction, | |
| 15 | −): ParsedInteractionPayload | null => { | |
| 16 | − try { | |
| 17 | − const parsed = JSON.parse(interaction.payloadJson) as { | |
| 18 | − elicitation?: { | |
| 19 | − message?: string; | |
| 20 | − mode?: "form" | "url"; | |
| 21 | − url?: string; | |
| 22 | − requestedSchema?: Record<string, unknown>; | |
| 23 | − }; | |
| 24 | − }; | |
| 25 | − | |
| 26 | − if (!parsed.elicitation || typeof parsed.elicitation.message !== "string") { | |
| 27 | − return null; | |
| 28 | − } | |
| 29 | − | |
| 30 | − return { | |
| 31 | − message: parsed.elicitation.message, | |
| 32 | − mode: parsed.elicitation.mode === "url" ? "url" : "form", | |
| 33 | − url: parsed.elicitation.url, | |
| 34 | − requestedSchema: | |
| 35 | − isRecord(parsed.elicitation.requestedSchema) | |
| 36 | − ? parsed.elicitation.requestedSchema | |
| 37 | − : undefined, | |
| 38 | − }; | |
| 39 | − } catch { | |
| 40 | − return null; | |
| 41 | − } | |
| 42 | −}; | |
| 43 | − | |
| 44 | −const shellEscape = (value: string): string => { | |
| 45 | − if (/^[A-Za-z0-9_./:=+-]+$/.test(value)) { | |
| 46 | − return value; | |
| 47 | − } | |
| 48 | − | |
| 49 | − return `'${value.replace(/'/g, `'"'"'`)}'`; | |
| 50 | −}; | |
| 51 | − | |
| 52 | −const renderCommand = (argv: readonly string[]): string => argv.map(shellEscape).join(" "); | |
| 53 | − | |
| 54 | −const describePauseReason = (interaction: ExecutionInteraction): string => { | |
| 55 | − switch (interaction.purpose) { | |
| 56 | − case "tool_execution_gate": | |
| 57 | − return "this tool call requires approval before executor can continue"; | |
| 58 | − default: | |
| 59 | − return "executor needs additional input before it can continue"; | |
| 60 | − } | |
| 61 | −}; | |
| 62 | − | |
| 63 | −const buildInstruction = (input: { | |
| 64 | − interaction: ExecutionInteraction; | |
| 65 | − parsed: ParsedInteractionPayload | null; | |
| 66 | − resumeCommand: string; | |
| 67 | −}): string => { | |
| 68 | − const reason = describePauseReason(input.interaction); | |
| 69 | − const prompt = input.parsed?.message ?? "Interaction required"; | |
| 70 | − | |
| 71 | − if (input.parsed?.mode === "url") { | |
| 72 | − const url = input.parsed.url?.trim(); | |
| 73 | − return url && url.length > 0 | |
| 74 | − ? `Execution paused because ${reason}. Open ${url} and complete the requested flow for "${prompt}", then run ${input.resumeCommand} to continue if it does not resume automatically.` | |
| 75 | − : `Execution paused because ${reason}. Run ${input.resumeCommand} to continue and complete the requested flow for "${prompt}".`; | |
| 76 | − } | |
| 77 | − | |
| 78 | − if (input.parsed?.requestedSchema) { | |
| 79 | − return `Execution paused because ${reason}. The interaction prompt is "${prompt}". Run ${input.resumeCommand} in an interactive terminal and respond with input matching interaction.requestedSchema.`; | |
| 80 | − } | |
| 81 | − | |
| 82 | − return `Execution paused because ${reason}. The interaction prompt is "${prompt}". Run ${input.resumeCommand} in an interactive terminal to continue.`; | |
| 83 | −}; | |
| 84 | − | |
| 85 | −export const buildPausedExecutionOutput = (input: { | |
| 86 | − executionId: string; | |
| 87 | − interaction: ExecutionInteraction; | |
| 88 | − baseUrl: string; | |
| 89 | − shouldOpenUrls: boolean; | |
| 90 | − cliName?: string; | |
| 91 | −}) => { | |
| 92 | − const cliName = input.cliName ?? "executor"; | |
| 93 | − const argv = [cliName, "resume", "--execution-id", input.executionId, "--base-url", input.baseUrl]; | |
| 94 | − if (!input.shouldOpenUrls) { | |
| 95 | − argv.push("--no-open"); | |
| 96 | − } | |
| 97 | − | |
| 98 | − const command = renderCommand(argv); | |
| 99 | − const parsed = parseInteractionPayload(input.interaction); | |
| 100 | − | |
| 101 | − return { | |
| 102 | − id: input.executionId, | |
| 103 | − status: "waiting_for_interaction" as const, | |
| 104 | − interactionId: input.interaction.id, | |
| 105 | − message: parsed?.message ?? "Interaction required", | |
| 106 | − resumeCommand: command, | |
| 107 | − interaction: { | |
| 108 | − id: input.interaction.id, | |
| 109 | − purpose: input.interaction.purpose, | |
| 110 | − mode: parsed?.mode ?? (input.interaction.kind === "url" ? "url" : "form"), | |
| 111 | − message: parsed?.message ?? "Interaction required", | |
| 112 | − url: parsed?.url ?? null, | |
| 113 | − requestedSchema: parsed?.requestedSchema ?? null, | |
| 114 | − }, | |
| 115 | − resume: { | |
| 116 | − command, | |
| 117 | − argv, | |
| 118 | − }, | |
| 119 | − instruction: buildInstruction({ | |
| 120 | − interaction: input.interaction, | |
| 121 | − parsed, | |
| 122 | − resumeCommand: command, | |
| 123 | − }), | |
| 124 | − }; | |
| 125 | −}; | |
| @@ -1,47 +0,0 @@ | ||
| 1 | −import { join } from "node:path"; | |
| 2 | −import { describe, expect, it } from "@effect/vitest"; | |
| 3 | − | |
| 4 | −import { | |
| 5 | − DEFAULT_EXECUTOR_DATA_DIR, | |
| 6 | − DEFAULT_LOCAL_DATA_DIR, | |
| 7 | −} from "@executor/server"; | |
| 8 | − | |
| 9 | −import { | |
| 10 | − resolveCliLocalDataDir, | |
| 11 | −} from "./runtime-paths"; | |
| 12 | − | |
| 13 | −describe("runtime-paths", () => { | |
| 14 | − it("uses the web dev local data dir for source-launched CLI runs", () => { | |
| 15 | − const originalArgv1 = process.argv[1]; | |
| 16 | − | |
| 17 | − try { | |
| 18 | − process.argv[1] = "/tmp/executor.ts"; | |
| 19 | − | |
| 20 | − expect(resolveCliLocalDataDir()).toBe( | |
| 21 | − join(DEFAULT_EXECUTOR_DATA_DIR, "control-plane-web-dev"), | |
| 22 | − ); | |
| 23 | − } finally { | |
| 24 | − if (originalArgv1 === undefined) { | |
| 25 | − delete process.argv[1]; | |
| 26 | − } else { | |
| 27 | − process.argv[1] = originalArgv1; | |
| 28 | − } | |
| 29 | − } | |
| 30 | − }); | |
| 31 | − | |
| 32 | − it("keeps the default local data dir for bundled launches", () => { | |
| 33 | − const originalArgv1 = process.argv[1]; | |
| 34 | − | |
| 35 | − try { | |
| 36 | − process.argv[1] = "/tmp/executor"; | |
| 37 | − | |
| 38 | − expect(resolveCliLocalDataDir()).toBe(DEFAULT_LOCAL_DATA_DIR); | |
| 39 | − } finally { | |
| 40 | − if (originalArgv1 === undefined) { | |
| 41 | − delete process.argv[1]; | |
| 42 | − } else { | |
| 43 | − process.argv[1] = originalArgv1; | |
| 44 | − } | |
| 45 | − } | |
| 46 | − }); | |
| 47 | −}); | |
| @@ -1,109 +0,0 @@ | ||
| 1 | −import { existsSync } from "node:fs"; | |
| 2 | −import { dirname, extname, join, resolve } from "node:path"; | |
| 3 | −import { fileURLToPath } from "node:url"; | |
| 4 | − | |
| 5 | −import { | |
| 6 | − DEFAULT_EXECUTOR_DATA_DIR, | |
| 7 | − DEFAULT_LOCAL_DATA_DIR, | |
| 8 | − EXECUTOR_LOCAL_DATA_DIR_ENV, | |
| 9 | − EXECUTOR_WEB_ASSETS_DIR_ENV, | |
| 10 | −} from "@executor/server"; | |
| 11 | − | |
| 12 | −const sourceDir = dirname(fileURLToPath(import.meta.url)); | |
| 13 | − | |
| 14 | −const trim = (value: string | undefined): string | undefined => { | |
| 15 | − const candidate = value?.trim(); | |
| 16 | − return candidate && candidate.length > 0 ? candidate : undefined; | |
| 17 | −}; | |
| 18 | − | |
| 19 | −const resolveIfExists = (value: string | undefined): string | null => { | |
| 20 | − const candidate = trim(value); | |
| 21 | − if (!candidate) { | |
| 22 | − return null; | |
| 23 | − } | |
| 24 | − | |
| 25 | − const resolved = resolve(candidate); | |
| 26 | − return existsSync(resolved) ? resolved : null; | |
| 27 | −}; | |
| 28 | − | |
| 29 | −const getSourceEntrypoint = (): string | null => { | |
| 30 | − const candidate = trim(process.argv[1]); | |
| 31 | − if (!candidate) { | |
| 32 | − return null; | |
| 33 | − } | |
| 34 | − | |
| 35 | − const resolved = resolve(candidate); | |
| 36 | − const extension = extname(resolved).toLowerCase(); | |
| 37 | − return [".ts", ".tsx", ".js", ".mjs", ".cjs"].includes(extension) | |
| 38 | − ? resolved | |
| 39 | − : null; | |
| 40 | −}; | |
| 41 | − | |
| 42 | −const isSourceCliLaunch = (): boolean => getSourceEntrypoint() !== null; | |
| 43 | − | |
| 44 | −const resolveBundledNodeLauncher = (): string | null => { | |
| 45 | − const candidate = resolve(sourceDir, "executor.js"); | |
| 46 | − return existsSync(candidate) ? candidate : null; | |
| 47 | −}; | |
| 48 | − | |
| 49 | − | |
| 50 | −const resolveRuntimeResourcesRoot = (): string | null => { | |
| 51 | − const compiledCandidate = resolve(dirname(process.execPath), "../resources"); | |
| 52 | − if (existsSync(compiledCandidate)) { | |
| 53 | − return compiledCandidate; | |
| 54 | − } | |
| 55 | − | |
| 56 | − const bundledCandidateFromModule = resolve(sourceDir, "../resources"); | |
| 57 | − if (existsSync(bundledCandidateFromModule)) { | |
| 58 | − return bundledCandidateFromModule; | |
| 59 | − } | |
| 60 | − | |
| 61 | − const sourceEntrypoint = getSourceEntrypoint(); | |
| 62 | − if (sourceEntrypoint) { | |
| 63 | − const bundledCandidate = resolve(dirname(sourceEntrypoint), "../resources"); | |
| 64 | − if (existsSync(bundledCandidate)) { | |
| 65 | − return bundledCandidate; | |
| 66 | − } | |
| 67 | − } | |
| 68 | − | |
| 69 | − return null; | |
| 70 | −}; | |
| 71 | − | |
| 72 | −export const resolveSelfCommand = (args: readonly string[]): readonly string[] => { | |
| 73 | − const bundledLauncher = resolveBundledNodeLauncher(); | |
| 74 | − if (bundledLauncher !== null) { | |
| 75 | − return [process.execPath, bundledLauncher, ...args]; | |
| 76 | − } | |
| 77 | − | |
| 78 | − const sourceEntrypoint = getSourceEntrypoint(); | |
| 79 | − return sourceEntrypoint === null | |
| 80 | − ? [process.execPath, ...args] | |
| 81 | − : [process.execPath, sourceEntrypoint, ...args]; | |
| 82 | −}; | |
| 83 | − | |
| 84 | −export const resolveCliLocalDataDir = (): string => { | |
| 85 | − if (trim(process.env[EXECUTOR_LOCAL_DATA_DIR_ENV])) { | |
| 86 | − return DEFAULT_LOCAL_DATA_DIR; | |
| 87 | − } | |
| 88 | − | |
| 89 | − return isSourceCliLaunch() | |
| 90 | − ? join(DEFAULT_EXECUTOR_DATA_DIR, "control-plane-web-dev") | |
| 91 | − : DEFAULT_LOCAL_DATA_DIR; | |
| 92 | −}; | |
| 93 | − | |
| 94 | −export const resolveRuntimeWebAssetsDir = (): string | null => { | |
| 95 | − const explicit = resolveIfExists(process.env[EXECUTOR_WEB_ASSETS_DIR_ENV]); | |
| 96 | − if (explicit) { | |
| 97 | − return explicit; | |
| 98 | − } | |
| 99 | − | |
| 100 | − const resourcesRoot = resolveRuntimeResourcesRoot(); | |
| 101 | − const bundled = resourcesRoot | |
| 102 | − ? resolveIfExists(resolve(resourcesRoot, "web")) | |
| 103 | − : null; | |
| 104 | − if (bundled) { | |
| 105 | − return bundled; | |
| 106 | − } | |
| 107 | − | |
| 108 | − return resolveIfExists(resolve(sourceDir, "../../../web/dist")); | |
| 109 | −}; | |
| @@ -1,60 +0,0 @@ | ||
| 1 | −import { describe, expect, it } from "@effect/vitest"; | |
| 2 | − | |
| 3 | −import { | |
| 4 | − appendUrlPath, | |
| 5 | − renderMcpSessionSummary, | |
| 6 | − renderUpSummary, | |
| 7 | − renderWebSessionSummary, | |
| 8 | −} from "./session-summary"; | |
| 9 | − | |
| 10 | −describe("session-summary", () => { | |
| 11 | − it("appends paths against a base url", () => { | |
| 12 | − expect(appendUrlPath("http://127.0.0.1:8788", "mcp")).toBe("http://127.0.0.1:8788/mcp"); | |
| 13 | − expect(appendUrlPath("http://127.0.0.1:8788/", "v1/openapi.json")).toBe( | |
| 14 | − "http://127.0.0.1:8788/v1/openapi.json", | |
| 15 | − ); | |
| 16 | − }); | |
| 17 | − | |
| 18 | − it("renders the web session summary around the browser url", () => { | |
| 19 | − const output = renderWebSessionSummary({ | |
| 20 | − baseUrl: "http://127.0.0.1:8788", | |
| 21 | − workspaceId: "ws_123", | |
| 22 | − }); | |
| 23 | − | |
| 24 | − expect(output).toContain("Executor web session is ready."); | |
| 25 | − expect(output).toContain("Web: http://127.0.0.1:8788"); | |
| 26 | − expect(output).toContain("MCP: http://127.0.0.1:8788/mcp"); | |
| 27 | − expect(output).toContain("Workspace: ws_123"); | |
| 28 | − expect(output).toContain("Press Ctrl+C to stop this session."); | |
| 29 | − }); | |
| 30 | − | |
| 31 | − it("renders the MCP session summary around the MCP url", () => { | |
| 32 | − const output = renderMcpSessionSummary({ | |
| 33 | − baseUrl: "http://127.0.0.1:8788", | |
| 34 | − workspaceId: "ws_456", | |
| 35 | − }); | |
| 36 | − | |
| 37 | − expect(output).toContain("Executor MCP session is ready."); | |
| 38 | − expect(output).toContain("MCP: http://127.0.0.1:8788/mcp"); | |
| 39 | − expect(output).toContain("Web: http://127.0.0.1:8788"); | |
| 40 | − expect(output).toContain("Workspace: ws_456"); | |
| 41 | − expect(output).toContain("Use this MCP URL in your client and keep this process running."); | |
| 42 | − }); | |
| 43 | − | |
| 44 | − it("adds session-first next steps to the up summary", () => { | |
| 45 | − const output = renderUpSummary({ | |
| 46 | − started: true, | |
| 47 | − status: { | |
| 48 | − baseUrl: "http://127.0.0.1:8788", | |
| 49 | − installation: { | |
| 50 | − workspaceId: "ws_789", | |
| 51 | − }, | |
| 52 | − }, | |
| 53 | − }); | |
| 54 | − | |
| 55 | − expect(output).toContain("Executor is ready."); | |
| 56 | − expect(output).toContain("executor web"); | |
| 57 | − expect(output).toContain("executor mcp"); | |
| 58 | − expect(output).toContain("executor call 'return 1 + 1'"); | |
| 59 | − }); | |
| 60 | −}); | |
| @@ -1,64 +0,0 @@ | ||
| 1 | −export const appendUrlPath = (baseUrl: string, pathname: string): string => | |
| 2 | − new URL(pathname, baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`).toString(); | |
| 3 | − | |
| 4 | −type SessionSummaryInput = { | |
| 5 | − readonly baseUrl: string; | |
| 6 | − readonly workspaceId?: string | null; | |
| 7 | −}; | |
| 8 | − | |
| 9 | −const renderSessionSummary = ( | |
| 10 | − kind: "web" | "mcp", | |
| 11 | − input: SessionSummaryInput, | |
| 12 | −): string => { | |
| 13 | − const displayKind = kind === "mcp" ? "MCP" : "web"; | |
| 14 | − const primaryLabel = kind === "web" ? "Web" : "MCP"; | |
| 15 | − const primaryUrl = kind === "web" ? input.baseUrl : appendUrlPath(input.baseUrl, "mcp"); | |
| 16 | − const secondaryLabel = kind === "web" ? "MCP" : "Web"; | |
| 17 | − const secondaryUrl = kind === "web" ? appendUrlPath(input.baseUrl, "mcp") : input.baseUrl; | |
| 18 | − const guidance = kind === "web" | |
| 19 | − ? "Keep this process running while you use the browser session." | |
| 20 | − : "Use this MCP URL in your client and keep this process running."; | |
| 21 | − | |
| 22 | − return [ | |
| 23 | − `Executor ${displayKind} session is ready.`, | |
| 24 | − `${primaryLabel}: ${primaryUrl}`, | |
| 25 | − `${secondaryLabel}: ${secondaryUrl}`, | |
| 26 | − `OpenAPI: ${appendUrlPath(input.baseUrl, "v1/openapi.json")}`, | |
| 27 | − `Workspace: ${input.workspaceId ?? "unavailable"}`, | |
| 28 | − "", | |
| 29 | − guidance, | |
| 30 | − "Press Ctrl+C to stop this session.", | |
| 31 | − ].join("\n"); | |
| 32 | −}; | |
| 33 | − | |
| 34 | −export const renderWebSessionSummary = (input: SessionSummaryInput): string => | |
| 35 | − renderSessionSummary("web", input); | |
| 36 | − | |
| 37 | −export const renderMcpSessionSummary = (input: SessionSummaryInput): string => | |
| 38 | − renderSessionSummary("mcp", input); | |
| 39 | − | |
| 40 | −type UpSummaryInput = { | |
| 41 | − readonly started: boolean; | |
| 42 | − readonly status: { | |
| 43 | − readonly baseUrl: string; | |
| 44 | − readonly installation: { | |
| 45 | − readonly workspaceId: string; | |
| 46 | − } | null; | |
| 47 | − }; | |
| 48 | −}; | |
| 49 | − | |
| 50 | −export const renderUpSummary = (input: UpSummaryInput): string => | |
| 51 | − [ | |
| 52 | − input.started ? "Executor is ready." : "Executor is already running.", | |
| 53 | − `API: ${input.status.baseUrl}`, | |
| 54 | − `MCP: ${appendUrlPath(input.status.baseUrl, "mcp")}`, | |
| 55 | − `OpenAPI: ${appendUrlPath(input.status.baseUrl, "v1/openapi.json")}`, | |
| 56 | − `Workspace: ${input.status.installation?.workspaceId ?? "unavailable"}`, | |
| 57 | − "", | |
| 58 | − "Try next:", | |
| 59 | − " executor web", | |
| 60 | − " executor mcp", | |
| 61 | − " executor call 'return 1 + 1'", | |
| 62 | − " executor status", | |
| 63 | − " executor down", | |
| 64 | − ].join("\n"); | |
| @@ -1,359 +0,0 @@ | ||
| 1 | −import { spawn } from "node:child_process"; | |
| 2 | −import { existsSync, readFileSync } from "node:fs"; | |
| 3 | −import { chmod, cp, mkdir, rename, rm, writeFile } from "node:fs/promises"; | |
| 4 | −import { createRequire } from "node:module"; | |
| 5 | −import { dirname, join, resolve } from "node:path"; | |
| 6 | − | |
| 7 | −import { readDistributionPackageMetadata, repoRoot } from "./metadata"; | |
| 8 | − | |
| 9 | −const defaultOutputDir = resolve(repoRoot, "apps/executor/dist/npm"); | |
| 10 | − | |
| 11 | − | |
| 12 | −export type BuildDistributionPackageOptions = { | |
| 13 | − outputDir?: string; | |
| 14 | − packageName?: string; | |
| 15 | − packageVersion?: string; | |
| 16 | − buildWeb?: boolean; | |
| 17 | −}; | |
| 18 | − | |
| 19 | −export type DistributionPackageArtifact = { | |
| 20 | − packageDir: string; | |
| 21 | − launcherPath: string; | |
| 22 | − bundlePath: string; | |
| 23 | − resourcesDir: string; | |
| 24 | −}; | |
| 25 | − | |
| 26 | −type BundledDependency = { | |
| 27 | − name: string; | |
| 28 | − version: string; | |
| 29 | − packageDir: string; | |
| 30 | −}; | |
| 31 | − | |
| 32 | −type CommandInput = { | |
| 33 | − command: string; | |
| 34 | − args: ReadonlyArray<string>; | |
| 35 | − cwd: string; | |
| 36 | −}; | |
| 37 | − | |
| 38 | −const runCommand = async (input: CommandInput): Promise<void> => { | |
| 39 | − const child = spawn(input.command, [...input.args], { | |
| 40 | − cwd: input.cwd, | |
| 41 | − env: process.env, | |
| 42 | − stdio: ["ignore", "pipe", "pipe"], | |
| 43 | − }); | |
| 44 | − | |
| 45 | − let stdout = ""; | |
| 46 | − let stderr = ""; | |
| 47 | − | |
| 48 | − child.stdout?.setEncoding("utf8"); | |
| 49 | − child.stdout?.on("data", (chunk) => { | |
| 50 | − stdout += chunk; | |
| 51 | − }); | |
| 52 | − | |
| 53 | − child.stderr?.setEncoding("utf8"); | |
| 54 | − child.stderr?.on("data", (chunk) => { | |
| 55 | − stderr += chunk; | |
| 56 | − }); | |
| 57 | − | |
| 58 | − const exitCode = await new Promise<number>((resolveExitCode, reject) => { | |
| 59 | − child.once("error", reject); | |
| 60 | − child.once("close", (code) => { | |
| 61 | − resolveExitCode(code ?? -1); | |
| 62 | − }); | |
| 63 | − }); | |
| 64 | − | |
| 65 | − if (exitCode === 0) { | |
| 66 | − return; | |
| 67 | − } | |
| 68 | − | |
| 69 | − throw new Error( | |
| 70 | − [ | |
| 71 | − `${input.command} ${input.args.join(" ")} exited with code ${exitCode}`, | |
| 72 | − stdout.trim().length > 0 ? `stdout:\n${stdout.trim()}` : null, | |
| 73 | − stderr.trim().length > 0 ? `stderr:\n${stderr.trim()}` : null, | |
| 74 | − ] | |
| 75 | − .filter((part) => part !== null) | |
| 76 | − .join("\n\n"), | |
| 77 | − ); | |
| 78 | −}; | |
| 79 | − | |
| 80 | −const resolveQuickJsWasmPath = (): string => { | |
| 81 | − const requireFromQuickJsRuntime = createRequire( | |
| 82 | − join(repoRoot, "packages/kernel/runtime-quickjs/package.json"), | |
| 83 | − ); | |
| 84 | − const quickJsPackagePath = requireFromQuickJsRuntime.resolve( | |
| 85 | − "quickjs-emscripten/package.json", | |
| 86 | − ); | |
| 87 | − const wasmPath = resolve( | |
| 88 | − dirname(quickJsPackagePath), | |
| 89 | − "../@jitl/quickjs-wasmfile-release-sync/dist/emscripten-module.wasm", | |
| 90 | − ); | |
| 91 | − | |
| 92 | − if (!existsSync(wasmPath)) { | |
| 93 | − throw new Error(`Unable to locate QuickJS wasm asset at ${wasmPath}`); | |
| 94 | − } | |
| 95 | − | |
| 96 | − return wasmPath; | |
| 97 | −}; | |
| 98 | − | |
| 99 | −const resolveInstalledPackage = (input: { | |
| 100 | − packageName: string; | |
| 101 | − fromPackageJsonPath: string; | |
| 102 | −}): BundledDependency => { | |
| 103 | − const requireFromPackage = createRequire(input.fromPackageJsonPath); | |
| 104 | − const packageEntrypointPath = requireFromPackage.resolve(input.packageName); | |
| 105 | − let packageDir = dirname(packageEntrypointPath); | |
| 106 | − let packageJsonPath = join(packageDir, "package.json"); | |
| 107 | − | |
| 108 | − while (!existsSync(packageJsonPath)) { | |
| 109 | − const parentDir = dirname(packageDir); | |
| 110 | − if (parentDir === packageDir) { | |
| 111 | − throw new Error(`Unable to locate package.json for ${input.packageName} from ${packageEntrypointPath}`); | |
| 112 | − } | |
| 113 | − packageDir = parentDir; | |
| 114 | − packageJsonPath = join(packageDir, "package.json"); | |
| 115 | − } | |
| 116 | − | |
| 117 | − const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8")) as { | |
| 118 | − name?: string; | |
| 119 | − version?: string; | |
| 120 | − }; | |
| 121 | − | |
| 122 | − if (!packageJson.name || !packageJson.version) { | |
| 123 | − throw new Error(`Invalid package metadata at ${packageJsonPath}`); | |
| 124 | − } | |
| 125 | − | |
| 126 | − return { | |
| 127 | − name: packageJson.name, | |
| 128 | − version: packageJson.version, | |
| 129 | − packageDir, | |
| 130 | − }; | |
| 131 | −}; | |
| 132 | − | |
| 133 | −const resolveBundledDependencies = (): ReadonlyArray<BundledDependency> => { | |
| 134 | − const onePasswordSdk = resolveInstalledPackage({ | |
| 135 | − packageName: "@1password/sdk", | |
| 136 | − fromPackageJsonPath: join(repoRoot, "plugins/onepassword/sdk/package.json"), | |
| 137 | − }); | |
| 138 | − const onePasswordSdkCore = resolveInstalledPackage({ | |
| 139 | − packageName: "@1password/sdk-core", | |
| 140 | − fromPackageJsonPath: join(onePasswordSdk.packageDir, "package.json"), | |
| 141 | − }); | |
| 142 | − | |
| 143 | − return [ | |
| 144 | − onePasswordSdk, | |
| 145 | − onePasswordSdkCore, | |
| 146 | − ]; | |
| 147 | −}; | |
| 148 | − | |
| 149 | − | |
| 150 | −const createPackageJson = (input: { | |
| 151 | − packageName: string; | |
| 152 | − packageVersion: string; | |
| 153 | − description: string; | |
| 154 | − keywords: ReadonlyArray<string>; | |
| 155 | − homepage?: string; | |
| 156 | − bugs?: { | |
| 157 | − url?: string; | |
| 158 | − }; | |
| 159 | − repository?: { | |
| 160 | − type?: string; | |
| 161 | − url?: string; | |
| 162 | − }; | |
| 163 | − license?: string; | |
| 164 | − dependencies?: Readonly<Record<string, string>>; | |
| 165 | − bundleDependencies?: ReadonlyArray<string>; | |
| 166 | −}) => { | |
| 167 | − const packageJson = { | |
| 168 | − name: input.packageName, | |
| 169 | − version: input.packageVersion, | |
| 170 | − description: input.description, | |
| 171 | − keywords: input.keywords, | |
| 172 | − homepage: input.homepage, | |
| 173 | − bugs: input.bugs, | |
| 174 | − repository: input.repository, | |
| 175 | − license: input.license ?? "MIT", | |
| 176 | − type: "module", | |
| 177 | − private: false, | |
| 178 | − bin: { | |
| 179 | − executor: "bin/executor.js", | |
| 180 | − }, | |
| 181 | − files: [ | |
| 182 | − "bin", | |
| 183 | − "node_modules", | |
| 184 | − "resources", | |
| 185 | − "README.md", | |
| 186 | − "package.json", | |
| 187 | − ], | |
| 188 | − engines: { | |
| 189 | − node: ">=20", | |
| 190 | − }, | |
| 191 | − dependencies: input.dependencies, | |
| 192 | − bundleDependencies: input.bundleDependencies, | |
| 193 | − }; | |
| 194 | − | |
| 195 | − return JSON.stringify(packageJson, null, 2) + "\n"; | |
| 196 | −}; | |
| 197 | − | |
| 198 | −const createLauncherSource = () => [ | |
| 199 | − "#!/usr/bin/env node", | |
| 200 | − 'import { readFileSync, readdirSync } from "node:fs";', | |
| 201 | − 'import { dirname, join } from "node:path";', | |
| 202 | − 'import { fileURLToPath } from "node:url";', | |
| 203 | − "", | |
| 204 | − "const isMusl = () => {", | |
| 205 | − ' try {', | |
| 206 | − ' return readFileSync("/usr/bin/ldd", "utf8").includes("musl");', | |
| 207 | − " } catch {}", | |
| 208 | − "", | |
| 209 | − ' if (typeof process.report?.getReport === "function") {', | |
| 210 | − " const report = process.report.getReport();", | |
| 211 | − " if (report?.header?.glibcVersionRuntime) {", | |
| 212 | − " return false;", | |
| 213 | − " }", | |
| 214 | − " if (Array.isArray(report?.sharedObjects)) {", | |
| 215 | − ' return report.sharedObjects.some((file) => file.includes("libc.musl-") || file.includes("ld-musl-"));', | |
| 216 | − " }", | |
| 217 | − " }", | |
| 218 | − "", | |
| 219 | − " return false;", | |
| 220 | − "};", | |
| 221 | − "", | |
| 222 | − "const resolveBundledKeyringNativeLibraryPath = () => {", | |
| 223 | − ' if (process.platform !== "linux" || process.arch !== "x64") {', | |
| 224 | − " return null;", | |
| 225 | − " }", | |
| 226 | − "", | |
| 227 | − " const binDir = dirname(fileURLToPath(import.meta.url));", | |
| 228 | − ' const pattern = isMusl()', | |
| 229 | − ' ? /^keyring\\.linux-x64-musl-.*\\.node$/', | |
| 230 | − ' : /^keyring\\.linux-x64-gnu-.*\\.node$/;', | |
| 231 | − ' const match = readdirSync(binDir).find((entry) => pattern.test(entry));', | |
| 232 | − " return match ? join(binDir, match) : null;", | |
| 233 | − "};", | |
| 234 | − "", | |
| 235 | − "const bundledKeyringNativeLibraryPath = resolveBundledKeyringNativeLibraryPath();", | |
| 236 | − 'if (bundledKeyringNativeLibraryPath && !process.env.NAPI_RS_NATIVE_LIBRARY_PATH) {', | |
| 237 | − " process.env.NAPI_RS_NATIVE_LIBRARY_PATH = bundledKeyringNativeLibraryPath;", | |
| 238 | − "}", | |
| 239 | − "", | |
| 240 | − 'await import("./executor.mjs");', | |
| 241 | − "", | |
| 242 | −].join("\n"); | |
| 243 | − | |
| 244 | −const buildCliBundle = async (input: { | |
| 245 | − binDir: string; | |
| 246 | − bundlePath: string; | |
| 247 | −}): Promise<void> => { | |
| 248 | − const builtEntrypointPath = join(input.binDir, "main.js"); | |
| 249 | − | |
| 250 | − await runCommand({ | |
| 251 | − command: "bun", | |
| 252 | − args: [ | |
| 253 | − "build", | |
| 254 | − "./apps/executor/src/cli/main.ts", | |
| 255 | − "--target", | |
| 256 | − "node", | |
| 257 | − "--outdir", | |
| 258 | − input.binDir, | |
| 259 | − "--external=@1password/sdk", | |
| 260 | − ], | |
| 261 | − cwd: repoRoot, | |
| 262 | − }); | |
| 263 | − | |
| 264 | − if (!existsSync(builtEntrypointPath)) { | |
| 265 | − throw new Error(`Missing bundled CLI entrypoint at ${builtEntrypointPath}`); | |
| 266 | − } | |
| 267 | − | |
| 268 | − await rm(input.bundlePath, { force: true }); | |
| 269 | − await rename(builtEntrypointPath, input.bundlePath); | |
| 270 | −}; | |
| 271 | − | |
| 272 | −export const buildDistributionPackage = async ( | |
| 273 | − options: BuildDistributionPackageOptions = {}, | |
| 274 | −): Promise<DistributionPackageArtifact> => { | |
| 275 | − const defaults = await readDistributionPackageMetadata(); | |
| 276 | − const packageDir = resolve(options.outputDir ?? defaultOutputDir); | |
| 277 | − const binDir = join(packageDir, "bin"); | |
| 278 | − const resourcesDir = join(packageDir, "resources"); | |
| 279 | − const webDir = join(resourcesDir, "web"); | |
| 280 | − const bundlePath = join(binDir, "executor.mjs"); | |
| 281 | − const launcherPath = join(binDir, "executor.js"); | |
| 282 | − const nodeModulesDir = join(packageDir, "node_modules"); | |
| 283 | − const quickJsWasmPath = resolveQuickJsWasmPath(); | |
| 284 | − const bundledDependencies = resolveBundledDependencies(); | |
| 285 | − | |
| 286 | − const webDistDir = join(repoRoot, "apps/web/dist"); | |
| 287 | − const readmePath = join(repoRoot, "README.md"); | |
| 288 | − const packageName = options.packageName ?? defaults.name; | |
| 289 | − const packageVersion = options.packageVersion ?? defaults.version; | |
| 290 | − await rm(packageDir, { recursive: true, force: true }); | |
| 291 | − await mkdir(binDir, { recursive: true }); | |
| 292 | − await mkdir(nodeModulesDir, { recursive: true }); | |
| 293 | − await mkdir(resourcesDir, { recursive: true }); | |
| 294 | − | |
| 295 | − if ((options.buildWeb ?? true) || !existsSync(webDistDir)) { | |
| 296 | − await runCommand({ | |
| 297 | − command: "bun", | |
| 298 | − args: ["run", "build"], | |
| 299 | − cwd: join(repoRoot, "apps/web"), | |
| 300 | − }); | |
| 301 | − } | |
| 302 | − | |
| 303 | − if (!existsSync(webDistDir)) { | |
| 304 | − throw new Error(`Missing built web assets at ${webDistDir}`); | |
| 305 | − } | |
| 306 | − | |
| 307 | − await buildCliBundle({ | |
| 308 | − binDir, | |
| 309 | − bundlePath, | |
| 310 | − }); | |
| 311 | − | |
| 312 | − await cp(webDistDir, webDir, { recursive: true }); | |
| 313 | − for (const dependency of bundledDependencies) { | |
| 314 | − const destinationDir = join(nodeModulesDir, ...dependency.name.split("/")); | |
| 315 | − await mkdir(dirname(destinationDir), { recursive: true }); | |
| 316 | − await cp(dependency.packageDir, destinationDir, { recursive: true }); | |
| 317 | − } | |
| 318 | − await cp(quickJsWasmPath, join(binDir, "emscripten-module.wasm")); | |
| 319 | − await cp( | |
| 320 | − join(repoRoot, "packages/kernel/runtime-deno-subprocess/src/deno-subprocess-worker.mjs"), | |
| 321 | − join(binDir, "deno-subprocess-worker.mjs"), | |
| 322 | − ); | |
| 323 | − await runCommand({ | |
| 324 | − command: "bun", | |
| 325 | − args: [ | |
| 326 | − "build", | |
| 327 | − "./packages/kernel/runtime-ses/src/sandbox-worker.mjs", | |
| 328 | − "--target", | |
| 329 | − "node", | |
| 330 | − "--outfile", | |
| 331 | − join(binDir, "sandbox-worker.mjs"), | |
| 332 | − ], | |
| 333 | − cwd: repoRoot, | |
| 334 | − }); | |
| 335 | − await writeFile(join(packageDir, "package.json"), createPackageJson({ | |
| 336 | − packageName, | |
| 337 | − packageVersion, | |
| 338 | − description: defaults.description, | |
| 339 | − keywords: defaults.keywords, | |
| 340 | − homepage: defaults.homepage, | |
| 341 | − bugs: defaults.bugs, | |
| 342 | − repository: defaults.repository, | |
| 343 | − license: defaults.license, | |
| 344 | − dependencies: Object.fromEntries( | |
| 345 | − bundledDependencies.map((dependency) => [dependency.name, dependency.version]), | |
| 346 | − ), | |
| 347 | − bundleDependencies: bundledDependencies.map((dependency) => dependency.name), | |
| 348 | − })); | |
| 349 | − await cp(readmePath, join(packageDir, "README.md")); | |
| 350 | − await writeFile(launcherPath, createLauncherSource()); | |
| 351 | − await chmod(launcherPath, 0o755); | |
| 352 | − | |
| 353 | − return { | |
| 354 | − packageDir, | |
| 355 | − launcherPath, | |
| 356 | − bundlePath, | |
| 357 | − resourcesDir, | |
| 358 | − }; | |
| 359 | −}; | |
| @@ -1,110 +0,0 @@ | ||
| 1 | −import { existsSync, readFileSync } from "node:fs"; | |
| 2 | −import { join } from "node:path"; | |
| 3 | − | |
| 4 | −import { describe, expect, it } from "@effect/vitest"; | |
| 5 | −import * as Effect from "effect/Effect"; | |
| 6 | − | |
| 7 | −import { | |
| 8 | − DistributionHarness, | |
| 9 | − LocalDistributionHarnessLive, | |
| 10 | −} from "./harness"; | |
| 11 | − | |
| 12 | −describe("distribution flow", () => { | |
| 13 | − const verifyInstallFlow = <R>( | |
| 14 | − runCommand: ( | |
| 15 | − args: ReadonlyArray<string>, | |
| 16 | − options?: { | |
| 17 | − readonly okExitCodes?: ReadonlyArray<number>; | |
| 18 | − }, | |
| 19 | − ) => Effect.Effect<{ stdout: string; stderr: string }, Error, R>, | |
| 20 | − ) => | |
| 21 | − Effect.gen(function* () { | |
| 22 | − const harness = yield* DistributionHarness; | |
| 23 | − const bundleSource = readFileSync(join(harness.packageDir, "bin/executor.mjs"), "utf8"); | |
| 24 | − | |
| 25 | − expect(bundleSource).not.toContain("core_bg.wasm"); | |
| 26 | − expect( | |
| 27 | − existsSync(join(harness.packageDir, "node_modules/@1password/sdk-core/nodejs/core_bg.wasm")), | |
| 28 | − ).toBe(true); | |
| 29 | − | |
| 30 | − yield* harness.writeProjectConfig(`{ | |
| 31 | − "runtime": "ses", | |
| 32 | − // local workspace config | |
| 33 | − "sources": {}, | |
| 34 | −} | |
| 35 | −`); | |
| 36 | − | |
| 37 | − expect(yield* harness.isReachable()).toBe(false); | |
| 38 | − | |
| 39 | − const initialCall = yield* runCommand([ | |
| 40 | − "call", | |
| 41 | − "return 1 + 1;", | |
| 42 | − "--base-url", | |
| 43 | − harness.baseUrl, | |
| 44 | − "--no-open", | |
| 45 | − ]); | |
| 46 | − expect(initialCall.stdout).toBe("2"); | |
| 47 | − expect(yield* harness.isReachable()).toBe(true); | |
| 48 | − | |
| 49 | − const html = yield* harness.fetchText("/"); | |
| 50 | − expect(html.status).toBe(200); | |
| 51 | − expect(html.contentType).toContain("text/html"); | |
| 52 | − expect(html.body).toContain("<div id=\"root\"></div>"); | |
| 53 | − | |
| 54 | − const installationResponse = yield* harness.fetchText("/v1/local/installation"); | |
| 55 | − expect(installationResponse.status).toBe(200); | |
| 56 | − const installation = JSON.parse(installationResponse.body) as { | |
| 57 | − scopeId: string; | |
| 58 | − actorScopeId: string; | |
| 59 | − }; | |
| 60 | − | |
| 61 | − const sesCall = yield* runCommand( | |
| 62 | − [ | |
| 63 | − "call", | |
| 64 | − 'await fetch("https://example.com"); return 1;', | |
| 65 | − "--base-url", | |
| 66 | − harness.baseUrl, | |
| 67 | − ], | |
| 68 | − { okExitCodes: [1] }, | |
| 69 | − ); | |
| 70 | − expect(sesCall.stderr).toContain("fetch is disabled in SES executor"); | |
| 71 | − | |
| 72 | − yield* harness.stopServer(); | |
| 73 | − expect(yield* harness.isReachable()).toBe(false); | |
| 74 | − | |
| 75 | − const restartedCall = yield* runCommand([ | |
| 76 | − "call", | |
| 77 | − "return 3;", | |
| 78 | − "--base-url", | |
| 79 | − harness.baseUrl, | |
| 80 | − "--no-open", | |
| 81 | − ]); | |
| 82 | − expect(restartedCall.stdout).toBe("3"); | |
| 83 | − | |
| 84 | − const installationAfterRestartResponse = yield* harness.fetchText("/v1/local/installation"); | |
| 85 | − expect(installationAfterRestartResponse.status).toBe(200); | |
| 86 | − const installationAfterRestart = JSON.parse( | |
| 87 | − installationAfterRestartResponse.body, | |
| 88 | − ) as { | |
| 89 | − scopeId: string; | |
| 90 | − actorScopeId: string; | |
| 91 | − }; | |
| 92 | − | |
| 93 | − expect(installationAfterRestart.scopeId).toBe(installation.scopeId); | |
| 94 | − expect(installationAfterRestart.actorScopeId).toBe(installation.actorScopeId); | |
| 95 | − | |
| 96 | − yield* harness.stopServer(); | |
| 97 | − expect(yield* harness.isReachable()).toBe(false); | |
| 98 | − }); | |
| 99 | − | |
| 100 | − it.live("boots a staged package artifact in a fresh home", () => | |
| 101 | − verifyInstallFlow((args, options) => | |
| 102 | − Effect.flatMap(DistributionHarness, (harness) => harness.run(args, options)) | |
| 103 | − ) | |
| 104 | − .pipe(Effect.provide(LocalDistributionHarnessLive)), 240_000); | |
| 105 | − | |
| 106 | − it.live("boots an npm-installed package in a fresh home", () => | |
| 107 | − verifyInstallFlow((args, options) => | |
| 108 | − Effect.flatMap(DistributionHarness, (harness) => harness.runInstalled(args, options)) | |
| 109 | − ).pipe(Effect.provide(LocalDistributionHarnessLive)), 240_000); | |
| 110 | −}); | |
| @@ -1,385 +0,0 @@ | ||
| 1 | −import { spawn } from "node:child_process"; | |
| 2 | −import { createServer } from "node:net"; | |
| 3 | −import { tmpdir } from "node:os"; | |
| 4 | −import { dirname, join } from "node:path"; | |
| 5 | − | |
| 6 | −import { FileSystem } from "@effect/platform"; | |
| 7 | −import { NodeFileSystem } from "@effect/platform-node"; | |
| 8 | −import * as Context from "effect/Context"; | |
| 9 | −import * as Effect from "effect/Effect"; | |
| 10 | −import * as Layer from "effect/Layer"; | |
| 11 | − | |
| 12 | −import { buildDistributionPackage } from "./artifact"; | |
| 13 | −import { executorAppEffectError } from "../effect-errors"; | |
| 14 | − | |
| 15 | −const toError = (cause: unknown): Error => | |
| 16 | − cause instanceof Error ? cause : new Error(String(cause)); | |
| 17 | − | |
| 18 | −type CommandResult = { | |
| 19 | − readonly stdout: string; | |
| 20 | − readonly stderr: string; | |
| 21 | − readonly exitCode: number; | |
| 22 | −}; | |
| 23 | − | |
| 24 | −export class DistributionHarness extends Context.Tag( | |
| 25 | − "@executor/apps/executor/distribution/DistributionHarness", | |
| 26 | −)< | |
| 27 | − DistributionHarness, | |
| 28 | − { | |
| 29 | − readonly packageDir: string; | |
| 30 | − readonly launcherPath: string; | |
| 31 | − readonly tarballPath: string; | |
| 32 | − readonly executorHome: string; | |
| 33 | − readonly baseUrl: string; | |
| 34 | − readonly writeProjectConfig: ( | |
| 35 | − contents: string, | |
| 36 | − ) => Effect.Effect<void, Error, never>; | |
| 37 | − readonly run: ( | |
| 38 | − args: ReadonlyArray<string>, | |
| 39 | − options?: { | |
| 40 | − readonly okExitCodes?: ReadonlyArray<number>; | |
| 41 | − }, | |
| 42 | − ) => Effect.Effect<CommandResult, Error, never>; | |
| 43 | − readonly runInstalled: ( | |
| 44 | − args: ReadonlyArray<string>, | |
| 45 | − options?: { | |
| 46 | − readonly okExitCodes?: ReadonlyArray<number>; | |
| 47 | − }, | |
| 48 | − ) => Effect.Effect<CommandResult, Error, never>; | |
| 49 | − readonly fetchText: ( | |
| 50 | − pathname: string, | |
| 51 | − ) => Effect.Effect<{ | |
| 52 | − readonly status: number; | |
| 53 | − readonly body: string; | |
| 54 | − readonly contentType: string | null; | |
| 55 | − }, Error, never>; | |
| 56 | − readonly isReachable: () => Effect.Effect<boolean, Error, never>; | |
| 57 | − readonly stopServer: () => Effect.Effect<void, Error, never>; | |
| 58 | − } | |
| 59 | −>() {} | |
| 60 | − | |
| 61 | −const SERVER_WAIT_TIMEOUT_MS = 5_000; | |
| 62 | −const SERVER_POLL_INTERVAL_MS = 100; | |
| 63 | − | |
| 64 | −const runCommand = (input: { | |
| 65 | − readonly command: string; | |
| 66 | − readonly args: ReadonlyArray<string>; | |
| 67 | − readonly cwd: string; | |
| 68 | − readonly env?: NodeJS.ProcessEnv; | |
| 69 | − readonly okExitCodes?: ReadonlyArray<number>; | |
| 70 | −}): Effect.Effect<CommandResult, Error, never> => | |
| 71 | − Effect.async((resume) => { | |
| 72 | − const child = spawn(input.command, [...input.args], { | |
| 73 | − cwd: input.cwd, | |
| 74 | − env: input.env, | |
| 75 | − stdio: ["ignore", "pipe", "pipe"], | |
| 76 | − }); | |
| 77 | − | |
| 78 | − let stdout = ""; | |
| 79 | − let stderr = ""; | |
| 80 | − | |
| 81 | − child.stdout?.setEncoding("utf8"); | |
| 82 | − child.stdout?.on("data", (chunk) => { | |
| 83 | − stdout += chunk; | |
| 84 | − }); | |
| 85 | − | |
| 86 | − child.stderr?.setEncoding("utf8"); | |
| 87 | − child.stderr?.on("data", (chunk) => { | |
| 88 | − stderr += chunk; | |
| 89 | − }); | |
| 90 | − | |
| 91 | − child.once("error", (error) => { | |
| 92 | − resume(Effect.fail(error)); | |
| 93 | − }); | |
| 94 | − | |
| 95 | − child.once("close", (code) => { | |
| 96 | − const exitCode = code ?? -1; | |
| 97 | − const result = { | |
| 98 | − stdout: stdout.trim(), | |
| 99 | − stderr: stderr.trim(), | |
| 100 | − exitCode, | |
| 101 | − } satisfies CommandResult; | |
| 102 | − const okExitCodes = input.okExitCodes ?? [0]; | |
| 103 | − | |
| 104 | − if (okExitCodes.includes(exitCode)) { | |
| 105 | − resume(Effect.succeed(result)); | |
| 106 | − return; | |
| 107 | − } | |
| 108 | − | |
| 109 | − resume(Effect.fail(executorAppEffectError("distribution/harness", | |
| 110 | − [ | |
| 111 | − `${input.command} ${input.args.join(" ")} exited with code ${exitCode}`, | |
| 112 | − stdout.length > 0 ? `stdout:\n${stdout.trim()}` : null, | |
| 113 | − stderr.length > 0 ? `stderr:\n${stderr.trim()}` : null, | |
| 114 | − ].filter((part) => part !== null).join("\n\n"), | |
| 115 | − ))); | |
| 116 | − }); | |
| 117 | − | |
| 118 | − return Effect.sync(() => { | |
| 119 | − child.kill("SIGTERM"); | |
| 120 | − }); | |
| 121 | − }); | |
| 122 | − | |
| 123 | −const allocatePort = (): Effect.Effect<number, Error, never> => | |
| 124 | − Effect.tryPromise({ | |
| 125 | − try: async () => { | |
| 126 | − return await new Promise<number>((resolvePort, reject) => { | |
| 127 | − const server = createServer(); | |
| 128 | − server.once("error", reject); | |
| 129 | − server.listen(0, "127.0.0.1", () => { | |
| 130 | − const address = server.address(); | |
| 131 | − if (!address || typeof address === "string") { | |
| 132 | − server.close(() => reject(new Error("Failed to allocate test port"))); | |
| 133 | − return; | |
| 134 | − } | |
| 135 | − | |
| 136 | − server.close((error) => { | |
| 137 | − if (error) { | |
| 138 | − reject(error); | |
| 139 | − return; | |
| 140 | − } | |
| 141 | − | |
| 142 | − resolvePort(address.port); | |
| 143 | − }); | |
| 144 | − }); | |
| 145 | − }); | |
| 146 | − }, | |
| 147 | − catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)), | |
| 148 | − }); | |
| 149 | − | |
| 150 | −const buildPackage = (packageDir: string) => | |
| 151 | − Effect.tryPromise({ | |
| 152 | − try: () => buildDistributionPackage({ | |
| 153 | − outputDir: packageDir, | |
| 154 | − buildWeb: false, | |
| 155 | − }), | |
| 156 | − catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)), | |
| 157 | − }); | |
| 158 | − | |
| 159 | −const packPackage = (packageDir: string, outputDir: string) => | |
| 160 | − runCommand({ | |
| 161 | − command: "npm", | |
| 162 | − args: ["pack", packageDir], | |
| 163 | − cwd: outputDir, | |
| 164 | − }).pipe( | |
| 165 | − Effect.flatMap((result) => { | |
| 166 | − const tarballName = result.stdout | |
| 167 | − .split(/\s+/) | |
| 168 | − .map((part) => part.trim()) | |
| 169 | − .filter((part) => part.length > 0) | |
| 170 | − .at(-1); | |
| 171 | − | |
| 172 | − if (!tarballName) { | |
| 173 | − return Effect.fail( | |
| 174 | − executorAppEffectError("distribution/harness", `Unable to determine tarball name from npm pack output: ${result.stdout}`), | |
| 175 | − ); | |
| 176 | − } | |
| 177 | − | |
| 178 | − return Effect.succeed(join(outputDir, tarballName)); | |
| 179 | − }), | |
| 180 | − ); | |
| 181 | − | |
| 182 | −const waitForReachability = (input: { | |
| 183 | − baseUrl: string; | |
| 184 | − expected: boolean; | |
| 185 | −}): Effect.Effect<void, Error, never> => | |
| 186 | − Effect.gen(function* () { | |
| 187 | − const startedAt = Date.now(); | |
| 188 | − | |
| 189 | − while (Date.now() - startedAt < SERVER_WAIT_TIMEOUT_MS) { | |
| 190 | − const reachable = yield* Effect.tryPromise({ | |
| 191 | − try: async () => { | |
| 192 | − const response = await fetch(new URL("/", input.baseUrl)); | |
| 193 | − return response.ok; | |
| 194 | − }, | |
| 195 | − catch: toError, | |
| 196 | − }).pipe(Effect.catchAll(() => Effect.succeed(false))); | |
| 197 | − | |
| 198 | − if (reachable === input.expected) { | |
| 199 | − return; | |
| 200 | − } | |
| 201 | − | |
| 202 | − yield* Effect.sleep(`${SERVER_POLL_INTERVAL_MS} millis`); | |
| 203 | − } | |
| 204 | − | |
| 205 | − return yield* Effect.fail( | |
| 206 | − new Error( | |
| 207 | − `Timed out waiting for executor server to become ${input.expected ? "reachable" : "unreachable"} at ${input.baseUrl}`, | |
| 208 | − ), | |
| 209 | − ); | |
| 210 | − }); | |
| 211 | − | |
| 212 | −export const LocalDistributionHarnessLive = Layer.scoped( | |
| 213 | − DistributionHarness, | |
| 214 | − Effect.gen(function* () { | |
| 215 | − const fs = yield* FileSystem.FileSystem; | |
| 216 | − const tempRoot = yield* Effect.acquireRelease( | |
| 217 | − fs.makeTempDirectory({ | |
| 218 | − directory: tmpdir(), | |
| 219 | − prefix: "executor-distribution-", | |
| 220 | − }).pipe(Effect.mapError(toError)), | |
| 221 | − (path) => | |
| 222 | − fs.remove(path, { recursive: true, force: true }).pipe( | |
| 223 | − Effect.mapError(toError), | |
| 224 | − Effect.orDie, | |
| 225 | − ), | |
| 226 | − ); | |
| 227 | − | |
| 228 | − const packageDir = join(tempRoot, "package"); | |
| 229 | − const prefixDir = join(tempRoot, "prefix"); | |
| 230 | − const homeDir = join(tempRoot, "home"); | |
| 231 | − const executorHome = join(homeDir, ".executor"); | |
| 232 | − const stagedWorkspaceRoot = packageDir; | |
| 233 | − const installedWorkspaceRoot = tempRoot; | |
| 234 | − const baseUrl = `http://127.0.0.1:${yield* allocatePort()}`; | |
| 235 | − | |
| 236 | − yield* Effect.all([ | |
| 237 | − fs.makeDirectory(prefixDir, { recursive: true }), | |
| 238 | − fs.makeDirectory(homeDir, { recursive: true }), | |
| 239 | − fs.makeDirectory(executorHome, { recursive: true }), | |
| 240 | − ]).pipe(Effect.mapError(toError)); | |
| 241 | − | |
| 242 | − const artifact = yield* buildPackage(packageDir); | |
| 243 | − const tarballPath = yield* packPackage(packageDir, tempRoot); | |
| 244 | − | |
| 245 | − | |
| 246 | − const env = { | |
| 247 | − ...process.env, | |
| 248 | − HOME: homeDir, | |
| 249 | − EXECUTOR_HOME: executorHome, | |
| 250 | − } satisfies NodeJS.ProcessEnv; | |
| 251 | − | |
| 252 | − const installedEnv = { | |
| 253 | − ...env, | |
| 254 | − NPM_CONFIG_PREFIX: prefixDir, | |
| 255 | − PATH: `${join(prefixDir, "bin")}:${process.env.PATH ?? ""}`, | |
| 256 | − } satisfies NodeJS.ProcessEnv; | |
| 257 | − | |
| 258 | − yield* runCommand({ | |
| 259 | − command: "npm", | |
| 260 | − args: ["install", "-g", tarballPath], | |
| 261 | − cwd: tempRoot, | |
| 262 | − env: installedEnv, | |
| 263 | − }); | |
| 264 | − | |
| 265 | − const run = ( | |
| 266 | − args: ReadonlyArray<string>, | |
| 267 | − options?: { readonly okExitCodes?: ReadonlyArray<number> }, | |
| 268 | − ) => | |
| 269 | − runCommand({ | |
| 270 | − command: "node", | |
| 271 | − args: [artifact.launcherPath, ...args], | |
| 272 | − cwd: dirname(artifact.launcherPath), | |
| 273 | − env, | |
| 274 | − okExitCodes: options?.okExitCodes, | |
| 275 | − }); | |
| 276 | − | |
| 277 | − const runInstalled = ( | |
| 278 | − args: ReadonlyArray<string>, | |
| 279 | − options?: { readonly okExitCodes?: ReadonlyArray<number> }, | |
| 280 | − ) => | |
| 281 | − runCommand({ | |
| 282 | − command: "executor", | |
| 283 | − args, | |
| 284 | − cwd: tempRoot, | |
| 285 | − env: installedEnv, | |
| 286 | − okExitCodes: options?.okExitCodes, | |
| 287 | − }); | |
| 288 | − | |
| 289 | − const fetchText = (pathname: string) => | |
| 290 | − Effect.tryPromise({ | |
| 291 | − try: async () => { | |
| 292 | − const response = await fetch(new URL(pathname, baseUrl)); | |
| 293 | − return { | |
| 294 | − status: response.status, | |
| 295 | − body: await response.text(), | |
| 296 | − contentType: response.headers.get("content-type"), | |
| 297 | − }; | |
| 298 | − }, | |
| 299 | − catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)), | |
| 300 | − }); | |
| 301 | − | |
| 302 | − const isReachable = () => | |
| 303 | − Effect.tryPromise({ | |
| 304 | − try: async () => { | |
| 305 | − const response = await fetch(new URL("/", baseUrl)); | |
| 306 | − return response.ok; | |
| 307 | − }, | |
| 308 | − catch: toError, | |
| 309 | − }).pipe(Effect.catchAll(() => Effect.succeed(false))); | |
| 310 | − | |
| 311 | − const stopServer = () => | |
| 312 | − Effect.gen(function* () { | |
| 313 | − const pidFile = join(executorHome, "run", "server.pid"); | |
| 314 | − const exists = yield* fs.exists(pidFile).pipe(Effect.mapError(toError)); | |
| 315 | − if (!exists) { | |
| 316 | − return; | |
| 317 | − } | |
| 318 | − | |
| 319 | − const contents = yield* fs.readFileString(pidFile).pipe( | |
| 320 | − Effect.mapError(toError), | |
| 321 | − ); | |
| 322 | − const parsed = JSON.parse(contents) as { pid?: number }; | |
| 323 | − const pid = parsed.pid; | |
| 324 | − | |
| 325 | − if (typeof pid === "number" && Number.isInteger(pid) && pid > 0) { | |
| 326 | − yield* Effect.try({ | |
| 327 | − try: () => process.kill(pid, "SIGTERM"), | |
| 328 | − catch: toError, | |
| 329 | − }).pipe(Effect.catchAll(() => Effect.void)); | |
| 330 | − | |
| 331 | − const stopped = yield* waitForReachability({ | |
| 332 | − baseUrl, | |
| 333 | − expected: false, | |
| 334 | − }).pipe( | |
| 335 | − Effect.as(true), | |
| 336 | − Effect.catchAll(() => Effect.succeed(false)), | |
| 337 | − ); | |
| 338 | − if (stopped) { | |
| 339 | − return; | |
| 340 | − } | |
| 341 | − | |
| 342 | − yield* Effect.try({ | |
| 343 | − try: () => process.kill(pid, "SIGKILL"), | |
| 344 | − catch: toError, | |
| 345 | − }).pipe(Effect.catchAll(() => Effect.void)); | |
| 346 | − } | |
| 347 | − | |
| 348 | − yield* waitForReachability({ | |
| 349 | − baseUrl, | |
| 350 | − expected: false, | |
| 351 | − }); | |
| 352 | − }); | |
| 353 | − | |
| 354 | − const writeProjectConfig = (contents: string) => | |
| 355 | − Effect.forEach( | |
| 356 | − [stagedWorkspaceRoot, installedWorkspaceRoot], | |
| 357 | − (workspaceRoot) => | |
| 358 | − Effect.gen(function* () { | |
| 359 | − const configDir = join(workspaceRoot, ".executor"); | |
| 360 | − yield* fs.makeDirectory(configDir, { recursive: true }).pipe( | |
| 361 | − Effect.mapError(toError), | |
| 362 | − ); | |
| 363 | − yield* fs.writeFileString( | |
| 364 | − join(configDir, "executor.jsonc"), | |
| 365 | − contents, | |
| 366 | − ).pipe(Effect.mapError(toError)); | |
| 367 | − }), | |
| 368 | − { discard: true }, | |
| 369 | − ); | |
| 370 | − | |
| 371 | − return DistributionHarness.of({ | |
| 372 | − packageDir, | |
| 373 | − launcherPath: artifact.launcherPath, | |
| 374 | − tarballPath, | |
| 375 | − executorHome, | |
| 376 | − baseUrl, | |
| 377 | − writeProjectConfig, | |
| 378 | − run, | |
| 379 | − runInstalled, | |
| 380 | − fetchText, | |
| 381 | − isReachable, | |
| 382 | − stopServer, | |
| 383 | − }); | |
| 384 | − }).pipe(Effect.provide(NodeFileSystem.layer)), | |
| 385 | −); | |
| @@ -1,38 +0,0 @@ | ||
| 1 | −import { readFile } from "node:fs/promises"; | |
| 2 | −import { dirname, resolve } from "node:path"; | |
| 3 | −import { fileURLToPath } from "node:url"; | |
| 4 | − | |
| 5 | −export const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../../../.."); | |
| 6 | −const packageMetadataPath = resolve(repoRoot, "apps/executor/package.json"); | |
| 7 | − | |
| 8 | −export type DistributionPackageMetadata = { | |
| 9 | − name: string; | |
| 10 | − version: string; | |
| 11 | − description: string; | |
| 12 | − keywords: ReadonlyArray<string>; | |
| 13 | − homepage?: string; | |
| 14 | − bugs?: { | |
| 15 | − url?: string; | |
| 16 | − }; | |
| 17 | − repository?: { | |
| 18 | − type?: string; | |
| 19 | − url?: string; | |
| 20 | − }; | |
| 21 | − license?: string; | |
| 22 | −}; | |
| 23 | − | |
| 24 | −export const readDistributionPackageMetadata = async (): Promise<DistributionPackageMetadata> => { | |
| 25 | − const contents = await readFile(packageMetadataPath, "utf8"); | |
| 26 | − const metadata = JSON.parse(contents) as Partial<DistributionPackageMetadata>; | |
| 27 | − | |
| 28 | − return { | |
| 29 | − name: metadata.name ?? "executor", | |
| 30 | − version: metadata.version ?? "0.0.0-local", | |
| 31 | − description: metadata.description ?? "Local AI executor with a CLI, local API server, and web UI.", | |
| 32 | − keywords: Array.isArray(metadata.keywords) ? metadata.keywords.filter((value): value is string => typeof value === "string") : ["executor", "ai", "agent", "cli"], | |
| 33 | − homepage: metadata.homepage, | |
| 34 | − bugs: metadata.bugs, | |
| 35 | − repository: metadata.repository, | |
| 36 | − license: metadata.license ?? "MIT", | |
| 37 | − }; | |
| 38 | −}; | |
| @@ -1,224 +0,0 @@ | ||
| 1 | −import { spawn } from "node:child_process"; | |
| 2 | −import { mkdir, rm } from "node:fs/promises"; | |
| 3 | −import { join, resolve } from "node:path"; | |
| 4 | − | |
| 5 | −import { buildDistributionPackage } from "./artifact"; | |
| 6 | −import { readDistributionPackageMetadata, repoRoot } from "./metadata"; | |
| 7 | − | |
| 8 | −const defaultReleaseDir = resolve(repoRoot, "apps/executor/dist/release"); | |
| 9 | −const semverPattern = | |
| 10 | − /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/; | |
| 11 | − | |
| 12 | −type PublishCliOptions = { | |
| 13 | − dryRun: boolean; | |
| 14 | −}; | |
| 15 | − | |
| 16 | −type CommandInput = { | |
| 17 | − command: string; | |
| 18 | − args: ReadonlyArray<string>; | |
| 19 | − cwd: string; | |
| 20 | −}; | |
| 21 | − | |
| 22 | −type CommandOutput = { | |
| 23 | − stdout: string; | |
| 24 | − stderr: string; | |
| 25 | −}; | |
| 26 | − | |
| 27 | −type PackResult = { | |
| 28 | − filename?: string; | |
| 29 | −}; | |
| 30 | − | |
| 31 | −const parseArgs = (argv: ReadonlyArray<string>): PublishCliOptions => { | |
| 32 | − const options: PublishCliOptions = { | |
| 33 | − dryRun: false, | |
| 34 | − }; | |
| 35 | − | |
| 36 | − for (const arg of argv) { | |
| 37 | − if (arg === "--dry-run") { | |
| 38 | − options.dryRun = true; | |
| 39 | − continue; | |
| 40 | − } | |
| 41 | − | |
| 42 | − throw new Error(`Unknown argument: ${arg}`); | |
| 43 | − } | |
| 44 | − | |
| 45 | − return options; | |
| 46 | −}; | |
| 47 | − | |
| 48 | −const runCommand = async (input: CommandInput): Promise<CommandOutput> => { | |
| 49 | − const child = spawn(input.command, [...input.args], { | |
| 50 | − cwd: input.cwd, | |
| 51 | − env: process.env, | |
| 52 | − stdio: ["ignore", "pipe", "pipe"], | |
| 53 | − }); | |
| 54 | − | |
| 55 | − let stdout = ""; | |
| 56 | − let stderr = ""; | |
| 57 | − | |
| 58 | − child.stdout?.setEncoding("utf8"); | |
| 59 | − child.stdout?.on("data", (chunk) => { | |
| 60 | − stdout += chunk; | |
| 61 | − }); | |
| 62 | − | |
| 63 | − child.stderr?.setEncoding("utf8"); | |
| 64 | − child.stderr?.on("data", (chunk) => { | |
| 65 | − stderr += chunk; | |
| 66 | − }); | |
| 67 | − | |
| 68 | − const exitCode = await new Promise<number>((resolveExitCode, reject) => { | |
| 69 | − child.once("error", reject); | |
| 70 | − child.once("close", (code) => { | |
| 71 | − resolveExitCode(code ?? -1); | |
| 72 | − }); | |
| 73 | − }); | |
| 74 | − | |
| 75 | − if (exitCode !== 0) { | |
| 76 | − throw new Error( | |
| 77 | − [ | |
| 78 | − `${input.command} ${input.args.join(" ")} exited with code ${exitCode}`, | |
| 79 | − stdout.trim().length > 0 ? `stdout:\n${stdout.trim()}` : null, | |
| 80 | − stderr.trim().length > 0 ? `stderr:\n${stderr.trim()}` : null, | |
| 81 | − ] | |
| 82 | − .filter((part) => part !== null) | |
| 83 | − .join("\n\n"), | |
| 84 | − ); | |
| 85 | − } | |
| 86 | − | |
| 87 | − return { | |
| 88 | − stdout: stdout.trim(), | |
| 89 | − stderr: stderr.trim(), | |
| 90 | − }; | |
| 91 | −}; | |
| 92 | − | |
| 93 | −const resolveTagFromEnvironment = (): string | undefined => { | |
| 94 | − const refName = process.env.GITHUB_REF_NAME?.trim(); | |
| 95 | − if (process.env.GITHUB_REF_TYPE === "tag" && refName) { | |
| 96 | − return refName; | |
| 97 | − } | |
| 98 | − | |
| 99 | − const ref = process.env.GITHUB_REF?.trim(); | |
| 100 | − if (ref?.startsWith("refs/tags/")) { | |
| 101 | − return ref.slice("refs/tags/".length); | |
| 102 | − } | |
| 103 | − | |
| 104 | − return undefined; | |
| 105 | −}; | |
| 106 | − | |
| 107 | −const resolveGitHubRepository = (): string => { | |
| 108 | − const repository = process.env.GH_REPO?.trim() || process.env.GITHUB_REPOSITORY?.trim(); | |
| 109 | − if (!repository) { | |
| 110 | − throw new Error("Set GH_REPO or GITHUB_REPOSITORY before creating a GitHub release."); | |
| 111 | − } | |
| 112 | − | |
| 113 | − return repository; | |
| 114 | −}; | |
| 115 | − | |
| 116 | −const validateVersion = (version: string): void => { | |
| 117 | − if (!semverPattern.test(version)) { | |
| 118 | − throw new Error(`apps/executor/package.json version is not valid semver: ${version}`); | |
| 119 | − } | |
| 120 | −}; | |
| 121 | − | |
| 122 | −const resolveChannel = (version: string): "latest" | "beta" => | |
| 123 | − version.includes("-") ? "beta" : "latest"; | |
| 124 | − | |
| 125 | −const packDistributionPackage = async (releaseDir: string): Promise<string> => { | |
| 126 | − const output = await runCommand({ | |
| 127 | − command: "npm", | |
| 128 | − args: ["pack", "./apps/executor/dist/npm", "--pack-destination", releaseDir, "--json"], | |
| 129 | − cwd: repoRoot, | |
| 130 | − }); | |
| 131 | − const [result] = JSON.parse(output.stdout) as ReadonlyArray<PackResult>; | |
| 132 | − const filename = result?.filename; | |
| 133 | − | |
| 134 | − if (!filename) { | |
| 135 | − throw new Error(`npm pack did not report an output filename. stdout:\n${output.stdout}`); | |
| 136 | − } | |
| 137 | − | |
| 138 | − return join(releaseDir, filename); | |
| 139 | −}; | |
| 140 | − | |
| 141 | −const publishDistributionPackage = async (channel: "latest" | "beta"): Promise<void> => { | |
| 142 | − const args = ["publish", "./dist/npm", "--access", "public", "--tag", channel]; | |
| 143 | − if (process.env.GITHUB_ACTIONS === "true") { | |
| 144 | − args.push("--provenance"); | |
| 145 | − } | |
| 146 | − | |
| 147 | − await runCommand({ | |
| 148 | − command: "npm", | |
| 149 | − args, | |
| 150 | − cwd: resolve(repoRoot, "apps/executor"), | |
| 151 | − }); | |
| 152 | −}; | |
| 153 | − | |
| 154 | −const createGitHubRelease = async (input: { | |
| 155 | − tag: string; | |
| 156 | − channel: "latest" | "beta"; | |
| 157 | − assetPath: string; | |
| 158 | −}): Promise<void> => { | |
| 159 | − if (!process.env.GH_TOKEN?.trim()) { | |
| 160 | − throw new Error("GH_TOKEN is required to create a GitHub release."); | |
| 161 | − } | |
| 162 | − | |
| 163 | − const args = [ | |
| 164 | − "release", | |
| 165 | − "create", | |
| 166 | − input.tag, | |
| 167 | − input.assetPath, | |
| 168 | − "--repo", | |
| 169 | − resolveGitHubRepository(), | |
| 170 | − "--title", | |
| 171 | − input.tag, | |
| 172 | − "--generate-notes", | |
| 173 | − "--verify-tag", | |
| 174 | − ]; | |
| 175 | − | |
| 176 | − if (input.channel === "beta") { | |
| 177 | − args.push("--prerelease"); | |
| 178 | − } else { | |
| 179 | − args.push("--latest"); | |
| 180 | − } | |
| 181 | − | |
| 182 | − await runCommand({ | |
| 183 | − command: "gh", | |
| 184 | − args, | |
| 185 | − cwd: repoRoot, | |
| 186 | − }); | |
| 187 | −}; | |
| 188 | − | |
| 189 | −const main = async () => { | |
| 190 | − const options = parseArgs(process.argv.slice(2)); | |
| 191 | − const metadata = await readDistributionPackageMetadata(); | |
| 192 | − const version = metadata.version; | |
| 193 | − const tag = `v${version}`; | |
| 194 | − const refTag = resolveTagFromEnvironment(); | |
| 195 | − | |
| 196 | − validateVersion(version); | |
| 197 | − | |
| 198 | − if (refTag && refTag !== tag) { | |
| 199 | − throw new Error(`GitHub tag ${refTag} does not match apps/executor/package.json version ${version}`); | |
| 200 | − } | |
| 201 | − | |
| 202 | − const channel = resolveChannel(version); | |
| 203 | − await rm(defaultReleaseDir, { recursive: true, force: true }); | |
| 204 | − await mkdir(defaultReleaseDir, { recursive: true }); | |
| 205 | − | |
| 206 | − await buildDistributionPackage(); | |
| 207 | − const archivePath = await packDistributionPackage(defaultReleaseDir); | |
| 208 | − | |
| 209 | − process.stdout.write(`Prepared executor@${version} for ${channel}\n`); | |
| 210 | − process.stdout.write(`${archivePath}\n`); | |
| 211 | − | |
| 212 | − if (options.dryRun) { | |
| 213 | − return; | |
| 214 | − } | |
| 215 | − | |
| 216 | − await publishDistributionPackage(channel); | |
| 217 | − await createGitHubRelease({ | |
| 218 | − tag, | |
| 219 | − channel, | |
| 220 | − assetPath: archivePath, | |
| 221 | − }); | |
| 222 | −}; | |
| 223 | − | |
| 224 | −await main(); | |
| @@ -1,40 +0,0 @@ | ||
| 1 | −import * as Data from "effect/Data"; | |
| 2 | − | |
| 3 | −export class ExecutorAppEffectError extends Data.TaggedError( | |
| 4 | − "ExecutorAppEffectError", | |
| 5 | −)<{ | |
| 6 | − readonly module: string; | |
| 7 | − readonly message: string; | |
| 8 | −}> {} | |
| 9 | − | |
| 10 | −export const executorAppEffectError = ( | |
| 11 | − module: string, | |
| 12 | − message: string, | |
| 13 | −) => new ExecutorAppEffectError({ module, message }); | |
| 14 | − | |
| 15 | −export class LocalServerReachabilityTimeoutError extends Data.TaggedError( | |
| 16 | − "LocalServerReachabilityTimeoutError", | |
| 17 | −)<{ | |
| 18 | − readonly baseUrl: string; | |
| 19 | − readonly action: "start" | "shutdown"; | |
| 20 | − readonly logFile: string; | |
| 21 | − readonly logTail: string | null; | |
| 22 | − readonly message: string; | |
| 23 | −}> {} | |
| 24 | − | |
| 25 | −export const localServerReachabilityTimeoutError = (input: { | |
| 26 | − baseUrl: string; | |
| 27 | − expected: boolean; | |
| 28 | − logFile: string; | |
| 29 | − logTail: string | null; | |
| 30 | −}) => | |
| 31 | − new LocalServerReachabilityTimeoutError({ | |
| 32 | − baseUrl: input.baseUrl, | |
| 33 | − action: input.expected ? "start" : "shutdown", | |
| 34 | − logFile: input.logFile, | |
| 35 | − logTail: input.logTail, | |
| 36 | − message: | |
| 37 | − input.logTail === null | |
| 38 | − ? `Timed out waiting for local executor server ${input.expected ? "start" : "shutdown"} at ${input.baseUrl}\n\nDaemon log: ${input.logFile}` | |
| 39 | − : `Timed out waiting for local executor server ${input.expected ? "start" : "shutdown"} at ${input.baseUrl}\n\nRecent daemon log (${input.logFile}):\n${input.logTail}`, | |
| 40 | − }); | |
| @@ -1,16 +0,0 @@ | ||
| 1 | −{ | |
| 2 | − "compilerOptions": { | |
| 3 | − "target": "ES2022", | |
| 4 | − "module": "ESNext", | |
| 5 | − "moduleResolution": "Bundler", | |
| 6 | − "strict": true, | |
| 7 | − "skipLibCheck": true, | |
| 8 | − "noEmit": true, | |
| 9 | − "lib": ["ES2022"], | |
| 10 | − "types": ["bun-types", "node"] | |
| 11 | − }, | |
| 12 | − "include": [ | |
| 13 | − "src/**/*.ts", | |
| 14 | − "src/**/*.d.ts" | |
| 15 | − ] | |
| 16 | −} | |
| @@ -0,0 +1,38 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@executor/server", | |
| 3 | + "version": "1.4.0-beta.0", | |
| 4 | + "private": true, | |
| 5 | + "type": "module", | |
| 6 | + "exports": { | |
| 7 | + ".": "./src/index.ts" | |
| 8 | + }, | |
| 9 | + "dependencies": { | |
| 10 | + "@effect/platform": "catalog:", | |
| 11 | + "@effect/platform-node": "catalog:", | |
| 12 | + "@effect/sql": "catalog:", | |
| 13 | + "@effect/sql-sqlite-bun": "catalog:", | |
| 14 | + "@executor/config": "workspace:*", | |
| 15 | + "@executor/api": "workspace:*", | |
| 16 | + "@executor/execution": "workspace:*", | |
| 17 | + "@executor/plugin-file-secrets": "workspace:*", | |
| 18 | + "@executor/plugin-google-discovery": "workspace:*", | |
| 19 | + "@executor/plugin-keychain": "workspace:*", | |
| 20 | + "@executor/plugin-onepassword": "workspace:*", | |
| 21 | + "@executor/plugin-mcp": "workspace:*", | |
| 22 | + "@executor/plugin-graphql": "workspace:*", | |
| 23 | + "@executor/plugin-openapi": "workspace:*", | |
| 24 | + "@executor/sdk": "workspace:*", | |
| 25 | + "@executor/host-mcp": "workspace:*", | |
| 26 | + "@modelcontextprotocol/sdk": "^1.12.1", | |
| 27 | + "@executor/storage-file": "workspace:*", | |
| 28 | + "effect": "catalog:" | |
| 29 | + }, | |
| 30 | + "devDependencies": { | |
| 31 | + "@types/node": "catalog:", | |
| 32 | + "bun-types": "catalog:", | |
| 33 | + "typescript": "^5.9.3" | |
| 34 | + }, | |
| 35 | + "scripts": { | |
| 36 | + "typecheck": "tsc --noEmit" | |
| 37 | + } | |
| 38 | +} | |
| @@ -0,0 +1,20 @@ | ||
| 1 | +import { createServerHandlersWithExecutor, type ServerHandlers } from "./main"; | |
| 2 | +import { createServerExecutorHandle } from "./services/executor"; | |
| 3 | + | |
| 4 | +export type HotBackend = ServerHandlers & { | |
| 5 | + readonly dispose: () => Promise<void>; | |
| 6 | +}; | |
| 7 | + | |
| 8 | +export const createHotBackend = async (): Promise<HotBackend> => { | |
| 9 | + const handle = await createServerExecutorHandle(); | |
| 10 | + const handlers = await createServerHandlersWithExecutor(handle.executor); | |
| 11 | + | |
| 12 | + return { | |
| 13 | + ...handlers, | |
| 14 | + dispose: async () => { | |
| 15 | + await handlers.api.dispose().catch(() => undefined); | |
| 16 | + await handlers.mcp.close().catch(() => undefined); | |
| 17 | + await handle.dispose(); | |
| 18 | + }, | |
| 19 | + }; | |
| 20 | +}; | |
| @@ -0,0 +1,67 @@ | ||
| 1 | +import { HttpApiBuilder } from "@effect/platform"; | |
| 2 | +import { Effect } from "effect"; | |
| 3 | + | |
| 4 | +import { ExecutorApi } from "@executor/api"; | |
| 5 | +import { | |
| 6 | + formatExecuteResult, | |
| 7 | + formatPausedExecution, | |
| 8 | + type ExecutionEngine, | |
| 9 | +} from "@executor/execution"; | |
| 10 | +import { ExecutionEngineService } from "../services/engine"; | |
| 11 | + | |
| 12 | +export const ExecutionsHandlers = HttpApiBuilder.group( | |
| 13 | + ExecutorApi, | |
| 14 | + "executions", | |
| 15 | + (handlers) => | |
| 16 | + handlers | |
| 17 | + .handle("execute", ({ payload }) => | |
| 18 | + Effect.gen(function* () { | |
| 19 | + const engine = yield* ExecutionEngineService; | |
| 20 | + const outcome = yield* Effect.promise(() => | |
| 21 | + engine.executeWithPause(payload.code), | |
| 22 | + ); | |
| 23 | + | |
| 24 | + if (outcome.status === "completed") { | |
| 25 | + const formatted = formatExecuteResult(outcome.result); | |
| 26 | + return { | |
| 27 | + status: "completed" as const, | |
| 28 | + text: formatted.text, | |
| 29 | + structured: formatted.structured, | |
| 30 | + isError: formatted.isError, | |
| 31 | + }; | |
| 32 | + } | |
| 33 | + | |
| 34 | + const formatted = formatPausedExecution(outcome.execution); | |
| 35 | + return { | |
| 36 | + status: "paused" as const, | |
| 37 | + text: formatted.text, | |
| 38 | + structured: formatted.structured, | |
| 39 | + }; | |
| 40 | + }), | |
| 41 | + ) | |
| 42 | + .handle("resume", ({ path, payload }) => | |
| 43 | + Effect.gen(function* () { | |
| 44 | + const engine = yield* ExecutionEngineService; | |
| 45 | + const result = yield* Effect.promise(() => | |
| 46 | + engine.resume(path.executionId, { | |
| 47 | + action: payload.action, | |
| 48 | + content: payload.content as Record<string, unknown> | undefined, | |
| 49 | + }), | |
| 50 | + ); | |
| 51 | + | |
| 52 | + if (!result) { | |
| 53 | + return yield* Effect.fail({ | |
| 54 | + _tag: "ExecutionNotFoundError" as const, | |
| 55 | + executionId: path.executionId, | |
| 56 | + }); | |
| 57 | + } | |
| 58 | + | |
| 59 | + const formatted = formatExecuteResult(result); | |
| 60 | + return { | |
| 61 | + text: formatted.text, | |
| 62 | + structured: formatted.structured, | |
| 63 | + isError: formatted.isError, | |
| 64 | + }; | |
| 65 | + }), | |
| 66 | + ), | |
| 67 | +); | |
| @@ -0,0 +1,16 @@ | ||
| 1 | +import { Effect, Layer } from "effect"; | |
| 2 | +import { | |
| 3 | + GoogleDiscoveryExtensionService, | |
| 4 | + GoogleDiscoveryHandlers, | |
| 5 | +} from "@executor/plugin-google-discovery/api"; | |
| 6 | +import { ExecutorService } from "../services/executor"; | |
| 7 | + | |
| 8 | +const GoogleDiscoveryExtensionLive = Layer.effect( | |
| 9 | + GoogleDiscoveryExtensionService, | |
| 10 | + Effect.map(ExecutorService, (executor) => executor.googleDiscovery), | |
| 11 | +); | |
| 12 | + | |
| 13 | +export const GoogleDiscoveryHandlersLive = Layer.provide( | |
| 14 | + GoogleDiscoveryHandlers, | |
| 15 | + GoogleDiscoveryExtensionLive, | |
| 16 | +); | |
| @@ -0,0 +1,17 @@ | ||
| 1 | +import { Effect, Layer } from "effect"; | |
| 2 | +import { | |
| 3 | + GraphqlHandlers, | |
| 4 | + GraphqlExtensionService, | |
| 5 | +} from "@executor/plugin-graphql/api"; | |
| 6 | +import { ExecutorService } from "../services/executor"; | |
| 7 | + | |
| 8 | +// Wire GraphqlExtensionService from the executor's graphql extension | |
| 9 | +const GraphqlExtensionLive = Layer.effect( | |
| 10 | + GraphqlExtensionService, | |
| 11 | + Effect.map(ExecutorService, (executor) => executor.graphql), | |
| 12 | +); | |
| 13 | + | |
| 14 | +export const GraphqlHandlersLive = Layer.provide( | |
| 15 | + GraphqlHandlers, | |
| 16 | + GraphqlExtensionLive, | |
| 17 | +); | |
| @@ -0,0 +1,17 @@ | ||
| 1 | +import { Effect, Layer } from "effect"; | |
| 2 | +import { | |
| 3 | + McpHandlers, | |
| 4 | + McpExtensionService, | |
| 5 | +} from "@executor/plugin-mcp/api"; | |
| 6 | +import { ExecutorService } from "../services/executor"; | |
| 7 | + | |
| 8 | +// Wire McpExtensionService from the executor's mcp extension | |
| 9 | +const McpExtensionLive = Layer.effect( | |
| 10 | + McpExtensionService, | |
| 11 | + Effect.map(ExecutorService, (executor) => executor.mcp), | |
| 12 | +); | |
| 13 | + | |
| 14 | +export const McpSourceHandlersLive = Layer.provide( | |
| 15 | + McpHandlers, | |
| 16 | + McpExtensionLive, | |
| 17 | +); | |
| @@ -0,0 +1,17 @@ | ||
| 1 | +import { Effect, Layer } from "effect"; | |
| 2 | +import { | |
| 3 | + OnePasswordHandlers, | |
| 4 | + OnePasswordExtensionService, | |
| 5 | +} from "@executor/plugin-onepassword/api"; | |
| 6 | +import { ExecutorService } from "../services/executor"; | |
| 7 | + | |
| 8 | +// Wire OnePasswordExtensionService from the executor's onepassword extension | |
| 9 | +const OnePasswordExtensionLive = Layer.effect( | |
| 10 | + OnePasswordExtensionService, | |
| 11 | + Effect.map(ExecutorService, (executor) => executor.onepassword), | |
| 12 | +); | |
| 13 | + | |
| 14 | +export const OnePasswordHandlersLive = Layer.provide( | |
| 15 | + OnePasswordHandlers, | |
| 16 | + OnePasswordExtensionLive, | |
| 17 | +); | |
| @@ -0,0 +1,17 @@ | ||
| 1 | +import { Effect, Layer } from "effect"; | |
| 2 | +import { | |
| 3 | + OpenApiHandlers, | |
| 4 | + OpenApiExtensionService, | |
| 5 | +} from "@executor/plugin-openapi/api"; | |
| 6 | +import { ExecutorService } from "../services/executor"; | |
| 7 | + | |
| 8 | +// Wire OpenApiExtensionService from the executor's openapi extension | |
| 9 | +const OpenApiExtensionLive = Layer.effect( | |
| 10 | + OpenApiExtensionService, | |
| 11 | + Effect.map(ExecutorService, (executor) => executor.openapi), | |
| 12 | +); | |
| 13 | + | |
| 14 | +export const OpenApiHandlersLive = Layer.provide( | |
| 15 | + OpenApiHandlers, | |
| 16 | + OpenApiExtensionLive, | |
| 17 | +); | |
| @@ -0,0 +1,20 @@ | ||
| 1 | +import { HttpApiBuilder } from "@effect/platform"; | |
| 2 | +import { Effect } from "effect"; | |
| 3 | + | |
| 4 | +import { ExecutorApi } from "@executor/api"; | |
| 5 | +import { ExecutorService } from "../services/executor"; | |
| 6 | + | |
| 7 | +export const ScopeHandlers = HttpApiBuilder.group( | |
| 8 | + ExecutorApi, | |
| 9 | + "scope", | |
| 10 | + (handlers) => | |
| 11 | + handlers.handle("info", () => | |
| 12 | + Effect.gen(function* () { | |
| 13 | + const executor = yield* ExecutorService; | |
| 14 | + return { | |
| 15 | + id: executor.scope.id, | |
| 16 | + name: executor.scope.name, | |
| 17 | + }; | |
| 18 | + }), | |
| 19 | + ), | |
| 20 | +); | |
| @@ -0,0 +1,70 @@ | ||
| 1 | +import { HttpApiBuilder } from "@effect/platform"; | |
| 2 | +import { Effect, Option } from "effect"; | |
| 3 | +import type { SecretId, ScopeId } from "@executor/sdk"; | |
| 4 | + | |
| 5 | +import { ExecutorApi } from "@executor/api"; | |
| 6 | +import { ExecutorService } from "../services/executor"; | |
| 7 | + | |
| 8 | +const refToResponse = (ref: { | |
| 9 | + id: SecretId; | |
| 10 | + scopeId: ScopeId; | |
| 11 | + name: string; | |
| 12 | + provider: Option.Option<string>; | |
| 13 | + purpose?: string; | |
| 14 | + createdAt: Date; | |
| 15 | +}) => ({ | |
| 16 | + id: ref.id, | |
| 17 | + scopeId: ref.scopeId, | |
| 18 | + name: ref.name, | |
| 19 | + provider: Option.getOrUndefined(ref.provider), | |
| 20 | + purpose: ref.purpose, | |
| 21 | + createdAt: ref.createdAt.getTime(), | |
| 22 | +}); | |
| 23 | + | |
| 24 | +export const SecretsHandlers = HttpApiBuilder.group( | |
| 25 | + ExecutorApi, | |
| 26 | + "secrets", | |
| 27 | + (handlers) => | |
| 28 | + handlers | |
| 29 | + .handle("list", ({ path }) => | |
| 30 | + Effect.gen(function* () { | |
| 31 | + const executor = yield* ExecutorService; | |
| 32 | + const refs = yield* executor.secrets.list(); | |
| 33 | + return refs.map(refToResponse); | |
| 34 | + }), | |
| 35 | + ) | |
| 36 | + .handle("status", ({ path }) => | |
| 37 | + Effect.gen(function* () { | |
| 38 | + const executor = yield* ExecutorService; | |
| 39 | + const status = yield* executor.secrets.status(path.secretId); | |
| 40 | + return { secretId: path.secretId, status }; | |
| 41 | + }), | |
| 42 | + ) | |
| 43 | + .handle("set", ({ path, payload }) => | |
| 44 | + Effect.gen(function* () { | |
| 45 | + const executor = yield* ExecutorService; | |
| 46 | + const ref = yield* executor.secrets.set({ | |
| 47 | + id: payload.id, | |
| 48 | + name: payload.name, | |
| 49 | + value: payload.value, | |
| 50 | + purpose: payload.purpose, | |
| 51 | + provider: payload.provider, | |
| 52 | + }); | |
| 53 | + return refToResponse(ref); | |
| 54 | + }), | |
| 55 | + ) | |
| 56 | + .handle("resolve", ({ path }) => | |
| 57 | + Effect.gen(function* () { | |
| 58 | + const executor = yield* ExecutorService; | |
| 59 | + const value = yield* executor.secrets.resolve(path.secretId); | |
| 60 | + return { secretId: path.secretId, value }; | |
| 61 | + }), | |
| 62 | + ) | |
| 63 | + .handle("remove", ({ path }) => | |
| 64 | + Effect.gen(function* () { | |
| 65 | + const executor = yield* ExecutorService; | |
| 66 | + const removed = yield* executor.secrets.remove(path.secretId); | |
| 67 | + return { removed }; | |
| 68 | + }), | |
| 69 | + ), | |
| 70 | +); | |
| @@ -0,0 +1,67 @@ | ||
| 1 | +import { HttpApiBuilder } from "@effect/platform"; | |
| 2 | +import { Effect } from "effect"; | |
| 3 | + | |
| 4 | +import { ExecutorApi } from "@executor/api"; | |
| 5 | +import { ExecutorService } from "../services/executor"; | |
| 6 | + | |
| 7 | +export const SourcesHandlers = HttpApiBuilder.group( | |
| 8 | + ExecutorApi, | |
| 9 | + "sources", | |
| 10 | + (handlers) => | |
| 11 | + handlers | |
| 12 | + .handle("list", ({ path }) => | |
| 13 | + Effect.gen(function* () { | |
| 14 | + const executor = yield* ExecutorService; | |
| 15 | + const sources = yield* executor.sources.list(); | |
| 16 | + return sources.map((s) => ({ | |
| 17 | + id: s.id, | |
| 18 | + name: s.name, | |
| 19 | + kind: s.kind, | |
| 20 | + runtime: s.runtime, | |
| 21 | + canRemove: s.canRemove, | |
| 22 | + canRefresh: s.canRefresh, | |
| 23 | + })); | |
| 24 | + }), | |
| 25 | + ) | |
| 26 | + .handle("remove", ({ path }) => | |
| 27 | + Effect.gen(function* () { | |
| 28 | + const executor = yield* ExecutorService; | |
| 29 | + yield* executor.sources.remove(path.sourceId); | |
| 30 | + return { removed: true }; | |
| 31 | + }), | |
| 32 | + ) | |
| 33 | + .handle("refresh", ({ path }) => | |
| 34 | + Effect.gen(function* () { | |
| 35 | + const executor = yield* ExecutorService; | |
| 36 | + yield* executor.sources.refresh(path.sourceId); | |
| 37 | + return { refreshed: true }; | |
| 38 | + }), | |
| 39 | + ) | |
| 40 | + .handle("tools", ({ path }) => | |
| 41 | + Effect.gen(function* () { | |
| 42 | + const executor = yield* ExecutorService; | |
| 43 | + const tools = yield* executor.tools.list({ sourceId: path.sourceId }); | |
| 44 | + return tools.map((t) => ({ | |
| 45 | + id: t.id, | |
| 46 | + pluginKey: t.pluginKey, | |
| 47 | + sourceId: t.sourceId, | |
| 48 | + name: t.name, | |
| 49 | + description: t.description, | |
| 50 | + mayElicit: t.mayElicit, | |
| 51 | + })); | |
| 52 | + }), | |
| 53 | + ) | |
| 54 | + .handle("detect", ({ path, payload }) => | |
| 55 | + Effect.gen(function* () { | |
| 56 | + const executor = yield* ExecutorService; | |
| 57 | + const results = yield* executor.sources.detect(payload.url); | |
| 58 | + return results.map((r) => ({ | |
| 59 | + kind: r.kind, | |
| 60 | + confidence: r.confidence, | |
| 61 | + endpoint: r.endpoint, | |
| 62 | + name: r.name, | |
| 63 | + namespace: r.namespace, | |
| 64 | + })); | |
| 65 | + }), | |
| 66 | + ), | |
| 67 | +); | |
| @@ -0,0 +1,32 @@ | ||
| 1 | +import { HttpApiBuilder } from "@effect/platform"; | |
| 2 | +import { Effect } from "effect"; | |
| 3 | + | |
| 4 | +import { ExecutorApi } from "@executor/api"; | |
| 5 | +import { ExecutorService } from "../services/executor"; | |
| 6 | + | |
| 7 | +export const ToolsHandlers = HttpApiBuilder.group( | |
| 8 | + ExecutorApi, | |
| 9 | + "tools", | |
| 10 | + (handlers) => | |
| 11 | + handlers | |
| 12 | + .handle("list", ({ path }) => | |
| 13 | + Effect.gen(function* () { | |
| 14 | + const executor = yield* ExecutorService; | |
| 15 | + const tools = yield* executor.tools.list(); | |
| 16 | + return tools.map((t) => ({ | |
| 17 | + id: t.id, | |
| 18 | + pluginKey: t.pluginKey, | |
| 19 | + sourceId: t.sourceId, | |
| 20 | + name: t.name, | |
| 21 | + description: t.description, | |
| 22 | + mayElicit: t.mayElicit, | |
| 23 | + })); | |
| 24 | + }), | |
| 25 | + ) | |
| 26 | + .handle("schema", ({ path }) => | |
| 27 | + Effect.gen(function* () { | |
| 28 | + const executor = yield* ExecutorService; | |
| 29 | + return yield* executor.tools.schema(path.toolId); | |
| 30 | + }), | |
| 31 | + ), | |
| 32 | +); | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +export { createApiHandler, createServerHandlers, type ApiHandler, type ServerHandlers, ApiLayer } from "./main"; | |
| 2 | +export { createServerHandlersWithExecutor } from "./main"; | |
| 3 | +export { ExecutorServiceLayer, createServerExecutorHandle, disposeExecutor, getExecutor, reloadExecutor } from "./services/executor"; | |
| 4 | +export { createMcpRequestHandler, runMcpStdioServer, type McpRequestHandler } from "./mcp"; | |
| @@ -0,0 +1,128 @@ | ||
| 1 | +import { | |
| 2 | + HttpApiBuilder, | |
| 3 | + HttpApiSwagger, | |
| 4 | + HttpMiddleware, | |
| 5 | + HttpServer, | |
| 6 | +} from "@effect/platform"; | |
| 7 | +import { Effect, Layer } from "effect"; | |
| 8 | + | |
| 9 | +import { addGroup } from "@executor/api"; | |
| 10 | +import { createExecutionEngine } from "@executor/execution"; | |
| 11 | +import { OpenApiGroup } from "@executor/plugin-openapi/api"; | |
| 12 | +import { McpGroup } from "@executor/plugin-mcp/api"; | |
| 13 | +import { GoogleDiscoveryGroup } from "@executor/plugin-google-discovery/api"; | |
| 14 | +import { OnePasswordGroup } from "@executor/plugin-onepassword/api"; | |
| 15 | +import { GraphqlGroup } from "@executor/plugin-graphql/api"; | |
| 16 | +import { ToolsHandlers } from "./handlers/tools"; | |
| 17 | +import { SourcesHandlers } from "./handlers/sources"; | |
| 18 | +import { SecretsHandlers } from "./handlers/secrets"; | |
| 19 | +import { ExecutionsHandlers } from "./handlers/executions"; | |
| 20 | +import { ScopeHandlers } from "./handlers/scope"; | |
| 21 | +import { OpenApiHandlersLive } from "./handlers/openapi"; | |
| 22 | +import { McpSourceHandlersLive } from "./handlers/mcp-source"; | |
| 23 | +import { GoogleDiscoveryHandlersLive } from "./handlers/google-discovery"; | |
| 24 | +import { OnePasswordHandlersLive } from "./handlers/onepassword"; | |
| 25 | +import { GraphqlHandlersLive } from "./handlers/graphql"; | |
| 26 | +import { ExecutorService, ExecutorServiceLayer, getExecutor, type ServerExecutor } from "./services/executor"; | |
| 27 | +import { ExecutionEngineService } from "./services/engine"; | |
| 28 | +import { createMcpRequestHandler, type McpRequestHandler } from "./mcp"; | |
| 29 | + | |
| 30 | +// --------------------------------------------------------------------------- | |
| 31 | +// Composed API — core + plugin groups | |
| 32 | +// --------------------------------------------------------------------------- | |
| 33 | + | |
| 34 | +const ExecutorApiWithPlugins = addGroup(OpenApiGroup) | |
| 35 | + .add(McpGroup) | |
| 36 | + .add(GoogleDiscoveryGroup) | |
| 37 | + .add(OnePasswordGroup) | |
| 38 | + .add(GraphqlGroup); | |
| 39 | + | |
| 40 | +// --------------------------------------------------------------------------- | |
| 41 | +// API Layer | |
| 42 | +// --------------------------------------------------------------------------- | |
| 43 | + | |
| 44 | +const ApiBase = HttpApiBuilder.api(ExecutorApiWithPlugins).pipe( | |
| 45 | + Layer.provide([ | |
| 46 | + ToolsHandlers, | |
| 47 | + SourcesHandlers, | |
| 48 | + SecretsHandlers, | |
| 49 | + ExecutionsHandlers, | |
| 50 | + ScopeHandlers, | |
| 51 | + OpenApiHandlersLive, | |
| 52 | + McpSourceHandlersLive, | |
| 53 | + GoogleDiscoveryHandlersLive, | |
| 54 | + OnePasswordHandlersLive, | |
| 55 | + GraphqlHandlersLive, | |
| 56 | + ]), | |
| 57 | +); | |
| 58 | + | |
| 59 | +// --------------------------------------------------------------------------- | |
| 60 | +// Composable API layer — for use with Effect platform HTTP servers | |
| 61 | +// --------------------------------------------------------------------------- | |
| 62 | + | |
| 63 | +export const ApiLayer = HttpApiSwagger.layer().pipe( | |
| 64 | + Layer.provideMerge(HttpApiBuilder.middlewareOpenApi()), | |
| 65 | + Layer.provideMerge(ApiBase), | |
| 66 | +); | |
| 67 | + | |
| 68 | +// --------------------------------------------------------------------------- | |
| 69 | +// Shared server — API + MCP from the same executor + engine instance | |
| 70 | +// --------------------------------------------------------------------------- | |
| 71 | + | |
| 72 | +export type ServerHandlers = { | |
| 73 | + readonly api: { | |
| 74 | + readonly handler: (request: Request) => Promise<Response>; | |
| 75 | + readonly dispose: () => Promise<void>; | |
| 76 | + }; | |
| 77 | + readonly mcp: McpRequestHandler; | |
| 78 | +}; | |
| 79 | + | |
| 80 | +const createApiHandlerWithExecutor = (executor: ServerExecutor, engine: ReturnType<typeof createExecutionEngine>) => | |
| 81 | + HttpApiBuilder.toWebHandler( | |
| 82 | + HttpApiSwagger.layer().pipe( | |
| 83 | + Layer.provideMerge(HttpApiBuilder.middlewareOpenApi()), | |
| 84 | + Layer.provideMerge(ApiBase), | |
| 85 | + Layer.provideMerge(Layer.succeed(ExecutorService, executor)), | |
| 86 | + Layer.provideMerge(Layer.succeed(ExecutionEngineService, engine)), | |
| 87 | + Layer.provideMerge(HttpServer.layerContext), | |
| 88 | + ), | |
| 89 | + { middleware: HttpMiddleware.logger }, | |
| 90 | + ); | |
| 91 | + | |
| 92 | +export const createServerHandlersWithExecutor = async ( | |
| 93 | + executor: ServerExecutor, | |
| 94 | +): Promise<ServerHandlers> => { | |
| 95 | + const engine = createExecutionEngine({ executor }); | |
| 96 | + const api = createApiHandlerWithExecutor(executor, engine); | |
| 97 | + const mcp = createMcpRequestHandler({ engine }); | |
| 98 | + | |
| 99 | + return { api, mcp }; | |
| 100 | +}; | |
| 101 | + | |
| 102 | +export const createServerHandlers = async (): Promise<ServerHandlers> => | |
| 103 | + createServerHandlersWithExecutor(await getExecutor()); | |
| 104 | + | |
| 105 | +// --------------------------------------------------------------------------- | |
| 106 | +// Backwards compat — standalone API handler (no MCP) | |
| 107 | +// --------------------------------------------------------------------------- | |
| 108 | + | |
| 109 | +const ExecutionEngineLayer = Layer.effect( | |
| 110 | + ExecutionEngineService, | |
| 111 | + Effect.map(ExecutorService, (executor) => createExecutionEngine({ executor })), | |
| 112 | +); | |
| 113 | + | |
| 114 | +export const createApiHandler = () => | |
| 115 | + HttpApiBuilder.toWebHandler( | |
| 116 | + HttpApiSwagger.layer().pipe( | |
| 117 | + Layer.provideMerge(HttpApiBuilder.middlewareOpenApi()), | |
| 118 | + Layer.provideMerge(ApiBase), | |
| 119 | + Layer.provideMerge(ExecutionEngineLayer), | |
| 120 | + Layer.provideMerge(ExecutorServiceLayer), | |
| 121 | + Layer.provideMerge(HttpServer.layerContext), | |
| 122 | + ), | |
| 123 | + { middleware: HttpMiddleware.logger }, | |
| 124 | + ); | |
| 125 | + | |
| 126 | +export type ApiHandler = ReturnType<typeof createApiHandler>; | |
| 127 | + | |
| 128 | +export { ExecutorServiceLayer } from "./services/executor"; | |
| @@ -0,0 +1,122 @@ | ||
| 1 | +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | |
| 2 | +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; | |
| 3 | +import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js"; | |
| 4 | + | |
| 5 | +import { createExecutorMcpServer, type ExecutorMcpServerConfig } from "@executor/host-mcp"; | |
| 6 | + | |
| 7 | +// --------------------------------------------------------------------------- | |
| 8 | +// Streamable HTTP handler | |
| 9 | +// --------------------------------------------------------------------------- | |
| 10 | + | |
| 11 | +export type McpRequestHandler = { | |
| 12 | + readonly handleRequest: (request: Request) => Promise<Response>; | |
| 13 | + readonly close: () => Promise<void>; | |
| 14 | +}; | |
| 15 | + | |
| 16 | +const jsonError = (status: number, code: number, message: string): Response => | |
| 17 | + new Response( | |
| 18 | + JSON.stringify({ jsonrpc: "2.0", error: { code, message }, id: null }), | |
| 19 | + { status, headers: { "content-type": "application/json" } }, | |
| 20 | + ); | |
| 21 | + | |
| 22 | +export const createMcpRequestHandler = ( | |
| 23 | + config: ExecutorMcpServerConfig, | |
| 24 | +): McpRequestHandler => { | |
| 25 | + const transports = new Map<string, WebStandardStreamableHTTPServerTransport>(); | |
| 26 | + const servers = new Map<string, McpServer>(); | |
| 27 | + | |
| 28 | + const dispose = async ( | |
| 29 | + id: string, | |
| 30 | + opts: { transport?: boolean; server?: boolean } = {}, | |
| 31 | + ) => { | |
| 32 | + const t = transports.get(id); | |
| 33 | + const s = servers.get(id); | |
| 34 | + transports.delete(id); | |
| 35 | + servers.delete(id); | |
| 36 | + if (opts.transport) await t?.close().catch(() => undefined); | |
| 37 | + if (opts.server) await s?.close().catch(() => undefined); | |
| 38 | + }; | |
| 39 | + | |
| 40 | + return { | |
| 41 | + handleRequest: async (request) => { | |
| 42 | + const sessionId = request.headers.get("mcp-session-id"); | |
| 43 | + | |
| 44 | + if (sessionId) { | |
| 45 | + const transport = transports.get(sessionId); | |
| 46 | + if (!transport) return jsonError(404, -32001, "Session not found"); | |
| 47 | + return transport.handleRequest(request); | |
| 48 | + } | |
| 49 | + | |
| 50 | + let created: McpServer | undefined; | |
| 51 | + const transport = new WebStandardStreamableHTTPServerTransport({ | |
| 52 | + sessionIdGenerator: () => crypto.randomUUID(), | |
| 53 | + enableJsonResponse: true, | |
| 54 | + onsessioninitialized: (sid) => { | |
| 55 | + transports.set(sid, transport); | |
| 56 | + if (created) servers.set(sid, created); | |
| 57 | + }, | |
| 58 | + onsessionclosed: (sid) => void dispose(sid, { server: true }), | |
| 59 | + }); | |
| 60 | + | |
| 61 | + transport.onclose = () => { | |
| 62 | + const sid = transport.sessionId; | |
| 63 | + if (sid) void dispose(sid, { server: true }); | |
| 64 | + }; | |
| 65 | + | |
| 66 | + try { | |
| 67 | + created = await createExecutorMcpServer(config); | |
| 68 | + await created.connect(transport); | |
| 69 | + const response = await transport.handleRequest(request); | |
| 70 | + | |
| 71 | + if (!transport.sessionId) { | |
| 72 | + await transport.close().catch(() => undefined); | |
| 73 | + await created.close().catch(() => undefined); | |
| 74 | + } | |
| 75 | + return response; | |
| 76 | + } catch (error) { | |
| 77 | + if (!transport.sessionId) { | |
| 78 | + await transport.close().catch(() => undefined); | |
| 79 | + await created?.close().catch(() => undefined); | |
| 80 | + } | |
| 81 | + return jsonError(500, -32603, error instanceof Error ? error.message : "Internal server error"); | |
| 82 | + } | |
| 83 | + }, | |
| 84 | + | |
| 85 | + close: async () => { | |
| 86 | + const ids = new Set([...transports.keys(), ...servers.keys()]); | |
| 87 | + await Promise.all([...ids].map((id) => dispose(id, { transport: true, server: true }))); | |
| 88 | + }, | |
| 89 | + }; | |
| 90 | +}; | |
| 91 | + | |
| 92 | +// --------------------------------------------------------------------------- | |
| 93 | +// Stdio transport | |
| 94 | +// --------------------------------------------------------------------------- | |
| 95 | + | |
| 96 | +export const runMcpStdioServer = async (config: ExecutorMcpServerConfig): Promise<void> => { | |
| 97 | + const server = await createExecutorMcpServer(config); | |
| 98 | + const transport = new StdioServerTransport(); | |
| 99 | + | |
| 100 | + const waitForExit = () => | |
| 101 | + new Promise<void>((resolve) => { | |
| 102 | + const finish = () => { | |
| 103 | + process.off("SIGINT", finish); | |
| 104 | + process.off("SIGTERM", finish); | |
| 105 | + process.stdin.off("end", finish); | |
| 106 | + process.stdin.off("close", finish); | |
| 107 | + resolve(); | |
| 108 | + }; | |
| 109 | + process.once("SIGINT", finish); | |
| 110 | + process.once("SIGTERM", finish); | |
| 111 | + process.stdin.once("end", finish); | |
| 112 | + process.stdin.once("close", finish); | |
| 113 | + }); | |
| 114 | + | |
| 115 | + try { | |
| 116 | + await server.connect(transport); | |
| 117 | + await waitForExit(); | |
| 118 | + } finally { | |
| 119 | + await transport.close().catch(() => undefined); | |
| 120 | + await server.close().catch(() => undefined); | |
| 121 | + } | |
| 122 | +}; | |
| @@ -0,0 +1,7 @@ | ||
| 1 | +import { Context } from "effect"; | |
| 2 | +import type { ExecutionEngine } from "@executor/execution"; | |
| 3 | + | |
| 4 | +export class ExecutionEngineService extends Context.Tag("ExecutionEngineService")< | |
| 5 | + ExecutionEngineService, | |
| 6 | + ExecutionEngine | |
| 7 | +>() {} | |
| @@ -0,0 +1,205 @@ | ||
| 1 | +import { Context, Effect, Layer, ManagedRuntime } from "effect"; | |
| 2 | +import { SqliteClient } from "@effect/sql-sqlite-bun"; | |
| 3 | +import * as SqlClient from "@effect/sql/SqlClient"; | |
| 4 | +import { NodeFileSystem } from "@effect/platform-node"; | |
| 5 | +import * as fs from "node:fs"; | |
| 6 | + | |
| 7 | +import { createExecutor, scopeKv } from "@executor/sdk"; | |
| 8 | +import { | |
| 9 | + makeSqliteKv, | |
| 10 | + makeKvConfig, | |
| 11 | + makeScopedKv, | |
| 12 | + migrate, | |
| 13 | +} from "@executor/storage-file"; | |
| 14 | +import { withConfigFile } from "@executor/config"; | |
| 15 | +import { | |
| 16 | + openApiPlugin, | |
| 17 | + makeKvOperationStore, | |
| 18 | + type OpenApiPluginExtension, | |
| 19 | +} from "@executor/plugin-openapi"; | |
| 20 | +import { | |
| 21 | + mcpPlugin, | |
| 22 | + makeKvBindingStore, | |
| 23 | + type McpPluginExtension, | |
| 24 | +} from "@executor/plugin-mcp"; | |
| 25 | +import { | |
| 26 | + googleDiscoveryPlugin, | |
| 27 | + makeKvBindingStore as makeKvGoogleDiscoveryBindingStore, | |
| 28 | + type GoogleDiscoveryPluginExtension, | |
| 29 | +} from "@executor/plugin-google-discovery"; | |
| 30 | +import { | |
| 31 | + graphqlPlugin, | |
| 32 | + makeKvOperationStore as makeKvGraphqlOperationStore, | |
| 33 | + type GraphqlPluginExtension, | |
| 34 | +} from "@executor/plugin-graphql"; | |
| 35 | +import { keychainPlugin } from "@executor/plugin-keychain"; | |
| 36 | +import { fileSecretsPlugin } from "@executor/plugin-file-secrets"; | |
| 37 | +import { | |
| 38 | + onepasswordPlugin, | |
| 39 | + type OnePasswordExtension, | |
| 40 | +} from "@executor/plugin-onepassword"; | |
| 41 | + | |
| 42 | +import type { Executor, ExecutorPlugin } from "@executor/sdk"; | |
| 43 | + | |
| 44 | +type ServerPlugins = readonly [ | |
| 45 | + ExecutorPlugin<"openapi", OpenApiPluginExtension>, | |
| 46 | + ExecutorPlugin<"mcp", McpPluginExtension>, | |
| 47 | + ExecutorPlugin<"googleDiscovery", GoogleDiscoveryPluginExtension>, | |
| 48 | + ExecutorPlugin<"graphql", GraphqlPluginExtension>, | |
| 49 | + ReturnType<typeof fileSecretsPlugin>, | |
| 50 | + ExecutorPlugin<"onepassword", OnePasswordExtension>, | |
| 51 | +]; | |
| 52 | +export type ServerExecutor = Executor<ServerPlugins>; | |
| 53 | +export type ServerExecutorHandle = { | |
| 54 | + readonly executor: ServerExecutor; | |
| 55 | + readonly dispose: () => Promise<void>; | |
| 56 | +}; | |
| 57 | + | |
| 58 | +// --------------------------------------------------------------------------- | |
| 59 | +// Service tag | |
| 60 | +// --------------------------------------------------------------------------- | |
| 61 | + | |
| 62 | +export class ExecutorService extends Context.Tag("ExecutorService")< | |
| 63 | + ExecutorService, | |
| 64 | + ServerExecutor | |
| 65 | +>() {} | |
| 66 | + | |
| 67 | +// --------------------------------------------------------------------------- | |
| 68 | +// Data directory | |
| 69 | +// --------------------------------------------------------------------------- | |
| 70 | + | |
| 71 | +import { homedir } from "node:os"; | |
| 72 | +import { join } from "node:path"; | |
| 73 | + | |
| 74 | +const resolveDataDir = (): string => { | |
| 75 | + if (process.env.EXECUTOR_DATA_DIR) return process.env.EXECUTOR_DATA_DIR; | |
| 76 | + return join(homedir(), ".executor"); | |
| 77 | +}; | |
| 78 | + | |
| 79 | +const DATA_DIR = resolveDataDir(); | |
| 80 | + | |
| 81 | +fs.mkdirSync(DATA_DIR, { recursive: true }); | |
| 82 | + | |
| 83 | +const DB_PATH = `${DATA_DIR}/data.db`; | |
| 84 | + | |
| 85 | +// --------------------------------------------------------------------------- | |
| 86 | +// Executor Layer — SQLite-backed, scoped to ManagedRuntime lifetime | |
| 87 | +// --------------------------------------------------------------------------- | |
| 88 | + | |
| 89 | +const ExecutorLayer = Layer.effect( | |
| 90 | + ExecutorService, | |
| 91 | + Effect.gen(function* () { | |
| 92 | + const sql = yield* SqlClient.SqlClient; | |
| 93 | + | |
| 94 | + yield* migrate.pipe(Effect.catchAll((e) => Effect.die(e))); | |
| 95 | + | |
| 96 | + const cwd = process.cwd(); | |
| 97 | + const kv = makeSqliteKv(sql); | |
| 98 | + const config = makeKvConfig(kv, { cwd }); | |
| 99 | + const scopedKv = makeScopedKv(kv, cwd); | |
| 100 | + | |
| 101 | + const configPath = join(process.cwd(), "executor.jsonc"); | |
| 102 | + const fsLayer = NodeFileSystem.layer; | |
| 103 | + | |
| 104 | + return yield* createExecutor({ | |
| 105 | + ...config, | |
| 106 | + plugins: [ | |
| 107 | + openApiPlugin({ | |
| 108 | + operationStore: withConfigFile.openapi( | |
| 109 | + makeKvOperationStore(scopedKv, "openapi"), | |
| 110 | + configPath, | |
| 111 | + fsLayer, | |
| 112 | + ), | |
| 113 | + }), | |
| 114 | + mcpPlugin({ | |
| 115 | + bindingStore: withConfigFile.mcp( | |
| 116 | + makeKvBindingStore(scopedKv, "mcp"), | |
| 117 | + configPath, | |
| 118 | + fsLayer, | |
| 119 | + ), | |
| 120 | + }), | |
| 121 | + googleDiscoveryPlugin({ | |
| 122 | + bindingStore: makeKvGoogleDiscoveryBindingStore( | |
| 123 | + scopedKv, | |
| 124 | + "google-discovery", | |
| 125 | + ), | |
| 126 | + }), | |
| 127 | + graphqlPlugin({ | |
| 128 | + operationStore: withConfigFile.graphql( | |
| 129 | + makeKvGraphqlOperationStore(scopedKv, "graphql"), | |
| 130 | + configPath, | |
| 131 | + fsLayer, | |
| 132 | + ), | |
| 133 | + }), | |
| 134 | + // keychainPlugin(), | |
| 135 | + fileSecretsPlugin(), | |
| 136 | + onepasswordPlugin({ | |
| 137 | + kv: scopeKv(scopedKv, "onepassword"), | |
| 138 | + }), | |
| 139 | + ] as const, | |
| 140 | + }); | |
| 141 | + }), | |
| 142 | +).pipe(Layer.provide(SqliteClient.layer({ filename: DB_PATH }))); | |
| 143 | + | |
| 144 | +// --------------------------------------------------------------------------- | |
| 145 | +// ManagedRuntime — shared singleton for production, scoped handles for dev HMR | |
| 146 | +// --------------------------------------------------------------------------- | |
| 147 | + | |
| 148 | +export const createServerExecutorHandle = | |
| 149 | + async (): Promise<ServerExecutorHandle> => { | |
| 150 | + const runtime = ManagedRuntime.make(ExecutorLayer); | |
| 151 | + const executor = await runtime.runPromise(ExecutorService); | |
| 152 | + | |
| 153 | + return { | |
| 154 | + executor, | |
| 155 | + dispose: async () => { | |
| 156 | + await Effect.runPromise(executor.close()).catch(() => undefined); | |
| 157 | + await runtime.dispose().catch(() => undefined); | |
| 158 | + }, | |
| 159 | + }; | |
| 160 | + }; | |
| 161 | + | |
| 162 | +let sharedHandlePromise: Promise<ServerExecutorHandle> | null = null; | |
| 163 | + | |
| 164 | +const loadSharedHandle = (): Promise<ServerExecutorHandle> => { | |
| 165 | + if (!sharedHandlePromise) { | |
| 166 | + sharedHandlePromise = createServerExecutorHandle(); | |
| 167 | + } | |
| 168 | + return sharedHandlePromise; | |
| 169 | +}; | |
| 170 | + | |
| 171 | +/** | |
| 172 | + * Get the shared executor instance. The ManagedRuntime keeps the SQLite | |
| 173 | + * connection (and everything else) alive until the process exits. | |
| 174 | + */ | |
| 175 | +export const getExecutor = (): Promise<ServerExecutor> => | |
| 176 | + loadSharedHandle().then((handle) => handle.executor); | |
| 177 | + | |
| 178 | +/** | |
| 179 | + * Dispose the shared executor/runtime. Mainly useful in development when the | |
| 180 | + * backend module graph is hot-reloaded and we need fresh plugin init. | |
| 181 | + */ | |
| 182 | +export const disposeExecutor = async (): Promise<void> => { | |
| 183 | + const currentHandlePromise = sharedHandlePromise; | |
| 184 | + sharedHandlePromise = null; | |
| 185 | + | |
| 186 | + const handle = await currentHandlePromise?.catch(() => null); | |
| 187 | + await handle?.dispose().catch(() => undefined); | |
| 188 | +}; | |
| 189 | + | |
| 190 | +/** | |
| 191 | + * Dispose and eagerly recreate the shared executor. | |
| 192 | + */ | |
| 193 | +export const reloadExecutor = async (): Promise<ServerExecutor> => { | |
| 194 | + await disposeExecutor(); | |
| 195 | + return getExecutor(); | |
| 196 | +}; | |
| 197 | + | |
| 198 | +/** | |
| 199 | + * Provide `ExecutorService` to an Effect layer using the shared runtime. | |
| 200 | + * Used by the API handler. | |
| 201 | + */ | |
| 202 | +export const ExecutorServiceLayer = Layer.effect( | |
| 203 | + ExecutorService, | |
| 204 | + Effect.promise(() => getExecutor()), | |
| 205 | +); | |
| @@ -0,0 +1,22 @@ | ||
| 1 | +{ | |
| 2 | + "compilerOptions": { | |
| 3 | + "target": "ESNext", | |
| 4 | + "module": "ESNext", | |
| 5 | + "moduleResolution": "bundler", | |
| 6 | + "strict": true, | |
| 7 | + "esModuleInterop": true, | |
| 8 | + "skipLibCheck": true, | |
| 9 | + "outDir": "dist", | |
| 10 | + "rootDir": "src", | |
| 11 | + "declaration": true, | |
| 12 | + "declarationMap": true, | |
| 13 | + "sourceMap": true, | |
| 14 | + "jsx": "react-jsx", | |
| 15 | + "plugins": [ | |
| 16 | + { | |
| 17 | + "name": "@effect/language-service" | |
| 18 | + } | |
| 19 | + ] | |
| 20 | + }, | |
| 21 | + "include": ["src"] | |
| 22 | +} | |
| @@ -1,8 +0,0 @@ | ||
| 1 | −# @executor/web | |
| 2 | − | |
| 3 | −## null | |
| 4 | − | |
| 5 | −### Patch Changes | |
| 6 | − | |
| 7 | −- @executor/react@null | |
| 8 | −- @executor/server@null | |
| @@ -1,21 +1,20 @@ | ||
| 1 | 1 | { |
| 2 | 2 | "$schema": "https://ui.shadcn.com/schema.json", |
| 3 | − "style": "base-nova", | |
| 3 | + "style": "new-york", | |
| 4 | 4 | "rsc": false, |
| 5 | 5 | "tsx": true, |
| 6 | 6 | "tailwind": { |
| 7 | 7 | "config": "", |
| 8 | − "css": "src/globals.css", | |
| 8 | + "css": "../../packages/ui/src/styles/globals.css", | |
| 9 | 9 | "baseColor": "neutral", |
| 10 | − "cssVariables": true, | |
| 11 | − "prefix": "" | |
| 10 | + "cssVariables": true | |
| 12 | 11 | }, |
| 13 | 12 | "iconLibrary": "lucide", |
| 14 | 13 | "aliases": { |
| 15 | 14 | "components": "@/components", |
| 16 | 15 | "hooks": "@/hooks", |
| 17 | 16 | "lib": "@/lib", |
| 18 | − "utils": "@/lib/utils", | |
| 19 | − "ui": "@/components/ui" | |
| 17 | + "utils": "@executor/ui/lib/utils", | |
| 18 | + "ui": "@executor/ui/components" | |
| 20 | 19 | } |
| 21 | 20 | } |
| @@ -0,0 +1,3 @@ | ||
| 1 | +{ | |
| 2 | + "sources": [] | |
| 3 | +} | |
| @@ -0,0 +1,15 @@ | ||
| 1 | +<!doctype html> | |
| 2 | +<html lang="en"> | |
| 3 | + <head> | |
| 4 | + <meta charset="UTF-8" /> | |
| 5 | + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| 6 | + <title>Executor</title> | |
| 7 | + <link rel="preconnect" href="https://fonts.googleapis.com" /> | |
| 8 | + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> | |
| 9 | + <link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300..700;1,9..40,300..700&family=Instrument+Serif&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" /> | |
| 10 | + </head> | |
| 11 | + <body> | |
| 12 | + <div id="root"></div> | |
| 13 | + <script type="module" src="/src/main.tsx"></script> | |
| 14 | + </body> | |
| 15 | +</html> | |
| @@ -1,51 +1,39 @@ | ||
| 1 | 1 | { |
| 2 | 2 | "name": "@executor/web", |
| 3 | + "version": "1.4.0-beta.0", | |
| 3 | 4 | "private": true, |
| 4 | 5 | "type": "module", |
| 5 | − "scripts": { | |
| 6 | − "dev": "bunx --bun vite dev", | |
| 7 | − "build": "bunx vite build --config vite.config.ts", | |
| 8 | − "typecheck": "bunx tsc --noEmit -p tsconfig.json", | |
| 9 | − "start": "NODE_ENV=production bun src/server.ts" | |
| 10 | − }, | |
| 11 | 6 | "dependencies": { |
| 12 | − "@base-ui/react": "^1.3.0", | |
| 13 | − "@executor/plugin-execution-history-react": "workspace:*", | |
| 14 | − "@executor/plugin-google-discovery-react": "workspace:*", | |
| 15 | − "@executor/plugin-graphql-react": "workspace:*", | |
| 16 | − "@executor/plugin-local-tools-react": "workspace:*", | |
| 17 | − "@executor/plugin-mcp-react": "workspace:*", | |
| 18 | − "@executor/plugin-onepassword-react": "workspace:*", | |
| 19 | − "@executor/plugin-openapi-react": "workspace:*", | |
| 7 | + "@executor/plugin-onepassword": "workspace:*", | |
| 8 | + "@executor/plugin-mcp": "workspace:*", | |
| 9 | + "@executor/plugin-google-discovery": "workspace:*", | |
| 10 | + "@executor/plugin-graphql": "workspace:*", | |
| 11 | + "@executor/plugin-openapi": "workspace:*", | |
| 12 | + "@executor/sdk": "workspace:*", | |
| 20 | 13 | "@executor/react": "workspace:*", |
| 21 | 14 | "@executor/server": "workspace:*", |
| 22 | − "@executor/source-core": "workspace:*", | |
| 23 | − "@shikijs/langs": "^4.0.1", | |
| 24 | − "@shikijs/themes": "^4.0.1", | |
| 25 | − "@tanstack/react-router": "^1.132.7", | |
| 26 | − "class-variance-authority": "^0.7.1", | |
| 27 | − "clsx": "^2.1.1", | |
| 28 | − "effect": "catalog:", | |
| 29 | − "lucide-react": "^1.7.0", | |
| 30 | − "react": "^19.2.0", | |
| 31 | − "react-dom": "^19.2.0", | |
| 32 | − "react-grab": "^0.1.26", | |
| 33 | − "shadcn": "^4.1.1", | |
| 34 | − "shiki": "^4.0.1", | |
| 35 | − "streamdown": "^2.3.0", | |
| 36 | − "tailwind-merge": "^3.5.0", | |
| 37 | − "tldts": "^7.0.23" | |
| 15 | + "@executor/ui": "workspace:*", | |
| 16 | + "@shikijs/langs": "^4.0.2", | |
| 17 | + "@shikijs/themes": "^4.0.2", | |
| 18 | + "@tanstack/react-router": "^1.168.10", | |
| 19 | + "react": "^19.1.0", | |
| 20 | + "react-dom": "^19.1.0", | |
| 21 | + "shiki": "^4.0.2", | |
| 22 | + "streamdown": "^2.5.0", | |
| 23 | + "tailwindcss": "^4.1.10" | |
| 38 | 24 | }, |
| 39 | 25 | "devDependencies": { |
| 40 | − "@hono/vite-dev-server": "^0.25.0", | |
| 41 | − "@tailwindcss/vite": "^4.2.1", | |
| 42 | − "@types/react": "^19.2.10", | |
| 43 | − "@types/react-dom": "^19.2.3", | |
| 44 | − "@vitejs/plugin-react": "^5.1.4", | |
| 45 | − "bun-types": "catalog:", | |
| 46 | − "tailwindcss": "^4.2.1", | |
| 47 | − "tw-animate-css": "^1.4.0", | |
| 48 | − "vite": "^7.3.1" | |
| 26 | + "@types/react": "^19.1.0", | |
| 27 | + "@types/react-dom": "^19.1.0", | |
| 28 | + "@types/node": "catalog:", | |
| 29 | + "@tailwindcss/vite": "^4.1.10", | |
| 30 | + "@vitejs/plugin-react": "^4.5.2", | |
| 31 | + "typescript": "^5.9.3", | |
| 32 | + "vite": "^6.3.5" | |
| 49 | 33 | }, |
| 50 | − "version": "0.0.0" | |
| 34 | + "scripts": { | |
| 35 | + "dev": "bunx --bun vite", | |
| 36 | + "build": "vite build", | |
| 37 | + "typecheck": "tsc --noEmit" | |
| 38 | + } | |
| 51 | 39 | } |
| @@ -0,0 +1,6 @@ | ||
| 1 | +import { RouterProvider } from "@tanstack/react-router"; | |
| 2 | +import { router } from "./router"; | |
| 3 | + | |
| 4 | +export function App() { | |
| 5 | + return <RouterProvider router={router} />; | |
| 6 | +} | |
| @@ -1,96 +0,0 @@ | ||
| 1 | −import { useEffect, useState, useRef, useCallback } from "react"; | |
| 2 | −import { Button } from "@executor/react/plugins"; | |
| 3 | −import { codeToHtml, resolveLang } from "../lib/shiki"; | |
| 4 | −import { cn } from "../lib/utils"; | |
| 5 | −import { IconCopy, IconCheck } from "./icons"; | |
| 6 | − | |
| 7 | −// Lazily loaded, cached across renders | |
| 8 | −const highlightCache = new Map<string, string>(); | |
| 9 | − | |
| 10 | −function cacheKey(code: string, lang: string) { | |
| 11 | − return `${lang}::${code.length}::${code.slice(0, 64)}`; | |
| 12 | −} | |
| 13 | − | |
| 14 | −function detectLanguage(code: string, hint?: string): string { | |
| 15 | − if (hint) return resolveLang(hint) ?? "json"; | |
| 16 | − const trimmed = code.trimStart(); | |
| 17 | − if (trimmed.startsWith("{") || trimmed.startsWith("[")) return "json"; | |
| 18 | − if (trimmed.startsWith("<")) return "xml"; | |
| 19 | − if (trimmed.startsWith("---")) return "yaml"; | |
| 20 | − return "json"; | |
| 21 | −} | |
| 22 | − | |
| 23 | −export function CodeBlock(props: { | |
| 24 | − code: string; | |
| 25 | − lang?: string; | |
| 26 | − className?: string; | |
| 27 | −}) { | |
| 28 | − const { code, lang: langHint, className } = props; | |
| 29 | − const [html, setHtml] = useState<string | null>(null); | |
| 30 | − const [copied, setCopied] = useState(false); | |
| 31 | − const mountedRef = useRef(true); | |
| 32 | − | |
| 33 | − const language = detectLanguage(code, langHint); | |
| 34 | − const key = cacheKey(code, language); | |
| 35 | − | |
| 36 | − useEffect(() => { | |
| 37 | − mountedRef.current = true; | |
| 38 | − return () => { | |
| 39 | − mountedRef.current = false; | |
| 40 | − }; | |
| 41 | − }, []); | |
| 42 | − | |
| 43 | − useEffect(() => { | |
| 44 | − const cached = highlightCache.get(key); | |
| 45 | − if (cached) { | |
| 46 | − setHtml(cached); | |
| 47 | − return; | |
| 48 | − } | |
| 49 | − | |
| 50 | − let cancelled = false; | |
| 51 | − codeToHtml(code, { lang: language }).then((result) => { | |
| 52 | − if (cancelled) return; | |
| 53 | − highlightCache.set(key, result); | |
| 54 | − if (mountedRef.current) setHtml(result); | |
| 55 | − }); | |
| 56 | − | |
| 57 | − return () => { | |
| 58 | − cancelled = true; | |
| 59 | − }; | |
| 60 | − }, [code, key, language]); | |
| 61 | − | |
| 62 | − const handleCopy = useCallback(() => { | |
| 63 | − void navigator.clipboard.writeText(code).then(() => { | |
| 64 | − setCopied(true); | |
| 65 | − setTimeout(() => setCopied(false), 1500); | |
| 66 | − }); | |
| 67 | − }, [code]); | |
| 68 | − | |
| 69 | − return ( | |
| 70 | − <div className={cn("group relative overflow-auto", className)}> | |
| 71 | − {/* Copy button */} | |
| 72 | − <Button | |
| 73 | − type="button" | |
| 74 | − variant="ghost" | |
| 75 | − size="icon" | |
| 76 | − onClick={handleCopy} | |
| 77 | − className="absolute right-2 top-2 z-10 size-7 rounded-md border border-border bg-card/90 text-muted-foreground/40 opacity-0 backdrop-blur-sm transition-all hover:text-foreground group-hover:opacity-100" | |
| 78 | − title="Copy to clipboard" | |
| 79 | − > | |
| 80 | − {copied ? <IconCheck className="size-3" /> : <IconCopy className="size-3" />} | |
| 81 | − </Button> | |
| 82 | − | |
| 83 | − {html ? ( | |
| 84 | − <div | |
| 85 | − className="shiki-container text-[12px] leading-relaxed [&_pre]:!bg-transparent [&_pre]:p-3 [&_code]:font-mono" | |
| 86 | − dangerouslySetInnerHTML={{ __html: html }} | |
| 87 | − /> | |
| 88 | − ) : ( | |
| 89 | − // Fallback while shiki loads | |
| 90 | − <pre className="p-3 font-mono text-[12px] leading-relaxed text-foreground/60"> | |
| 91 | − {code} | |
| 92 | − </pre> | |
| 93 | − )} | |
| 94 | − </div> | |
| 95 | − ); | |
| 96 | −} | |
| @@ -1,30 +0,0 @@ | ||
| 1 | −import { cn } from "../lib/utils"; | |
| 2 | −import { CodeBlock } from "./code-block"; | |
| 3 | − | |
| 4 | −export function DocumentPanel(props: { | |
| 5 | − title: string; | |
| 6 | − body: string | null; | |
| 7 | − lang?: string; | |
| 8 | − empty: string; | |
| 9 | − compact?: boolean; | |
| 10 | −}) { | |
| 11 | − return ( | |
| 12 | − <section | |
| 13 | − className={cn( | |
| 14 | − "overflow-hidden rounded-lg border border-border bg-card/60", | |
| 15 | − props.compact && "min-h-48", | |
| 16 | − )} | |
| 17 | − > | |
| 18 | − <div className="border-b border-border px-3 py-2 text-[11px] font-medium uppercase tracking-wider text-muted-foreground/70"> | |
| 19 | − {props.title} | |
| 20 | − </div> | |
| 21 | − {props.body ? ( | |
| 22 | − <CodeBlock code={props.body} lang={props.lang} className="max-h-[32rem]" /> | |
| 23 | − ) : ( | |
| 24 | − <div className="flex items-center justify-center p-6 text-[13px] text-muted-foreground/40"> | |
| 25 | − {props.empty} | |
| 26 | − </div> | |
| 27 | − )} | |
| 28 | − </section> | |
| 29 | − ); | |
| 30 | −} | |
| @@ -1,160 +0,0 @@ | ||
| 1 | −import type { SVGProps } from "react"; | |
| 2 | −import { cn } from "../lib/utils"; | |
| 3 | − | |
| 4 | −type IconProps = SVGProps<SVGSVGElement> & { className?: string }; | |
| 5 | − | |
| 6 | −export function IconSources({ className, ...props }: IconProps) { | |
| 7 | − return ( | |
| 8 | − <svg viewBox="0 0 16 16" fill="none" className={cn("size-4", className)} {...props}> | |
| 9 | − <rect x="2" y="2" width="5" height="5" rx="1" stroke="currentColor" strokeWidth="1.3" /> | |
| 10 | − <rect x="9" y="2" width="5" height="5" rx="1" stroke="currentColor" strokeWidth="1.3" /> | |
| 11 | − <rect x="2" y="9" width="5" height="5" rx="1" stroke="currentColor" strokeWidth="1.3" /> | |
| 12 | − <rect x="9" y="9" width="5" height="5" rx="1" stroke="currentColor" strokeWidth="1.3" /> | |
| 13 | − </svg> | |
| 14 | − ); | |
| 15 | −} | |
| 16 | − | |
| 17 | −export function IconTool({ className, ...props }: IconProps) { | |
| 18 | − return ( | |
| 19 | − <svg viewBox="0 0 16 16" fill="none" className={cn("size-4", className)} {...props}> | |
| 20 | − <path d="M4 8h8M8 4v8" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" /> | |
| 21 | − </svg> | |
| 22 | − ); | |
| 23 | −} | |
| 24 | − | |
| 25 | −export function IconSearch({ className, ...props }: IconProps) { | |
| 26 | − return ( | |
| 27 | − <svg viewBox="0 0 16 16" fill="none" className={cn("size-4", className)} {...props}> | |
| 28 | − <circle cx="7" cy="7" r="4.5" stroke="currentColor" strokeWidth="1.3" /> | |
| 29 | − <path d="M10.5 10.5L14 14" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" /> | |
| 30 | − </svg> | |
| 31 | − ); | |
| 32 | −} | |
| 33 | − | |
| 34 | −export function IconChevron({ className, ...props }: IconProps) { | |
| 35 | − return ( | |
| 36 | − <svg viewBox="0 0 16 16" fill="none" className={cn("size-3", className)} {...props}> | |
| 37 | − <path d="M6 4l4 4-4 4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" /> | |
| 38 | − </svg> | |
| 39 | − ); | |
| 40 | −} | |
| 41 | − | |
| 42 | −export function IconFolder({ className, ...props }: IconProps) { | |
| 43 | − return ( | |
| 44 | − <svg viewBox="0 0 16 16" fill="none" className={cn("size-3", className)} {...props}> | |
| 45 | − <path d="M2 4h5l2 2h5v7H2V4z" stroke="currentColor" strokeWidth="1.2" strokeLinejoin="round" /> | |
| 46 | − </svg> | |
| 47 | − ); | |
| 48 | −} | |
| 49 | − | |
| 50 | −export function IconDocument({ className, ...props }: IconProps) { | |
| 51 | − return ( | |
| 52 | − <svg viewBox="0 0 16 16" fill="none" className={cn("size-4", className)} {...props}> | |
| 53 | − <path d="M4 2h5l3 3v9H4V2z" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round" /> | |
| 54 | − <path d="M6 8h4M6 10.5h3" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" /> | |
| 55 | − </svg> | |
| 56 | − ); | |
| 57 | −} | |
| 58 | − | |
| 59 | −export function IconDiscover({ className, ...props }: IconProps) { | |
| 60 | − return ( | |
| 61 | − <svg viewBox="0 0 16 16" fill="none" className={cn("size-4", className)} {...props}> | |
| 62 | − <circle cx="8" cy="8" r="6" stroke="currentColor" strokeWidth="1.3" /> | |
| 63 | − <path d="M6.5 5.5l4.5 2-2 4.5-4.5-2z" stroke="currentColor" strokeWidth="1.2" strokeLinejoin="round" /> | |
| 64 | − </svg> | |
| 65 | − ); | |
| 66 | −} | |
| 67 | − | |
| 68 | −export function IconCopy({ className, ...props }: IconProps) { | |
| 69 | − return ( | |
| 70 | − <svg viewBox="0 0 16 16" fill="none" className={cn("size-3.5", className)} {...props}> | |
| 71 | − <rect x="5" y="5" width="8" height="8" rx="1" stroke="currentColor" strokeWidth="1.2" /> | |
| 72 | − <path d="M11 3H4a1 1 0 00-1 1v7" stroke="currentColor" strokeWidth="1.2" /> | |
| 73 | − </svg> | |
| 74 | − ); | |
| 75 | −} | |
| 76 | − | |
| 77 | −export function IconCheck({ className, ...props }: IconProps) { | |
| 78 | − return ( | |
| 79 | − <svg viewBox="0 0 16 16" fill="none" className={cn("size-3.5", className)} {...props}> | |
| 80 | − <path d="M4 8.5l3 3 5-6" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round" /> | |
| 81 | − </svg> | |
| 82 | − ); | |
| 83 | −} | |
| 84 | − | |
| 85 | −export function IconClose({ className, ...props }: IconProps) { | |
| 86 | − return ( | |
| 87 | − <svg viewBox="0 0 16 16" fill="none" className={cn("size-3", className)} {...props}> | |
| 88 | − <path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" /> | |
| 89 | − </svg> | |
| 90 | − ); | |
| 91 | −} | |
| 92 | − | |
| 93 | −export function IconEmpty({ className, ...props }: IconProps) { | |
| 94 | − return ( | |
| 95 | − <svg viewBox="0 0 48 48" fill="none" className={cn("size-12", className)} {...props}> | |
| 96 | − <rect x="6" y="6" width="36" height="36" rx="4" stroke="currentColor" strokeWidth="1.5" /> | |
| 97 | − <path d="M16 18h16M16 24h12M16 30h8" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" /> | |
| 98 | − </svg> | |
| 99 | − ); | |
| 100 | −} | |
| 101 | − | |
| 102 | −export function IconSpinner({ className, ...props }: IconProps) { | |
| 103 | − return ( | |
| 104 | − <svg viewBox="0 0 16 16" fill="none" className={cn("size-4 animate-spin", className)} {...props}> | |
| 105 | − <circle cx="8" cy="8" r="6" stroke="currentColor" strokeWidth="1.5" opacity="0.2" /> | |
| 106 | − <path d="M14 8a6 6 0 00-6-6" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" /> | |
| 107 | − </svg> | |
| 108 | − ); | |
| 109 | −} | |
| 110 | − | |
| 111 | −export function IconInfo({ className, ...props }: IconProps) { | |
| 112 | − return ( | |
| 113 | − <svg viewBox="0 0 16 16" fill="none" className={cn("size-4", className)} {...props}> | |
| 114 | − <circle cx="8" cy="8" r="5.75" stroke="currentColor" strokeWidth="1.2" /> | |
| 115 | − <path d="M8 7v3.25" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" /> | |
| 116 | − <circle cx="8" cy="4.75" r="0.8" fill="currentColor" /> | |
| 117 | − </svg> | |
| 118 | − ); | |
| 119 | −} | |
| 120 | − | |
| 121 | −export function IconPlus({ className, ...props }: IconProps) { | |
| 122 | − return ( | |
| 123 | − <svg viewBox="0 0 16 16" fill="none" className={cn("size-4", className)} {...props}> | |
| 124 | − <path d="M8 3.25v9.5M3.25 8h9.5" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" /> | |
| 125 | − </svg> | |
| 126 | − ); | |
| 127 | −} | |
| 128 | − | |
| 129 | −export function IconPencil({ className, ...props }: IconProps) { | |
| 130 | − return ( | |
| 131 | − <svg viewBox="0 0 16 16" fill="none" className={cn("size-4", className)} {...props}> | |
| 132 | − <path d="M3 11.75L11.6 3.15a1.2 1.2 0 011.7 0l.55.55a1.2 1.2 0 010 1.7L5.25 14H3v-2.25z" stroke="currentColor" strokeWidth="1.2" strokeLinejoin="round" /> | |
| 133 | − <path d="M9.75 5l1.25 1.25" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" /> | |
| 134 | − </svg> | |
| 135 | − ); | |
| 136 | −} | |
| 137 | − | |
| 138 | −export function IconTrash({ className, ...props }: IconProps) { | |
| 139 | − return ( | |
| 140 | − <svg viewBox="0 0 16 16" fill="none" className={cn("size-4", className)} {...props}> | |
| 141 | − <path d="M3.5 4.5h9M6 2.75h4M5 4.5v7.25m3-7.25v7.25m3-7.25v7.25M4.5 4.5l.4 8.1c.03.52.46.9.98.9h4.24c.52 0 .95-.38.98-.9l.4-8.1" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round" /> | |
| 142 | − </svg> | |
| 143 | − ); | |
| 144 | −} | |
| 145 | − | |
| 146 | −export function IconArrowLeft({ className, ...props }: IconProps) { | |
| 147 | − return ( | |
| 148 | − <svg viewBox="0 0 16 16" fill="none" className={cn("size-4", className)} {...props}> | |
| 149 | − <path d="M12.75 8H3.25M6.75 4.5L3.25 8l3.5 3.5" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" /> | |
| 150 | − </svg> | |
| 151 | − ); | |
| 152 | −} | |
| 153 | − | |
| 154 | −export function IconMenu({ className, ...props }: IconProps) { | |
| 155 | − return ( | |
| 156 | − <svg viewBox="0 0 16 16" fill="none" className={cn("size-4", className)} {...props}> | |
| 157 | − <path d="M3 4.5h10M3 8h10M3 11.5h10" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" /> | |
| 158 | − </svg> | |
| 159 | − ); | |
| 160 | −} | |
| @@ -1,50 +0,0 @@ | ||
| 1 | −import type { ReactNode } from "react"; | |
| 2 | −import type { Loadable } from "@executor/react"; | |
| 3 | −import { IconSpinner, IconEmpty } from "./icons"; | |
| 4 | − | |
| 5 | −export function LoadableBlock<T>(props: { | |
| 6 | − loadable: Loadable<T>; | |
| 7 | − loading?: string; | |
| 8 | − children: (data: T) => ReactNode; | |
| 9 | −}) { | |
| 10 | − if (props.loadable.status === "loading") { | |
| 11 | − return ( | |
| 12 | − <div className="flex h-full min-h-48 items-center justify-center"> | |
| 13 | − <div className="flex items-center gap-3 text-sm text-muted-foreground"> | |
| 14 | − <IconSpinner /> | |
| 15 | − <span>{props.loading ?? "Loading..."}</span> | |
| 16 | − </div> | |
| 17 | − </div> | |
| 18 | − ); | |
| 19 | − } | |
| 20 | − | |
| 21 | − if (props.loadable.status === "error") { | |
| 22 | − return ( | |
| 23 | − <div className="flex h-full min-h-48 items-center justify-center"> | |
| 24 | − <div className="rounded-lg border border-destructive/25 bg-destructive/5 px-4 py-3 text-sm text-destructive"> | |
| 25 | − {props.loadable.error.message} | |
| 26 | − </div> | |
| 27 | − </div> | |
| 28 | − ); | |
| 29 | − } | |
| 30 | − | |
| 31 | − return <>{props.children(props.loadable.data)}</>; | |
| 32 | −} | |
| 33 | − | |
| 34 | −export function EmptyState(props: { | |
| 35 | − title: string; | |
| 36 | − description?: string; | |
| 37 | − className?: string; | |
| 38 | −}) { | |
| 39 | − return ( | |
| 40 | − <div className={`flex h-full items-center justify-center ${props.className ?? ""}`}> | |
| 41 | − <div className="text-center"> | |
| 42 | − <IconEmpty className="mx-auto mb-3 text-muted-foreground/20" /> | |
| 43 | − <p className="text-[13px] text-muted-foreground/60">{props.title}</p> | |
| 44 | − {props.description && ( | |
| 45 | − <p className="mt-1 text-[11px] text-muted-foreground/40">{props.description}</p> | |
| 46 | − )} | |
| 47 | − </div> | |
| 48 | − </div> | |
| 49 | − ); | |
| 50 | −} | |
| @@ -1,213 +0,0 @@ | ||
| 1 | −import { useEffect, useRef, useState } from "react"; | |
| 2 | −import { Button } from "@executor/react/plugins"; | |
| 3 | −import { CodeBlock } from "./code-block"; | |
| 4 | − | |
| 5 | −type LocalMcpInstallMode = "stdio" | "http"; | |
| 6 | − | |
| 7 | −const isDevBuild = import.meta.env.DEV; | |
| 8 | − | |
| 9 | −/** | |
| 10 | − * Fetch the execute tool description from the local MCP server using the | |
| 11 | − * Streamable HTTP transport. Performs initialize → tools/list → returns the | |
| 12 | − * description of the "execute" tool. | |
| 13 | − */ | |
| 14 | −async function fetchExecuteToolDescription( | |
| 15 | − mcpOrigin: string, | |
| 16 | −): Promise<string | null> { | |
| 17 | − const endpoint = `${mcpOrigin}/mcp`; | |
| 18 | − | |
| 19 | − const jsonRpcHeaders = { | |
| 20 | − "Content-Type": "application/json", | |
| 21 | − "Accept": "application/json, text/event-stream", | |
| 22 | − }; | |
| 23 | − | |
| 24 | − // 1. Initialize – get a session id | |
| 25 | − const initRes = await fetch(endpoint, { | |
| 26 | − method: "POST", | |
| 27 | − headers: jsonRpcHeaders, | |
| 28 | − body: JSON.stringify({ | |
| 29 | − jsonrpc: "2.0", | |
| 30 | − id: 1, | |
| 31 | − method: "initialize", | |
| 32 | − params: { | |
| 33 | − protocolVersion: "2025-03-26", | |
| 34 | − capabilities: {}, | |
| 35 | − clientInfo: { name: "executor-web", version: "0.1.0" }, | |
| 36 | − }, | |
| 37 | − }), | |
| 38 | − }); | |
| 39 | − | |
| 40 | − const sessionId = initRes.headers.get("mcp-session-id"); | |
| 41 | − if (!sessionId) return null; | |
| 42 | − | |
| 43 | − // 2. List tools | |
| 44 | − const listRes = await fetch(endpoint, { | |
| 45 | − method: "POST", | |
| 46 | − headers: { | |
| 47 | − ...jsonRpcHeaders, | |
| 48 | − "mcp-session-id": sessionId, | |
| 49 | − }, | |
| 50 | − body: JSON.stringify({ | |
| 51 | − jsonrpc: "2.0", | |
| 52 | − id: 2, | |
| 53 | − method: "tools/list", | |
| 54 | − params: {}, | |
| 55 | − }), | |
| 56 | − }); | |
| 57 | − | |
| 58 | − const listBody = await listRes.json(); | |
| 59 | − const tools: Array<{ name: string; description?: string }> = | |
| 60 | − listBody?.result?.tools ?? []; | |
| 61 | − | |
| 62 | − const executeTool = tools.find((t) => t.name === "execute"); | |
| 63 | − | |
| 64 | − // 3. Tear down the session (best-effort) | |
| 65 | − void fetch(endpoint, { | |
| 66 | − method: "DELETE", | |
| 67 | − headers: { "mcp-session-id": sessionId }, | |
| 68 | − }).catch(() => {}); | |
| 69 | − | |
| 70 | − return executeTool?.description ?? null; | |
| 71 | −} | |
| 72 | − | |
| 73 | −function ToolDescriptionDisclosure() { | |
| 74 | − const [open, setOpen] = useState(false); | |
| 75 | − const [description, setDescription] = useState<string | null>(null); | |
| 76 | − const [loading, setLoading] = useState(false); | |
| 77 | − const fetchedRef = useRef(false); | |
| 78 | − const bodyRef = useRef<HTMLDivElement>(null); | |
| 79 | − const [height, setHeight] = useState(0); | |
| 80 | − | |
| 81 | − // Fetch lazily on first open | |
| 82 | − useEffect(() => { | |
| 83 | − if (!open || fetchedRef.current) return; | |
| 84 | − fetchedRef.current = true; | |
| 85 | − setLoading(true); | |
| 86 | − fetchExecuteToolDescription(window.location.origin) | |
| 87 | − .then(setDescription) | |
| 88 | − .catch(() => setDescription(null)) | |
| 89 | − .finally(() => setLoading(false)); | |
| 90 | − }, [open]); | |
| 91 | − | |
| 92 | − useEffect(() => { | |
| 93 | − if (bodyRef.current) { | |
| 94 | − setHeight(bodyRef.current.scrollHeight); | |
| 95 | − } | |
| 96 | − }, [open, description, loading]); | |
| 97 | − | |
| 98 | − return ( | |
| 99 | − <div className="mt-3"> | |
| 100 | − <button | |
| 101 | − type="button" | |
| 102 | − onClick={() => setOpen((v) => !v)} | |
| 103 | − className="flex items-center gap-1.5 text-[12px] font-medium text-muted-foreground/70 transition-colors hover:text-foreground/80" | |
| 104 | − > | |
| 105 | − <svg | |
| 106 | − viewBox="0 0 10 10" | |
| 107 | − className="size-2.5 fill-current transition-transform duration-200" | |
| 108 | − style={{ transform: open ? "rotate(90deg)" : "rotate(0deg)" }} | |
| 109 | − > | |
| 110 | − <path d="M3 1.5 L7 5 L3 8.5Z" /> | |
| 111 | − </svg> | |
| 112 | − <span>View tool description</span> | |
| 113 | − </button> | |
| 114 | − <div | |
| 115 | − className="overflow-hidden transition-[max-height,opacity] duration-200 ease-out" | |
| 116 | − style={{ | |
| 117 | − maxHeight: open ? height : 0, | |
| 118 | − opacity: open ? 1 : 0, | |
| 119 | − }} | |
| 120 | − > | |
| 121 | − <div ref={bodyRef}> | |
| 122 | − {loading ? ( | |
| 123 | − <p className="mt-2 text-[11px] text-muted-foreground/60"> | |
| 124 | − Loading... | |
| 125 | − </p> | |
| 126 | − ) : description ? ( | |
| 127 | − <pre className="mt-2 max-h-64 overflow-y-auto rounded-lg border border-border/60 bg-background/50 p-3 font-mono text-[11px] leading-relaxed text-muted-foreground whitespace-pre-wrap"> | |
| 128 | − {description} | |
| 129 | − </pre> | |
| 130 | − ) : open && !loading ? ( | |
| 131 | − <p className="mt-2 text-[11px] text-muted-foreground/60"> | |
| 132 | − Could not load tool description. | |
| 133 | − </p> | |
| 134 | − ) : null} | |
| 135 | − </div> | |
| 136 | − </div> | |
| 137 | − </div> | |
| 138 | − ); | |
| 139 | −} | |
| 140 | − | |
| 141 | −export function LocalMcpInstallCard(props: { | |
| 142 | − title?: string; | |
| 143 | − description?: string; | |
| 144 | − className?: string; | |
| 145 | −}) { | |
| 146 | − const [origin, setOrigin] = useState<string | null>(null); | |
| 147 | − const [mode, setMode] = useState<LocalMcpInstallMode>("stdio"); | |
| 148 | − | |
| 149 | − useEffect(() => { | |
| 150 | − setOrigin(window.location.origin); | |
| 151 | − }, []); | |
| 152 | − | |
| 153 | − const command = mode === "stdio" | |
| 154 | − ? isDevBuild | |
| 155 | − ? 'npx add-mcp "bun run executor mcp --stdio" --name "executor-stdio"' | |
| 156 | − : 'npx add-mcp "executor mcp --stdio" --name "executor-stdio"' | |
| 157 | − : origin | |
| 158 | − ? `npx add-mcp "${origin}/mcp" --transport http --name "executor"` | |
| 159 | − : 'npx add-mcp "<this-server>/mcp" --transport http --name "executor"'; | |
| 160 | − | |
| 161 | − return ( | |
| 162 | − <section className={props.className ?? "rounded-2xl border border-border bg-card/80 p-5"}> | |
| 163 | − <div className="mb-3 space-y-1"> | |
| 164 | − <h2 className="text-sm font-semibold text-foreground"> | |
| 165 | − {props.title ?? "Install local MCP"} | |
| 166 | − </h2> | |
| 167 | − <p className="text-[13px] text-muted-foreground"> | |
| 168 | − {props.description | |
| 169 | − ?? (mode === "stdio" | |
| 170 | − ? "Preferred for local agents. This installs executor as a stdio MCP command and starts a local web sidecar automatically when needed." | |
| 171 | − : "Use the current web origin as a remote MCP endpoint over HTTP.")} | |
| 172 | − </p> | |
| 173 | − </div> | |
| 174 | − <div className="mb-3 inline-flex rounded-lg border border-border bg-background/70 p-1"> | |
| 175 | − {[ | |
| 176 | − { key: "stdio" as const, label: "Standard I/O" }, | |
| 177 | − { key: "http" as const, label: "Remote HTTP" }, | |
| 178 | − ].map((option) => ( | |
| 179 | − <Button | |
| 180 | − key={option.key} | |
| 181 | − type="button" | |
| 182 | − variant={mode === option.key ? "default" : "ghost"} | |
| 183 | − size="sm" | |
| 184 | − onClick={() => setMode(option.key)} | |
| 185 | − className="rounded-md px-3 py-1.5" | |
| 186 | − > | |
| 187 | − {option.label} | |
| 188 | − </Button> | |
| 189 | − ))} | |
| 190 | − </div> | |
| 191 | − <CodeBlock code={command} lang="bash" className="rounded-xl border border-border bg-background/70" /> | |
| 192 | − <ToolDescriptionDisclosure /> | |
| 193 | − {mode === "stdio" ? ( | |
| 194 | − <div className="mt-3 space-y-1 text-[12px] text-muted-foreground"> | |
| 195 | − {!isDevBuild ? ( | |
| 196 | − <p> | |
| 197 | − Requires the `executor` CLI on your PATH. Uses a distinct MCP name to avoid colliding with an existing remote `executor` entry. | |
| 198 | − </p> | |
| 199 | − ) : ( | |
| 200 | − <> | |
| 201 | − <p> | |
| 202 | − Uses the repo-local dev CLI: <code>bun run executor mcp --stdio</code>. | |
| 203 | − </p> | |
| 204 | − <p> | |
| 205 | − Run the `add-mcp` command from the repository root, or set your MCP client working directory to this repo before using the saved entry. | |
| 206 | − </p> | |
| 207 | − </> | |
| 208 | − )} | |
| 209 | − </div> | |
| 210 | − ) : null} | |
| 211 | − </section> | |
| 212 | − ); | |
| 213 | −} | |
| @@ -0,0 +1,77 @@ | ||
| 1 | +import { useEffect, useState } from "react"; | |
| 2 | +import { Button } from "@executor/ui/components/button"; | |
| 3 | +import { CodeBlock } from "@executor/ui/components/code-block"; | |
| 4 | + | |
| 5 | +type TransportMode = "stdio" | "http"; | |
| 6 | + | |
| 7 | +const isDev = import.meta.env.DEV; | |
| 8 | + | |
| 9 | +export function McpInstallCard(props: { className?: string }) { | |
| 10 | + const [mode, setMode] = useState<TransportMode>("http"); | |
| 11 | + const [origin, setOrigin] = useState<string | null>(null); | |
| 12 | + | |
| 13 | + useEffect(() => { | |
| 14 | + setOrigin(window.location.origin); | |
| 15 | + }, []); | |
| 16 | + | |
| 17 | + const command = | |
| 18 | + mode === "stdio" | |
| 19 | + ? isDev | |
| 20 | + ? 'npx add-mcp "bun run executor mcp --stdio" --name "executor-stdio"' | |
| 21 | + : 'npx add-mcp "executor mcp --stdio" --name "executor-stdio"' | |
| 22 | + : origin | |
| 23 | + ? `npx add-mcp "${origin}/mcp" --transport http --name "executor"` | |
| 24 | + : 'npx add-mcp "<this-server>/mcp" --transport http --name "executor"'; | |
| 25 | + | |
| 26 | + const description = | |
| 27 | + mode === "stdio" | |
| 28 | + ? "Starts executor as a local stdio MCP server. Best for CLI agents like Claude Code." | |
| 29 | + : "Use the current web origin as a remote MCP endpoint over streamable HTTP."; | |
| 30 | + | |
| 31 | + return ( | |
| 32 | + <section | |
| 33 | + className={ | |
| 34 | + props.className ?? | |
| 35 | + "rounded-2xl border border-border bg-card/80 p-5" | |
| 36 | + } | |
| 37 | + > | |
| 38 | + <div className="mb-3 space-y-1"> | |
| 39 | + <h2 className="text-sm font-semibold text-foreground"> | |
| 40 | + Connect an agent | |
| 41 | + </h2> | |
| 42 | + <p className="text-[13px] text-muted-foreground">{description}</p> | |
| 43 | + </div> | |
| 44 | + | |
| 45 | + {/* Transport toggle */} | |
| 46 | + <div className="mb-3 inline-flex rounded-lg border border-border bg-background/70 p-1"> | |
| 47 | + {( | |
| 48 | + [ | |
| 49 | + { key: "http", label: "Remote HTTP" }, | |
| 50 | + { key: "stdio", label: "Standard I/O" }, | |
| 51 | + ] as const | |
| 52 | + ).map((opt) => ( | |
| 53 | + <Button | |
| 54 | + key={opt.key} | |
| 55 | + type="button" | |
| 56 | + variant={mode === opt.key ? "default" : "ghost"} | |
| 57 | + size="sm" | |
| 58 | + onClick={() => setMode(opt.key)} | |
| 59 | + className="rounded-md px-3 py-1.5" | |
| 60 | + > | |
| 61 | + {opt.label} | |
| 62 | + </Button> | |
| 63 | + ))} | |
| 64 | + </div> | |
| 65 | + | |
| 66 | + <CodeBlock code={command} lang="bash" /> | |
| 67 | + | |
| 68 | + {mode === "stdio" && ( | |
| 69 | + <p className="mt-3 text-[12px] text-muted-foreground"> | |
| 70 | + {isDev | |
| 71 | + ? "Uses the repo-local dev CLI. Run from the repository root." | |
| 72 | + : "Requires the executor CLI on your PATH."} | |
| 73 | + </p> | |
| 74 | + )} | |
| 75 | + </section> | |
| 76 | + ); | |
| 77 | +} | |
| @@ -1,561 +0,0 @@ | ||
| 1 | −import { Link, Outlet, useLocation, useMatchRoute } from "@tanstack/react-router"; | |
| 2 | −import { useCallback, useEffect, useState } from "react"; | |
| 3 | −import { useSources, type Source } from "@executor/react"; | |
| 4 | −import { Button, sourcePluginsIndexPath } from "@executor/react/plugins"; | |
| 5 | −import { cn } from "../lib/utils"; | |
| 6 | −import { IconPlus, IconCopy, IconCheck, IconClose, IconMenu } from "./icons"; | |
| 7 | −import { LoadableBlock } from "./loadable"; | |
| 8 | −import { SourceFavicon } from "./source-favicon"; | |
| 9 | −import { | |
| 10 | − getSourceFrontendPaths, | |
| 11 | − registeredFrontendPluginNavRoutes, | |
| 12 | −} from "../plugins"; | |
| 13 | − | |
| 14 | −// ── Status dot color ───────────────────────────────────────────────────── | |
| 15 | − | |
| 16 | −const statusColor: Record<string, string> = { | |
| 17 | − connected: "bg-primary", | |
| 18 | − probing: "bg-amber-400", | |
| 19 | − draft: "bg-muted-foreground/30", | |
| 20 | − auth_required: "bg-amber-500", | |
| 21 | − error: "bg-destructive", | |
| 22 | −}; | |
| 23 | − | |
| 24 | −type AppMetaEnv = { | |
| 25 | − readonly VITE_APP_VERSION: string; | |
| 26 | − readonly VITE_GITHUB_URL: string; | |
| 27 | −}; | |
| 28 | − | |
| 29 | −const { VITE_APP_VERSION, VITE_GITHUB_URL } = (import.meta as ImportMeta & { | |
| 30 | − readonly env: AppMetaEnv; | |
| 31 | −}).env; | |
| 32 | − | |
| 33 | −type UpdateChannel = "latest" | "beta"; | |
| 34 | − | |
| 35 | −const EXECUTOR_DIST_TAGS_PATH = "/v1/app/npm/dist-tags"; | |
| 36 | − | |
| 37 | −type ParsedVersion = { | |
| 38 | − readonly major: number; | |
| 39 | − readonly minor: number; | |
| 40 | − readonly patch: number; | |
| 41 | − readonly prerelease: ReadonlyArray<string | number> | null; | |
| 42 | −}; | |
| 43 | − | |
| 44 | −const semverPattern = | |
| 45 | − /^(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)(?:-(?<prerelease>[0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/; | |
| 46 | − | |
| 47 | −const resolveUpdateChannel = (version: string): UpdateChannel => | |
| 48 | − version.includes("-beta.") ? "beta" : "latest"; | |
| 49 | − | |
| 50 | −const parseVersion = (version: string): ParsedVersion | null => { | |
| 51 | − const match = version.trim().match(semverPattern); | |
| 52 | − if (!match?.groups) { | |
| 53 | − return null; | |
| 54 | − } | |
| 55 | − | |
| 56 | − return { | |
| 57 | − major: Number(match.groups.major), | |
| 58 | − minor: Number(match.groups.minor), | |
| 59 | − patch: Number(match.groups.patch), | |
| 60 | − prerelease: match.groups.prerelease | |
| 61 | − ? match.groups.prerelease.split(".").map((identifier) => | |
| 62 | − /^\d+$/.test(identifier) ? Number(identifier) : identifier, | |
| 63 | − ) | |
| 64 | − : null, | |
| 65 | − }; | |
| 66 | −}; | |
| 67 | − | |
| 68 | −const comparePrereleaseIdentifiers = ( | |
| 69 | − left: ReadonlyArray<string | number> | null, | |
| 70 | − right: ReadonlyArray<string | number> | null, | |
| 71 | −): number => { | |
| 72 | − if (left === null && right === null) { | |
| 73 | − return 0; | |
| 74 | − } | |
| 75 | − | |
| 76 | − if (left === null) { | |
| 77 | − return 1; | |
| 78 | − } | |
| 79 | − | |
| 80 | − if (right === null) { | |
| 81 | − return -1; | |
| 82 | − } | |
| 83 | − | |
| 84 | − const length = Math.max(left.length, right.length); | |
| 85 | − for (let index = 0; index < length; index += 1) { | |
| 86 | − const leftIdentifier = left[index]; | |
| 87 | − const rightIdentifier = right[index]; | |
| 88 | − | |
| 89 | − if (leftIdentifier === rightIdentifier) { | |
| 90 | − continue; | |
| 91 | − } | |
| 92 | − | |
| 93 | − if (leftIdentifier === undefined) { | |
| 94 | − return -1; | |
| 95 | − } | |
| 96 | − | |
| 97 | − if (rightIdentifier === undefined) { | |
| 98 | − return 1; | |
| 99 | − } | |
| 100 | − | |
| 101 | − if (typeof leftIdentifier === "number" && typeof rightIdentifier === "number") { | |
| 102 | − return leftIdentifier < rightIdentifier ? -1 : 1; | |
| 103 | − } | |
| 104 | − | |
| 105 | − if (typeof leftIdentifier === "number") { | |
| 106 | − return -1; | |
| 107 | − } | |
| 108 | − | |
| 109 | − if (typeof rightIdentifier === "number") { | |
| 110 | − return 1; | |
| 111 | − } | |
| 112 | − | |
| 113 | − return leftIdentifier < rightIdentifier ? -1 : 1; | |
| 114 | − } | |
| 115 | − | |
| 116 | − return 0; | |
| 117 | −}; | |
| 118 | − | |
| 119 | −const compareVersions = (left: string, right: string): number | null => { | |
| 120 | − const leftVersion = parseVersion(left); | |
| 121 | − const rightVersion = parseVersion(right); | |
| 122 | − if (!leftVersion || !rightVersion) { | |
| 123 | − return null; | |
| 124 | − } | |
| 125 | − | |
| 126 | − if (leftVersion.major !== rightVersion.major) { | |
| 127 | − return leftVersion.major < rightVersion.major ? -1 : 1; | |
| 128 | − } | |
| 129 | − | |
| 130 | − if (leftVersion.minor !== rightVersion.minor) { | |
| 131 | − return leftVersion.minor < rightVersion.minor ? -1 : 1; | |
| 132 | − } | |
| 133 | − | |
| 134 | − if (leftVersion.patch !== rightVersion.patch) { | |
| 135 | − return leftVersion.patch < rightVersion.patch ? -1 : 1; | |
| 136 | − } | |
| 137 | − | |
| 138 | − return comparePrereleaseIdentifiers(leftVersion.prerelease, rightVersion.prerelease); | |
| 139 | −}; | |
| 140 | − | |
| 141 | −// ── useLatestVersion ───────────────────────────────────────────────────── | |
| 142 | − | |
| 143 | −function useLatestVersion(currentVersion: string) { | |
| 144 | − const channel = resolveUpdateChannel(currentVersion); | |
| 145 | − const [latestVersion, setLatestVersion] = useState<string | null>(null); | |
| 146 | − | |
| 147 | − useEffect(() => { | |
| 148 | − let cancelled = false; | |
| 149 | − fetch(EXECUTOR_DIST_TAGS_PATH) | |
| 150 | − .then(async (res) => { | |
| 151 | − if (!res.ok) { | |
| 152 | − throw new Error(`Failed to load dist tags: ${res.status}`); | |
| 153 | − } | |
| 154 | − return res.json() as Promise<Partial<Record<UpdateChannel, string>>>; | |
| 155 | − }) | |
| 156 | − .then((data: Partial<Record<UpdateChannel, string>>) => { | |
| 157 | − if (!cancelled) { | |
| 158 | − setLatestVersion(data[channel] ?? null); | |
| 159 | − } | |
| 160 | − }) | |
| 161 | − .catch(() => {}); | |
| 162 | − return () => { | |
| 163 | − cancelled = true; | |
| 164 | − }; | |
| 165 | − }, [channel]); | |
| 166 | − | |
| 167 | − const updateAvailable = | |
| 168 | − latestVersion !== null && compareVersions(currentVersion, latestVersion) === -1; | |
| 169 | − | |
| 170 | − return { latestVersion, updateAvailable, channel }; | |
| 171 | −} | |
| 172 | − | |
| 173 | −// ── UpdateCard ─────────────────────────────────────────────────────────── | |
| 174 | − | |
| 175 | −function UpdateCard(props: { latestVersion: string; channel: UpdateChannel }) { | |
| 176 | − const command = `npm i -g executor@${props.channel}`; | |
| 177 | − const [copied, setCopied] = useState(false); | |
| 178 | − | |
| 179 | − const handleCopy = useCallback(() => { | |
| 180 | − void navigator.clipboard.writeText(command).then(() => { | |
| 181 | − setCopied(true); | |
| 182 | − setTimeout(() => setCopied(false), 1500); | |
| 183 | − }); | |
| 184 | − }, [command]); | |
| 185 | − | |
| 186 | − return ( | |
| 187 | − <div className="mx-2 mb-2 rounded-xl border border-primary/25 bg-primary/[0.06] p-3"> | |
| 188 | − <div className="flex items-center gap-2"> | |
| 189 | − <div className="flex size-5 shrink-0 items-center justify-center rounded-full bg-primary/15"> | |
| 190 | − <svg viewBox="0 0 16 16" fill="none" className="size-3 text-primary"> | |
| 191 | − <path d="M8 3v7M5 7l3 3 3-3" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" /> | |
| 192 | − <path d="M3 12h10" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" /> | |
| 193 | − </svg> | |
| 194 | − </div> | |
| 195 | − <div className="min-w-0"> | |
| 196 | − <p className="text-[11px] font-semibold text-foreground">Update available</p> | |
| 197 | − <p className="text-[10px] text-muted-foreground"> | |
| 198 | − v{props.latestVersion} | |
| 199 | − </p> | |
| 200 | − </div> | |
| 201 | − </div> | |
| 202 | − <Button | |
| 203 | − type="button" | |
| 204 | − variant="outline" | |
| 205 | − onClick={handleCopy} | |
| 206 | − className="mt-2.5 flex w-full items-center justify-between gap-2 rounded-lg border-border/60 bg-background/50 px-2.5 py-1.5 text-left hover:bg-background/80" | |
| 207 | − > | |
| 208 | − <code className="truncate font-mono text-[10px] text-sidebar-foreground"> | |
| 209 | − {command} | |
| 210 | − </code> | |
| 211 | − <span className="shrink-0 text-muted-foreground transition-colors group-hover:text-foreground"> | |
| 212 | − {copied ? ( | |
| 213 | − <IconCheck className="size-3 text-primary" /> | |
| 214 | − ) : ( | |
| 215 | − <IconCopy className="size-3" /> | |
| 216 | − )} | |
| 217 | − </span> | |
| 218 | − </Button> | |
| 219 | − </div> | |
| 220 | − ); | |
| 221 | −} | |
| 222 | − | |
| 223 | −// ── AppShell ───────────────────────────────────────────────────────────── | |
| 224 | −export function AppShell() { | |
| 225 | − const sources = useSources(); | |
| 226 | − const location = useLocation(); | |
| 227 | − const matchRoute = useMatchRoute(); | |
| 228 | − const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false); | |
| 229 | − const isHome = matchRoute({ to: "/" }); | |
| 230 | − const isSecrets = matchRoute({ to: "/secrets" }); | |
| 231 | − const isPolicies = matchRoute({ to: "/policies" }); | |
| 232 | − const { latestVersion, updateAvailable, channel } = useLatestVersion(VITE_APP_VERSION); | |
| 233 | − const mainPluginNavItems = registeredFrontendPluginNavRoutes.filter( | |
| 234 | − ({ route }) => (route.nav?.section ?? "main") === "main", | |
| 235 | − ); | |
| 236 | − const sourcePluginNavItems = registeredFrontendPluginNavRoutes.filter( | |
| 237 | − ({ route }) => route.nav?.section === "sources", | |
| 238 | − ); | |
| 239 | − | |
| 240 | − useEffect(() => { | |
| 241 | − setMobileSidebarOpen(false); | |
| 242 | − }, [location.pathname]); | |
| 243 | − | |
| 244 | − useEffect(() => { | |
| 245 | − if (!mobileSidebarOpen) { | |
| 246 | − return; | |
| 247 | − } | |
| 248 | − | |
| 249 | − const previousOverflow = document.body.style.overflow; | |
| 250 | − document.body.style.overflow = "hidden"; | |
| 251 | − return () => { | |
| 252 | − document.body.style.overflow = previousOverflow; | |
| 253 | − }; | |
| 254 | − }, [mobileSidebarOpen]); | |
| 255 | − | |
| 256 | − return ( | |
| 257 | − <div className="flex h-screen overflow-hidden"> | |
| 258 | − <aside className="hidden w-52 shrink-0 border-r border-sidebar-border bg-sidebar md:flex md:flex-col lg:w-56"> | |
| 259 | − <SidebarContent | |
| 260 | − isHome={!!isHome} | |
| 261 | − isSecrets={!!isSecrets} | |
| 262 | − isPolicies={!!isPolicies} | |
| 263 | − latestVersion={latestVersion} | |
| 264 | − updateAvailable={updateAvailable} | |
| 265 | − channel={channel} | |
| 266 | − locationPathname={location.pathname} | |
| 267 | − mainPluginNavItems={mainPluginNavItems} | |
| 268 | − sourcePluginNavItems={sourcePluginNavItems} | |
| 269 | − sources={sources} | |
| 270 | − /> | |
| 271 | − </aside> | |
| 272 | − | |
| 273 | − {mobileSidebarOpen && ( | |
| 274 | − <div className="fixed inset-0 z-50 flex md:hidden"> | |
| 275 | − <button | |
| 276 | − type="button" | |
| 277 | − aria-label="Close navigation" | |
| 278 | − className="absolute inset-0 bg-black/45 backdrop-blur-[1px]" | |
| 279 | − onClick={() => setMobileSidebarOpen(false)} | |
| 280 | − /> | |
| 281 | − <div className="relative flex h-full w-[84vw] max-w-xs flex-col border-r border-sidebar-border bg-sidebar shadow-2xl"> | |
| 282 | − <div className="flex h-12 shrink-0 items-center justify-between border-b border-sidebar-border px-4"> | |
| 283 | − <Link to="/" className="flex items-center gap-1.5"> | |
| 284 | − <span className="font-display text-base tracking-tight text-foreground"> | |
| 285 | − executor | |
| 286 | − </span> | |
| 287 | − <span className="rounded bg-primary/15 px-1.5 py-0.5 text-[10px] font-medium text-primary"> | |
| 288 | − v3 | |
| 289 | − </span> | |
| 290 | − </Link> | |
| 291 | − <Button | |
| 292 | − type="button" | |
| 293 | − variant="ghost" | |
| 294 | − size="icon" | |
| 295 | − aria-label="Close navigation" | |
| 296 | − onClick={() => setMobileSidebarOpen(false)} | |
| 297 | − className="size-8 text-sidebar-foreground hover:bg-sidebar-active hover:text-foreground" | |
| 298 | − > | |
| 299 | − <IconClose className="size-3.5" /> | |
| 300 | − </Button> | |
| 301 | − </div> | |
| 302 | − <SidebarContent | |
| 303 | − isHome={!!isHome} | |
| 304 | − isSecrets={!!isSecrets} | |
| 305 | − isPolicies={!!isPolicies} | |
| 306 | − latestVersion={latestVersion} | |
| 307 | − updateAvailable={updateAvailable} | |
| 308 | − channel={channel} | |
| 309 | − locationPathname={location.pathname} | |
| 310 | − mainPluginNavItems={mainPluginNavItems} | |
| 311 | − sourcePluginNavItems={sourcePluginNavItems} | |
| 312 | − sources={sources} | |
| 313 | − onNavigate={() => setMobileSidebarOpen(false)} | |
| 314 | − showBrand={false} | |
| 315 | − /> | |
| 316 | − </div> | |
| 317 | − </div> | |
| 318 | − )} | |
| 319 | − | |
| 320 | − {/* Main content */} | |
| 321 | − <main className="flex min-h-0 flex-1 flex-col min-w-0 overflow-hidden"> | |
| 322 | − <div className="flex h-12 shrink-0 items-center justify-between border-b border-border bg-background px-4 md:hidden"> | |
| 323 | − <Button | |
| 324 | − type="button" | |
| 325 | − variant="outline" | |
| 326 | − size="icon" | |
| 327 | − aria-label="Open navigation" | |
| 328 | − onClick={() => setMobileSidebarOpen(true)} | |
| 329 | − className="size-8 bg-card hover:bg-accent/50" | |
| 330 | − > | |
| 331 | − <IconMenu className="size-4" /> | |
| 332 | − </Button> | |
| 333 | − <Link to="/" className="flex items-center gap-1.5"> | |
| 334 | − <span className="font-display text-base tracking-tight text-foreground"> | |
| 335 | − executor | |
| 336 | − </span> | |
| 337 | − <span className="rounded bg-primary/15 px-1.5 py-0.5 text-[10px] font-medium text-primary"> | |
| 338 | − v3 | |
| 339 | − </span> | |
| 340 | − </Link> | |
| 341 | − <div className="w-8 shrink-0" /> | |
| 342 | − </div> | |
| 343 | − <Outlet /> | |
| 344 | − </main> | |
| 345 | − </div> | |
| 346 | − ); | |
| 347 | −} | |
| 348 | − | |
| 349 | −function SidebarContent(props: { | |
| 350 | − isHome: boolean; | |
| 351 | − isSecrets: boolean; | |
| 352 | − isPolicies: boolean; | |
| 353 | − latestVersion: string | null; | |
| 354 | − updateAvailable: boolean; | |
| 355 | − channel: UpdateChannel; | |
| 356 | − locationPathname: string; | |
| 357 | − mainPluginNavItems: typeof registeredFrontendPluginNavRoutes; | |
| 358 | − sourcePluginNavItems: typeof registeredFrontendPluginNavRoutes; | |
| 359 | − sources: ReturnType<typeof useSources>; | |
| 360 | − onNavigate?: () => void; | |
| 361 | − showBrand?: boolean; | |
| 362 | −}) { | |
| 363 | − return ( | |
| 364 | − <> | |
| 365 | − {props.showBrand !== false && ( | |
| 366 | − <div className="flex h-12 shrink-0 items-center border-b border-sidebar-border px-4"> | |
| 367 | − <Link to="/" className="flex items-center gap-1.5"> | |
| 368 | − <span className="font-display text-base tracking-tight text-foreground"> | |
| 369 | − executor | |
| 370 | − </span> | |
| 371 | − <span className="rounded bg-primary/15 px-1.5 py-0.5 text-[10px] font-medium text-primary"> | |
| 372 | − v3 | |
| 373 | − </span> | |
| 374 | − </Link> | |
| 375 | − </div> | |
| 376 | − )} | |
| 377 | − | |
| 378 | − <nav className="flex flex-1 flex-col overflow-y-auto p-2"> | |
| 379 | − <NavItem | |
| 380 | − to="/" | |
| 381 | − label="Dashboard" | |
| 382 | − active={props.isHome} | |
| 383 | − onNavigate={props.onNavigate} | |
| 384 | − /> | |
| 385 | − <NavItem | |
| 386 | − to="/secrets" | |
| 387 | − label="Secrets" | |
| 388 | − active={props.isSecrets} | |
| 389 | − onNavigate={props.onNavigate} | |
| 390 | − /> | |
| 391 | − <NavItem | |
| 392 | − to="/policies" | |
| 393 | − label="Policies" | |
| 394 | − active={props.isPolicies} | |
| 395 | − onNavigate={props.onNavigate} | |
| 396 | − /> | |
| 397 | − {props.mainPluginNavItems.map(({ plugin, route, to }) => ( | |
| 398 | − <NavItem | |
| 399 | − key={`${plugin.key}:${route.key}`} | |
| 400 | − to={to} | |
| 401 | − label={route.nav?.label ?? route.key} | |
| 402 | − active={ | |
| 403 | − props.locationPathname === to | |
| 404 | − || props.locationPathname.startsWith(`${to}/`) | |
| 405 | − } | |
| 406 | − onNavigate={props.onNavigate} | |
| 407 | − /> | |
| 408 | − ))} | |
| 409 | − | |
| 410 | − <div className="mt-5 mb-1 px-2.5 text-[10px] font-medium uppercase tracking-widest text-muted-foreground/50"> | |
| 411 | − <div className="flex items-center justify-between gap-2"> | |
| 412 | − <span>Sources</span> | |
| 413 | − <Link | |
| 414 | − to={sourcePluginsIndexPath} | |
| 415 | − onClick={props.onNavigate} | |
| 416 | − className="inline-flex items-center gap-1 rounded-md px-1.5 py-1 text-[10px] font-medium normal-case tracking-normal text-primary transition-colors hover:bg-sidebar-active hover:text-foreground" | |
| 417 | − > | |
| 418 | − <IconPlus className="size-3" /> | |
| 419 | − Add | |
| 420 | − </Link> | |
| 421 | − </div> | |
| 422 | − </div> | |
| 423 | − {props.sourcePluginNavItems.length > 0 && ( | |
| 424 | − <div className="mb-2 flex flex-col gap-px"> | |
| 425 | − {props.sourcePluginNavItems.map(({ plugin, route, to }) => ( | |
| 426 | − <NavItem | |
| 427 | − key={`${plugin.key}:${route.key}`} | |
| 428 | − to={to} | |
| 429 | − label={route.nav?.label ?? route.key} | |
| 430 | − active={ | |
| 431 | − props.locationPathname === to | |
| 432 | − || props.locationPathname.startsWith(`${to}/`) | |
| 433 | − } | |
| 434 | − onNavigate={props.onNavigate} | |
| 435 | − /> | |
| 436 | − ))} | |
| 437 | − </div> | |
| 438 | − )} | |
| 439 | − <LoadableBlock loadable={props.sources} loading="Loading..."> | |
| 440 | − {(items) => | |
| 441 | − !Array.isArray(items) ? ( | |
| 442 | − <div className="px-2.5 py-2 text-[11px] leading-relaxed text-destructive"> | |
| 443 | − Sources returned an unexpected payload. | |
| 444 | − </div> | |
| 445 | − ) : items.length === 0 ? ( | |
| 446 | − <div className="px-2.5 py-2 text-[11px] leading-relaxed text-muted-foreground/40"> | |
| 447 | − No sources yet | |
| 448 | − </div> | |
| 449 | − ) : ( | |
| 450 | − <div className="flex flex-col gap-px"> | |
| 451 | − {items.map((source) => ( | |
| 452 | − <SourceItem | |
| 453 | − key={source.id} | |
| 454 | − pathname={props.locationPathname} | |
| 455 | − source={source} | |
| 456 | − onNavigate={props.onNavigate} | |
| 457 | − /> | |
| 458 | − ))} | |
| 459 | − </div> | |
| 460 | − ) | |
| 461 | − } | |
| 462 | − </LoadableBlock> | |
| 463 | − </nav> | |
| 464 | − | |
| 465 | − {props.updateAvailable && props.latestVersion && ( | |
| 466 | − <UpdateCard latestVersion={props.latestVersion} channel={props.channel} /> | |
| 467 | − )} | |
| 468 | − | |
| 469 | − <div className="shrink-0 border-t border-sidebar-border px-4 py-2.5"> | |
| 470 | − <div className="flex items-center justify-between text-[10px] leading-none"> | |
| 471 | − <span className="text-muted-foreground/70 tabular-nums">v{VITE_APP_VERSION}</span> | |
| 472 | − <a | |
| 473 | − href={VITE_GITHUB_URL} | |
| 474 | − target="_blank" | |
| 475 | − rel="noreferrer" | |
| 476 | − className="text-muted-foreground/70 transition-colors hover:text-foreground" | |
| 477 | − > | |
| 478 | − GitHub | |
| 479 | − </a> | |
| 480 | − </div> | |
| 481 | − </div> | |
| 482 | − </> | |
| 483 | − ); | |
| 484 | −} | |
| 485 | − | |
| 486 | −// ── SourceItem ─────────────────────────────────────────────────────────── | |
| 487 | − | |
| 488 | −function SourceItem(props: { | |
| 489 | − pathname: string; | |
| 490 | − source: Source; | |
| 491 | − onNavigate?: () => void; | |
| 492 | −}) { | |
| 493 | − const paths = getSourceFrontendPaths(props.source.kind); | |
| 494 | − | |
| 495 | − if (!paths) { | |
| 496 | − return ( | |
| 497 | − <div className="group flex items-center gap-2 rounded-md px-2.5 py-1.5 text-[13px] text-sidebar-foreground/60"> | |
| 498 | − <div className="flex size-3 shrink-0 items-center justify-center text-muted-foreground/50"> | |
| 499 | − <SourceFavicon source={props.source} className="size-3" /> | |
| 500 | − </div> | |
| 501 | − <span className="flex-1 truncate">{props.source.name}</span> | |
| 502 | − <span | |
| 503 | − className={cn("size-1.5 shrink-0 rounded-full", statusColor[props.source.status] ?? "bg-muted-foreground/30")} | |
| 504 | − title={props.source.status} | |
| 505 | − /> | |
| 506 | − </div> | |
| 507 | − ); | |
| 508 | − } | |
| 509 | − | |
| 510 | − const detailPath = paths.detail(props.source.id); | |
| 511 | − const active = | |
| 512 | − props.pathname === detailPath | |
| 513 | − || props.pathname.startsWith(`${detailPath}/`); | |
| 514 | − | |
| 515 | − return ( | |
| 516 | − <Link | |
| 517 | − to={detailPath} | |
| 518 | − search={{ tab: "model" }} | |
| 519 | − onClick={props.onNavigate} | |
| 520 | − className={cn( | |
| 521 | − "group flex items-center gap-2 rounded-md px-2.5 py-1.5 text-[13px] transition-colors", | |
| 522 | − active | |
| 523 | − ? "bg-sidebar-active text-foreground font-medium" | |
| 524 | − : "text-sidebar-foreground hover:bg-sidebar-active/60 hover:text-foreground", | |
| 525 | − )} | |
| 526 | − > | |
| 527 | − <div className="flex size-3 shrink-0 items-center justify-center text-muted-foreground/50"> | |
| 528 | − <SourceFavicon source={props.source} className="size-3" /> | |
| 529 | − </div> | |
| 530 | − <span className="flex-1 truncate">{props.source.name}</span> | |
| 531 | − <span | |
| 532 | − className={cn("size-1.5 shrink-0 rounded-full", statusColor[props.source.status] ?? "bg-muted-foreground/30")} | |
| 533 | − title={props.source.status} | |
| 534 | − /> | |
| 535 | − </Link> | |
| 536 | − ); | |
| 537 | −} | |
| 538 | − | |
| 539 | −// ── NavItem ────────────────────────────────────────────────────────────── | |
| 540 | − | |
| 541 | −function NavItem(props: { | |
| 542 | − to: string; | |
| 543 | − label: string; | |
| 544 | − active: boolean; | |
| 545 | − onNavigate?: () => void; | |
| 546 | −}) { | |
| 547 | − return ( | |
| 548 | − <Link | |
| 549 | − to={props.to} | |
| 550 | − onClick={props.onNavigate} | |
| 551 | − className={cn( | |
| 552 | − "flex items-center gap-2.5 rounded-md px-2.5 py-1.5 text-[13px] transition-colors", | |
| 553 | − props.active | |
| 554 | − ? "bg-sidebar-active text-foreground font-medium" | |
| 555 | − : "text-sidebar-foreground hover:bg-sidebar-active/60 hover:text-foreground", | |
| 556 | − )} | |
| 557 | − > | |
| 558 | − {props.label} | |
| 559 | − </Link> | |
| 560 | − ); | |
| 561 | −} | |
| @@ -1,133 +0,0 @@ | ||
| 1 | −import { useState } from "react"; | |
| 2 | −import type { Source } from "@executor/react"; | |
| 3 | −import { getGoogleDiscoveryIconUrlForService } from "@executor/plugin-google-discovery-react"; | |
| 4 | −import { getSourceFrontendIconUrl } from "../plugins"; | |
| 5 | −import type { SourcePreset } from "../plugins/source-presets"; | |
| 6 | −import { getSourceFaviconUrl } from "../lib/source-favicon"; | |
| 7 | −import { cn } from "../lib/utils"; | |
| 8 | − | |
| 9 | −type SourceKind = Source["kind"] | SourcePreset["kind"] | string; | |
| 10 | − | |
| 11 | −export function SourceFavicon({ | |
| 12 | − source, | |
| 13 | − className, | |
| 14 | − size = 16, | |
| 15 | −}: { | |
| 16 | − source: Source; | |
| 17 | − className?: string; | |
| 18 | − size?: number; | |
| 19 | −}) { | |
| 20 | − return ( | |
| 21 | − <ResolvedSourceIcon | |
| 22 | − kind={source.kind} | |
| 23 | − faviconUrl={getSourceFrontendIconUrl(source)} | |
| 24 | − className={className} | |
| 25 | − size={size} | |
| 26 | − /> | |
| 27 | − ); | |
| 28 | −} | |
| 29 | − | |
| 30 | −export function SourcePresetFavicon({ | |
| 31 | − preset, | |
| 32 | − className, | |
| 33 | − size = 16, | |
| 34 | −}: { | |
| 35 | − preset: SourcePreset; | |
| 36 | − className?: string; | |
| 37 | − size?: number; | |
| 38 | −}) { | |
| 39 | − const faviconUrl = preset.kind === "google_discovery" | |
| 40 | − ? getGoogleDiscoveryIconUrlForService(preset.service) | |
| 41 | − : getSourceFaviconUrl(preset.previewUrl); | |
| 42 | − | |
| 43 | − return ( | |
| 44 | − <ResolvedSourceIcon | |
| 45 | − kind={preset.kind} | |
| 46 | − faviconUrl={faviconUrl ?? getSourceFaviconUrl(preset.name)} | |
| 47 | − className={className} | |
| 48 | − size={size} | |
| 49 | − /> | |
| 50 | − ); | |
| 51 | −} | |
| 52 | − | |
| 53 | −function ResolvedSourceIcon({ | |
| 54 | − kind, | |
| 55 | − faviconUrl, | |
| 56 | − className, | |
| 57 | − size = 16, | |
| 58 | −}: { | |
| 59 | − kind: SourceKind; | |
| 60 | − faviconUrl: string | null; | |
| 61 | − className?: string; | |
| 62 | − size?: number; | |
| 63 | −}) { | |
| 64 | − const [failedUrl, setFailedUrl] = useState<string | null>(null); | |
| 65 | − const isFailed = Boolean(faviconUrl && failedUrl === faviconUrl); | |
| 66 | − | |
| 67 | − if (!faviconUrl || isFailed) { | |
| 68 | − return <DefaultSourceIcon kind={kind} className={className} />; | |
| 69 | − } | |
| 70 | − | |
| 71 | − return ( | |
| 72 | − <img | |
| 73 | − key={faviconUrl} | |
| 74 | − src={faviconUrl} | |
| 75 | − alt="" | |
| 76 | − width={size} | |
| 77 | − height={size} | |
| 78 | − className={cn("size-full object-contain", className)} | |
| 79 | − loading="lazy" | |
| 80 | − referrerPolicy="no-referrer" | |
| 81 | − onError={() => setFailedUrl(faviconUrl)} | |
| 82 | − /> | |
| 83 | − ); | |
| 84 | −} | |
| 85 | − | |
| 86 | −export function DefaultSourceIcon({ | |
| 87 | − kind, | |
| 88 | − className, | |
| 89 | −}: { | |
| 90 | − kind: SourceKind; | |
| 91 | − className?: string; | |
| 92 | −}) { | |
| 93 | − const base = cn("shrink-0", className); | |
| 94 | − | |
| 95 | − switch (kind) { | |
| 96 | − case "mcp": | |
| 97 | − return ( | |
| 98 | − <svg viewBox="0 0 16 16" fill="none" className={base}> | |
| 99 | − <rect x="2" y="3" width="12" height="10" rx="1.5" stroke="currentColor" strokeWidth="1.2" /> | |
| 100 | − <path d="M5 7h1M5 9h4" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" /> | |
| 101 | − </svg> | |
| 102 | − ); | |
| 103 | − case "graphql": | |
| 104 | − return ( | |
| 105 | − <svg viewBox="0 0 16 16" fill="none" className={base}> | |
| 106 | − <path d="M8 2L14 5.5V10.5L8 14L2 10.5V5.5L8 2Z" stroke="currentColor" strokeWidth="1.2" strokeLinejoin="round" /> | |
| 107 | − <circle cx="8" cy="8" r="1.5" fill="currentColor" opacity="0.5" /> | |
| 108 | − </svg> | |
| 109 | − ); | |
| 110 | − case "google_discovery": | |
| 111 | − return ( | |
| 112 | − <svg viewBox="0 0 16 16" fill="none" className={base}> | |
| 113 | − <path d="M8 2.5a5.5 5.5 0 1 0 0 11 5.3 5.3 0 0 0 3.82-1.55" stroke="currentColor" strokeWidth="1.2" /> | |
| 114 | − <path d="M13 8H8" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" /> | |
| 115 | − <circle cx="12.5" cy="8" r="1.2" fill="currentColor" /> | |
| 116 | − </svg> | |
| 117 | − ); | |
| 118 | − case "openapi": | |
| 119 | − return ( | |
| 120 | − <svg viewBox="0 0 16 16" fill="none" className={base}> | |
| 121 | − <circle cx="8" cy="8" r="6" stroke="currentColor" strokeWidth="1.2" /> | |
| 122 | − <path d="M5 6h6M5 8h4M5 10h5" stroke="currentColor" strokeWidth="1.1" strokeLinecap="round" /> | |
| 123 | − </svg> | |
| 124 | − ); | |
| 125 | − default: | |
| 126 | − return ( | |
| 127 | − <svg viewBox="0 0 16 16" fill="none" className={base}> | |
| 128 | − <rect x="2.5" y="2.5" width="11" height="11" rx="2" stroke="currentColor" strokeWidth="1.2" /> | |
| 129 | − <path d="M5 6h6M5 8h4M5 10h3" stroke="currentColor" strokeWidth="1.1" strokeLinecap="round" /> | |
| 130 | − </svg> | |
| 131 | − ); | |
| 132 | − } | |
| 133 | −} | |
| @@ -1,39 +0,0 @@ | ||
| 1 | −import { Link } from "@tanstack/react-router"; | |
| 2 | −import { sourcePluginsIndexPath } from "@executor/react/plugins"; | |
| 3 | − | |
| 4 | −import { IconEmpty } from "./icons"; | |
| 5 | −import { cn } from "../lib/utils"; | |
| 6 | − | |
| 7 | −export function SourceNotFoundState() { | |
| 8 | − return ( | |
| 9 | − <div className="flex h-full min-h-48 items-center justify-center px-6"> | |
| 10 | − <div className="flex max-w-sm flex-col items-center text-center"> | |
| 11 | − <IconEmpty className="mb-4 text-muted-foreground/20" /> | |
| 12 | − <h2 className="text-sm font-semibold text-foreground">Source not found</h2> | |
| 13 | − <p className="mt-2 text-sm text-muted-foreground"> | |
| 14 | − This source no longer exists in the current workspace. | |
| 15 | − </p> | |
| 16 | − <div className="mt-5 flex items-center gap-2"> | |
| 17 | − <Link | |
| 18 | − to="/" | |
| 19 | − className={cn( | |
| 20 | − "inline-flex h-7 items-center justify-center rounded-md border border-input bg-transparent px-2.5 text-xs font-medium transition-all", | |
| 21 | − "hover:bg-accent hover:text-accent-foreground", | |
| 22 | − )} | |
| 23 | − > | |
| 24 | − Back to dashboard | |
| 25 | − </Link> | |
| 26 | − <Link | |
| 27 | − to={sourcePluginsIndexPath} | |
| 28 | − className={cn( | |
| 29 | − "inline-flex h-7 items-center justify-center rounded-md bg-primary px-2.5 text-xs font-medium text-primary-foreground transition-all", | |
| 30 | − "hover:bg-primary/90", | |
| 31 | − )} | |
| 32 | − > | |
| 33 | − Add source | |
| 34 | − </Link> | |
| 35 | − </div> | |
| 36 | − </div> | |
| 37 | − </div> | |
| 38 | − ); | |
| 39 | −} | |
| @@ -1,27 +0,0 @@ | ||
| 1 | −import type { ReactNode } from "react"; | |
| 2 | − | |
| 3 | −type SourcePluginsResetStateProps = { | |
| 4 | − title: string; | |
| 5 | − message: string; | |
| 6 | − action?: ReactNode; | |
| 7 | −}; | |
| 8 | − | |
| 9 | −export function SourcePluginsResetState( | |
| 10 | − input: SourcePluginsResetStateProps, | |
| 11 | −) { | |
| 12 | − return ( | |
| 13 | − <div className="min-h-0 flex-1 overflow-y-auto"> | |
| 14 | − <div className="mx-auto max-w-3xl px-6 py-10 lg:px-10 lg:py-14"> | |
| 15 | − <div className="rounded-2xl border border-border bg-card p-8"> | |
| 16 | − <h2 className="font-display text-xl tracking-tight text-foreground"> | |
| 17 | − {input.title} | |
| 18 | − </h2> | |
| 19 | − <p className="mt-2 max-w-2xl text-sm leading-6 text-muted-foreground"> | |
| 20 | − {input.message} | |
| 21 | − </p> | |
| 22 | − {input.action ? <div className="mt-5">{input.action}</div> : null} | |
| 23 | − </div> | |
| 24 | − </div> | |
| 25 | − </div> | |
| 26 | − ); | |
| 27 | −} | |
| @@ -1,57 +0,0 @@ | ||
| 1 | −import type { Source } from "@executor/react"; | |
| 2 | − | |
| 3 | −import { Badge, Button } from "@executor/react/plugins"; | |
| 4 | −import { cn } from "../lib/utils"; | |
| 5 | −import { IconSpinner, IconTool } from "./icons"; | |
| 6 | − | |
| 7 | −export function SourceRecoveryState(props: { | |
| 8 | − source: Source; | |
| 9 | − title: string; | |
| 10 | − description: string; | |
| 11 | − refreshLabel?: string; | |
| 12 | − refreshTitle?: string; | |
| 13 | − refreshDisabled?: boolean; | |
| 14 | − refreshPending?: boolean; | |
| 15 | − feedback?: { | |
| 16 | − tone: "success" | "error"; | |
| 17 | − text: string; | |
| 18 | − } | null; | |
| 19 | − onRefresh: () => void; | |
| 20 | −}) { | |
| 21 | − return ( | |
| 22 | − <div className="flex h-full min-h-48 items-center justify-center px-6"> | |
| 23 | − <div className="flex max-w-md flex-col items-center text-center"> | |
| 24 | − <div className="mb-4 flex size-12 items-center justify-center rounded-2xl bg-muted text-muted-foreground"> | |
| 25 | − <IconTool className="size-5" /> | |
| 26 | − </div> | |
| 27 | − <h2 className="text-sm font-semibold text-foreground">{props.title}</h2> | |
| 28 | − <div className="mt-2 flex items-center gap-2"> | |
| 29 | − <span className="text-sm text-muted-foreground">{props.source.name}</span> | |
| 30 | − <Badge variant="outline">{props.source.kind}</Badge> | |
| 31 | − </div> | |
| 32 | − <p className="mt-3 text-sm text-muted-foreground">{props.description}</p> | |
| 33 | − {props.feedback && ( | |
| 34 | − <p | |
| 35 | − className={cn( | |
| 36 | − "mt-4 text-sm font-medium", | |
| 37 | − props.feedback.tone === "success" ? "text-primary" : "text-destructive", | |
| 38 | − )} | |
| 39 | − > | |
| 40 | − {props.feedback.text} | |
| 41 | − </p> | |
| 42 | − )} | |
| 43 | − <div className="mt-5 flex items-center gap-2"> | |
| 44 | − <Button | |
| 45 | − size="sm" | |
| 46 | − onClick={props.onRefresh} | |
| 47 | − disabled={props.refreshDisabled} | |
| 48 | − title={props.refreshTitle} | |
| 49 | − > | |
| 50 | − {props.refreshPending ? <IconSpinner className="size-3" /> : null} | |
| 51 | − {props.refreshLabel ?? "Refresh source"} | |
| 52 | − </Button> | |
| 53 | − </div> | |
| 54 | − </div> | |
| 55 | − </div> | |
| 56 | − ); | |
| 57 | −} | |
| @@ -0,0 +1,203 @@ | ||
| 1 | +import { useMemo, useState } from "react"; | |
| 2 | +import { useAtomValue, toolSchemaAtom, Result, ScopeId, ToolId } from "@executor/react"; | |
| 3 | +import { CodeBlock } from "@executor/ui/components/code-block"; | |
| 4 | +import { Markdown } from "@executor/ui/components/markdown"; | |
| 5 | +import { schemaToTypeDeclaration } from "../lib/schema-type-signature"; | |
| 6 | + | |
| 7 | +// --------------------------------------------------------------------------- | |
| 8 | +// Copy button | |
| 9 | +// --------------------------------------------------------------------------- | |
| 10 | + | |
| 11 | +function CopyButton(props: { text: string; label?: string }) { | |
| 12 | + const [copied, setCopied] = useState(false); | |
| 13 | + | |
| 14 | + return ( | |
| 15 | + <button | |
| 16 | + type="button" | |
| 17 | + onClick={() => { | |
| 18 | + void navigator.clipboard.writeText(props.text).then(() => { | |
| 19 | + setCopied(true); | |
| 20 | + setTimeout(() => setCopied(false), 1500); | |
| 21 | + }); | |
| 22 | + }} | |
| 23 | + className="size-6 shrink-0 flex items-center justify-center text-muted-foreground/30 hover:text-muted-foreground transition-colors" | |
| 24 | + title={props.label ?? "Copy"} | |
| 25 | + > | |
| 26 | + {copied ? ( | |
| 27 | + <svg viewBox="0 0 16 16" className="size-3.5"> | |
| 28 | + <path d="M3 8l3 3 7-7" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" /> | |
| 29 | + </svg> | |
| 30 | + ) : ( | |
| 31 | + <svg viewBox="0 0 16 16" className="size-3.5"> | |
| 32 | + <rect x="5" y="5" width="8" height="8" rx="1" fill="none" stroke="currentColor" strokeWidth="1.2" /> | |
| 33 | + <path d="M3 11V3h8" fill="none" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" /> | |
| 34 | + </svg> | |
| 35 | + )} | |
| 36 | + </button> | |
| 37 | + ); | |
| 38 | +} | |
| 39 | + | |
| 40 | +// --------------------------------------------------------------------------- | |
| 41 | +// Build type declarations from schemas | |
| 42 | +// --------------------------------------------------------------------------- | |
| 43 | + | |
| 44 | +const buildCallSignature = ( | |
| 45 | + toolName: string, | |
| 46 | + inputSchema: unknown, | |
| 47 | + outputSchema: unknown, | |
| 48 | +): string => { | |
| 49 | + const inputType = inputSchema | |
| 50 | + ? schemaToTypeDeclaration(inputSchema) | |
| 51 | + : "void"; | |
| 52 | + const outputType = outputSchema | |
| 53 | + ? schemaToTypeDeclaration(outputSchema) | |
| 54 | + : "void"; | |
| 55 | + | |
| 56 | + const leaf = toolName.split(".").pop() ?? toolName; | |
| 57 | + return `declare function ${leaf}(input: ${inputType}): ${outputType}`; | |
| 58 | +}; | |
| 59 | + | |
| 60 | +// --------------------------------------------------------------------------- | |
| 61 | +// ToolDetail | |
| 62 | +// --------------------------------------------------------------------------- | |
| 63 | + | |
| 64 | +export function ToolDetail(props: { | |
| 65 | + toolId: string; | |
| 66 | + toolName: string; | |
| 67 | + toolDescription?: string; | |
| 68 | + scopeId: ScopeId; | |
| 69 | +}) { | |
| 70 | + const schema = useAtomValue( | |
| 71 | + toolSchemaAtom(props.scopeId, props.toolId as ToolId), | |
| 72 | + ); | |
| 73 | + | |
| 74 | + const types = useMemo(() => { | |
| 75 | + if (!Result.isSuccess(schema)) return null; | |
| 76 | + const v = schema.value; | |
| 77 | + return { | |
| 78 | + input: v.inputSchema ? schemaToTypeDeclaration(v.inputSchema, "Input") : null, | |
| 79 | + output: v.outputSchema ? schemaToTypeDeclaration(v.outputSchema, "Output") : null, | |
| 80 | + callSignature: buildCallSignature(props.toolName, v.inputSchema, v.outputSchema), | |
| 81 | + inputJson: v.inputSchema ? JSON.stringify(v.inputSchema, null, 2) : null, | |
| 82 | + outputJson: v.outputSchema ? JSON.stringify(v.outputSchema, null, 2) : null, | |
| 83 | + }; | |
| 84 | + }, [schema, props.toolName]); | |
| 85 | + | |
| 86 | + return ( | |
| 87 | + <div className="flex h-full flex-col overflow-hidden"> | |
| 88 | + {/* Header */} | |
| 89 | + <div className="shrink-0 max-h-[40%] overflow-y-auto border-b border-border bg-background/95 backdrop-blur-sm"> | |
| 90 | + <div className="flex items-start gap-3 px-5 py-3.5"> | |
| 91 | + <div className="flex size-8 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary"> | |
| 92 | + <svg viewBox="0 0 16 16" className="size-4"> | |
| 93 | + <path | |
| 94 | + d="M4 2h8l1 3H3l1-3zM3 6h10v8H3V6z" | |
| 95 | + fill="none" | |
| 96 | + stroke="currentColor" | |
| 97 | + strokeWidth="1.2" | |
| 98 | + /> | |
| 99 | + </svg> | |
| 100 | + </div> | |
| 101 | + <div className="min-w-0 flex-1"> | |
| 102 | + <div className="flex items-center gap-2"> | |
| 103 | + <h3 className="truncate text-sm font-semibold text-foreground font-mono"> | |
| 104 | + {props.toolName} | |
| 105 | + </h3> | |
| 106 | + <CopyButton text={props.toolId} label="Copy tool ID" /> | |
| 107 | + </div> | |
| 108 | + {props.toolDescription && ( | |
| 109 | + <div className="mt-1"> | |
| 110 | + <Markdown>{props.toolDescription}</Markdown> | |
| 111 | + </div> | |
| 112 | + )} | |
| 113 | + </div> | |
| 114 | + </div> | |
| 115 | + </div> | |
| 116 | + | |
| 117 | + {/* Content */} | |
| 118 | + <div className="flex-1 overflow-y-auto"> | |
| 119 | + {Result.match(schema, { | |
| 120 | + onInitial: () => ( | |
| 121 | + <div className="p-5 text-sm text-muted-foreground">Loading schema…</div> | |
| 122 | + ), | |
| 123 | + onFailure: () => ( | |
| 124 | + <div className="p-5 text-sm text-destructive">Failed to load schema</div> | |
| 125 | + ), | |
| 126 | + onSuccess: () => ( | |
| 127 | + <div className="space-y-4 px-5 py-4"> | |
| 128 | + {/* Call signature */} | |
| 129 | + {types?.callSignature && ( | |
| 130 | + <CodeBlock | |
| 131 | + title="Call Signature" | |
| 132 | + code={types.callSignature} | |
| 133 | + lang="typescript" | |
| 134 | + /> | |
| 135 | + )} | |
| 136 | + | |
| 137 | + {/* Type declarations */} | |
| 138 | + <div className="grid grid-cols-1 gap-3 xl:grid-cols-2"> | |
| 139 | + {types?.input ? ( | |
| 140 | + <CodeBlock title="Input" code={types.input} lang="typescript" /> | |
| 141 | + ) : ( | |
| 142 | + <div className="rounded-lg border border-border bg-card/60 px-3 py-6 text-center text-[13px] text-muted-foreground/40"> | |
| 143 | + No input | |
| 144 | + </div> | |
| 145 | + )} | |
| 146 | + {types?.output ? ( | |
| 147 | + <CodeBlock title="Output" code={types.output} lang="typescript" /> | |
| 148 | + ) : ( | |
| 149 | + <div className="rounded-lg border border-border bg-card/60 px-3 py-6 text-center text-[13px] text-muted-foreground/40"> | |
| 150 | + No output | |
| 151 | + </div> | |
| 152 | + )} | |
| 153 | + </div> | |
| 154 | + | |
| 155 | + {/* JSON Schemas */} | |
| 156 | + <div className="grid grid-cols-1 gap-3 xl:grid-cols-2"> | |
| 157 | + {types?.inputJson ? ( | |
| 158 | + <CodeBlock title="Input Schema" code={types.inputJson} /> | |
| 159 | + ) : ( | |
| 160 | + <div className="rounded-lg border border-border bg-card/60 px-3 py-6 text-center text-[13px] text-muted-foreground/40"> | |
| 161 | + No input schema | |
| 162 | + </div> | |
| 163 | + )} | |
| 164 | + {types?.outputJson ? ( | |
| 165 | + <CodeBlock title="Output Schema" code={types.outputJson} /> | |
| 166 | + ) : ( | |
| 167 | + <div className="rounded-lg border border-border bg-card/60 px-3 py-6 text-center text-[13px] text-muted-foreground/40"> | |
| 168 | + No output schema | |
| 169 | + </div> | |
| 170 | + )} | |
| 171 | + </div> | |
| 172 | + </div> | |
| 173 | + ), | |
| 174 | + })} | |
| 175 | + </div> | |
| 176 | + </div> | |
| 177 | + ); | |
| 178 | +} | |
| 179 | + | |
| 180 | +// --------------------------------------------------------------------------- | |
| 181 | +// Empty state | |
| 182 | +// --------------------------------------------------------------------------- | |
| 183 | + | |
| 184 | +export function ToolDetailEmpty(props: { hasTools: boolean }) { | |
| 185 | + return ( | |
| 186 | + <div className="flex h-full items-center justify-center"> | |
| 187 | + <div className="text-center"> | |
| 188 | + <p className="text-sm font-medium text-foreground/70"> | |
| 189 | + {props.hasTools ? "Select a tool" : "No tools available"} | |
| 190 | + </p> | |
| 191 | + {props.hasTools && ( | |
| 192 | + <p className="mt-1 text-xs text-muted-foreground"> | |
| 193 | + Choose from the list or press{" "} | |
| 194 | + <kbd className="rounded border border-border bg-muted px-1 py-px text-[10px]"> | |
| 195 | + / | |
| 196 | + </kbd>{" "} | |
| 197 | + to search. | |
| 198 | + </p> | |
| 199 | + )} | |
| 200 | + </div> | |
| 201 | + </div> | |
| 202 | + ); | |
| 203 | +} | |
| @@ -0,0 +1,367 @@ | ||
| 1 | +import { useEffect, useMemo, useRef, useState } from "react"; | |
| 2 | + | |
| 3 | +// --------------------------------------------------------------------------- | |
| 4 | +// Types | |
| 5 | +// --------------------------------------------------------------------------- | |
| 6 | + | |
| 7 | +export interface ToolSummary { | |
| 8 | + readonly id: string; | |
| 9 | + readonly name: string; | |
| 10 | + readonly pluginKey: string; | |
| 11 | + readonly description?: string; | |
| 12 | +} | |
| 13 | + | |
| 14 | +type TreeNode = { | |
| 15 | + segment: string; | |
| 16 | + tool?: ToolSummary; | |
| 17 | + children: Map<string, TreeNode>; | |
| 18 | +}; | |
| 19 | + | |
| 20 | +// --------------------------------------------------------------------------- | |
| 21 | +// Tree builder | |
| 22 | +// --------------------------------------------------------------------------- | |
| 23 | + | |
| 24 | +const buildTree = (tools: readonly ToolSummary[]): TreeNode => { | |
| 25 | + const root: TreeNode = { segment: "", children: new Map() }; | |
| 26 | + | |
| 27 | + for (const tool of tools) { | |
| 28 | + const parts = tool.name.split("."); | |
| 29 | + let node = root; | |
| 30 | + for (const part of parts) { | |
| 31 | + let child = node.children.get(part); | |
| 32 | + if (!child) { | |
| 33 | + child = { segment: part, children: new Map() }; | |
| 34 | + node.children.set(part, child); | |
| 35 | + } | |
| 36 | + node = child; | |
| 37 | + } | |
| 38 | + node.tool = tool; | |
| 39 | + } | |
| 40 | + | |
| 41 | + return root; | |
| 42 | +}; | |
| 43 | + | |
| 44 | +const countLeaves = (node: TreeNode): number => { | |
| 45 | + let count = node.tool ? 1 : 0; | |
| 46 | + for (const child of node.children.values()) { | |
| 47 | + count += countLeaves(child); | |
| 48 | + } | |
| 49 | + return count; | |
| 50 | +}; | |
| 51 | + | |
| 52 | +// --------------------------------------------------------------------------- | |
| 53 | +// Highlight | |
| 54 | +// --------------------------------------------------------------------------- | |
| 55 | + | |
| 56 | +const highlightMatch = (text: string, search: string) => { | |
| 57 | + if (!search.trim()) return text; | |
| 58 | + | |
| 59 | + const terms = search.trim().toLowerCase().split(/\s+/); | |
| 60 | + const lower = text.toLowerCase(); | |
| 61 | + const ranges: [number, number][] = []; | |
| 62 | + | |
| 63 | + for (const term of terms) { | |
| 64 | + let idx = 0; | |
| 65 | + while (idx < lower.length) { | |
| 66 | + const found = lower.indexOf(term, idx); | |
| 67 | + if (found === -1) break; | |
| 68 | + ranges.push([found, found + term.length]); | |
| 69 | + idx = found + 1; | |
| 70 | + } | |
| 71 | + } | |
| 72 | + | |
| 73 | + if (ranges.length === 0) return text; | |
| 74 | + | |
| 75 | + ranges.sort((a, b) => a[0] - b[0]); | |
| 76 | + const merged: [number, number][] = [ranges[0]!]; | |
| 77 | + for (let i = 1; i < ranges.length; i++) { | |
| 78 | + const last = merged[merged.length - 1]!; | |
| 79 | + const cur = ranges[i]!; | |
| 80 | + if (cur[0] <= last[1]) { | |
| 81 | + last[1] = Math.max(last[1], cur[1]); | |
| 82 | + } else { | |
| 83 | + merged.push(cur); | |
| 84 | + } | |
| 85 | + } | |
| 86 | + | |
| 87 | + const parts: { text: string; hl: boolean }[] = []; | |
| 88 | + let cursor = 0; | |
| 89 | + for (const [start, end] of merged) { | |
| 90 | + if (cursor < start) parts.push({ text: text.slice(cursor, start), hl: false }); | |
| 91 | + parts.push({ text: text.slice(start, end), hl: true }); | |
| 92 | + cursor = end; | |
| 93 | + } | |
| 94 | + if (cursor < text.length) parts.push({ text: text.slice(cursor), hl: false }); | |
| 95 | + | |
| 96 | + return ( | |
| 97 | + <> | |
| 98 | + {parts.map((p, i) => | |
| 99 | + p.hl ? ( | |
| 100 | + <mark key={i} className="rounded-sm bg-primary/20 px-px text-foreground"> | |
| 101 | + {p.text} | |
| 102 | + </mark> | |
| 103 | + ) : ( | |
| 104 | + <span key={i}>{p.text}</span> | |
| 105 | + ), | |
| 106 | + )} | |
| 107 | + </> | |
| 108 | + ); | |
| 109 | +}; | |
| 110 | + | |
| 111 | +// --------------------------------------------------------------------------- | |
| 112 | +// Tree node view | |
| 113 | +// --------------------------------------------------------------------------- | |
| 114 | + | |
| 115 | +function TreeNodeView(props: { | |
| 116 | + node: TreeNode; | |
| 117 | + depth: number; | |
| 118 | + selectedToolId: string | null; | |
| 119 | + onSelect: (toolId: string) => void; | |
| 120 | + search: string; | |
| 121 | + defaultOpen: boolean; | |
| 122 | +}) { | |
| 123 | + const { node, depth, selectedToolId, onSelect, search, defaultOpen } = props; | |
| 124 | + const hasChildren = node.children.size > 0; | |
| 125 | + const isLeaf = !!node.tool && !hasChildren; | |
| 126 | + | |
| 127 | + const hasSelectedDescendant = useMemo(() => { | |
| 128 | + if (!selectedToolId) return false; | |
| 129 | + const check = (n: TreeNode): boolean => { | |
| 130 | + if (n.tool?.id === selectedToolId) return true; | |
| 131 | + for (const child of n.children.values()) { | |
| 132 | + if (check(child)) return true; | |
| 133 | + } | |
| 134 | + return false; | |
| 135 | + }; | |
| 136 | + return check(node); | |
| 137 | + }, [node, selectedToolId]); | |
| 138 | + | |
| 139 | + const [open, setOpen] = useState(defaultOpen || hasSelectedDescendant); | |
| 140 | + | |
| 141 | + useEffect(() => { | |
| 142 | + if (defaultOpen || hasSelectedDescendant) setOpen(true); | |
| 143 | + }, [defaultOpen, hasSelectedDescendant]); | |
| 144 | + | |
| 145 | + const paddingLeft = 8 + depth * 16; | |
| 146 | + | |
| 147 | + if (isLeaf) { | |
| 148 | + return ( | |
| 149 | + <ToolLeafItem | |
| 150 | + tool={node.tool!} | |
| 151 | + active={node.tool!.id === selectedToolId} | |
| 152 | + onSelect={() => onSelect(node.tool!.id)} | |
| 153 | + search={search} | |
| 154 | + depth={depth} | |
| 155 | + /> | |
| 156 | + ); | |
| 157 | + } | |
| 158 | + | |
| 159 | + const sorted = [...node.children.values()].sort((a, b) => | |
| 160 | + a.segment.localeCompare(b.segment), | |
| 161 | + ); | |
| 162 | + const leafCount = countLeaves(node); | |
| 163 | + | |
| 164 | + return ( | |
| 165 | + <div> | |
| 166 | + <button | |
| 167 | + type="button" | |
| 168 | + onClick={() => setOpen((v) => !v)} | |
| 169 | + aria-expanded={open} | |
| 170 | + className="group flex h-auto w-full items-center gap-1.5 rounded-md py-1 pr-2.5 text-[12px] hover:bg-accent/40 text-left" | |
| 171 | + style={{ paddingLeft }} | |
| 172 | + > | |
| 173 | + <svg | |
| 174 | + viewBox="0 0 8 8" | |
| 175 | + className="size-2 shrink-0 text-muted-foreground/30 transition-transform duration-150" | |
| 176 | + style={{ transform: open ? "rotate(90deg)" : "rotate(0deg)" }} | |
| 177 | + > | |
| 178 | + <path d="M2 1l4 3-4 3z" fill="currentColor" /> | |
| 179 | + </svg> | |
| 180 | + <svg viewBox="0 0 16 16" className="size-3 shrink-0 text-muted-foreground/30"> | |
| 181 | + <path | |
| 182 | + d="M2 4h5l2 2h5v7H2V4z" | |
| 183 | + fill="none" | |
| 184 | + stroke="currentColor" | |
| 185 | + strokeWidth="1.2" | |
| 186 | + /> | |
| 187 | + </svg> | |
| 188 | + <span className="flex-1 truncate font-mono text-foreground/70"> | |
| 189 | + {highlightMatch(node.segment, search)} | |
| 190 | + </span> | |
| 191 | + <span className="shrink-0 tabular-nums text-[10px] text-muted-foreground/25"> | |
| 192 | + {leafCount} | |
| 193 | + </span> | |
| 194 | + </button> | |
| 195 | + | |
| 196 | + {open && hasChildren && ( | |
| 197 | + <div className="relative flex flex-col gap-px"> | |
| 198 | + <span | |
| 199 | + className="absolute bottom-1 top-0 w-px bg-border/40" | |
| 200 | + style={{ left: paddingLeft + 5 }} | |
| 201 | + aria-hidden | |
| 202 | + /> | |
| 203 | + {sorted.map((child) => ( | |
| 204 | + <TreeNodeView | |
| 205 | + key={child.segment} | |
| 206 | + node={child} | |
| 207 | + depth={depth + 1} | |
| 208 | + selectedToolId={selectedToolId} | |
| 209 | + onSelect={onSelect} | |
| 210 | + search={search} | |
| 211 | + defaultOpen={defaultOpen} | |
| 212 | + /> | |
| 213 | + ))} | |
| 214 | + </div> | |
| 215 | + )} | |
| 216 | + </div> | |
| 217 | + ); | |
| 218 | +} | |
| 219 | + | |
| 220 | +// --------------------------------------------------------------------------- | |
| 221 | +// Leaf item | |
| 222 | +// --------------------------------------------------------------------------- | |
| 223 | + | |
| 224 | +function ToolLeafItem(props: { | |
| 225 | + tool: ToolSummary; | |
| 226 | + active: boolean; | |
| 227 | + onSelect: () => void; | |
| 228 | + search: string; | |
| 229 | + depth: number; | |
| 230 | +}) { | |
| 231 | + const ref = useRef<HTMLButtonElement>(null); | |
| 232 | + const paddingLeft = 8 + props.depth * 16 + 8; | |
| 233 | + const label = props.tool.name.split(".").pop() ?? props.tool.name; | |
| 234 | + | |
| 235 | + useEffect(() => { | |
| 236 | + if (props.active && ref.current) { | |
| 237 | + ref.current.scrollIntoView({ block: "nearest" }); | |
| 238 | + } | |
| 239 | + }, [props.active]); | |
| 240 | + | |
| 241 | + return ( | |
| 242 | + <button | |
| 243 | + ref={ref} | |
| 244 | + type="button" | |
| 245 | + onClick={props.onSelect} | |
| 246 | + className={[ | |
| 247 | + "group flex h-auto w-full items-center gap-2 rounded-md py-1.5 pr-2.5 text-left", | |
| 248 | + props.active | |
| 249 | + ? "border-l-2 border-l-primary bg-primary/10 text-foreground" | |
| 250 | + : "text-foreground/70 hover:bg-accent/50 hover:text-foreground", | |
| 251 | + ].join(" ")} | |
| 252 | + style={{ paddingLeft }} | |
| 253 | + > | |
| 254 | + <svg viewBox="0 0 16 16" className="size-3 shrink-0 text-muted-foreground/40"> | |
| 255 | + <path | |
| 256 | + d="M4 2h8l1 3H3l1-3zM3 6h10v8H3V6z" | |
| 257 | + fill="none" | |
| 258 | + stroke="currentColor" | |
| 259 | + strokeWidth="1.2" | |
| 260 | + /> | |
| 261 | + </svg> | |
| 262 | + <span className="flex-1 truncate font-mono text-[12px]"> | |
| 263 | + {highlightMatch(label, props.search)} | |
| 264 | + </span> | |
| 265 | + </button> | |
| 266 | + ); | |
| 267 | +} | |
| 268 | + | |
| 269 | +// --------------------------------------------------------------------------- | |
| 270 | +// ToolTree — main export | |
| 271 | +// --------------------------------------------------------------------------- | |
| 272 | + | |
| 273 | +export function ToolTree(props: { | |
| 274 | + tools: readonly ToolSummary[]; | |
| 275 | + selectedToolId: string | null; | |
| 276 | + onSelect: (toolId: string) => void; | |
| 277 | +}) { | |
| 278 | + const [search, setSearch] = useState(""); | |
| 279 | + const searchRef = useRef<HTMLInputElement>(null); | |
| 280 | + const terms = search.trim().toLowerCase().split(/\s+/).filter(Boolean); | |
| 281 | + | |
| 282 | + const filteredTools = useMemo(() => { | |
| 283 | + if (terms.length === 0) return props.tools; | |
| 284 | + return props.tools.filter((t) => { | |
| 285 | + const corpus = [t.name, t.description ?? ""].join(" ").toLowerCase(); | |
| 286 | + return terms.every((term) => corpus.includes(term)); | |
| 287 | + }); | |
| 288 | + }, [props.tools, terms]); | |
| 289 | + | |
| 290 | + const tree = useMemo(() => buildTree(filteredTools), [filteredTools]); | |
| 291 | + | |
| 292 | + useEffect(() => { | |
| 293 | + const handler = (e: KeyboardEvent) => { | |
| 294 | + if (e.key === "/" && document.activeElement?.tagName !== "INPUT") { | |
| 295 | + e.preventDefault(); | |
| 296 | + searchRef.current?.focus(); | |
| 297 | + } | |
| 298 | + if (e.key === "Escape") { | |
| 299 | + searchRef.current?.blur(); | |
| 300 | + if (search.length > 0) setSearch(""); | |
| 301 | + } | |
| 302 | + }; | |
| 303 | + document.addEventListener("keydown", handler); | |
| 304 | + return () => document.removeEventListener("keydown", handler); | |
| 305 | + }, [search]); | |
| 306 | + | |
| 307 | + const entries = [...tree.children.values()].sort((a, b) => | |
| 308 | + a.segment.localeCompare(b.segment), | |
| 309 | + ); | |
| 310 | + | |
| 311 | + return ( | |
| 312 | + <div className="flex h-full flex-col"> | |
| 313 | + {/* Search */} | |
| 314 | + <div className="shrink-0 border-b border-border px-3 py-2"> | |
| 315 | + <div className="flex h-8 items-center gap-2 rounded-md border border-input bg-background px-2.5"> | |
| 316 | + <svg viewBox="0 0 16 16" className="size-3.5 shrink-0 text-muted-foreground/40"> | |
| 317 | + <circle cx="6.5" cy="6.5" r="5" fill="none" stroke="currentColor" strokeWidth="1.2" /> | |
| 318 | + <path d="M10 10l4.5 4.5" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" /> | |
| 319 | + </svg> | |
| 320 | + <input | |
| 321 | + ref={searchRef} | |
| 322 | + value={search} | |
| 323 | + onChange={(e) => setSearch(e.target.value)} | |
| 324 | + placeholder={`Filter ${props.tools.length} tools…`} | |
| 325 | + className="min-w-0 flex-1 border-0 bg-transparent p-0 text-[13px] shadow-none outline-none placeholder:text-muted-foreground/40" | |
| 326 | + /> | |
| 327 | + {search.length > 0 ? ( | |
| 328 | + <button | |
| 329 | + type="button" | |
| 330 | + onClick={() => setSearch("")} | |
| 331 | + className="size-5 shrink-0 flex items-center justify-center text-muted-foreground/40 hover:text-foreground" | |
| 332 | + > | |
| 333 | + × | |
| 334 | + </button> | |
| 335 | + ) : ( | |
| 336 | + <kbd className="shrink-0 rounded border border-border bg-muted px-1 py-px text-[10px] leading-none text-muted-foreground/50"> | |
| 337 | + / | |
| 338 | + </kbd> | |
| 339 | + )} | |
| 340 | + </div> | |
| 341 | + </div> | |
| 342 | + | |
| 343 | + {/* Tree */} | |
| 344 | + <div className="flex-1 overflow-y-auto p-1.5"> | |
| 345 | + {filteredTools.length === 0 ? ( | |
| 346 | + <div className="p-4 text-center text-[13px] text-muted-foreground/50"> | |
| 347 | + {terms.length > 0 ? "No tools match your filter" : "No tools available"} | |
| 348 | + </div> | |
| 349 | + ) : ( | |
| 350 | + <div className="flex flex-col gap-px"> | |
| 351 | + {entries.map((node) => ( | |
| 352 | + <TreeNodeView | |
| 353 | + key={node.segment} | |
| 354 | + node={node} | |
| 355 | + depth={0} | |
| 356 | + selectedToolId={props.selectedToolId} | |
| 357 | + onSelect={props.onSelect} | |
| 358 | + search={search} | |
| 359 | + defaultOpen={terms.length > 0} | |
| 360 | + /> | |
| 361 | + ))} | |
| 362 | + </div> | |
| 363 | + )} | |
| 364 | + </div> | |
| 365 | + </div> | |
| 366 | + ); | |
| 367 | +} | |
| @@ -1,123 +0,0 @@ | ||
| 1 | −/** | |
| 2 | − * Dev entry point for @hono/vite-dev-server. | |
| 3 | − * | |
| 4 | − * Exports `{ fetch }` so Vite can forward API requests to the executor | |
| 5 | − * control-plane handler. Everything else (frontend assets, HMR) is | |
| 6 | − * handled by Vite itself. | |
| 7 | − */ | |
| 8 | −import { join } from "node:path"; | |
| 9 | −import * as Cause from "effect/Cause"; | |
| 10 | −import * as Effect from "effect/Effect"; | |
| 11 | −import * as Exit from "effect/Exit"; | |
| 12 | −import * as Runtime from "effect/Runtime"; | |
| 13 | −import * as Scope from "effect/Scope"; | |
| 14 | −import { | |
| 15 | − createLocalExecutorRequestHandler, | |
| 16 | − DEFAULT_EXECUTOR_DATA_DIR, | |
| 17 | −} from "@executor/server"; | |
| 18 | − | |
| 19 | −const MAX_LOGGED_ERROR_BODY_LENGTH = 4_000; | |
| 20 | −const EXECUTOR_WEB_DEV_LOCAL_DATA_DIR_ENV = "EXECUTOR_WEB_DEV_LOCAL_DATA_DIR"; | |
| 21 | −const DEFAULT_WEB_DEV_LOCAL_DATA_DIR = join( | |
| 22 | − DEFAULT_EXECUTOR_DATA_DIR, | |
| 23 | − "control-plane-web-dev", | |
| 24 | −); | |
| 25 | − | |
| 26 | −const truncateForLog = (value: string): string => | |
| 27 | − value.length > MAX_LOGGED_ERROR_BODY_LENGTH | |
| 28 | − ? `${value.slice(0, MAX_LOGGED_ERROR_BODY_LENGTH)}... [truncated]` | |
| 29 | − : value; | |
| 30 | − | |
| 31 | −const resolveWebDevLocalDataDir = (): string => { | |
| 32 | − const configured = process.env[EXECUTOR_WEB_DEV_LOCAL_DATA_DIR_ENV]?.trim(); | |
| 33 | − return configured && configured.length > 0 | |
| 34 | − ? configured | |
| 35 | − : DEFAULT_WEB_DEV_LOCAL_DATA_DIR; | |
| 36 | −}; | |
| 37 | − | |
| 38 | −/** | |
| 39 | − * Extract a detailed, human-readable description from an error. | |
| 40 | − * | |
| 41 | − * When Effect rejects via `runPromise`, the thrown value is a | |
| 42 | − * `FiberFailure` wrapping a `Cause`. `Cause.pretty` renders the full | |
| 43 | − * failure tree (defects, interrupts, tagged errors, etc.) rather than the | |
| 44 | − * opaque fallback message ("An error has occurred"). | |
| 45 | − */ | |
| 46 | −const formatErrorForLog = (error: unknown): string => { | |
| 47 | − if (Runtime.isFiberFailure(error)) { | |
| 48 | − const cause = error[Runtime.FiberFailureCauseId]; | |
| 49 | − return Cause.pretty(cause); | |
| 50 | − } | |
| 51 | − | |
| 52 | − if (error instanceof Error) { | |
| 53 | − return error.stack ?? error.message; | |
| 54 | − } | |
| 55 | − | |
| 56 | − return String(error); | |
| 57 | −}; | |
| 58 | − | |
| 59 | −// Create a long-lived scope that stays open for the lifetime of the process. | |
| 60 | −const handlerPromise = (async () => { | |
| 61 | − const exit = await Effect.runPromiseExit( | |
| 62 | − Effect.gen(function* () { | |
| 63 | − const scope = yield* Scope.make(); | |
| 64 | − const handler = yield* createLocalExecutorRequestHandler({ | |
| 65 | − localDataDir: resolveWebDevLocalDataDir(), | |
| 66 | − }).pipe( | |
| 67 | − Effect.provideService(Scope.Scope, scope), | |
| 68 | − ); | |
| 69 | − return handler; | |
| 70 | − }), | |
| 71 | − ); | |
| 72 | − | |
| 73 | − if (Exit.isSuccess(exit)) { | |
| 74 | − return exit.value; | |
| 75 | − } | |
| 76 | − | |
| 77 | − // Log the full Cause tree — this captures typed errors, defects (uncaught | |
| 78 | − // throws), and interrupts with their original stack traces. | |
| 79 | − console.error( | |
| 80 | − "[executor dev api] failed to initialize request handler\n\n" + | |
| 81 | − Cause.pretty(exit.cause), | |
| 82 | − ); | |
| 83 | − | |
| 84 | − // Re-throw so every subsequent request sees the init failure. | |
| 85 | − throw Cause.squash(exit.cause); | |
| 86 | −})(); | |
| 87 | − | |
| 88 | −export default { | |
| 89 | − async fetch(request: Request) { | |
| 90 | − const url = new URL(request.url); | |
| 91 | − | |
| 92 | − try { | |
| 93 | − const handler = await handlerPromise; | |
| 94 | − handler.setBaseUrl(url.origin); | |
| 95 | − | |
| 96 | − const response = await handler.handleApiRequest(request); | |
| 97 | − | |
| 98 | − if (url.pathname.startsWith("/v1/") && response.status >= 500) { | |
| 99 | − let bodyText = "<unavailable>"; | |
| 100 | − try { | |
| 101 | − bodyText = truncateForLog(await response.clone().text()); | |
| 102 | − } catch {} | |
| 103 | − | |
| 104 | − console.error("[executor dev api] request failed", { | |
| 105 | − method: request.method, | |
| 106 | − url: url.toString(), | |
| 107 | − status: response.status, | |
| 108 | − contentType: response.headers.get("content-type"), | |
| 109 | − body: bodyText, | |
| 110 | − }); | |
| 111 | − } | |
| 112 | − | |
| 113 | − return response; | |
| 114 | − } catch (error) { | |
| 115 | − console.error("[executor dev api] unhandled request error", { | |
| 116 | − method: request.method, | |
| 117 | − url: url.toString(), | |
| 118 | − error: formatErrorForLog(error), | |
| 119 | − }); | |
| 120 | − throw error; | |
| 121 | − } | |
| 122 | − }, | |
| 123 | −}; | |
| @@ -1,19 +0,0 @@ | ||
| 1 | −import { createRoot } from "react-dom/client"; | |
| 2 | − | |
| 3 | −class BrowserBuffer extends Uint8Array {} | |
| 4 | − | |
| 5 | −const browserGlobal = globalThis as any; | |
| 6 | − | |
| 7 | −if (browserGlobal.Buffer === undefined) { | |
| 8 | − browserGlobal.Buffer = BrowserBuffer; | |
| 9 | −} | |
| 10 | − | |
| 11 | −const { App } = await import("./main"); | |
| 12 | − | |
| 13 | −const rootElement = document.getElementById("root"); | |
| 14 | − | |
| 15 | −if (!rootElement) { | |
| 16 | − throw new Error("Missing #root element"); | |
| 17 | −} | |
| 18 | − | |
| 19 | −createRoot(rootElement).render(<App />); | |
| @@ -1,30 +0,0 @@ | ||
| 1 | −<!doctype html> | |
| 2 | −<html lang="en"> | |
| 3 | − <head> | |
| 4 | − <meta charset="UTF-8" /> | |
| 5 | − <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| 6 | − <meta name="color-scheme" content="light dark" /> | |
| 7 | − <title>Executor</title> | |
| 8 | − <meta | |
| 9 | − name="description" | |
| 10 | − content="Executor — manage sources, inspect tools, and monitor executions." | |
| 11 | − /> | |
| 12 | − <link rel="preconnect" href="https://fonts.googleapis.com" /> | |
| 13 | − <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> | |
| 14 | − <script type="module"> | |
| 15 | − // first npm i react-grab | |
| 16 | − // then in head: | |
| 17 | − if (import.meta.env.DEV) { | |
| 18 | − import("react-grab"); | |
| 19 | − } | |
| 20 | − </script> | |
| 21 | − <link | |
| 22 | − href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&family=Instrument+Serif&family=JetBrains+Mono:wght@400;500&display=swap" | |
| 23 | − rel="stylesheet" | |
| 24 | − /> | |
| 25 | − </head> | |
| 26 | − <body> | |
| 27 | − <div id="root"></div> | |
| 28 | − <script type="module" src="./frontend.tsx"></script> | |
| 29 | − </body> | |
| 30 | −</html> | |
| @@ -0,0 +1,223 @@ | ||
| 1 | +/** | |
| 2 | + * Convert a JSON Schema into TypeScript-like type signatures. | |
| 3 | + * | |
| 4 | + * Two modes: | |
| 5 | + * - `schemaToTypeSignature(schema)` — compact single-line for badges/previews | |
| 6 | + * - `schemaToTypeDeclaration(schema)` — multi-line with indentation for code blocks | |
| 7 | + * | |
| 8 | + * TODO: Ugly file, has limitations | |
| 9 | + */ | |
| 10 | + | |
| 11 | +type JsonSchemaRecord = Record<string, unknown>; | |
| 12 | + | |
| 13 | +const asRecord = (value: unknown): JsonSchemaRecord => | |
| 14 | + typeof value === "object" && value !== null && !Array.isArray(value) | |
| 15 | + ? (value as JsonSchemaRecord) | |
| 16 | + : {}; | |
| 17 | + | |
| 18 | +const asStringArray = (value: unknown): string[] => | |
| 19 | + Array.isArray(value) | |
| 20 | + ? value.filter((item): item is string => typeof item === "string") | |
| 21 | + : []; | |
| 22 | + | |
| 23 | +// --------------------------------------------------------------------------- | |
| 24 | +// Compact single-line signature | |
| 25 | +// --------------------------------------------------------------------------- | |
| 26 | + | |
| 27 | +const truncate = (value: string, maxLength: number): string => | |
| 28 | + value.length <= maxLength | |
| 29 | + ? value | |
| 30 | + : `${value.slice(0, Math.max(0, maxLength - 4))} ...`; | |
| 31 | + | |
| 32 | +const propertyLabel = ( | |
| 33 | + name: string, | |
| 34 | + schema: JsonSchemaRecord, | |
| 35 | + optional: boolean, | |
| 36 | +): string => `${name}${optional ? "?" : ""}: ${schemaToTypeSignature(schema)}`; | |
| 37 | + | |
| 38 | +const compositeLabel = ( | |
| 39 | + key: "oneOf" | "anyOf" | "allOf", | |
| 40 | + schema: JsonSchemaRecord, | |
| 41 | +): string | null => { | |
| 42 | + const items = Array.isArray(schema[key]) ? schema[key].map(asRecord) : []; | |
| 43 | + if (items.length === 0) return null; | |
| 44 | + const labels = items | |
| 45 | + .map((item) => schemaToTypeSignature(item)) | |
| 46 | + .filter((label) => label.length > 0); | |
| 47 | + if (labels.length === 0) return null; | |
| 48 | + return labels.join(key === "allOf" ? " & " : " | "); | |
| 49 | +}; | |
| 50 | + | |
| 51 | +export const schemaToTypeSignature = ( | |
| 52 | + input: unknown, | |
| 53 | + maxLength: number = 220, | |
| 54 | +): string => { | |
| 55 | + const schema = asRecord(input); | |
| 56 | + | |
| 57 | + if (typeof schema.$ref === "string") { | |
| 58 | + const ref = schema.$ref.trim(); | |
| 59 | + return ref.length > 0 ? ref.split("/").at(-1) ?? ref : "unknown"; | |
| 60 | + } | |
| 61 | + if ("const" in schema) return JSON.stringify(schema.const); | |
| 62 | + | |
| 63 | + const enumValues = Array.isArray(schema.enum) ? schema.enum : []; | |
| 64 | + if (enumValues.length > 0) { | |
| 65 | + return truncate(enumValues.map((v) => JSON.stringify(v)).join(" | "), maxLength); | |
| 66 | + } | |
| 67 | + | |
| 68 | + const composite = | |
| 69 | + compositeLabel("oneOf", schema) ?? | |
| 70 | + compositeLabel("anyOf", schema) ?? | |
| 71 | + compositeLabel("allOf", schema); | |
| 72 | + if (composite) return truncate(composite, maxLength); | |
| 73 | + | |
| 74 | + if (schema.type === "array") { | |
| 75 | + const itemLabel = schema.items | |
| 76 | + ? schemaToTypeSignature(schema.items, maxLength) | |
| 77 | + : "unknown"; | |
| 78 | + return truncate(`${itemLabel}[]`, maxLength); | |
| 79 | + } | |
| 80 | + | |
| 81 | + if (schema.type === "object" || schema.properties) { | |
| 82 | + const properties = asRecord(schema.properties); | |
| 83 | + const keys = Object.keys(properties); | |
| 84 | + if (keys.length === 0) { | |
| 85 | + return schema.additionalProperties ? "Record<string, unknown>" : "object"; | |
| 86 | + } | |
| 87 | + const required = new Set(asStringArray(schema.required)); | |
| 88 | + const parts = keys.map((key) => | |
| 89 | + propertyLabel(key, asRecord(properties[key]), !required.has(key)), | |
| 90 | + ); | |
| 91 | + return truncate(`{ ${parts.join(", ")} }`, maxLength); | |
| 92 | + } | |
| 93 | + | |
| 94 | + if (Array.isArray(schema.type)) return truncate(schema.type.join(" | "), maxLength); | |
| 95 | + if (typeof schema.type === "string") return schema.type; | |
| 96 | + return "unknown"; | |
| 97 | +}; | |
| 98 | + | |
| 99 | +// --------------------------------------------------------------------------- | |
| 100 | +// Multi-line type declaration | |
| 101 | +// --------------------------------------------------------------------------- | |
| 102 | + | |
| 103 | +const INDENT = " "; | |
| 104 | + | |
| 105 | +const refName = (ref: string): string => { | |
| 106 | + const trimmed = ref.trim(); | |
| 107 | + return trimmed.length > 0 ? trimmed.split("/").at(-1) ?? trimmed : "unknown"; | |
| 108 | +}; | |
| 109 | + | |
| 110 | +const compositeDecl = ( | |
| 111 | + key: "oneOf" | "anyOf" | "allOf", | |
| 112 | + schema: JsonSchemaRecord, | |
| 113 | + depth: number, | |
| 114 | +): string | null => { | |
| 115 | + const items = Array.isArray(schema[key]) ? schema[key].map(asRecord) : []; | |
| 116 | + if (items.length === 0) return null; | |
| 117 | + | |
| 118 | + const sep = key === "allOf" ? " & " : " | "; | |
| 119 | + const parts = items.map((item) => formatNode(item, depth)); | |
| 120 | + if (parts.length === 0) return null; | |
| 121 | + | |
| 122 | + // If all parts are short primitives, inline | |
| 123 | + const joined = parts.join(sep); | |
| 124 | + if (joined.length < 80 && !joined.includes("\n")) return joined; | |
| 125 | + | |
| 126 | + // Multi-line | |
| 127 | + const prefix = INDENT.repeat(depth); | |
| 128 | + return parts.join(`\n${prefix}${sep.trim()} `); | |
| 129 | +}; | |
| 130 | + | |
| 131 | +const formatNode = (input: unknown, depth: number): string => { | |
| 132 | + const schema = asRecord(input); | |
| 133 | + const prefix = INDENT.repeat(depth); | |
| 134 | + const innerPrefix = INDENT.repeat(depth + 1); | |
| 135 | + | |
| 136 | + // $ref | |
| 137 | + if (typeof schema.$ref === "string") return refName(schema.$ref); | |
| 138 | + | |
| 139 | + // const | |
| 140 | + if ("const" in schema) return JSON.stringify(schema.const); | |
| 141 | + | |
| 142 | + // enum | |
| 143 | + const enumValues = Array.isArray(schema.enum) ? schema.enum : []; | |
| 144 | + if (enumValues.length > 0) { | |
| 145 | + const joined = enumValues.map((v) => JSON.stringify(v)).join(" | "); | |
| 146 | + return joined.length < 80 ? joined : enumValues.map((v) => JSON.stringify(v)).join(`\n${prefix}| `); | |
| 147 | + } | |
| 148 | + | |
| 149 | + // composites | |
| 150 | + const composite = | |
| 151 | + compositeDecl("oneOf", schema, depth) ?? | |
| 152 | + compositeDecl("anyOf", schema, depth) ?? | |
| 153 | + compositeDecl("allOf", schema, depth); | |
| 154 | + if (composite) return composite; | |
| 155 | + | |
| 156 | + // array | |
| 157 | + if (schema.type === "array") { | |
| 158 | + const itemType = schema.items ? formatNode(schema.items, depth) : "unknown"; | |
| 159 | + if (itemType.includes("\n")) { | |
| 160 | + return `Array<\n${innerPrefix}${itemType}\n${prefix}>`; | |
| 161 | + } | |
| 162 | + return `${itemType}[]`; | |
| 163 | + } | |
| 164 | + | |
| 165 | + // object | |
| 166 | + if (schema.type === "object" || schema.properties) { | |
| 167 | + const properties = asRecord(schema.properties); | |
| 168 | + const keys = Object.keys(properties); | |
| 169 | + | |
| 170 | + if (keys.length === 0) { | |
| 171 | + return schema.additionalProperties ? "Record<string, unknown>" : "{}"; | |
| 172 | + } | |
| 173 | + | |
| 174 | + const required = new Set(asStringArray(schema.required)); | |
| 175 | + const lines = keys.map((key) => { | |
| 176 | + const propSchema = asRecord(properties[key]); | |
| 177 | + const opt = required.has(key) ? "" : "?"; | |
| 178 | + const typeStr = formatNode(propSchema, depth + 1); | |
| 179 | + | |
| 180 | + // Add description as comment if present | |
| 181 | + const desc = typeof propSchema.description === "string" ? propSchema.description : null; | |
| 182 | + const comment = desc ? `${innerPrefix}/** ${desc} */\n` : ""; | |
| 183 | + | |
| 184 | + if (typeStr.includes("\n")) { | |
| 185 | + return `${comment}${innerPrefix}${key}${opt}: ${typeStr};`; | |
| 186 | + } | |
| 187 | + return `${comment}${innerPrefix}${key}${opt}: ${typeStr};`; | |
| 188 | + }); | |
| 189 | + | |
| 190 | + return `{\n${lines.join("\n")}\n${prefix}}`; | |
| 191 | + } | |
| 192 | + | |
| 193 | + // union type array | |
| 194 | + if (Array.isArray(schema.type)) return schema.type.join(" | "); | |
| 195 | + | |
| 196 | + // primitive | |
| 197 | + if (typeof schema.type === "string") { | |
| 198 | + switch (schema.type) { | |
| 199 | + case "string": return "string"; | |
| 200 | + case "number": case "integer": return "number"; | |
| 201 | + case "boolean": return "boolean"; | |
| 202 | + case "null": return "null"; | |
| 203 | + default: return schema.type; | |
| 204 | + } | |
| 205 | + } | |
| 206 | + | |
| 207 | + return "unknown"; | |
| 208 | +}; | |
| 209 | + | |
| 210 | +/** | |
| 211 | + * Convert a JSON Schema to a multi-line TypeScript-like type declaration. | |
| 212 | + * Suitable for rendering in a code block with syntax highlighting. | |
| 213 | + */ | |
| 214 | +export const schemaToTypeDeclaration = ( | |
| 215 | + input: unknown, | |
| 216 | + name?: string, | |
| 217 | +): string => { | |
| 218 | + const body = formatNode(input, 0); | |
| 219 | + if (name) { | |
| 220 | + return `type ${name} = ${body}`; | |
| 221 | + } | |
| 222 | + return body; | |
| 223 | +}; | |
| @@ -1,4 +0,0 @@ | ||
| 1 | −export { | |
| 2 | − getFallbackSourceFaviconUrl, | |
| 3 | − getSourceFaviconUrl, | |
| 4 | −} from "@executor/source-core"; | |
| @@ -0,0 +1 @@ | ||
| 1 | +export { useScope } from "@executor/react"; | |
| @@ -1,6 +0,0 @@ | ||
| 1 | −import { clsx, type ClassValue } from "clsx" | |
| 2 | −import { twMerge } from "tailwind-merge" | |
| 3 | − | |
| 4 | −export function cn(...inputs: ClassValue[]) { | |
| 5 | − return twMerge(clsx(inputs)) | |
| 6 | −} | |
| @@ -1,138 +1,7 @@ | ||
| 1 | −import { | |
| 2 | − RouterProvider, | |
| 3 | − createRootRoute, | |
| 4 | − createRoute, | |
| 5 | − createRouter, | |
| 6 | − useNavigate, | |
| 7 | −} from "@tanstack/react-router"; | |
| 8 | −import { ExecutorReactProvider } from "@executor/react"; | |
| 9 | −import { | |
| 10 | − createExecutorPluginPaths, | |
| 11 | − sourcePluginsIndexPath, | |
| 12 | − type ExecutorPluginNavigation, | |
| 13 | − type FrontendPluginRouteSearch, | |
| 14 | −} from "@executor/react/plugins"; | |
| 1 | +import React from "react"; | |
| 2 | +import { createRoot } from "react-dom/client"; | |
| 3 | +import "@executor/ui/globals.css"; | |
| 4 | +import { App } from "./App"; | |
| 15 | 5 | |
| 16 | −import "./globals.css"; | |
| 17 | − | |
| 18 | −import { AppShell } from "./components/shell"; | |
| 19 | −import { | |
| 20 | − registeredFrontendPluginRoutes, | |
| 21 | −} from "./plugins"; | |
| 22 | −import { | |
| 23 | − ExecutorPluginRoutePage, | |
| 24 | − SourcePluginsIndexPage, | |
| 25 | −} from "./plugins/pages"; | |
| 26 | −import { HomePage } from "./views/home"; | |
| 27 | −import { PoliciesPage } from "./views/policies"; | |
| 28 | −import { SecretsPage } from "./views/secrets"; | |
| 29 | − | |
| 30 | −const rootRoute = createRootRoute({ | |
| 31 | − component: AppShell, | |
| 32 | −}); | |
| 33 | − | |
| 34 | −const homeRoute = createRoute({ | |
| 35 | − getParentRoute: () => rootRoute, | |
| 36 | − path: "/", | |
| 37 | − component: HomePage, | |
| 38 | −}); | |
| 39 | − | |
| 40 | −const sourcePluginsIndexRoute = createRoute({ | |
| 41 | − getParentRoute: () => rootRoute, | |
| 42 | − path: sourcePluginsIndexPath, | |
| 43 | − component: SourcePluginsIndexPage, | |
| 44 | −}); | |
| 45 | − | |
| 46 | −const secretsRoute = createRoute({ | |
| 47 | − getParentRoute: () => rootRoute, | |
| 48 | − path: "/secrets", | |
| 49 | − component: SecretsPage, | |
| 50 | −}); | |
| 51 | − | |
| 52 | −const policiesRoute = createRoute({ | |
| 53 | − getParentRoute: () => rootRoute, | |
| 54 | − path: "/policies", | |
| 55 | − component: PoliciesPage, | |
| 56 | −}); | |
| 57 | − | |
| 58 | −const createExecutorPluginNavigation = ( | |
| 59 | − pluginKey: string, | |
| 60 | − input: { | |
| 61 | − navigateTo: ( | |
| 62 | − to: string, | |
| 63 | − search?: FrontendPluginRouteSearch, | |
| 64 | − ) => void | Promise<void>; | |
| 65 | − updateSearch?: ( | |
| 66 | − search: FrontendPluginRouteSearch, | |
| 67 | − ) => void | Promise<void>; | |
| 68 | − }, | |
| 69 | −): ExecutorPluginNavigation => { | |
| 70 | − const paths = createExecutorPluginPaths(pluginKey); | |
| 71 | − | |
| 72 | − return { | |
| 73 | − paths, | |
| 74 | − home: () => input.navigateTo("/"), | |
| 75 | − route: (path = "", search) => input.navigateTo(paths.route(path), search), | |
| 76 | − updateSearch: (search) => input.updateSearch?.(search), | |
| 77 | − }; | |
| 78 | −}; | |
| 79 | − | |
| 80 | −const frontendPluginRoutes = registeredFrontendPluginRoutes.map(({ plugin, route }) => { | |
| 81 | − const paths = createExecutorPluginPaths(plugin.key); | |
| 82 | − | |
| 83 | − const PluginRouteComponent = () => { | |
| 84 | − const params = pluginRoute.useParams() as Record<string, string | undefined>; | |
| 85 | − const search = pluginRoute.useSearch(); | |
| 86 | − const navigate = useNavigate(); | |
| 87 | − const navigateFromRoute = useNavigate({ from: pluginRoute.fullPath }); | |
| 88 | − const navigation = createExecutorPluginNavigation(plugin.key, { | |
| 89 | − navigateTo: (to, nextSearch) => | |
| 90 | − nextSearch === undefined ? navigate({ to }) : navigate({ to, search: nextSearch }), | |
| 91 | − updateSearch: (nextSearch) => navigateFromRoute({ search: nextSearch }), | |
| 92 | − }); | |
| 93 | − | |
| 94 | − return ( | |
| 95 | − <ExecutorPluginRoutePage | |
| 96 | − pluginKey={plugin.key} | |
| 97 | − routeKey={route.key} | |
| 98 | − params={params} | |
| 99 | − search={search} | |
| 100 | − navigation={navigation} | |
| 101 | − /> | |
| 102 | − ); | |
| 103 | − }; | |
| 104 | − | |
| 105 | − const pluginRoute = createRoute({ | |
| 106 | − getParentRoute: () => rootRoute, | |
| 107 | − path: paths.routePattern(route.path ?? ""), | |
| 108 | − component: PluginRouteComponent, | |
| 109 | − }); | |
| 110 | − | |
| 111 | − return pluginRoute; | |
| 112 | −}); | |
| 113 | − | |
| 114 | −const routeTree = rootRoute.addChildren([ | |
| 115 | − homeRoute, | |
| 116 | − secretsRoute, | |
| 117 | − policiesRoute, | |
| 118 | − sourcePluginsIndexRoute, | |
| 119 | − ...frontendPluginRoutes, | |
| 120 | −]); | |
| 121 | − | |
| 122 | −const router = createRouter({ | |
| 123 | − routeTree, | |
| 124 | − defaultPreload: "intent", | |
| 125 | − defaultPreloadStaleTime: 0, | |
| 126 | −}); | |
| 127 | − | |
| 128 | −declare module "@tanstack/react-router" { | |
| 129 | − interface Register { | |
| 130 | − router: typeof router; | |
| 131 | − } | |
| 132 | −} | |
| 133 | − | |
| 134 | −export const App = () => ( | |
| 135 | − <ExecutorReactProvider> | |
| 136 | − <RouterProvider router={router} /> | |
| 137 | − </ExecutorReactProvider> | |
| 138 | −); | |
| 6 | +const root = createRoot(document.getElementById("root")!); | |
| 7 | +root.render(<App />); | |
| @@ -0,0 +1,391 @@ | ||
| 1 | +import { useState, Suspense } from "react"; | |
| 2 | +import { | |
| 3 | + useAtomValue, | |
| 4 | + useAtomSet, | |
| 5 | + useAtomRefresh, | |
| 6 | + Result, | |
| 7 | + secretsAtom, | |
| 8 | + setSecret, | |
| 9 | + removeSecret, | |
| 10 | +} from "@executor/react"; | |
| 11 | +import type { SecretProviderPlugin } from "@executor/react"; | |
| 12 | +import { SecretId } from "@executor/sdk"; | |
| 13 | +import { useScope } from "../lib/use-scope"; | |
| 14 | +import { onePasswordSecretProviderPlugin } from "@executor/plugin-onepassword/react"; | |
| 15 | +import { | |
| 16 | + Dialog, | |
| 17 | + DialogContent, | |
| 18 | + DialogHeader, | |
| 19 | + DialogTitle, | |
| 20 | + DialogDescription, | |
| 21 | + DialogFooter, | |
| 22 | + DialogClose, | |
| 23 | +} from "@executor/ui/components/dialog"; | |
| 24 | +import { Button } from "@executor/ui/components/button"; | |
| 25 | +import { Input } from "@executor/ui/components/input"; | |
| 26 | +import { Label } from "@executor/ui/components/label"; | |
| 27 | +import { Badge } from "@executor/ui/components/badge"; | |
| 28 | +import { | |
| 29 | + DropdownMenu, | |
| 30 | + DropdownMenuContent, | |
| 31 | + DropdownMenuItem, | |
| 32 | + DropdownMenuTrigger, | |
| 33 | +} from "@executor/ui/components/dropdown-menu"; | |
| 34 | +import { | |
| 35 | + Select, | |
| 36 | + SelectContent, | |
| 37 | + SelectItem, | |
| 38 | + SelectTrigger, | |
| 39 | + SelectValue, | |
| 40 | +} from "@executor/ui/components/select"; | |
| 41 | + | |
| 42 | +// --------------------------------------------------------------------------- | |
| 43 | +// Add secret dialog | |
| 44 | +// --------------------------------------------------------------------------- | |
| 45 | + | |
| 46 | +function AddSecretDialog(props: { open: boolean; onOpenChange: (v: boolean) => void }) { | |
| 47 | + const [id, setId] = useState(""); | |
| 48 | + const [name, setName] = useState(""); | |
| 49 | + const [value, setValue] = useState(""); | |
| 50 | + const [purpose, setPurpose] = useState(""); | |
| 51 | + const [provider, setProvider] = useState("auto"); | |
| 52 | + const [saving, setSaving] = useState(false); | |
| 53 | + const [error, setError] = useState<string | null>(null); | |
| 54 | + | |
| 55 | + const scopeId = useScope(); | |
| 56 | + const doSet = useAtomSet(setSecret, { mode: "promise" }); | |
| 57 | + const refresh = useAtomRefresh(secretsAtom(scopeId)); | |
| 58 | + | |
| 59 | + const reset = () => { | |
| 60 | + setId(""); | |
| 61 | + setName(""); | |
| 62 | + setValue(""); | |
| 63 | + setPurpose(""); | |
| 64 | + setProvider("auto"); | |
| 65 | + setError(null); | |
| 66 | + setSaving(false); | |
| 67 | + }; | |
| 68 | + | |
| 69 | + const handleSave = async () => { | |
| 70 | + if (!id.trim() || !name.trim() || !value.trim()) return; | |
| 71 | + setSaving(true); | |
| 72 | + setError(null); | |
| 73 | + try { | |
| 74 | + await doSet({ | |
| 75 | + path: { scopeId }, | |
| 76 | + payload: { | |
| 77 | + id: SecretId.make(id.trim()), | |
| 78 | + name: name.trim(), | |
| 79 | + value: value.trim(), | |
| 80 | + purpose: purpose.trim() || undefined, | |
| 81 | + provider: provider === "auto" ? undefined : provider, | |
| 82 | + }, | |
| 83 | + }); | |
| 84 | + reset(); | |
| 85 | + props.onOpenChange(false); | |
| 86 | + refresh(); | |
| 87 | + } catch (e) { | |
| 88 | + setError(e instanceof Error ? e.message : "Failed to save secret"); | |
| 89 | + setSaving(false); | |
| 90 | + } | |
| 91 | + }; | |
| 92 | + | |
| 93 | + return ( | |
| 94 | + <Dialog | |
| 95 | + open={props.open} | |
| 96 | + onOpenChange={(v) => { | |
| 97 | + if (!v) reset(); | |
| 98 | + props.onOpenChange(v); | |
| 99 | + }} | |
| 100 | + > | |
| 101 | + <DialogContent className="sm:max-w-[440px]"> | |
| 102 | + <DialogHeader> | |
| 103 | + <DialogTitle className="font-display text-xl">New secret</DialogTitle> | |
| 104 | + <DialogDescription className="text-[13px] leading-relaxed"> | |
| 105 | + Store a credential or API key. Values are kept in your system | |
| 106 | + keychain when available, with a local encrypted file fallback. | |
| 107 | + </DialogDescription> | |
| 108 | + </DialogHeader> | |
| 109 | + | |
| 110 | + <div className="grid gap-5 py-3"> | |
| 111 | + <div className="grid grid-cols-2 gap-3"> | |
| 112 | + <div className="grid gap-1.5"> | |
| 113 | + <Label htmlFor="secret-id" className="text-[11px] font-medium uppercase tracking-wider text-muted-foreground"> | |
| 114 | + ID | |
| 115 | + </Label> | |
| 116 | + <Input | |
| 117 | + id="secret-id" | |
| 118 | + placeholder="github-token" | |
| 119 | + value={id} | |
| 120 | + onChange={(e) => setId((e.target as HTMLInputElement).value)} | |
| 121 | + className="font-mono text-[13px] h-9" | |
| 122 | + /> | |
| 123 | + </div> | |
| 124 | + <div className="grid gap-1.5"> | |
| 125 | + <Label htmlFor="secret-name" className="text-[11px] font-medium uppercase tracking-wider text-muted-foreground"> | |
| 126 | + Name | |
| 127 | + </Label> | |
| 128 | + <Input | |
| 129 | + id="secret-name" | |
| 130 | + placeholder="GitHub PAT" | |
| 131 | + value={name} | |
| 132 | + onChange={(e) => setName((e.target as HTMLInputElement).value)} | |
| 133 | + className="text-[13px] h-9" | |
| 134 | + /> | |
| 135 | + </div> | |
| 136 | + </div> | |
| 137 | + | |
| 138 | + <div className="grid gap-1.5"> | |
| 139 | + <Label htmlFor="secret-value" className="text-[11px] font-medium uppercase tracking-wider text-muted-foreground"> | |
| 140 | + Value | |
| 141 | + </Label> | |
| 142 | + <Input | |
| 143 | + id="secret-value" | |
| 144 | + type="password" | |
| 145 | + placeholder="ghp_xxxxxxxxxxxxxxxxxxxx" | |
| 146 | + value={value} | |
| 147 | + onChange={(e) => setValue((e.target as HTMLInputElement).value)} | |
| 148 | + className="font-mono text-[13px] h-9" | |
| 149 | + /> | |
| 150 | + </div> | |
| 151 | + | |
| 152 | + <div className="grid grid-cols-2 gap-3"> | |
| 153 | + <div className="grid gap-1.5"> | |
| 154 | + <Label htmlFor="secret-purpose" className="text-[11px] font-medium uppercase tracking-wider text-muted-foreground"> | |
| 155 | + Purpose <span className="normal-case tracking-normal font-normal text-muted-foreground/60">(opt.)</span> | |
| 156 | + </Label> | |
| 157 | + <Input | |
| 158 | + id="secret-purpose" | |
| 159 | + placeholder="GitHub API auth" | |
| 160 | + value={purpose} | |
| 161 | + onChange={(e) => setPurpose((e.target as HTMLInputElement).value)} | |
| 162 | + className="text-[13px] h-9" | |
| 163 | + /> | |
| 164 | + </div> | |
| 165 | + <div className="grid gap-1.5"> | |
| 166 | + <Label htmlFor="secret-provider" className="text-[11px] font-medium uppercase tracking-wider text-muted-foreground"> | |
| 167 | + Storage | |
| 168 | + </Label> | |
| 169 | + <Select value={provider} onValueChange={setProvider}> | |
| 170 | + <SelectTrigger id="secret-provider" className="h-9 text-[13px]"> | |
| 171 | + <SelectValue /> | |
| 172 | + </SelectTrigger> | |
| 173 | + <SelectContent> | |
| 174 | + <SelectItem value="auto">Auto</SelectItem> | |
| 175 | + <SelectItem value="keychain">Keychain</SelectItem> | |
| 176 | + <SelectItem value="file">File</SelectItem> | |
| 177 | + </SelectContent> | |
| 178 | + </Select> | |
| 179 | + </div> | |
| 180 | + </div> | |
| 181 | + | |
| 182 | + {error && ( | |
| 183 | + <div className="rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2"> | |
| 184 | + <p className="text-[12px] text-destructive">{error}</p> | |
| 185 | + </div> | |
| 186 | + )} | |
| 187 | + </div> | |
| 188 | + | |
| 189 | + <DialogFooter> | |
| 190 | + <DialogClose asChild> | |
| 191 | + <Button variant="ghost" size="sm">Cancel</Button> | |
| 192 | + </DialogClose> | |
| 193 | + <Button | |
| 194 | + size="sm" | |
| 195 | + onClick={handleSave} | |
| 196 | + disabled={!id.trim() || !name.trim() || !value.trim() || saving} | |
| 197 | + > | |
| 198 | + {saving ? "Saving…" : "Save secret"} | |
| 199 | + </Button> | |
| 200 | + </DialogFooter> | |
| 201 | + </DialogContent> | |
| 202 | + </Dialog> | |
| 203 | + ); | |
| 204 | +} | |
| 205 | + | |
| 206 | +// --------------------------------------------------------------------------- | |
| 207 | +// Secret row | |
| 208 | +// --------------------------------------------------------------------------- | |
| 209 | + | |
| 210 | +function SecretRow(props: { | |
| 211 | + secret: { id: string; name: string; purpose?: string; provider?: string }; | |
| 212 | + onRemove: () => void; | |
| 213 | +}) { | |
| 214 | + const { secret } = props; | |
| 215 | + | |
| 216 | + return ( | |
| 217 | + <div className="group relative flex items-center gap-4 rounded-lg border border-border/60 bg-card px-4 py-3 transition-all hover:border-border hover:shadow-[0_1px_3px_rgba(0,0,0,0.04)]"> | |
| 218 | + {/* Content */} | |
| 219 | + <div className="min-w-0 flex-1"> | |
| 220 | + <div className="flex items-center gap-2"> | |
| 221 | + <p className="text-[13px] font-medium text-foreground leading-none">{secret.name}</p> | |
| 222 | + <span className="rounded bg-muted px-1.5 py-0.5 font-mono text-[10px] leading-none text-muted-foreground"> | |
| 223 | + {secret.id} | |
| 224 | + </span> | |
| 225 | + </div> | |
| 226 | + {secret.purpose && ( | |
| 227 | + <p className="mt-1 text-[12px] text-muted-foreground/70 leading-none">{secret.purpose}</p> | |
| 228 | + )} | |
| 229 | + </div> | |
| 230 | + | |
| 231 | + {/* Provider + actions */} | |
| 232 | + <div className="flex items-center gap-1.5"> | |
| 233 | + {secret.provider && ( | |
| 234 | + <span className="rounded-full border border-border/60 px-2 py-0.5 text-[10px] font-medium text-muted-foreground leading-none"> | |
| 235 | + {secret.provider} | |
| 236 | + </span> | |
| 237 | + )} | |
| 238 | + <DropdownMenu> | |
| 239 | + <DropdownMenuTrigger asChild> | |
| 240 | + <Button | |
| 241 | + variant="ghost" | |
| 242 | + size="icon" | |
| 243 | + className="size-7 opacity-0 group-hover:opacity-100 transition-opacity" | |
| 244 | + > | |
| 245 | + <svg viewBox="0 0 16 16" className="size-3"> | |
| 246 | + <circle cx="8" cy="3" r="1.2" fill="currentColor" /> | |
| 247 | + <circle cx="8" cy="8" r="1.2" fill="currentColor" /> | |
| 248 | + <circle cx="8" cy="13" r="1.2" fill="currentColor" /> | |
| 249 | + </svg> | |
| 250 | + </Button> | |
| 251 | + </DropdownMenuTrigger> | |
| 252 | + <DropdownMenuContent align="end" className="w-40"> | |
| 253 | + <DropdownMenuItem | |
| 254 | + className="text-destructive focus:text-destructive text-[12px]" | |
| 255 | + onClick={props.onRemove} | |
| 256 | + > | |
| 257 | + Remove secret | |
| 258 | + </DropdownMenuItem> | |
| 259 | + </DropdownMenuContent> | |
| 260 | + </DropdownMenu> | |
| 261 | + </div> | |
| 262 | + </div> | |
| 263 | + ); | |
| 264 | +} | |
| 265 | + | |
| 266 | +// --------------------------------------------------------------------------- | |
| 267 | +// Secret provider plugins | |
| 268 | +// --------------------------------------------------------------------------- | |
| 269 | + | |
| 270 | +const secretProviderPlugins: SecretProviderPlugin[] = [ | |
| 271 | + onePasswordSecretProviderPlugin, | |
| 272 | +]; | |
| 273 | + | |
| 274 | +// --------------------------------------------------------------------------- | |
| 275 | +// Page | |
| 276 | +// --------------------------------------------------------------------------- | |
| 277 | + | |
| 278 | +export function SecretsPage() { | |
| 279 | + const [addOpen, setAddOpen] = useState(false); | |
| 280 | + const scopeId = useScope(); | |
| 281 | + const secrets = useAtomValue(secretsAtom(scopeId)); | |
| 282 | + const doRemove = useAtomSet(removeSecret, { mode: "promise" }); | |
| 283 | + const refresh = useAtomRefresh(secretsAtom(scopeId)); | |
| 284 | + | |
| 285 | + const handleRemove = async (secretId: string) => { | |
| 286 | + try { | |
| 287 | + await doRemove({ | |
| 288 | + path: { | |
| 289 | + scopeId, | |
| 290 | + secretId: SecretId.make(secretId), | |
| 291 | + }, | |
| 292 | + }); | |
| 293 | + refresh(); | |
| 294 | + } catch { | |
| 295 | + // TODO: toast | |
| 296 | + } | |
| 297 | + }; | |
| 298 | + | |
| 299 | + return ( | |
| 300 | + <div className="min-h-0 flex-1 overflow-y-auto"> | |
| 301 | + <div className="mx-auto max-w-3xl px-6 py-10 lg:px-8 lg:py-14"> | |
| 302 | + {/* Header */} | |
| 303 | + <div className="flex items-end justify-between mb-10"> | |
| 304 | + <div> | |
| 305 | + <h1 className="font-display text-[2rem] tracking-tight text-foreground leading-none"> | |
| 306 | + Secrets | |
| 307 | + </h1> | |
| 308 | + <p className="mt-2 text-[13px] text-muted-foreground leading-relaxed"> | |
| 309 | + Credentials and API keys used by your connected sources. | |
| 310 | + </p> | |
| 311 | + </div> | |
| 312 | + <Button size="sm" onClick={() => setAddOpen(true)}> | |
| 313 | + Add secret | |
| 314 | + </Button> | |
| 315 | + </div> | |
| 316 | + | |
| 317 | + {/* Provider plugins */} | |
| 318 | + {secretProviderPlugins.length > 0 && ( | |
| 319 | + <div className="mb-10"> | |
| 320 | + <div className="flex items-center gap-3 mb-4"> | |
| 321 | + <h2 className="text-[11px] font-semibold uppercase tracking-[0.08em] text-muted-foreground/60"> | |
| 322 | + Providers | |
| 323 | + </h2> | |
| 324 | + <div className="flex-1 h-px bg-border/50" /> | |
| 325 | + </div> | |
| 326 | + <div className="grid gap-3"> | |
| 327 | + {secretProviderPlugins.map((plugin) => ( | |
| 328 | + <Suspense | |
| 329 | + key={plugin.key} | |
| 330 | + fallback={ | |
| 331 | + <div className="rounded-xl border border-border/60 bg-card p-5 animate-pulse"> | |
| 332 | + <div className="h-4 w-24 rounded bg-muted" /> | |
| 333 | + </div> | |
| 334 | + } | |
| 335 | + > | |
| 336 | + <plugin.settings /> | |
| 337 | + </Suspense> | |
| 338 | + ))} | |
| 339 | + </div> | |
| 340 | + </div> | |
| 341 | + )} | |
| 342 | + | |
| 343 | + {/* Secrets list */} | |
| 344 | + {Result.match(secrets, { | |
| 345 | + onInitial: () => ( | |
| 346 | + <div className="flex items-center gap-2 py-8"> | |
| 347 | + <div className="size-1.5 rounded-full bg-muted-foreground/30 animate-pulse" /> | |
| 348 | + <p className="text-[13px] text-muted-foreground/60">Loading secrets…</p> | |
| 349 | + </div> | |
| 350 | + ), | |
| 351 | + onFailure: () => ( | |
| 352 | + <div className="rounded-lg border border-destructive/30 bg-destructive/5 px-4 py-3"> | |
| 353 | + <p className="text-[13px] text-destructive">Failed to load secrets</p> | |
| 354 | + </div> | |
| 355 | + ), | |
| 356 | + onSuccess: ({ value }) => | |
| 357 | + value.length === 0 ? ( | |
| 358 | + <div className="flex flex-col items-center justify-center rounded-xl border border-dashed border-border/70 py-16"> | |
| 359 | + <p className="text-[13px] font-medium text-foreground/60 mb-1"> | |
| 360 | + No secrets yet | |
| 361 | + </p> | |
| 362 | + <p className="text-[12px] text-muted-foreground/50 mb-5 max-w-[240px] text-center leading-relaxed"> | |
| 363 | + Add API keys and credentials to authenticate your sources. | |
| 364 | + </p> | |
| 365 | + <Button variant="outline" size="sm" onClick={() => setAddOpen(true)}> | |
| 366 | + Add your first secret | |
| 367 | + </Button> | |
| 368 | + </div> | |
| 369 | + ) : ( | |
| 370 | + <div className="grid gap-1.5"> | |
| 371 | + {value.map((s) => ( | |
| 372 | + <SecretRow | |
| 373 | + key={s.id} | |
| 374 | + secret={{ | |
| 375 | + id: s.id, | |
| 376 | + name: s.name, | |
| 377 | + purpose: s.purpose, | |
| 378 | + provider: s.provider ? String(s.provider) : undefined, | |
| 379 | + }} | |
| 380 | + onRemove={() => handleRemove(s.id)} | |
| 381 | + /> | |
| 382 | + ))} | |
| 383 | + </div> | |
| 384 | + ), | |
| 385 | + })} | |
| 386 | + | |
| 387 | + <AddSecretDialog open={addOpen} onOpenChange={setAddOpen} /> | |
| 388 | + </div> | |
| 389 | + </div> | |
| 390 | + ); | |
| 391 | +} | |
| @@ -0,0 +1,195 @@ | ||
| 1 | +import { useEffect, useMemo, useState } from "react"; | |
| 2 | +import { useNavigate } from "@tanstack/react-router"; | |
| 3 | +import { | |
| 4 | + useAtomValue, | |
| 5 | + useAtomSet, | |
| 6 | + useAtomRefresh, | |
| 7 | + sourceToolsAtom, | |
| 8 | + sourcesAtom, | |
| 9 | + sourceAtom, | |
| 10 | + removeSource, | |
| 11 | + refreshSource, | |
| 12 | + Result, | |
| 13 | +} from "@executor/react"; | |
| 14 | +import { ToolTree } from "../components/tool-tree"; | |
| 15 | +import { ToolDetail, ToolDetailEmpty } from "../components/tool-detail"; | |
| 16 | +import type { ToolSummary } from "../components/tool-tree"; | |
| 17 | +import { useScope } from "../lib/use-scope"; | |
| 18 | + | |
| 19 | +export function SourceDetailPage(props: { namespace: string }) { | |
| 20 | + const { namespace } = props; | |
| 21 | + const scopeId = useScope(); | |
| 22 | + const source = useAtomValue(sourceAtom(namespace, scopeId)); | |
| 23 | + const tools = useAtomValue(sourceToolsAtom(namespace, scopeId)); | |
| 24 | + const refreshSources = useAtomRefresh(sourcesAtom(scopeId)); | |
| 25 | + const refreshTools = useAtomRefresh(sourceToolsAtom(namespace, scopeId)); | |
| 26 | + const doRemove = useAtomSet(removeSource, { mode: "promise" }); | |
| 27 | + const doRefresh = useAtomSet(refreshSource, { mode: "promise" }); | |
| 28 | + const navigate = useNavigate(); | |
| 29 | + | |
| 30 | + // HMR: refresh source tools when the backend is hot-reloaded | |
| 31 | + useEffect(() => { | |
| 32 | + if (!import.meta.hot) return; | |
| 33 | + const refresh = () => { refreshTools(); refreshSources(); }; | |
| 34 | + import.meta.hot.on("executor:backend-updated", refresh); | |
| 35 | + return () => { import.meta.hot?.off("executor:backend-updated", refresh); }; | |
| 36 | + }, [refreshTools, refreshSources]); | |
| 37 | + | |
| 38 | + const [selectedToolId, setSelectedToolId] = useState<string | null>(null); | |
| 39 | + const [confirmDelete, setConfirmDelete] = useState(false); | |
| 40 | + const [deleting, setDeleting] = useState(false); | |
| 41 | + const [refreshing, setRefreshing] = useState(false); | |
| 42 | + | |
| 43 | + const sourceData = Result.isSuccess(source) ? source.value : null; | |
| 44 | + const canRefresh = sourceData ? (sourceData.canRefresh ?? true) : false; | |
| 45 | + const canRemove = sourceData ? (sourceData.canRemove ?? true) : false; | |
| 46 | + | |
| 47 | + const sourceTools: ToolSummary[] = useMemo(() => { | |
| 48 | + if (!Result.isSuccess(tools)) return []; | |
| 49 | + return tools.value.map((t) => ({ | |
| 50 | + id: t.id, | |
| 51 | + name: t.name, | |
| 52 | + pluginKey: t.pluginKey, | |
| 53 | + description: t.description, | |
| 54 | + })); | |
| 55 | + }, [tools]); | |
| 56 | + | |
| 57 | + const selectedTool = useMemo( | |
| 58 | + () => sourceTools.find((t) => t.id === selectedToolId) ?? null, | |
| 59 | + [sourceTools, selectedToolId], | |
| 60 | + ); | |
| 61 | + | |
| 62 | + const handleDelete = async () => { | |
| 63 | + setDeleting(true); | |
| 64 | + try { | |
| 65 | + await doRemove({ | |
| 66 | + path: { scopeId, sourceId: namespace }, | |
| 67 | + }); | |
| 68 | + refreshSources(); | |
| 69 | + void navigate({ to: "/" }); | |
| 70 | + } catch { | |
| 71 | + setDeleting(false); | |
| 72 | + setConfirmDelete(false); | |
| 73 | + } | |
| 74 | + }; | |
| 75 | + | |
| 76 | + const handleRefresh = async () => { | |
| 77 | + setRefreshing(true); | |
| 78 | + try { | |
| 79 | + await doRefresh({ | |
| 80 | + path: { scopeId, sourceId: namespace }, | |
| 81 | + }); | |
| 82 | + refreshTools(); | |
| 83 | + refreshSources(); | |
| 84 | + } finally { | |
| 85 | + setRefreshing(false); | |
| 86 | + } | |
| 87 | + }; | |
| 88 | + | |
| 89 | + return ( | |
| 90 | + <div className="flex min-h-0 flex-1 flex-col overflow-hidden"> | |
| 91 | + {/* Header bar */} | |
| 92 | + <div className="flex h-12 shrink-0 items-center justify-between border-b border-border bg-background/95 px-4 backdrop-blur-sm"> | |
| 93 | + <div className="flex min-w-0 items-center gap-3"> | |
| 94 | + <h2 className="truncate text-sm font-semibold text-foreground"> | |
| 95 | + {sourceData?.name ?? namespace} | |
| 96 | + </h2> | |
| 97 | + {sourceData?.runtime && ( | |
| 98 | + <span className="rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground"> | |
| 99 | + built-in | |
| 100 | + </span> | |
| 101 | + )} | |
| 102 | + <span className="rounded bg-secondary px-1.5 py-0.5 text-[10px] font-medium text-secondary-foreground"> | |
| 103 | + {sourceData?.kind ?? "source"} | |
| 104 | + </span> | |
| 105 | + {Result.isSuccess(tools) && ( | |
| 106 | + <span className="hidden text-[11px] tabular-nums text-muted-foreground/50 sm:block"> | |
| 107 | + {sourceTools.length} {sourceTools.length === 1 ? "tool" : "tools"} | |
| 108 | + </span> | |
| 109 | + )} | |
| 110 | + </div> | |
| 111 | + | |
| 112 | + <div className="flex shrink-0 items-center gap-2"> | |
| 113 | + {canRefresh && ( | |
| 114 | + <button | |
| 115 | + type="button" | |
| 116 | + onClick={() => void handleRefresh()} | |
| 117 | + disabled={refreshing} | |
| 118 | + className="inline-flex items-center gap-1.5 rounded-md border border-border bg-background px-2.5 py-1 text-[12px] font-medium text-foreground transition-colors hover:bg-accent disabled:opacity-50" | |
| 119 | + > | |
| 120 | + {refreshing ? "Refreshing…" : "Refresh"} | |
| 121 | + </button> | |
| 122 | + )} | |
| 123 | + | |
| 124 | + {canRemove && (confirmDelete ? ( | |
| 125 | + <div className="flex items-center gap-2"> | |
| 126 | + <span className="text-[11px] font-medium text-destructive"> | |
| 127 | + Confirm? | |
| 128 | + </span> | |
| 129 | + <button | |
| 130 | + type="button" | |
| 131 | + onClick={() => setConfirmDelete(false)} | |
| 132 | + disabled={deleting} | |
| 133 | + className="inline-flex items-center rounded-md border border-border bg-background px-2.5 py-1 text-[12px] font-medium text-foreground transition-colors hover:bg-accent disabled:opacity-50" | |
| 134 | + > | |
| 135 | + Cancel | |
| 136 | + </button> | |
| 137 | + <button | |
| 138 | + type="button" | |
| 139 | + onClick={() => void handleDelete()} | |
| 140 | + disabled={deleting} | |
| 141 | + className="inline-flex items-center rounded-md border border-destructive/30 bg-destructive/10 px-2.5 py-1 text-[12px] font-medium text-destructive transition-colors hover:bg-destructive/20 disabled:opacity-50" | |
| 142 | + > | |
| 143 | + {deleting ? "Deleting…" : "Delete"} | |
| 144 | + </button> | |
| 145 | + </div> | |
| 146 | + ) : ( | |
| 147 | + <button | |
| 148 | + type="button" | |
| 149 | + onClick={() => setConfirmDelete(true)} | |
| 150 | + className="inline-flex items-center rounded-md border border-destructive/30 bg-background px-2.5 py-1 text-[12px] font-medium text-destructive transition-colors hover:bg-destructive/10" | |
| 151 | + > | |
| 152 | + Delete | |
| 153 | + </button> | |
| 154 | + ))} | |
| 155 | + </div> | |
| 156 | + </div> | |
| 157 | + | |
| 158 | + {/* Content — split pane */} | |
| 159 | + {Result.match(tools, { | |
| 160 | + onInitial: () => ( | |
| 161 | + <div className="p-6 text-sm text-muted-foreground">Loading…</div> | |
| 162 | + ), | |
| 163 | + onFailure: () => ( | |
| 164 | + <div className="p-6 text-sm text-destructive">Failed to load tools</div> | |
| 165 | + ), | |
| 166 | + onSuccess: () => ( | |
| 167 | + <div className="flex min-h-0 flex-1 overflow-hidden"> | |
| 168 | + {/* Left: tool tree */} | |
| 169 | + <div className="flex w-72 shrink-0 flex-col border-r border-border bg-card/30 lg:w-80 xl:w-[22rem]"> | |
| 170 | + <ToolTree | |
| 171 | + tools={sourceTools} | |
| 172 | + selectedToolId={selectedToolId} | |
| 173 | + onSelect={setSelectedToolId} | |
| 174 | + /> | |
| 175 | + </div> | |
| 176 | + | |
| 177 | + {/* Right: tool detail */} | |
| 178 | + <div className="flex min-w-0 flex-1 flex-col overflow-hidden"> | |
| 179 | + {selectedTool ? ( | |
| 180 | + <ToolDetail | |
| 181 | + toolId={selectedTool.id} | |
| 182 | + toolName={selectedTool.name} | |
| 183 | + toolDescription={selectedTool.description} | |
| 184 | + scopeId={scopeId} | |
| 185 | + /> | |
| 186 | + ) : ( | |
| 187 | + <ToolDetailEmpty hasTools={sourceTools.length > 0} /> | |
| 188 | + )} | |
| 189 | + </div> | |
| 190 | + </div> | |
| 191 | + ), | |
| 192 | + })} | |
| 193 | + </div> | |
| 194 | + ); | |
| 195 | +} | |
| @@ -0,0 +1,377 @@ | ||
| 1 | +import { useReducer, useCallback, useMemo, Suspense } from "react"; | |
| 2 | +import { Link } from "@tanstack/react-router"; | |
| 3 | +import { Result, useAtomValue, useAtomRefresh, useAtomSet, sourcesAtom, detectSource } from "@executor/react"; | |
| 4 | +import { useScope } from "../lib/use-scope"; | |
| 5 | +import type { SourcePlugin, SourcePreset } from "@executor/react"; | |
| 6 | +import { openApiSourcePlugin } from "@executor/plugin-openapi/react"; | |
| 7 | +import { mcpSourcePlugin } from "@executor/plugin-mcp/react"; | |
| 8 | +import { googleDiscoverySourcePlugin } from "@executor/plugin-google-discovery/react"; | |
| 9 | +import { graphqlSourcePlugin } from "@executor/plugin-graphql/react"; | |
| 10 | +import { McpInstallCard } from "../components/mcp-install-card"; | |
| 11 | + | |
| 12 | +// --------------------------------------------------------------------------- | |
| 13 | +// Registered source plugins | |
| 14 | +// --------------------------------------------------------------------------- | |
| 15 | + | |
| 16 | +const sourcePlugins: SourcePlugin[] = [ | |
| 17 | + openApiSourcePlugin, | |
| 18 | + mcpSourcePlugin, | |
| 19 | + googleDiscoverySourcePlugin, | |
| 20 | + graphqlSourcePlugin, | |
| 21 | +]; | |
| 22 | + | |
| 23 | +const KIND_TO_PLUGIN_KEY: Record<string, string> = { | |
| 24 | + openapi: "openapi", | |
| 25 | + mcp: "mcp", | |
| 26 | + graphql: "graphql", | |
| 27 | + googleDiscovery: "googleDiscovery", | |
| 28 | +}; | |
| 29 | + | |
| 30 | +// --------------------------------------------------------------------------- | |
| 31 | +// State machine | |
| 32 | +// --------------------------------------------------------------------------- | |
| 33 | + | |
| 34 | +type State = { | |
| 35 | + step: "list" | "detecting" | "adding"; | |
| 36 | + url: string; | |
| 37 | + error: string | null; | |
| 38 | + pluginKey: string | null; | |
| 39 | + initialUrl: string | undefined; | |
| 40 | +}; | |
| 41 | + | |
| 42 | +type Action = | |
| 43 | + | { type: "set-url"; url: string } | |
| 44 | + | { type: "detect-start" } | |
| 45 | + | { type: "detect-ok"; pluginKey: string; url: string } | |
| 46 | + | { type: "detect-no-match" } | |
| 47 | + | { type: "detect-unknown-kind"; kind: string } | |
| 48 | + | { type: "detect-fail" } | |
| 49 | + | { type: "add-manual"; pluginKey: string } | |
| 50 | + | { type: "add-preset"; pluginKey: string; url: string } | |
| 51 | + | { type: "back" }; | |
| 52 | + | |
| 53 | +const init: State = { step: "list", url: "", error: null, pluginKey: null, initialUrl: undefined }; | |
| 54 | + | |
| 55 | +function reducer(state: State, action: Action): State { | |
| 56 | + switch (action.type) { | |
| 57 | + case "set-url": | |
| 58 | + return { ...state, step: "list", url: action.url, error: null }; | |
| 59 | + case "detect-start": | |
| 60 | + return { ...state, step: "detecting", error: null }; | |
| 61 | + case "detect-ok": | |
| 62 | + return { ...state, step: "adding", pluginKey: action.pluginKey, initialUrl: action.url }; | |
| 63 | + case "detect-no-match": | |
| 64 | + return { ...state, step: "list", error: "Could not detect a source type from this URL. Try adding manually." }; | |
| 65 | + case "detect-unknown-kind": | |
| 66 | + return { ...state, step: "list", error: `Detected source type "${action.kind}" but no plugin is available for it.` }; | |
| 67 | + case "detect-fail": | |
| 68 | + return { ...state, step: "list", error: "Detection failed. Try adding a source manually." }; | |
| 69 | + case "add-manual": | |
| 70 | + return { ...state, step: "adding", pluginKey: action.pluginKey, initialUrl: undefined }; | |
| 71 | + case "add-preset": | |
| 72 | + return { ...state, step: "adding", pluginKey: action.pluginKey, initialUrl: action.url }; | |
| 73 | + case "back": | |
| 74 | + return init; | |
| 75 | + default: | |
| 76 | + return state; | |
| 77 | + } | |
| 78 | +} | |
| 79 | + | |
| 80 | +// --------------------------------------------------------------------------- | |
| 81 | +// Page | |
| 82 | +// --------------------------------------------------------------------------- | |
| 83 | + | |
| 84 | +export function SourcesPage() { | |
| 85 | + const [state, dispatch] = useReducer(reducer, init); | |
| 86 | + const scopeId = useScope(); | |
| 87 | + const sources = useAtomValue(sourcesAtom(scopeId)); | |
| 88 | + const refreshSources = useAtomRefresh(sourcesAtom(scopeId)); | |
| 89 | + const doDetect = useAtomSet(detectSource, { mode: "promise" }); | |
| 90 | + | |
| 91 | + const handleDetect = useCallback(async () => { | |
| 92 | + const trimmed = state.url.trim(); | |
| 93 | + if (!trimmed) return; | |
| 94 | + dispatch({ type: "detect-start" }); | |
| 95 | + try { | |
| 96 | + const results = await doDetect({ | |
| 97 | + path: { scopeId }, | |
| 98 | + payload: { url: trimmed }, | |
| 99 | + }); | |
| 100 | + if (results.length === 0) { | |
| 101 | + dispatch({ type: "detect-no-match" }); | |
| 102 | + return; | |
| 103 | + } | |
| 104 | + const pluginKey = KIND_TO_PLUGIN_KEY[results[0].kind]; | |
| 105 | + if (pluginKey) { | |
| 106 | + dispatch({ type: "detect-ok", pluginKey, url: trimmed }); | |
| 107 | + } else { | |
| 108 | + dispatch({ type: "detect-unknown-kind", kind: results[0].kind }); | |
| 109 | + } | |
| 110 | + } catch { | |
| 111 | + dispatch({ type: "detect-fail" }); | |
| 112 | + } | |
| 113 | + }, [state.url, doDetect]); | |
| 114 | + | |
| 115 | + // --------------------------------------------------------------------------- | |
| 116 | + // Adding view | |
| 117 | + // --------------------------------------------------------------------------- | |
| 118 | + | |
| 119 | + if (state.step === "adding" && state.pluginKey) { | |
| 120 | + const plugin = sourcePlugins.find((p) => p.key === state.pluginKey); | |
| 121 | + if (!plugin) return null; | |
| 122 | + const AddComponent = plugin.add; | |
| 123 | + return ( | |
| 124 | + <div className="min-h-0 flex-1 overflow-y-auto"> | |
| 125 | + <div className="mx-auto max-w-4xl px-6 py-10 lg:px-10 lg:py-14"> | |
| 126 | + <Suspense fallback={<p className="text-sm text-muted-foreground">Loading…</p>}> | |
| 127 | + <AddComponent | |
| 128 | + initialUrl={state.initialUrl} | |
| 129 | + onComplete={() => { | |
| 130 | + dispatch({ type: "back" }); | |
| 131 | + refreshSources(); | |
| 132 | + }} | |
| 133 | + onCancel={() => dispatch({ type: "back" })} | |
| 134 | + /> | |
| 135 | + </Suspense> | |
| 136 | + </div> | |
| 137 | + </div> | |
| 138 | + ); | |
| 139 | + } | |
| 140 | + | |
| 141 | + // --------------------------------------------------------------------------- | |
| 142 | + // List view | |
| 143 | + // --------------------------------------------------------------------------- | |
| 144 | + | |
| 145 | + const isDetecting = state.step === "detecting"; | |
| 146 | + const error = state.step === "list" ? state.error : null; | |
| 147 | + | |
| 148 | + return ( | |
| 149 | + <div className="min-h-0 flex-1 overflow-y-auto"> | |
| 150 | + <div className="mx-auto max-w-4xl px-6 py-10 lg:px-10 lg:py-14"> | |
| 151 | + {/* Header */} | |
| 152 | + <div className="mb-8"> | |
| 153 | + <div className="flex items-end justify-between"> | |
| 154 | + <div> | |
| 155 | + <h1 className="font-display text-3xl tracking-tight text-foreground lg:text-4xl"> | |
| 156 | + Sources | |
| 157 | + </h1> | |
| 158 | + <p className="mt-1.5 text-[14px] text-muted-foreground"> | |
| 159 | + Tool providers available in this workspace. | |
| 160 | + </p> | |
| 161 | + </div> | |
| 162 | + </div> | |
| 163 | + | |
| 164 | + {/* URL detection input */} | |
| 165 | + <div className="mt-5"> | |
| 166 | + <div className="flex gap-2"> | |
| 167 | + <input | |
| 168 | + type="url" | |
| 169 | + value={state.url} | |
| 170 | + onChange={(e) => dispatch({ type: "set-url", url: e.target.value })} | |
| 171 | + onKeyDown={(e) => { if (e.key === "Enter") handleDetect(); }} | |
| 172 | + placeholder="Paste a URL to auto-detect source type..." | |
| 173 | + disabled={isDetecting} | |
| 174 | + className="flex-1 rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50" | |
| 175 | + /> | |
| 176 | + <button | |
| 177 | + onClick={handleDetect} | |
| 178 | + disabled={isDetecting || !state.url.trim()} | |
| 179 | + className="inline-flex items-center gap-1.5 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:opacity-50 disabled:pointer-events-none" | |
| 180 | + > | |
| 181 | + {isDetecting ? "Detecting..." : "Detect"} | |
| 182 | + </button> | |
| 183 | + </div> | |
| 184 | + {error && ( | |
| 185 | + <p className="mt-2 text-sm text-destructive">{error}</p> | |
| 186 | + )} | |
| 187 | + <div className="mt-3 flex items-center gap-2 text-xs text-muted-foreground"> | |
| 188 | + <span>Or add manually:</span> | |
| 189 | + {sourcePlugins.map((p) => ( | |
| 190 | + <button | |
| 191 | + key={p.key} | |
| 192 | + onClick={() => dispatch({ type: "add-manual", pluginKey: p.key })} | |
| 193 | + className="rounded-md border border-border px-2 py-1 text-xs font-medium transition-colors hover:bg-muted" | |
| 194 | + > | |
| 195 | + {p.label} | |
| 196 | + </button> | |
| 197 | + ))} | |
| 198 | + </div> | |
| 199 | + </div> | |
| 200 | + </div> | |
| 201 | + | |
| 202 | + <McpInstallCard className="mb-8 rounded-2xl border border-border bg-card/80 p-5" /> | |
| 203 | + | |
| 204 | + <PresetGrid plugins={sourcePlugins} dispatch={dispatch} /> | |
| 205 | + | |
| 206 | + {Result.match(sources, { | |
| 207 | + onInitial: () => ( | |
| 208 | + <p className="text-sm text-muted-foreground">Loading…</p> | |
| 209 | + ), | |
| 210 | + onFailure: () => ( | |
| 211 | + <p className="text-sm text-destructive">Failed to load sources</p> | |
| 212 | + ), | |
| 213 | + onSuccess: ({ value }) => { | |
| 214 | + const builtInSources = value.filter((source) => source.runtime); | |
| 215 | + const connectedSources = value.filter((source) => !source.runtime); | |
| 216 | + | |
| 217 | + return value.length === 0 ? ( | |
| 218 | + <div className="flex flex-col items-center justify-center rounded-2xl border border-dashed border-border py-20"> | |
| 219 | + <div className="flex size-12 items-center justify-center rounded-2xl bg-muted text-muted-foreground mb-4"> | |
| 220 | + <svg viewBox="0 0 24 24" fill="none" className="size-5"> | |
| 221 | + <path d="M12 6v12M6 12h12" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" /> | |
| 222 | + </svg> | |
| 223 | + </div> | |
| 224 | + <p className="text-[14px] font-medium text-foreground/70 mb-1"> | |
| 225 | + No sources yet | |
| 226 | + </p> | |
| 227 | + <p className="text-[13px] text-muted-foreground/60 mb-5"> | |
| 228 | + Add a source to get started. | |
| 229 | + </p> | |
| 230 | + </div> | |
| 231 | + ) : ( | |
| 232 | + <div className="space-y-8"> | |
| 233 | + {builtInSources.length > 0 && ( | |
| 234 | + <section className="space-y-3"> | |
| 235 | + <div> | |
| 236 | + <h2 className="text-sm font-semibold text-foreground"> | |
| 237 | + Built-in | |
| 238 | + </h2> | |
| 239 | + <p className="mt-1 text-[13px] text-muted-foreground"> | |
| 240 | + Runtime sources exposed by the loaded executor plugins. | |
| 241 | + </p> | |
| 242 | + </div> | |
| 243 | + <SourceGrid sources={builtInSources} /> | |
| 244 | + </section> | |
| 245 | + )} | |
| 246 | + | |
| 247 | + {connectedSources.length > 0 && ( | |
| 248 | + <section className="space-y-3"> | |
| 249 | + <div> | |
| 250 | + <h2 className="text-sm font-semibold text-foreground"> | |
| 251 | + Connected | |
| 252 | + </h2> | |
| 253 | + <p className="mt-1 text-[13px] text-muted-foreground"> | |
| 254 | + User-configured sources available in this workspace. | |
| 255 | + </p> | |
| 256 | + </div> | |
| 257 | + <SourceGrid sources={connectedSources} /> | |
| 258 | + </section> | |
| 259 | + )} | |
| 260 | + </div> | |
| 261 | + ); | |
| 262 | + }, | |
| 263 | + })} | |
| 264 | + </div> | |
| 265 | + </div> | |
| 266 | + ); | |
| 267 | +} | |
| 268 | + | |
| 269 | +// --------------------------------------------------------------------------- | |
| 270 | +// Preset grid | |
| 271 | +// --------------------------------------------------------------------------- | |
| 272 | + | |
| 273 | +function PresetGrid(props: { | |
| 274 | + plugins: readonly SourcePlugin[]; | |
| 275 | + dispatch: React.Dispatch<Action>; | |
| 276 | +}) { | |
| 277 | + const allPresets = useMemo(() => { | |
| 278 | + const out: { preset: SourcePreset; pluginKey: string; pluginLabel: string }[] = []; | |
| 279 | + for (const plugin of props.plugins) { | |
| 280 | + for (const preset of plugin.presets ?? []) { | |
| 281 | + out.push({ preset, pluginKey: plugin.key, pluginLabel: plugin.label }); | |
| 282 | + } | |
| 283 | + } | |
| 284 | + return out; | |
| 285 | + }, [props.plugins]); | |
| 286 | + | |
| 287 | + if (allPresets.length === 0) return null; | |
| 288 | + | |
| 289 | + return ( | |
| 290 | + <section className="mb-8 space-y-3"> | |
| 291 | + <div> | |
| 292 | + <h2 className="text-sm font-semibold text-foreground">Presets</h2> | |
| 293 | + <p className="mt-1 text-[13px] text-muted-foreground"> | |
| 294 | + One-click setup for common APIs and services. | |
| 295 | + </p> | |
| 296 | + </div> | |
| 297 | + <div className="grid gap-2 sm:grid-cols-2 lg:grid-cols-3"> | |
| 298 | + {allPresets.map(({ preset, pluginKey, pluginLabel }) => ( | |
| 299 | + <button | |
| 300 | + key={`${pluginKey}-${preset.id}`} | |
| 301 | + onClick={() => props.dispatch({ type: "add-preset", pluginKey, url: preset.url })} | |
| 302 | + className="flex items-start gap-3 rounded-xl border border-border bg-card px-4 py-3 text-left transition-colors hover:border-primary/25 hover:bg-card/90" | |
| 303 | + > | |
| 304 | + <div className="flex size-8 shrink-0 items-center justify-center rounded-lg bg-muted text-muted-foreground overflow-hidden"> | |
| 305 | + {preset.icon ? ( | |
| 306 | + <img src={preset.icon} alt="" className="size-5 object-contain" loading="lazy" /> | |
| 307 | + ) : ( | |
| 308 | + <svg viewBox="0 0 16 16" className="size-3.5" fill="none"> | |
| 309 | + <circle cx="8" cy="8" r="6" stroke="currentColor" strokeWidth="1.2" /> | |
| 310 | + </svg> | |
| 311 | + )} | |
| 312 | + </div> | |
| 313 | + <div className="min-w-0 flex-1"> | |
| 314 | + <div className="flex items-center gap-2"> | |
| 315 | + <span className="truncate text-sm font-medium text-foreground">{preset.name}</span> | |
| 316 | + <span className="shrink-0 rounded bg-secondary px-1.5 py-0.5 text-[10px] font-medium text-secondary-foreground"> | |
| 317 | + {pluginLabel} | |
| 318 | + </span> | |
| 319 | + </div> | |
| 320 | + <p className="mt-0.5 text-xs text-muted-foreground line-clamp-1">{preset.summary}</p> | |
| 321 | + </div> | |
| 322 | + </button> | |
| 323 | + ))} | |
| 324 | + </div> | |
| 325 | + </section> | |
| 326 | + ); | |
| 327 | +} | |
| 328 | + | |
| 329 | +// --------------------------------------------------------------------------- | |
| 330 | +// Source grid | |
| 331 | +// --------------------------------------------------------------------------- | |
| 332 | + | |
| 333 | +function SourceGrid(props: { | |
| 334 | + sources: readonly { id: string; name: string; kind: string; runtime?: boolean }[]; | |
| 335 | +}) { | |
| 336 | + return ( | |
| 337 | + <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3"> | |
| 338 | + {props.sources.map((s) => ( | |
| 339 | + <Link | |
| 340 | + key={s.id} | |
| 341 | + to="/sources/$namespace" | |
| 342 | + params={{ namespace: s.id }} | |
| 343 | + className="flex h-full flex-col rounded-2xl border border-border bg-card px-5 py-4 transition-colors hover:border-primary/25 hover:bg-card/90" | |
| 344 | + > | |
| 345 | + <div className="flex items-start gap-3"> | |
| 346 | + <div className="flex size-9 shrink-0 items-center justify-center rounded-lg bg-muted text-muted-foreground"> | |
| 347 | + <svg viewBox="0 0 16 16" className="size-4"> | |
| 348 | + <circle cx="8" cy="8" r="6" fill="none" stroke="currentColor" strokeWidth="1.2" /> | |
| 349 | + <path d="M8 5v6M5 8h6" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" /> | |
| 350 | + </svg> | |
| 351 | + </div> | |
| 352 | + <div className="min-w-0 flex-1"> | |
| 353 | + <div className="flex items-start justify-between gap-2"> | |
| 354 | + <div className="truncate text-sm font-semibold text-foreground"> | |
| 355 | + {s.name} | |
| 356 | + </div> | |
| 357 | + <div className="flex shrink-0 items-center gap-1.5"> | |
| 358 | + {s.runtime && ( | |
| 359 | + <span className="rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground"> | |
| 360 | + built-in | |
| 361 | + </span> | |
| 362 | + )} | |
| 363 | + <span className="rounded bg-secondary px-1.5 py-0.5 text-[10px] font-medium text-secondary-foreground"> | |
| 364 | + {s.kind} | |
| 365 | + </span> | |
| 366 | + </div> | |
| 367 | + </div> | |
| 368 | + <div className="mt-0.5 text-xs text-muted-foreground"> | |
| 369 | + {s.id} | |
| 370 | + </div> | |
| 371 | + </div> | |
| 372 | + </div> | |
| 373 | + </Link> | |
| 374 | + ))} | |
| 375 | + </div> | |
| 376 | + ); | |
| 377 | +} | |
| @@ -0,0 +1,73 @@ | ||
| 1 | +import { useAtomValue, Result, toolsAtom } from "@executor/react"; | |
| 2 | +import { useScope } from "../lib/use-scope"; | |
| 3 | + | |
| 4 | +export function ToolsPage() { | |
| 5 | + const scopeId = useScope(); | |
| 6 | + const tools = useAtomValue(toolsAtom(scopeId)); | |
| 7 | + | |
| 8 | + return ( | |
| 9 | + <div className="min-h-0 flex-1 overflow-y-auto"> | |
| 10 | + <div className="mx-auto max-w-4xl px-6 py-10 lg:px-10 lg:py-14"> | |
| 11 | + {/* Header */} | |
| 12 | + <div className="flex items-end justify-between mb-8"> | |
| 13 | + <div> | |
| 14 | + <h1 className="font-display text-3xl tracking-tight text-foreground lg:text-4xl"> | |
| 15 | + Tools | |
| 16 | + </h1> | |
| 17 | + <p className="mt-1.5 text-[14px] text-muted-foreground"> | |
| 18 | + All registered tools across your connected sources. | |
| 19 | + </p> | |
| 20 | + </div> | |
| 21 | + </div> | |
| 22 | + | |
| 23 | + {Result.match(tools, { | |
| 24 | + onInitial: () => ( | |
| 25 | + <p className="text-sm text-muted-foreground">Loading tools…</p> | |
| 26 | + ), | |
| 27 | + onFailure: () => ( | |
| 28 | + <p className="text-sm text-destructive">Failed to load tools</p> | |
| 29 | + ), | |
| 30 | + onSuccess: ({ value }) => | |
| 31 | + value.length === 0 ? ( | |
| 32 | + <div className="flex flex-col items-center justify-center rounded-2xl border border-dashed border-border py-20"> | |
| 33 | + <div className="flex size-12 items-center justify-center rounded-2xl bg-muted text-muted-foreground mb-4"> | |
| 34 | + <svg viewBox="0 0 16 16" className="size-5"> | |
| 35 | + <path d="M4 2h8l1 3H3l1-3zM3 6h10v8H3V6z" fill="none" stroke="currentColor" strokeWidth="1.2" /> | |
| 36 | + </svg> | |
| 37 | + </div> | |
| 38 | + <p className="text-[14px] font-medium text-foreground/70 mb-1"> | |
| 39 | + No tools registered | |
| 40 | + </p> | |
| 41 | + <p className="text-[13px] text-muted-foreground/60"> | |
| 42 | + Add a source to start discovering tools. | |
| 43 | + </p> | |
| 44 | + </div> | |
| 45 | + ) : ( | |
| 46 | + <div className="grid gap-2"> | |
| 47 | + {value.map((t) => ( | |
| 48 | + <div | |
| 49 | + key={t.id} | |
| 50 | + className="flex items-start justify-between gap-3 rounded-xl border border-border bg-card px-5 py-3.5 transition-colors hover:border-primary/25 hover:bg-card/90" | |
| 51 | + > | |
| 52 | + <div className="min-w-0 flex-1"> | |
| 53 | + <p className="text-sm font-semibold text-foreground truncate font-mono"> | |
| 54 | + {t.name} | |
| 55 | + </p> | |
| 56 | + {t.description && ( | |
| 57 | + <p className="mt-0.5 text-xs text-muted-foreground line-clamp-2"> | |
| 58 | + {t.description} | |
| 59 | + </p> | |
| 60 | + )} | |
| 61 | + </div> | |
| 62 | + <span className="shrink-0 rounded bg-secondary px-1.5 py-0.5 text-[10px] font-medium text-secondary-foreground"> | |
| 63 | + {t.sourceId} | |
| 64 | + </span> | |
| 65 | + </div> | |
| 66 | + ))} | |
| 67 | + </div> | |
| 68 | + ), | |
| 69 | + })} | |
| 70 | + </div> | |
| 71 | + </div> | |
| 72 | + ); | |
| 73 | +} | |
| @@ -1,96 +0,0 @@ | ||
| 1 | −import type { | |
| 2 | − Source, | |
| 3 | −} from "@executor/react"; | |
| 4 | −import { | |
| 5 | − ExecutionHistoryReactPlugin, | |
| 6 | −} from "@executor/plugin-execution-history-react"; | |
| 7 | −import { | |
| 8 | − GoogleDiscoveryReactPlugin, | |
| 9 | − getGoogleDiscoveryIconUrl, | |
| 10 | −} from "@executor/plugin-google-discovery-react"; | |
| 11 | −import { | |
| 12 | − GraphqlReactPlugin, | |
| 13 | −} from "@executor/plugin-graphql-react"; | |
| 14 | −import { | |
| 15 | − McpReactPlugin, | |
| 16 | −} from "@executor/plugin-mcp-react"; | |
| 17 | −import { | |
| 18 | − OpenApiReactPlugin, | |
| 19 | −} from "@executor/plugin-openapi-react"; | |
| 20 | −import { | |
| 21 | − createExecutorPluginPaths, | |
| 22 | − createSourcePluginPaths, | |
| 23 | − registerExecutorFrontendPlugins, | |
| 24 | − type ExecutorFrontendPlugin, | |
| 25 | −} from "@executor/react/plugins"; | |
| 26 | −import { getFallbackSourceFaviconUrl } from "../lib/source-favicon"; | |
| 27 | − | |
| 28 | −const frontendPlugins = [ | |
| 29 | − ExecutionHistoryReactPlugin, | |
| 30 | − McpReactPlugin, | |
| 31 | − GraphqlReactPlugin, | |
| 32 | − GoogleDiscoveryReactPlugin, | |
| 33 | − OpenApiReactPlugin, | |
| 34 | −] as const satisfies readonly ExecutorFrontendPlugin[]; | |
| 35 | − | |
| 36 | −const frontendPluginRegistry = registerExecutorFrontendPlugins(frontendPlugins); | |
| 37 | − | |
| 38 | −const hasRouteKey = ( | |
| 39 | − plugin: ExecutorFrontendPlugin, | |
| 40 | − routeKey: string, | |
| 41 | −): boolean => | |
| 42 | − (plugin.routes ?? []).some((route) => route.key === routeKey); | |
| 43 | − | |
| 44 | −const isSourceFrontendPlugin = ( | |
| 45 | − plugin: ExecutorFrontendPlugin, | |
| 46 | −): boolean => | |
| 47 | − hasRouteKey(plugin, "add") | |
| 48 | − && hasRouteKey(plugin, "detail"); | |
| 49 | − | |
| 50 | −export const registeredFrontendPlugins = frontendPluginRegistry.plugins; | |
| 51 | −export const registeredFrontendPluginRoutes = frontendPluginRegistry.routes; | |
| 52 | −export const registeredFrontendPluginNavRoutes = | |
| 53 | − registeredFrontendPluginRoutes | |
| 54 | − .filter(({ route }) => route.nav !== undefined) | |
| 55 | − .map(({ plugin, route }) => ({ | |
| 56 | − plugin, | |
| 57 | − route, | |
| 58 | − to: createExecutorPluginPaths(plugin.key).route(route.path ?? ""), | |
| 59 | − })); | |
| 60 | −export const registeredSourceFrontendPlugins = | |
| 61 | − registeredFrontendPlugins.filter(isSourceFrontendPlugin); | |
| 62 | − | |
| 63 | −export const getFrontendPlugin = (key: string) => | |
| 64 | − frontendPluginRegistry.getPlugin(key); | |
| 65 | − | |
| 66 | −export const getFrontendPluginRoute = ( | |
| 67 | − pluginKey: string, | |
| 68 | − routeKey: string, | |
| 69 | −) => frontendPluginRegistry.getRoute(pluginKey, routeKey); | |
| 70 | − | |
| 71 | −const resolveSourcePluginKey = (kind: string): string => | |
| 72 | − isGoogleDiscoverySource(kind) ? "google-discovery" : kind; | |
| 73 | − | |
| 74 | −export const getSourceFrontendPlugin = (kind: string) => { | |
| 75 | − const plugin = getFrontendPlugin(resolveSourcePluginKey(kind)); | |
| 76 | − return plugin && isSourceFrontendPlugin(plugin) ? plugin : null; | |
| 77 | −}; | |
| 78 | − | |
| 79 | −export const getSourceFrontendPaths = (kind: string) => { | |
| 80 | − const plugin = getSourceFrontendPlugin(kind); | |
| 81 | − return plugin ? createSourcePluginPaths(plugin.key) : null; | |
| 82 | −}; | |
| 83 | − | |
| 84 | −const isGoogleDiscoverySource = (kind: string): boolean => | |
| 85 | − kind === "google_discovery" | |
| 86 | − || kind === "google-discovery"; | |
| 87 | − | |
| 88 | −export const getSourceFrontendIconUrl = (source: Source) => | |
| 89 | − source.iconUrl | |
| 90 | − ?? (isGoogleDiscoverySource(source.kind) | |
| 91 | − ? getGoogleDiscoveryIconUrl(source) | |
| 92 | − : null) | |
| 93 | − ?? getFallbackSourceFaviconUrl(source); | |
| 94 | − | |
| 95 | −export const getSecretStoreFrontendPlugin = (kind: string) => | |
| 96 | − registeredFrontendPlugins.find((plugin) => plugin.secretStore?.kind === kind) ?? null; | |
| @@ -1,260 +0,0 @@ | ||
| 1 | −import { useState, type FormEvent } from "react"; | |
| 2 | −import { Link, useNavigate } from "@tanstack/react-router"; | |
| 3 | −import { | |
| 4 | − Alert, | |
| 5 | − Button, | |
| 6 | − Card, | |
| 7 | − Input, | |
| 8 | − ExecutorPluginRouteProvider, | |
| 9 | − createSourcePluginPaths, | |
| 10 | − type ExecutorPluginNavigation, | |
| 11 | − type FrontendPluginRouteDefinition, | |
| 12 | − type FrontendPluginRouteParams, | |
| 13 | − type FrontendPluginRouteSearch, | |
| 14 | −} from "@executor/react/plugins"; | |
| 15 | − | |
| 16 | −import { SourcePresetFavicon } from "../components/source-favicon"; | |
| 17 | −import { LocalMcpInstallCard } from "../components/local-mcp-install-card"; | |
| 18 | −import { SourcePluginsResetState } from "../components/source-plugins-reset-state"; | |
| 19 | −import { | |
| 20 | − getFrontendPlugin, | |
| 21 | − getFrontendPluginRoute, | |
| 22 | − registeredSourceFrontendPlugins, | |
| 23 | −} from "./index"; | |
| 24 | −import { | |
| 25 | − buildSourcePresetSearch, | |
| 26 | − resolveQuickSourceInput, | |
| 27 | − sourcePresets, | |
| 28 | −} from "./source-presets"; | |
| 29 | − | |
| 30 | −const FrontendPluginUnavailableState = () => ( | |
| 31 | − <SourcePluginsResetState | |
| 32 | − title="Plugins unavailable" | |
| 33 | − message="No plugins are available in this build." | |
| 34 | − /> | |
| 35 | −); | |
| 36 | − | |
| 37 | −const SourcePluginUnavailableState = () => ( | |
| 38 | − <SourcePluginsResetState | |
| 39 | − title="No source plugins available" | |
| 40 | − message="No source plugins are available in this build." | |
| 41 | − /> | |
| 42 | −); | |
| 43 | − | |
| 44 | −const SourceQuickEntry = () => { | |
| 45 | − const navigate = useNavigate(); | |
| 46 | − const [value, setValue] = useState(""); | |
| 47 | − const [error, setError] = useState<string | null>(null); | |
| 48 | − | |
| 49 | − const handleSubmit = (event: FormEvent<HTMLFormElement>) => { | |
| 50 | − event.preventDefault(); | |
| 51 | − | |
| 52 | − const resolved = resolveQuickSourceInput(value); | |
| 53 | − if (resolved === null) { | |
| 54 | − setError( | |
| 55 | − "Could not recognize that input. Try a GraphQL endpoint, MCP URL, Google Discovery URL, OpenAPI spec URL, or a local MCP command.", | |
| 56 | − ); | |
| 57 | − return; | |
| 58 | − } | |
| 59 | − | |
| 60 | − setError(null); | |
| 61 | − void navigate({ | |
| 62 | − to: createSourcePluginPaths(resolved.pluginKey).add, | |
| 63 | − search: resolved.search, | |
| 64 | − }); | |
| 65 | − }; | |
| 66 | − | |
| 67 | − return ( | |
| 68 | − <Card className="rounded-2xl"> | |
| 69 | − <h2 className="font-display text-lg font-semibold tracking-tight text-foreground"> | |
| 70 | − Quick add | |
| 71 | − </h2> | |
| 72 | − <p className="mt-1 text-sm leading-6 text-muted-foreground"> | |
| 73 | − Paste a URL or command and we'll detect the right plugin automatically. | |
| 74 | − </p> | |
| 75 | − | |
| 76 | − <form onSubmit={handleSubmit} className="mt-4"> | |
| 77 | − <div className="flex flex-col gap-3 sm:flex-row"> | |
| 78 | − <Input | |
| 79 | − value={value} | |
| 80 | − onChange={(event) => setValue(event.target.value)} | |
| 81 | − placeholder="https://api.github.com/graphql or npx -y chrome-devtools-mcp@latest" | |
| 82 | − className="h-10 flex-1 px-3.5 text-sm" | |
| 83 | − /> | |
| 84 | − <Button type="submit" className="h-10"> | |
| 85 | − Add source | |
| 86 | − </Button> | |
| 87 | − </div> | |
| 88 | − | |
| 89 | − {error && ( | |
| 90 | − <Alert variant="destructive" className="mt-3"> | |
| 91 | − {error} | |
| 92 | − </Alert> | |
| 93 | − )} | |
| 94 | − </form> | |
| 95 | − </Card> | |
| 96 | − ); | |
| 97 | −}; | |
| 98 | − | |
| 99 | −export function ExecutorPluginRoutePage(input: { | |
| 100 | − pluginKey: string; | |
| 101 | − routeKey: FrontendPluginRouteDefinition["key"]; | |
| 102 | − params: FrontendPluginRouteParams; | |
| 103 | − search: FrontendPluginRouteSearch; | |
| 104 | − navigation: ExecutorPluginNavigation; | |
| 105 | −}) { | |
| 106 | − const plugin = getFrontendPlugin(input.pluginKey); | |
| 107 | − if (plugin === null) { | |
| 108 | − return <FrontendPluginUnavailableState />; | |
| 109 | − } | |
| 110 | − | |
| 111 | − const routeEntry = getFrontendPluginRoute(input.pluginKey, input.routeKey); | |
| 112 | − if (routeEntry === null) { | |
| 113 | − return ( | |
| 114 | − <SourcePluginsResetState | |
| 115 | − title="Route unavailable" | |
| 116 | − message={`The route "${input.routeKey}" is not available for this plugin.`} | |
| 117 | − /> | |
| 118 | − ); | |
| 119 | − } | |
| 120 | − | |
| 121 | − const PluginPage = routeEntry.route.component; | |
| 122 | − | |
| 123 | − return ( | |
| 124 | − <ExecutorPluginRouteProvider | |
| 125 | − value={{ | |
| 126 | − plugin, | |
| 127 | − route: routeEntry.route, | |
| 128 | − params: input.params, | |
| 129 | − search: input.search, | |
| 130 | − navigation: input.navigation, | |
| 131 | − }} | |
| 132 | − > | |
| 133 | − <div className="flex h-full min-h-0 flex-col overflow-hidden"> | |
| 134 | − <PluginPage /> | |
| 135 | − </div> | |
| 136 | − </ExecutorPluginRouteProvider> | |
| 137 | − ); | |
| 138 | −} | |
| 139 | − | |
| 140 | −export function SourcePluginsIndexPage() { | |
| 141 | − if (registeredSourceFrontendPlugins.length === 0) { | |
| 142 | − return <SourcePluginUnavailableState />; | |
| 143 | − } | |
| 144 | − | |
| 145 | − const hasMcpPlugin = registeredSourceFrontendPlugins.some( | |
| 146 | − (plugin) => plugin.key === "mcp", | |
| 147 | − ); | |
| 148 | − | |
| 149 | − const presetsByPlugin = registeredSourceFrontendPlugins | |
| 150 | − .map((plugin) => ({ | |
| 151 | − plugin, | |
| 152 | − presets: sourcePresets.filter((preset) => preset.pluginKey === plugin.key), | |
| 153 | − })) | |
| 154 | − .filter((entry) => entry.presets.length > 0); | |
| 155 | − | |
| 156 | − return ( | |
| 157 | − <div className="min-h-0 flex-1 overflow-y-auto"> | |
| 158 | − <div className="mx-auto max-w-5xl px-6 py-10 lg:px-10 lg:py-14"> | |
| 159 | − <div className="mb-8"> | |
| 160 | − <h1 className="font-display text-3xl tracking-tight text-foreground lg:text-4xl"> | |
| 161 | − Add source | |
| 162 | − </h1> | |
| 163 | − <p className="mt-1.5 text-[14px] text-muted-foreground"> | |
| 164 | − Connect a new tool provider to this workspace. | |
| 165 | − </p> | |
| 166 | − </div> | |
| 167 | − | |
| 168 | − <SourceQuickEntry /> | |
| 169 | − | |
| 170 | − {hasMcpPlugin && ( | |
| 171 | − <LocalMcpInstallCard | |
| 172 | − className="mt-8" | |
| 173 | − title="Install this executor as MCP" | |
| 174 | − description="Prefer a one-command setup? Install this local executor server into your MCP client, or add an external MCP source below." | |
| 175 | − /> | |
| 176 | − )} | |
| 177 | − | |
| 178 | − {presetsByPlugin.length > 0 && ( | |
| 179 | − <div className="mt-10"> | |
| 180 | − <h2 className="text-lg font-semibold text-foreground">Popular sources</h2> | |
| 181 | − <p className="mt-1 text-sm leading-6 text-muted-foreground"> | |
| 182 | − One-click presets for common APIs and tools. | |
| 183 | − </p> | |
| 184 | − | |
| 185 | − <div className="mt-5 space-y-8"> | |
| 186 | − {presetsByPlugin.map(({ plugin, presets }) => { | |
| 187 | − const paths = createSourcePluginPaths(plugin.key); | |
| 188 | − | |
| 189 | − return ( | |
| 190 | − <section key={plugin.key}> | |
| 191 | − <h3 className="mb-3 text-sm font-semibold text-foreground"> | |
| 192 | − {plugin.displayName ?? plugin.key} | |
| 193 | − </h3> | |
| 194 | − | |
| 195 | − <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3"> | |
| 196 | − {presets.map((preset) => ( | |
| 197 | − <Link | |
| 198 | − key={preset.id} | |
| 199 | − to={paths.add} | |
| 200 | − search={buildSourcePresetSearch(preset)} | |
| 201 | − className="rounded-xl border border-border bg-card px-4 py-3 text-left transition-colors hover:border-primary/25 hover:bg-card/90" | |
| 202 | − > | |
| 203 | − <div className="mb-2 flex items-center gap-2.5"> | |
| 204 | − <div className="flex size-8 shrink-0 items-center justify-center rounded-lg bg-muted text-muted-foreground"> | |
| 205 | − <SourcePresetFavicon preset={preset} className="size-4" /> | |
| 206 | − </div> | |
| 207 | − <div className="min-w-0"> | |
| 208 | − <div className="truncate text-sm font-semibold text-foreground"> | |
| 209 | − {preset.name} | |
| 210 | − </div> | |
| 211 | − <div className="mt-0.5 text-[11px] text-muted-foreground"> | |
| 212 | − {preset.kind} | |
| 213 | − </div> | |
| 214 | − </div> | |
| 215 | − </div> | |
| 216 | − | |
| 217 | − <p className="text-sm leading-6 text-muted-foreground"> | |
| 218 | − {preset.summary} | |
| 219 | − </p> | |
| 220 | − </Link> | |
| 221 | − ))} | |
| 222 | − </div> | |
| 223 | − </section> | |
| 224 | − ); | |
| 225 | − })} | |
| 226 | − </div> | |
| 227 | − </div> | |
| 228 | − )} | |
| 229 | − | |
| 230 | − <div className="mt-10"> | |
| 231 | − <h2 className="text-lg font-semibold text-foreground">All source plugins</h2> | |
| 232 | − <p className="mt-1 text-sm leading-6 text-muted-foreground"> | |
| 233 | − Start from a clean configuration page for any installed source plugin. | |
| 234 | − </p> | |
| 235 | − | |
| 236 | − <div className="mt-5 grid gap-3 sm:grid-cols-2 lg:grid-cols-3"> | |
| 237 | − {registeredSourceFrontendPlugins.map((plugin) => { | |
| 238 | − const paths = createSourcePluginPaths(plugin.key); | |
| 239 | − | |
| 240 | − return ( | |
| 241 | − <Link | |
| 242 | − key={plugin.key} | |
| 243 | − to={paths.add} | |
| 244 | − className="rounded-xl border border-border bg-card px-4 py-3 text-left transition-colors hover:border-primary/25 hover:bg-card/90" | |
| 245 | − > | |
| 246 | − <div className="mb-2 text-sm font-semibold text-foreground"> | |
| 247 | − {plugin.displayName ?? plugin.key} | |
| 248 | − </div> | |
| 249 | − <p className="text-sm leading-6 text-muted-foreground"> | |
| 250 | − {plugin.description ?? "Configure a new source for this plugin."} | |
| 251 | − </p> | |
| 252 | − </Link> | |
| 253 | − ); | |
| 254 | − })} | |
| 255 | − </div> | |
| 256 | − </div> | |
| 257 | − </div> | |
| 258 | − </div> | |
| 259 | − ); | |
| 260 | −} | |
| @@ -1,657 +0,0 @@ | ||
| 1 | −const GOOGLE_DISCOVERY_PLUGIN_KEY = "google-discovery" as const; | |
| 2 | −const GOOGLE_DISCOVERY_SOURCE_KIND = "google_discovery" as const; | |
| 3 | − | |
| 4 | −export type SourcePreset = | |
| 5 | − | { | |
| 6 | − id: string; | |
| 7 | − pluginKey: "mcp"; | |
| 8 | − kind: "mcp"; | |
| 9 | − name: string; | |
| 10 | − summary: string; | |
| 11 | − previewUrl: string; | |
| 12 | − endpoint?: string; | |
| 13 | − transport?: "auto" | "streamable-http" | "sse" | "stdio"; | |
| 14 | − command?: string; | |
| 15 | − args?: string[]; | |
| 16 | − env?: Record<string, string>; | |
| 17 | − cwd?: string; | |
| 18 | − } | |
| 19 | − | { | |
| 20 | − id: string; | |
| 21 | − pluginKey: "openapi"; | |
| 22 | − kind: "openapi"; | |
| 23 | − name: string; | |
| 24 | − summary: string; | |
| 25 | − previewUrl: string; | |
| 26 | − baseUrl: string; | |
| 27 | − specUrl: string; | |
| 28 | − } | |
| 29 | − | { | |
| 30 | − id: string; | |
| 31 | − pluginKey: "graphql"; | |
| 32 | − kind: "graphql"; | |
| 33 | − name: string; | |
| 34 | − summary: string; | |
| 35 | − previewUrl: string; | |
| 36 | − endpoint: string; | |
| 37 | − } | |
| 38 | − | { | |
| 39 | − id: string; | |
| 40 | − pluginKey: typeof GOOGLE_DISCOVERY_PLUGIN_KEY; | |
| 41 | − kind: typeof GOOGLE_DISCOVERY_SOURCE_KIND; | |
| 42 | − name: string; | |
| 43 | − summary: string; | |
| 44 | − previewUrl: string; | |
| 45 | − service: string; | |
| 46 | − version: string; | |
| 47 | − discoveryUrl: string; | |
| 48 | − }; | |
| 49 | − | |
| 50 | −const googleDiscoveryPreset = (input: { | |
| 51 | − id: string; | |
| 52 | − name: string; | |
| 53 | − summary: string; | |
| 54 | − service: string; | |
| 55 | − version: string; | |
| 56 | − discoveryUrl: string; | |
| 57 | −}): SourcePreset => ({ | |
| 58 | − id: input.id, | |
| 59 | − pluginKey: GOOGLE_DISCOVERY_PLUGIN_KEY, | |
| 60 | − kind: GOOGLE_DISCOVERY_SOURCE_KIND, | |
| 61 | − name: input.name, | |
| 62 | − summary: input.summary, | |
| 63 | − previewUrl: input.discoveryUrl, | |
| 64 | − service: input.service, | |
| 65 | − version: input.version, | |
| 66 | − discoveryUrl: input.discoveryUrl, | |
| 67 | −}); | |
| 68 | − | |
| 69 | −export const sourcePresets: ReadonlyArray<SourcePreset> = [ | |
| 70 | − { | |
| 71 | − id: "deepwiki-mcp", | |
| 72 | − pluginKey: "mcp", | |
| 73 | − kind: "mcp", | |
| 74 | − name: "DeepWiki MCP", | |
| 75 | − summary: "Repository docs and knowledge graphs via MCP.", | |
| 76 | − previewUrl: "https://mcp.deepwiki.com/mcp", | |
| 77 | − endpoint: "https://mcp.deepwiki.com/mcp", | |
| 78 | − transport: "auto", | |
| 79 | − }, | |
| 80 | − { | |
| 81 | − id: "axiom-mcp", | |
| 82 | − pluginKey: "mcp", | |
| 83 | − kind: "mcp", | |
| 84 | − name: "Axiom MCP", | |
| 85 | − summary: "Query, stream, and analyze logs, traces, and event data.", | |
| 86 | − previewUrl: "https://mcp.axiom.co/mcp", | |
| 87 | − endpoint: "https://mcp.axiom.co/mcp", | |
| 88 | − transport: "auto", | |
| 89 | − }, | |
| 90 | − { | |
| 91 | − id: "neon-mcp", | |
| 92 | − pluginKey: "mcp", | |
| 93 | − kind: "mcp", | |
| 94 | − name: "Neon MCP", | |
| 95 | − summary: "Manage Postgres databases, branches, and queries via MCP.", | |
| 96 | − previewUrl: "https://mcp.neon.tech/mcp", | |
| 97 | − endpoint: "https://mcp.neon.tech/mcp", | |
| 98 | − transport: "auto", | |
| 99 | − }, | |
| 100 | − { | |
| 101 | − id: "chrome-devtools-mcp", | |
| 102 | − pluginKey: "mcp", | |
| 103 | − kind: "mcp", | |
| 104 | − name: "Chrome DevTools MCP", | |
| 105 | − summary: "Debug a live Chrome browser session over a local MCP stdio transport.", | |
| 106 | − previewUrl: "npx -y chrome-devtools-mcp@latest", | |
| 107 | − transport: "stdio", | |
| 108 | − command: "npx", | |
| 109 | − args: ["-y", "chrome-devtools-mcp@latest"], | |
| 110 | − }, | |
| 111 | − { | |
| 112 | − id: "neon-api", | |
| 113 | − pluginKey: "openapi", | |
| 114 | − kind: "openapi", | |
| 115 | − name: "Neon API", | |
| 116 | − summary: "Projects, branches, endpoints, databases, and API keys.", | |
| 117 | − previewUrl: "https://console.neon.tech/api/v2", | |
| 118 | − baseUrl: "https://console.neon.tech/api/v2", | |
| 119 | − specUrl: "https://neon.com/api_spec/release/v2.json", | |
| 120 | − }, | |
| 121 | − { | |
| 122 | − id: "github-rest", | |
| 123 | − pluginKey: "openapi", | |
| 124 | − kind: "openapi", | |
| 125 | − name: "GitHub REST API", | |
| 126 | − summary: "Repos, issues, pull requests, actions, and org settings.", | |
| 127 | − previewUrl: "https://api.github.com", | |
| 128 | − baseUrl: "https://api.github.com", | |
| 129 | − specUrl: "https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.yaml", | |
| 130 | − }, | |
| 131 | − { | |
| 132 | − id: "github-graphql", | |
| 133 | − pluginKey: "graphql", | |
| 134 | − kind: "graphql", | |
| 135 | − name: "GitHub GraphQL", | |
| 136 | − summary: "Issues, pull requests, discussions, and repository objects via GraphQL.", | |
| 137 | − previewUrl: "https://api.github.com/graphql", | |
| 138 | − endpoint: "https://api.github.com/graphql", | |
| 139 | − }, | |
| 140 | − { | |
| 141 | − id: "gitlab-graphql", | |
| 142 | − pluginKey: "graphql", | |
| 143 | − kind: "graphql", | |
| 144 | − name: "GitLab GraphQL", | |
| 145 | − summary: "Projects, merge requests, issues, CI pipelines, and users.", | |
| 146 | − previewUrl: "https://gitlab.com/api/graphql", | |
| 147 | − endpoint: "https://gitlab.com/api/graphql", | |
| 148 | − }, | |
| 149 | − { | |
| 150 | − id: "openai-api", | |
| 151 | − pluginKey: "openapi", | |
| 152 | − kind: "openapi", | |
| 153 | − name: "OpenAI API", | |
| 154 | − summary: "Models, files, responses, and fine-tuning.", | |
| 155 | − previewUrl: "https://api.openai.com/v1", | |
| 156 | − baseUrl: "https://api.openai.com/v1", | |
| 157 | − specUrl: "https://app.stainless.com/api/spec/documented/openai/openapi.documented.yml", | |
| 158 | − }, | |
| 159 | − { | |
| 160 | − id: "vercel-api", | |
| 161 | − pluginKey: "openapi", | |
| 162 | − kind: "openapi", | |
| 163 | − name: "Vercel API", | |
| 164 | − summary: "Deployments, projects, domains, and environments.", | |
| 165 | − previewUrl: "https://api.vercel.com", | |
| 166 | − baseUrl: "https://api.vercel.com", | |
| 167 | − specUrl: "https://openapi.vercel.sh", | |
| 168 | − }, | |
| 169 | − { | |
| 170 | − id: "stripe-api", | |
| 171 | − pluginKey: "openapi", | |
| 172 | − kind: "openapi", | |
| 173 | − name: "Stripe API", | |
| 174 | − summary: "Payments, billing, subscriptions, and invoices.", | |
| 175 | − previewUrl: "https://api.stripe.com", | |
| 176 | − baseUrl: "https://api.stripe.com", | |
| 177 | − specUrl: "https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json", | |
| 178 | − }, | |
| 179 | − { | |
| 180 | − id: "linear-graphql", | |
| 181 | − pluginKey: "graphql", | |
| 182 | − kind: "graphql", | |
| 183 | − name: "Linear GraphQL", | |
| 184 | − summary: "Issues, teams, cycles, and projects.", | |
| 185 | − previewUrl: "https://api.linear.app/graphql", | |
| 186 | − endpoint: "https://api.linear.app/graphql", | |
| 187 | − }, | |
| 188 | − { | |
| 189 | − id: "monday-graphql", | |
| 190 | − pluginKey: "graphql", | |
| 191 | − kind: "graphql", | |
| 192 | − name: "Monday GraphQL", | |
| 193 | − summary: "Boards, items, updates, users, and workspace metadata.", | |
| 194 | − previewUrl: "https://api.monday.com/v2", | |
| 195 | − endpoint: "https://api.monday.com/v2", | |
| 196 | − }, | |
| 197 | − { | |
| 198 | − id: "anilist-graphql", | |
| 199 | − pluginKey: "graphql", | |
| 200 | − kind: "graphql", | |
| 201 | − name: "AniList GraphQL", | |
| 202 | − summary: "Anime, manga, characters, media lists, and recommendations.", | |
| 203 | − previewUrl: "https://graphql.anilist.co", | |
| 204 | − endpoint: "https://graphql.anilist.co", | |
| 205 | − }, | |
| 206 | − googleDiscoveryPreset({ | |
| 207 | − id: "google-calendar", | |
| 208 | − name: "Google Calendar", | |
| 209 | − summary: "Calendars, events, ACLs, and scheduling workflows.", | |
| 210 | − service: "calendar", | |
| 211 | − version: "v3", | |
| 212 | − discoveryUrl: "https://calendar-json.googleapis.com/$discovery/rest?version=v3", | |
| 213 | − }), | |
| 214 | − googleDiscoveryPreset({ | |
| 215 | − id: "google-drive", | |
| 216 | − name: "Google Drive", | |
| 217 | − summary: "Files, folders, permissions, comments, and shared drives.", | |
| 218 | − service: "drive", | |
| 219 | − version: "v3", | |
| 220 | − discoveryUrl: "https://www.googleapis.com/discovery/v1/apis/drive/v3/rest", | |
| 221 | − }), | |
| 222 | − googleDiscoveryPreset({ | |
| 223 | − id: "google-gmail", | |
| 224 | − name: "Gmail", | |
| 225 | − summary: "Messages, threads, labels, drafts, and mailbox automation.", | |
| 226 | − service: "gmail", | |
| 227 | − version: "v1", | |
| 228 | − discoveryUrl: "https://gmail.googleapis.com/$discovery/rest?version=v1", | |
| 229 | − }), | |
| 230 | − googleDiscoveryPreset({ | |
| 231 | − id: "google-docs", | |
| 232 | − name: "Google Docs", | |
| 233 | − summary: "Documents, structural edits, text ranges, and formatting.", | |
| 234 | − service: "docs", | |
| 235 | − version: "v1", | |
| 236 | − discoveryUrl: "https://docs.googleapis.com/$discovery/rest?version=v1", | |
| 237 | − }), | |
| 238 | − googleDiscoveryPreset({ | |
| 239 | − id: "google-sheets", | |
| 240 | − name: "Google Sheets", | |
| 241 | − summary: "Spreadsheets, values, ranges, formatting, and batch updates.", | |
| 242 | − service: "sheets", | |
| 243 | − version: "v4", | |
| 244 | − discoveryUrl: "https://sheets.googleapis.com/$discovery/rest?version=v4", | |
| 245 | − }), | |
| 246 | − googleDiscoveryPreset({ | |
| 247 | − id: "google-slides", | |
| 248 | − name: "Google Slides", | |
| 249 | − summary: "Presentations, slides, page elements, and deck updates.", | |
| 250 | − service: "slides", | |
| 251 | − version: "v1", | |
| 252 | − discoveryUrl: "https://slides.googleapis.com/$discovery/rest?version=v1", | |
| 253 | − }), | |
| 254 | − googleDiscoveryPreset({ | |
| 255 | − id: "google-forms", | |
| 256 | − name: "Google Forms", | |
| 257 | − summary: "Forms, questions, responses, quizzes, and form metadata.", | |
| 258 | − service: "forms", | |
| 259 | − version: "v1", | |
| 260 | − discoveryUrl: "https://forms.googleapis.com/$discovery/rest?version=v1", | |
| 261 | − }), | |
| 262 | − googleDiscoveryPreset({ | |
| 263 | − id: "google-search-console", | |
| 264 | − name: "Google Search Console", | |
| 265 | − summary: "Sites, sitemaps, URL inspection, and search and Discover performance.", | |
| 266 | − service: "searchconsole", | |
| 267 | − version: "v1", | |
| 268 | − discoveryUrl: "https://searchconsole.googleapis.com/$discovery/rest?version=v1", | |
| 269 | − }), | |
| 270 | − googleDiscoveryPreset({ | |
| 271 | − id: "google-people", | |
| 272 | − name: "Google People", | |
| 273 | − summary: "Contacts, profiles, directory people, and contact groups.", | |
| 274 | − service: "people", | |
| 275 | − version: "v1", | |
| 276 | − discoveryUrl: "https://people.googleapis.com/$discovery/rest?version=v1", | |
| 277 | − }), | |
| 278 | − googleDiscoveryPreset({ | |
| 279 | − id: "google-tasks", | |
| 280 | − name: "Google Tasks", | |
| 281 | − summary: "Task lists, task items, notes, and due dates.", | |
| 282 | − service: "tasks", | |
| 283 | − version: "v1", | |
| 284 | − discoveryUrl: "https://tasks.googleapis.com/$discovery/rest?version=v1", | |
| 285 | − }), | |
| 286 | − googleDiscoveryPreset({ | |
| 287 | − id: "google-chat", | |
| 288 | − name: "Google Chat", | |
| 289 | − summary: "Spaces, messages, members, reactions, and chat workflows.", | |
| 290 | − service: "chat", | |
| 291 | − version: "v1", | |
| 292 | − discoveryUrl: "https://chat.googleapis.com/$discovery/rest?version=v1", | |
| 293 | − }), | |
| 294 | − googleDiscoveryPreset({ | |
| 295 | − id: "google-keep", | |
| 296 | − name: "Google Keep", | |
| 297 | − summary: "Notes, lists, attachments, and collaborative annotations.", | |
| 298 | − service: "keep", | |
| 299 | − version: "v1", | |
| 300 | − discoveryUrl: "https://keep.googleapis.com/$discovery/rest?version=v1", | |
| 301 | − }), | |
| 302 | − googleDiscoveryPreset({ | |
| 303 | − id: "google-classroom", | |
| 304 | − name: "Google Classroom", | |
| 305 | − summary: "Courses, rosters, coursework, submissions, and grading data.", | |
| 306 | − service: "classroom", | |
| 307 | − version: "v1", | |
| 308 | − discoveryUrl: "https://classroom.googleapis.com/$discovery/rest?version=v1", | |
| 309 | − }), | |
| 310 | − googleDiscoveryPreset({ | |
| 311 | − id: "google-admin-directory", | |
| 312 | − name: "Google Admin Directory", | |
| 313 | − summary: "Users, groups, org units, roles, and domain directory resources.", | |
| 314 | − service: "admin", | |
| 315 | − version: "directory_v1", | |
| 316 | − discoveryUrl: "https://admin.googleapis.com/$discovery/rest?version=directory_v1", | |
| 317 | − }), | |
| 318 | − googleDiscoveryPreset({ | |
| 319 | − id: "google-admin-reports", | |
| 320 | − name: "Google Admin Reports", | |
| 321 | − summary: "Audit events, usage reports, and admin activity logs.", | |
| 322 | − service: "admin", | |
| 323 | − version: "reports_v1", | |
| 324 | − discoveryUrl: "https://admin.googleapis.com/$discovery/rest?version=reports_v1", | |
| 325 | − }), | |
| 326 | − googleDiscoveryPreset({ | |
| 327 | − id: "google-apps-script", | |
| 328 | − name: "Google Apps Script", | |
| 329 | − summary: "Projects, deployments, script execution, and Apps Script metadata.", | |
| 330 | − service: "script", | |
| 331 | − version: "v1", | |
| 332 | − discoveryUrl: "https://script.googleapis.com/$discovery/rest?version=v1", | |
| 333 | − }), | |
| 334 | − googleDiscoveryPreset({ | |
| 335 | − id: "google-bigquery", | |
| 336 | − name: "Google BigQuery", | |
| 337 | − summary: "Datasets, tables, jobs, routines, and analytical query workflows.", | |
| 338 | − service: "bigquery", | |
| 339 | − version: "v2", | |
| 340 | − discoveryUrl: "https://bigquery.googleapis.com/$discovery/rest?version=v2", | |
| 341 | − }), | |
| 342 | − googleDiscoveryPreset({ | |
| 343 | − id: "google-cloud-resource-manager", | |
| 344 | − name: "Google Cloud Resource Manager", | |
| 345 | − summary: "Projects, folders, organizations, and IAM-oriented resource hierarchy.", | |
| 346 | − service: "cloudresourcemanager", | |
| 347 | − version: "v3", | |
| 348 | − discoveryUrl: "https://cloudresourcemanager.googleapis.com/$discovery/rest?version=v3", | |
| 349 | − }), | |
| 350 | − googleDiscoveryPreset({ | |
| 351 | − id: "google-youtube-data", | |
| 352 | − name: "YouTube Data", | |
| 353 | − summary: "Channels, playlists, videos, comments, captions, and uploads.", | |
| 354 | − service: "youtube", | |
| 355 | − version: "v3", | |
| 356 | − discoveryUrl: "https://youtube.googleapis.com/$discovery/rest?version=v3", | |
| 357 | − }), | |
| 358 | −] as const; | |
| 359 | − | |
| 360 | −export const buildSourcePresetSearch = ( | |
| 361 | − preset: SourcePreset, | |
| 362 | −): Record<string, string> => { | |
| 363 | − switch (preset.pluginKey) { | |
| 364 | − case "openapi": | |
| 365 | − return { | |
| 366 | − preset: preset.id, | |
| 367 | − presetName: preset.name, | |
| 368 | − presetBaseUrl: preset.baseUrl, | |
| 369 | − presetSpecUrl: preset.specUrl, | |
| 370 | − }; | |
| 371 | − case "graphql": | |
| 372 | − return { | |
| 373 | − preset: preset.id, | |
| 374 | − presetName: preset.name, | |
| 375 | − presetEndpoint: preset.endpoint, | |
| 376 | − }; | |
| 377 | − case "mcp": | |
| 378 | − return { | |
| 379 | − preset: preset.id, | |
| 380 | − presetName: preset.name, | |
| 381 | − ...(preset.endpoint ? { presetEndpoint: preset.endpoint } : {}), | |
| 382 | − ...(preset.transport ? { presetTransport: preset.transport } : {}), | |
| 383 | − ...(preset.command ? { presetCommand: preset.command } : {}), | |
| 384 | − ...(preset.args ? { presetArgs: JSON.stringify(preset.args) } : {}), | |
| 385 | − ...(preset.env ? { presetEnv: JSON.stringify(preset.env) } : {}), | |
| 386 | − ...(preset.cwd ? { presetCwd: preset.cwd } : {}), | |
| 387 | − }; | |
| 388 | − default: | |
| 389 | − return { | |
| 390 | − preset: preset.id, | |
| 391 | − presetName: preset.name, | |
| 392 | − presetService: preset.service, | |
| 393 | − presetVersion: preset.version, | |
| 394 | − presetDiscoveryUrl: preset.discoveryUrl, | |
| 395 | − }; | |
| 396 | − } | |
| 397 | −}; | |
| 398 | − | |
| 399 | −const normalizeComparableUrl = (value: string): string => { | |
| 400 | − const trimmed = value.trim(); | |
| 401 | − try { | |
| 402 | − const url = new URL(trimmed); | |
| 403 | − if (url.pathname.length > 1 && url.pathname.endsWith("/")) { | |
| 404 | − url.pathname = url.pathname.slice(0, -1); | |
| 405 | − } | |
| 406 | − return url.toString(); | |
| 407 | − } catch { | |
| 408 | − return trimmed; | |
| 409 | − } | |
| 410 | −}; | |
| 411 | − | |
| 412 | −const tryParseUrl = (value: string): URL | null => { | |
| 413 | − try { | |
| 414 | − return new URL(value.trim()); | |
| 415 | − } catch { | |
| 416 | − return null; | |
| 417 | − } | |
| 418 | −}; | |
| 419 | − | |
| 420 | −const sourceNameFromUrl = (url: URL, fallback: string): string => { | |
| 421 | − const hostname = url.hostname.replace(/^www\./, ""); | |
| 422 | − if (hostname.length === 0) { | |
| 423 | − return fallback; | |
| 424 | − } | |
| 425 | − | |
| 426 | − const head = hostname.split(".")[0]?.trim(); | |
| 427 | − if (!head) { | |
| 428 | − return fallback; | |
| 429 | − } | |
| 430 | − | |
| 431 | − return `${head.charAt(0).toUpperCase()}${head.slice(1)} ${fallback}`; | |
| 432 | −}; | |
| 433 | − | |
| 434 | −const parseGoogleDiscoveryUrl = (value: string): { | |
| 435 | − service: string; | |
| 436 | − version: string; | |
| 437 | − discoveryUrl: string; | |
| 438 | −} | null => { | |
| 439 | − const url = tryParseUrl(value); | |
| 440 | − if (!url) { | |
| 441 | − return null; | |
| 442 | − } | |
| 443 | − | |
| 444 | − const byDirectory = url.pathname.match( | |
| 445 | − /^\/discovery\/v1\/apis\/([^/]+)\/([^/]+)\/rest$/, | |
| 446 | − ); | |
| 447 | − if (byDirectory) { | |
| 448 | − return { | |
| 449 | − service: decodeURIComponent(byDirectory[1] ?? ""), | |
| 450 | − version: decodeURIComponent(byDirectory[2] ?? ""), | |
| 451 | − discoveryUrl: url.toString(), | |
| 452 | − }; | |
| 453 | − } | |
| 454 | − | |
| 455 | − const versionParam = url.searchParams.get("version")?.trim(); | |
| 456 | − const isHostScopedDiscovery = | |
| 457 | − url.pathname === "/$discovery/rest" | |
| 458 | − && url.hostname.endsWith(".googleapis.com") | |
| 459 | − && url.hostname !== "www.googleapis.com"; | |
| 460 | − | |
| 461 | − if (versionParam && isHostScopedDiscovery) { | |
| 462 | − const service = url.hostname.split(".")[0]?.trim(); | |
| 463 | − if (!service) { | |
| 464 | − return null; | |
| 465 | − } | |
| 466 | − | |
| 467 | − return { | |
| 468 | − service, | |
| 469 | − version: versionParam, | |
| 470 | − discoveryUrl: url.toString(), | |
| 471 | − }; | |
| 472 | − } | |
| 473 | − | |
| 474 | − return null; | |
| 475 | −}; | |
| 476 | − | |
| 477 | −const isGraphqlUrl = (url: URL): boolean => { | |
| 478 | − const path = url.pathname.toLowerCase(); | |
| 479 | − const hostname = url.hostname.toLowerCase(); | |
| 480 | − return ( | |
| 481 | − path.endsWith("/graphql") | |
| 482 | − || path === "/graphql" | |
| 483 | − || hostname.startsWith("graphql.") | |
| 484 | − || hostname.includes("graphql") | |
| 485 | − ); | |
| 486 | −}; | |
| 487 | − | |
| 488 | −const isMcpUrl = (url: URL): boolean => { | |
| 489 | − const path = url.pathname.toLowerCase(); | |
| 490 | − const hostname = url.hostname.toLowerCase(); | |
| 491 | − return path.endsWith("/mcp") || path.includes("/mcp/") || hostname.startsWith("mcp."); | |
| 492 | −}; | |
| 493 | − | |
| 494 | −const isLikelyOpenApiSpecUrl = (url: URL): boolean => { | |
| 495 | − const path = url.pathname.toLowerCase(); | |
| 496 | − return ( | |
| 497 | − path.endsWith(".json") | |
| 498 | − || path.endsWith(".yaml") | |
| 499 | − || path.endsWith(".yml") | |
| 500 | − || path.includes("openapi") | |
| 501 | − || path.includes("swagger") | |
| 502 | − ); | |
| 503 | −}; | |
| 504 | − | |
| 505 | −const findPresetByInput = (value: string): SourcePreset | null => { | |
| 506 | − const comparable = normalizeComparableUrl(value); | |
| 507 | − for (const preset of sourcePresets) { | |
| 508 | − if (normalizeComparableUrl(preset.previewUrl) === comparable) { | |
| 509 | − return preset; | |
| 510 | − } | |
| 511 | − | |
| 512 | − if (preset.pluginKey === "openapi") { | |
| 513 | − if (normalizeComparableUrl(preset.baseUrl) === comparable) { | |
| 514 | − return preset; | |
| 515 | − } | |
| 516 | − if (normalizeComparableUrl(preset.specUrl) === comparable) { | |
| 517 | − return preset; | |
| 518 | − } | |
| 519 | − continue; | |
| 520 | − } | |
| 521 | − | |
| 522 | − if (preset.pluginKey === "graphql" || preset.pluginKey === "mcp") { | |
| 523 | − if (preset.endpoint && normalizeComparableUrl(preset.endpoint) === comparable) { | |
| 524 | − return preset; | |
| 525 | − } | |
| 526 | − continue; | |
| 527 | − } | |
| 528 | − | |
| 529 | − if (normalizeComparableUrl(preset.discoveryUrl) === comparable) { | |
| 530 | − return preset; | |
| 531 | − } | |
| 532 | − } | |
| 533 | − | |
| 534 | − return null; | |
| 535 | −}; | |
| 536 | − | |
| 537 | −export type ResolvedQuickSourceInput = { | |
| 538 | − pluginKey: SourcePreset["pluginKey"]; | |
| 539 | − search: Record<string, string>; | |
| 540 | −}; | |
| 541 | − | |
| 542 | −export const resolveQuickSourceInput = ( | |
| 543 | − rawValue: string, | |
| 544 | −): ResolvedQuickSourceInput | null => { | |
| 545 | − const trimmed = rawValue.trim(); | |
| 546 | − if (trimmed.length === 0) { | |
| 547 | − return null; | |
| 548 | − } | |
| 549 | − | |
| 550 | − const commandParts = | |
| 551 | − trimmed.match(/[^\s"]+|"([^"]*)"/g)?.map((part) => | |
| 552 | − part.startsWith("\"") && part.endsWith("\"") | |
| 553 | − ? part.slice(1, -1) | |
| 554 | − : part | |
| 555 | − ) ?? null; | |
| 556 | − if (commandParts && commandParts.length > 0) { | |
| 557 | − const [command, ...args] = commandParts; | |
| 558 | − const isKnownCommand = | |
| 559 | − command === "npx" | |
| 560 | − || command === "bunx" | |
| 561 | − || command === "uvx" | |
| 562 | − || (command === "pnpm" && args[0] === "dlx"); | |
| 563 | − | |
| 564 | − if (isKnownCommand) { | |
| 565 | − return { | |
| 566 | − pluginKey: "mcp", | |
| 567 | − search: { | |
| 568 | − presetName: "Local MCP", | |
| 569 | − presetTransport: "stdio", | |
| 570 | − presetCommand: command, | |
| 571 | − ...(args.length > 0 ? { presetArgs: JSON.stringify(args) } : {}), | |
| 572 | − quickInput: trimmed, | |
| 573 | − }, | |
| 574 | − }; | |
| 575 | − } | |
| 576 | − } | |
| 577 | − | |
| 578 | − const preset = findPresetByInput(trimmed); | |
| 579 | − if (preset) { | |
| 580 | − return { | |
| 581 | − pluginKey: preset.pluginKey, | |
| 582 | − search: buildSourcePresetSearch(preset), | |
| 583 | − }; | |
| 584 | − } | |
| 585 | − | |
| 586 | − const googleDiscovery = parseGoogleDiscoveryUrl(trimmed); | |
| 587 | − if (googleDiscovery) { | |
| 588 | − const googlePreset = sourcePresets.find( | |
| 589 | − (presetEntry) => | |
| 590 | − presetEntry.pluginKey === GOOGLE_DISCOVERY_PLUGIN_KEY | |
| 591 | − && presetEntry.service === googleDiscovery.service | |
| 592 | − && presetEntry.version === googleDiscovery.version, | |
| 593 | − ); | |
| 594 | − | |
| 595 | − return { | |
| 596 | − pluginKey: GOOGLE_DISCOVERY_PLUGIN_KEY, | |
| 597 | − search: { | |
| 598 | − ...(googlePreset ? buildSourcePresetSearch(googlePreset) : {}), | |
| 599 | − presetName: | |
| 600 | − googlePreset?.name | |
| 601 | − ?? `Google ${googleDiscovery.service} ${googleDiscovery.version}`, | |
| 602 | − presetService: googleDiscovery.service, | |
| 603 | − presetVersion: googleDiscovery.version, | |
| 604 | − presetDiscoveryUrl: googleDiscovery.discoveryUrl, | |
| 605 | − quickInput: trimmed, | |
| 606 | − }, | |
| 607 | − }; | |
| 608 | − } | |
| 609 | − | |
| 610 | − const url = tryParseUrl(trimmed); | |
| 611 | − if (!url) { | |
| 612 | − return null; | |
| 613 | − } | |
| 614 | − | |
| 615 | − if (isGraphqlUrl(url)) { | |
| 616 | − return { | |
| 617 | − pluginKey: "graphql", | |
| 618 | − search: { | |
| 619 | − presetName: sourceNameFromUrl(url, "GraphQL"), | |
| 620 | − presetEndpoint: trimmed, | |
| 621 | − quickInput: trimmed, | |
| 622 | − }, | |
| 623 | − }; | |
| 624 | − } | |
| 625 | − | |
| 626 | − if (isMcpUrl(url)) { | |
| 627 | − return { | |
| 628 | − pluginKey: "mcp", | |
| 629 | − search: { | |
| 630 | − presetName: sourceNameFromUrl(url, "MCP"), | |
| 631 | − presetEndpoint: trimmed, | |
| 632 | − presetTransport: "auto", | |
| 633 | − quickInput: trimmed, | |
| 634 | − }, | |
| 635 | − }; | |
| 636 | − } | |
| 637 | − | |
| 638 | − if (isLikelyOpenApiSpecUrl(url)) { | |
| 639 | − return { | |
| 640 | − pluginKey: "openapi", | |
| 641 | − search: { | |
| 642 | − presetName: sourceNameFromUrl(url, "OpenAPI"), | |
| 643 | − presetSpecUrl: trimmed, | |
| 644 | − quickInput: trimmed, | |
| 645 | − }, | |
| 646 | − }; | |
| 647 | − } | |
| 648 | − | |
| 649 | − return { | |
| 650 | − pluginKey: "openapi", | |
| 651 | − search: { | |
| 652 | − presetName: sourceNameFromUrl(url, "OpenAPI"), | |
| 653 | − presetBaseUrl: trimmed, | |
| 654 | − quickInput: trimmed, | |
| 655 | − }, | |
| 656 | − }; | |
| 657 | −}; | |
| @@ -0,0 +1,73 @@ | ||
| 1 | +import { | |
| 2 | + createRouter, | |
| 3 | + createRootRoute, | |
| 4 | + createRoute, | |
| 5 | +} from "@tanstack/react-router"; | |
| 6 | +import { ExecutorProvider } from "@executor/react"; | |
| 7 | +import { ToolsPage } from "./pages/tools"; | |
| 8 | +import { SourcesPage } from "./pages/sources"; | |
| 9 | +import { SourceDetailPage } from "./pages/source-detail"; | |
| 10 | +import { SecretsPage } from "./pages/secrets"; | |
| 11 | +import { Shell } from "./shell"; | |
| 12 | + | |
| 13 | +// --------------------------------------------------------------------------- | |
| 14 | +// Root layout — Shell renders <Outlet /> directly | |
| 15 | +// --------------------------------------------------------------------------- | |
| 16 | + | |
| 17 | +const rootRoute = createRootRoute({ | |
| 18 | + component: () => ( | |
| 19 | + <ExecutorProvider> | |
| 20 | + <Shell /> | |
| 21 | + </ExecutorProvider> | |
| 22 | + ), | |
| 23 | +}); | |
| 24 | + | |
| 25 | +// --------------------------------------------------------------------------- | |
| 26 | +// Routes | |
| 27 | +// --------------------------------------------------------------------------- | |
| 28 | + | |
| 29 | +const indexRoute = createRoute({ | |
| 30 | + getParentRoute: () => rootRoute, | |
| 31 | + path: "/", | |
| 32 | + component: SourcesPage, | |
| 33 | +}); | |
| 34 | + | |
| 35 | +const toolsRoute = createRoute({ | |
| 36 | + getParentRoute: () => rootRoute, | |
| 37 | + path: "/tools", | |
| 38 | + component: ToolsPage, | |
| 39 | +}); | |
| 40 | + | |
| 41 | +const sourceDetailRoute = createRoute({ | |
| 42 | + getParentRoute: () => rootRoute, | |
| 43 | + path: "/sources/$namespace", | |
| 44 | + component: () => { | |
| 45 | + const { namespace } = sourceDetailRoute.useParams(); | |
| 46 | + return <SourceDetailPage namespace={namespace} />; | |
| 47 | + }, | |
| 48 | +}); | |
| 49 | + | |
| 50 | +const secretsRoute = createRoute({ | |
| 51 | + getParentRoute: () => rootRoute, | |
| 52 | + path: "/secrets", | |
| 53 | + component: SecretsPage, | |
| 54 | +}); | |
| 55 | + | |
| 56 | +// --------------------------------------------------------------------------- | |
| 57 | +// Router | |
| 58 | +// --------------------------------------------------------------------------- | |
| 59 | + | |
| 60 | +const routeTree = rootRoute.addChildren([ | |
| 61 | + indexRoute, | |
| 62 | + toolsRoute, | |
| 63 | + sourceDetailRoute, | |
| 64 | + secretsRoute, | |
| 65 | +]); | |
| 66 | + | |
| 67 | +export const router = createRouter({ routeTree }); | |
| 68 | + | |
| 69 | +declare module "@tanstack/react-router" { | |
| 70 | + interface Register { | |
| 71 | + router: typeof router; | |
| 72 | + } | |
| 73 | +} | |
| @@ -1,13 +0,0 @@ | ||
| 1 | −/** | |
| 2 | − * Production server. Serves the API + Vite-built static assets. | |
| 3 | − * | |
| 4 | − * In development, use `bun run dev` which starts Vite with | |
| 5 | − * @hono/vite-dev-server embedding the API via dev.ts. | |
| 6 | − */ | |
| 7 | −import { runLocalExecutorServer } from "@executor/server"; | |
| 8 | − | |
| 9 | −await runLocalExecutorServer({ | |
| 10 | − ui: { | |
| 11 | − assetsDir: new URL("../dist", import.meta.url).pathname, | |
| 12 | − }, | |
| 13 | −}); | |
| @@ -0,0 +1,473 @@ | ||
| 1 | +import { Link, Outlet, useLocation } from "@tanstack/react-router"; | |
| 2 | +import { useCallback, useEffect, useRef, useState } from "react"; | |
| 3 | +import { | |
| 4 | + useAtomRefresh, | |
| 5 | + useAtomValue, | |
| 6 | + Result, | |
| 7 | + sourcesAtom, | |
| 8 | + toolsAtom, | |
| 9 | + useScope, | |
| 10 | + useScopeInfo, | |
| 11 | +} from "@executor/react"; | |
| 12 | +import { Button } from "@executor/ui/components/button"; | |
| 13 | + | |
| 14 | +// ── Env ───────────────────────────────────────────────────────────────── | |
| 15 | + | |
| 16 | +type AppMetaEnv = { | |
| 17 | + readonly VITE_APP_VERSION: string; | |
| 18 | + readonly VITE_GITHUB_URL: string; | |
| 19 | +}; | |
| 20 | + | |
| 21 | +const { VITE_APP_VERSION, VITE_GITHUB_URL } = (import.meta as ImportMeta & { | |
| 22 | + readonly env: AppMetaEnv; | |
| 23 | +}).env; | |
| 24 | + | |
| 25 | +// ── Version helpers ───────────────────────────────────────────────────── | |
| 26 | + | |
| 27 | +type UpdateChannel = "latest" | "beta"; | |
| 28 | + | |
| 29 | +const EXECUTOR_DIST_TAGS_PATH = "/v1/app/npm/dist-tags"; | |
| 30 | + | |
| 31 | +type ParsedVersion = { | |
| 32 | + readonly major: number; | |
| 33 | + readonly minor: number; | |
| 34 | + readonly patch: number; | |
| 35 | + readonly prerelease: ReadonlyArray<string | number> | null; | |
| 36 | +}; | |
| 37 | + | |
| 38 | +const semverPattern = | |
| 39 | + /^(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)(?:-(?<prerelease>[0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/; | |
| 40 | + | |
| 41 | +const resolveUpdateChannel = (version: string): UpdateChannel => | |
| 42 | + version.includes("-beta.") ? "beta" : "latest"; | |
| 43 | + | |
| 44 | +const parseVersion = (version: string): ParsedVersion | null => { | |
| 45 | + const match = version.trim().match(semverPattern); | |
| 46 | + if (!match?.groups) return null; | |
| 47 | + return { | |
| 48 | + major: Number(match.groups.major), | |
| 49 | + minor: Number(match.groups.minor), | |
| 50 | + patch: Number(match.groups.patch), | |
| 51 | + prerelease: match.groups.prerelease | |
| 52 | + ? match.groups.prerelease.split(".").map((id) => | |
| 53 | + /^\d+$/.test(id) ? Number(id) : id, | |
| 54 | + ) | |
| 55 | + : null, | |
| 56 | + }; | |
| 57 | +}; | |
| 58 | + | |
| 59 | +const comparePrereleaseIdentifiers = ( | |
| 60 | + left: ReadonlyArray<string | number> | null, | |
| 61 | + right: ReadonlyArray<string | number> | null, | |
| 62 | +): number => { | |
| 63 | + if (left === null && right === null) return 0; | |
| 64 | + if (left === null) return 1; | |
| 65 | + if (right === null) return -1; | |
| 66 | + const max = Math.max(left.length, right.length); | |
| 67 | + for (let i = 0; i < max; i++) { | |
| 68 | + const l = left[i]; | |
| 69 | + const r = right[i]; | |
| 70 | + if (l === undefined) return -1; | |
| 71 | + if (r === undefined) return 1; | |
| 72 | + if (l === r) continue; | |
| 73 | + if (typeof l === "number" && typeof r === "number") return l < r ? -1 : 1; | |
| 74 | + if (typeof l === "number") return -1; | |
| 75 | + if (typeof r === "number") return 1; | |
| 76 | + return l < r ? -1 : 1; | |
| 77 | + } | |
| 78 | + return 0; | |
| 79 | +}; | |
| 80 | + | |
| 81 | +const compareVersions = (left: string, right: string): number | null => { | |
| 82 | + const lv = parseVersion(left); | |
| 83 | + const rv = parseVersion(right); | |
| 84 | + if (!lv || !rv) return null; | |
| 85 | + if (lv.major !== rv.major) return lv.major < rv.major ? -1 : 1; | |
| 86 | + if (lv.minor !== rv.minor) return lv.minor < rv.minor ? -1 : 1; | |
| 87 | + if (lv.patch !== rv.patch) return lv.patch < rv.patch ? -1 : 1; | |
| 88 | + return comparePrereleaseIdentifiers(lv.prerelease, rv.prerelease); | |
| 89 | +}; | |
| 90 | + | |
| 91 | +// ── useLatestVersion ──────────────────────────────────────────────────── | |
| 92 | + | |
| 93 | +function useLatestVersion(currentVersion: string) { | |
| 94 | + const channel = resolveUpdateChannel(currentVersion); | |
| 95 | + const [latestVersion, setLatestVersion] = useState<string | null>(null); | |
| 96 | + | |
| 97 | + useEffect(() => { | |
| 98 | + let cancelled = false; | |
| 99 | + fetch(EXECUTOR_DIST_TAGS_PATH) | |
| 100 | + .then(async (res) => { | |
| 101 | + if (!res.ok) throw new Error(`Failed to load dist tags: ${res.status}`); | |
| 102 | + return res.json() as Promise<Partial<Record<UpdateChannel, string>>>; | |
| 103 | + }) | |
| 104 | + .then((data) => { | |
| 105 | + if (!cancelled) setLatestVersion(data[channel] ?? null); | |
| 106 | + }) | |
| 107 | + .catch(() => {}); | |
| 108 | + return () => { cancelled = true; }; | |
| 109 | + }, [channel]); | |
| 110 | + | |
| 111 | + const updateAvailable = | |
| 112 | + latestVersion !== null && compareVersions(currentVersion, latestVersion) === -1; | |
| 113 | + | |
| 114 | + return { latestVersion, updateAvailable, channel }; | |
| 115 | +} | |
| 116 | + | |
| 117 | +// ── UpdateCard ────────────────────────────────────────────────────────── | |
| 118 | + | |
| 119 | +function UpdateCard(props: { latestVersion: string; channel: UpdateChannel }) { | |
| 120 | + const command = `npm i -g executor@${props.channel}`; | |
| 121 | + const [copied, setCopied] = useState(false); | |
| 122 | + | |
| 123 | + const handleCopy = useCallback(() => { | |
| 124 | + void navigator.clipboard.writeText(command).then(() => { | |
| 125 | + setCopied(true); | |
| 126 | + setTimeout(() => setCopied(false), 1500); | |
| 127 | + }); | |
| 128 | + }, [command]); | |
| 129 | + | |
| 130 | + return ( | |
| 131 | + <div className="mx-2 mb-2 rounded-xl border border-primary/25 bg-primary/[0.06] p-3"> | |
| 132 | + <div className="flex items-center gap-2"> | |
| 133 | + <div className="flex size-5 shrink-0 items-center justify-center rounded-full bg-primary/15"> | |
| 134 | + <svg viewBox="0 0 16 16" fill="none" className="size-3 text-primary"> | |
| 135 | + <path d="M8 3v7M5 7l3 3 3-3" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" /> | |
| 136 | + <path d="M3 12h10" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" /> | |
| 137 | + </svg> | |
| 138 | + </div> | |
| 139 | + <div className="min-w-0"> | |
| 140 | + <p className="text-[11px] font-semibold text-foreground">Update available</p> | |
| 141 | + <p className="text-[10px] text-muted-foreground"> | |
| 142 | + v{props.latestVersion} | |
| 143 | + </p> | |
| 144 | + </div> | |
| 145 | + </div> | |
| 146 | + <Button | |
| 147 | + type="button" | |
| 148 | + variant="outline" | |
| 149 | + onClick={handleCopy} | |
| 150 | + className="mt-2.5 flex w-full items-center justify-between gap-2 rounded-lg border-border/60 bg-background/50 px-2.5 py-1.5 text-left hover:bg-background/80" | |
| 151 | + > | |
| 152 | + <code className="truncate font-mono text-[10px] text-sidebar-foreground"> | |
| 153 | + {command} | |
| 154 | + </code> | |
| 155 | + <span className="shrink-0 text-muted-foreground transition-colors group-hover:text-foreground"> | |
| 156 | + {copied ? ( | |
| 157 | + <svg viewBox="0 0 16 16" fill="none" className="size-3 text-primary"> | |
| 158 | + <path d="M3 8.5l3.5 3.5L13 4" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" /> | |
| 159 | + </svg> | |
| 160 | + ) : ( | |
| 161 | + <svg viewBox="0 0 16 16" fill="none" className="size-3"> | |
| 162 | + <rect x="5" y="5" width="8" height="8" rx="1.5" stroke="currentColor" strokeWidth="1.2" /> | |
| 163 | + <path d="M3 11V3.5A.5.5 0 013.5 3H11" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" /> | |
| 164 | + </svg> | |
| 165 | + )} | |
| 166 | + </span> | |
| 167 | + </Button> | |
| 168 | + </div> | |
| 169 | + ); | |
| 170 | +} | |
| 171 | + | |
| 172 | +// ── NavItem ────────────────────────────────────────────────────────────── | |
| 173 | + | |
| 174 | +function NavItem(props: { to: string; label: string; active: boolean; onNavigate?: () => void }) { | |
| 175 | + return ( | |
| 176 | + <Link | |
| 177 | + to={props.to} | |
| 178 | + onClick={props.onNavigate} | |
| 179 | + className={[ | |
| 180 | + "flex items-center gap-2.5 rounded-md px-2.5 py-1.5 text-[13px] transition-colors", | |
| 181 | + props.active | |
| 182 | + ? "bg-sidebar-active text-foreground font-medium" | |
| 183 | + : "text-sidebar-foreground hover:bg-sidebar-active/60 hover:text-foreground", | |
| 184 | + ].join(" ")} | |
| 185 | + > | |
| 186 | + {props.label} | |
| 187 | + </Link> | |
| 188 | + ); | |
| 189 | +} | |
| 190 | + | |
| 191 | +// ── SourceList ─────────────────────────────────────────────────────────── | |
| 192 | + | |
| 193 | +function SourceList(props: { pathname: string; onNavigate?: () => void }) { | |
| 194 | + const scopeId = useScope(); | |
| 195 | + const sources = useAtomValue(sourcesAtom(scopeId)); | |
| 196 | + | |
| 197 | + return Result.match(sources, { | |
| 198 | + onInitial: () => ( | |
| 199 | + <div className="px-2.5 py-2 text-[11px] text-muted-foreground/40">Loading…</div> | |
| 200 | + ), | |
| 201 | + onFailure: () => ( | |
| 202 | + <div className="px-2.5 py-2 text-[11px] text-muted-foreground/40">No sources yet</div> | |
| 203 | + ), | |
| 204 | + onSuccess: ({ value }) => | |
| 205 | + value.length === 0 ? ( | |
| 206 | + <div className="px-2.5 py-2 text-[11px] leading-relaxed text-muted-foreground/40"> | |
| 207 | + No sources yet | |
| 208 | + </div> | |
| 209 | + ) : ( | |
| 210 | + <div className="flex flex-col gap-px"> | |
| 211 | + {value.map((s) => { | |
| 212 | + const detailPath = `/sources/${s.id}`; | |
| 213 | + const active = | |
| 214 | + props.pathname === detailPath || | |
| 215 | + props.pathname.startsWith(`${detailPath}/`); | |
| 216 | + return ( | |
| 217 | + <Link | |
| 218 | + key={s.id} | |
| 219 | + to="/sources/$namespace" | |
| 220 | + params={{ namespace: s.id }} | |
| 221 | + onClick={props.onNavigate} | |
| 222 | + className={[ | |
| 223 | + "group flex items-center gap-2 rounded-md px-2.5 py-1.5 text-[13px] transition-colors", | |
| 224 | + active | |
| 225 | + ? "bg-sidebar-active text-foreground font-medium" | |
| 226 | + : "text-sidebar-foreground hover:bg-sidebar-active/60 hover:text-foreground", | |
| 227 | + ].join(" ")} | |
| 228 | + > | |
| 229 | + <span className="flex-1 truncate">{s.name}</span> | |
| 230 | + <span className="rounded bg-secondary/50 px-1 py-px text-[9px] font-medium text-muted-foreground/50"> | |
| 231 | + {s.kind} | |
| 232 | + </span> | |
| 233 | + </Link> | |
| 234 | + ); | |
| 235 | + })} | |
| 236 | + </div> | |
| 237 | + ), | |
| 238 | + }); | |
| 239 | +} | |
| 240 | + | |
| 241 | +// ── ScopeLabel ─────────────────────────────────────────────────────────── | |
| 242 | + | |
| 243 | +function ScopeLabel() { | |
| 244 | + const { name } = useScopeInfo(); | |
| 245 | + // Show just the last folder name, with full path as tooltip | |
| 246 | + const parts = name.replace(/\/+$/, "").split("/"); | |
| 247 | + const folder = parts[parts.length - 1] || name; | |
| 248 | + | |
| 249 | + return ( | |
| 250 | + <div className="mb-1.5 flex items-center gap-1.5 rounded-md px-2.5 py-1.5" title={name}> | |
| 251 | + <svg viewBox="0 0 16 16" fill="none" className="size-3.5 shrink-0 text-muted-foreground/50"> | |
| 252 | + <path | |
| 253 | + d="M2 4.5C2 3.67 2.67 3 3.5 3h3.09a1 1 0 0 1 .7.29l1.42 1.42a1 1 0 0 0 .7.29H12.5c.83 0 1.5.67 1.5 1.5v5.5c0 .83-.67 1.5-1.5 1.5h-9A1.5 1.5 0 0 1 2 12V4.5z" | |
| 254 | + stroke="currentColor" | |
| 255 | + strokeWidth="1.2" | |
| 256 | + /> | |
| 257 | + </svg> | |
| 258 | + <span className="truncate text-[12px] font-medium text-foreground/80"> | |
| 259 | + {folder} | |
| 260 | + </span> | |
| 261 | + </div> | |
| 262 | + ); | |
| 263 | +} | |
| 264 | + | |
| 265 | +// ── SidebarContent ─────────────────────────────────────────────────────── | |
| 266 | + | |
| 267 | +function SidebarContent(props: { | |
| 268 | + pathname: string; | |
| 269 | + onNavigate?: () => void; | |
| 270 | + showBrand?: boolean; | |
| 271 | + updateAvailable: boolean; | |
| 272 | + latestVersion: string | null; | |
| 273 | + channel: UpdateChannel; | |
| 274 | +}) { | |
| 275 | + const isHome = props.pathname === "/"; | |
| 276 | + const isSecrets = props.pathname === "/secrets"; | |
| 277 | + | |
| 278 | + return ( | |
| 279 | + <> | |
| 280 | + {props.showBrand !== false && ( | |
| 281 | + <div className="flex h-12 shrink-0 items-center border-b border-sidebar-border px-4"> | |
| 282 | + <Link to="/" className="flex items-center gap-1.5"> | |
| 283 | + <span className="font-display text-base tracking-tight text-foreground"> | |
| 284 | + executor | |
| 285 | + </span> | |
| 286 | + <span className="rounded bg-primary/15 px-1.5 py-0.5 text-[10px] font-medium text-primary"> | |
| 287 | + v4 | |
| 288 | + </span> | |
| 289 | + </Link> | |
| 290 | + </div> | |
| 291 | + )} | |
| 292 | + | |
| 293 | + <nav className="flex flex-1 flex-col overflow-y-auto p-2"> | |
| 294 | + <ScopeLabel /> | |
| 295 | + <NavItem | |
| 296 | + to="/" | |
| 297 | + label="Sources" | |
| 298 | + active={isHome} | |
| 299 | + onNavigate={props.onNavigate} | |
| 300 | + /> | |
| 301 | + <NavItem | |
| 302 | + to="/secrets" | |
| 303 | + label="Secrets" | |
| 304 | + active={isSecrets} | |
| 305 | + onNavigate={props.onNavigate} | |
| 306 | + /> | |
| 307 | + | |
| 308 | + {/* Sources list */} | |
| 309 | + <div className="mt-5 mb-1 px-2.5 text-[10px] font-medium uppercase tracking-widest text-muted-foreground/50"> | |
| 310 | + <span>Configured</span> | |
| 311 | + </div> | |
| 312 | + | |
| 313 | + <SourceList pathname={props.pathname} onNavigate={props.onNavigate} /> | |
| 314 | + </nav> | |
| 315 | + | |
| 316 | + {props.updateAvailable && props.latestVersion && ( | |
| 317 | + <UpdateCard latestVersion={props.latestVersion} channel={props.channel} /> | |
| 318 | + )} | |
| 319 | + | |
| 320 | + {/* Footer */} | |
| 321 | + <div className="shrink-0 border-t border-sidebar-border px-4 py-2.5"> | |
| 322 | + <div className="flex flex-col gap-1.5 text-[11px] leading-none"> | |
| 323 | + <a | |
| 324 | + href={`${VITE_GITHUB_URL}/issues`} | |
| 325 | + target="_blank" | |
| 326 | + rel="noreferrer" | |
| 327 | + className="text-muted-foreground/70 transition-colors hover:text-foreground" | |
| 328 | + > | |
| 329 | + Feedback / bug? | |
| 330 | + </a> | |
| 331 | + <a | |
| 332 | + href={VITE_GITHUB_URL} | |
| 333 | + target="_blank" | |
| 334 | + rel="noreferrer" | |
| 335 | + className="text-muted-foreground/70 transition-colors hover:text-foreground" | |
| 336 | + > | |
| 337 | + Star on GitHub | |
| 338 | + </a> | |
| 339 | + <span className="mt-0.5 text-[10px] text-muted-foreground/50 tabular-nums">v{VITE_APP_VERSION}</span> | |
| 340 | + </div> | |
| 341 | + </div> | |
| 342 | + </> | |
| 343 | + ); | |
| 344 | +} | |
| 345 | + | |
| 346 | +// ── Shell ───────────────────────────────────────────────────────────────── | |
| 347 | + | |
| 348 | +export function Shell() { | |
| 349 | + const location = useLocation(); | |
| 350 | + const pathname = location.pathname; | |
| 351 | + const scopeId = useScope(); | |
| 352 | + const refreshSources = useAtomRefresh(sourcesAtom(scopeId)); | |
| 353 | + const refreshTools = useAtomRefresh(toolsAtom(scopeId)); | |
| 354 | + const { latestVersion, updateAvailable, channel } = useLatestVersion(VITE_APP_VERSION); | |
| 355 | + const lastPathname = useRef(pathname); | |
| 356 | + const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false); | |
| 357 | + if (lastPathname.current !== pathname) { | |
| 358 | + lastPathname.current = pathname; | |
| 359 | + if (mobileSidebarOpen) setMobileSidebarOpen(false); | |
| 360 | + } | |
| 361 | + | |
| 362 | + // Lock scroll when mobile sidebar open | |
| 363 | + useEffect(() => { | |
| 364 | + if (!mobileSidebarOpen) return; | |
| 365 | + const prev = document.body.style.overflow; | |
| 366 | + document.body.style.overflow = "hidden"; | |
| 367 | + return () => { | |
| 368 | + document.body.style.overflow = prev; | |
| 369 | + }; | |
| 370 | + }, [mobileSidebarOpen]); | |
| 371 | + | |
| 372 | + useEffect(() => { | |
| 373 | + if (!import.meta.hot) { | |
| 374 | + return; | |
| 375 | + } | |
| 376 | + | |
| 377 | + const refreshBackendData = () => { | |
| 378 | + refreshSources(); | |
| 379 | + refreshTools(); | |
| 380 | + }; | |
| 381 | + | |
| 382 | + import.meta.hot.on("executor:backend-updated", refreshBackendData); | |
| 383 | + | |
| 384 | + return () => { | |
| 385 | + import.meta.hot?.off("executor:backend-updated", refreshBackendData); | |
| 386 | + }; | |
| 387 | + }, [refreshSources, refreshTools]); | |
| 388 | + | |
| 389 | + return ( | |
| 390 | + <div className="flex h-screen overflow-hidden"> | |
| 391 | + {/* Desktop sidebar */} | |
| 392 | + <aside className="hidden w-52 shrink-0 border-r border-sidebar-border bg-sidebar md:flex md:flex-col lg:w-56"> | |
| 393 | + <SidebarContent | |
| 394 | + pathname={pathname} | |
| 395 | + updateAvailable={updateAvailable} | |
| 396 | + latestVersion={latestVersion} | |
| 397 | + channel={channel} | |
| 398 | + /> | |
| 399 | + </aside> | |
| 400 | + | |
| 401 | + {/* Mobile sidebar overlay */} | |
| 402 | + {mobileSidebarOpen && ( | |
| 403 | + <div className="fixed inset-0 z-50 flex md:hidden"> | |
| 404 | + <button | |
| 405 | + type="button" | |
| 406 | + aria-label="Close navigation" | |
| 407 | + className="absolute inset-0 bg-black/45 backdrop-blur-[1px]" | |
| 408 | + onClick={() => setMobileSidebarOpen(false)} | |
| 409 | + /> | |
| 410 | + <div className="relative flex h-full w-[84vw] max-w-xs flex-col border-r border-sidebar-border bg-sidebar shadow-2xl"> | |
| 411 | + <div className="flex h-12 shrink-0 items-center justify-between border-b border-sidebar-border px-4"> | |
| 412 | + <Link to="/" className="flex items-center gap-1.5"> | |
| 413 | + <span className="font-display text-base tracking-tight text-foreground"> | |
| 414 | + executor | |
| 415 | + </span> | |
| 416 | + <span className="rounded bg-primary/15 px-1.5 py-0.5 text-[10px] font-medium text-primary"> | |
| 417 | + v4 | |
| 418 | + </span> | |
| 419 | + </Link> | |
| 420 | + <button | |
| 421 | + type="button" | |
| 422 | + aria-label="Close navigation" | |
| 423 | + onClick={() => setMobileSidebarOpen(false)} | |
| 424 | + className="size-8 flex items-center justify-center rounded-md text-sidebar-foreground hover:bg-sidebar-active hover:text-foreground" | |
| 425 | + > | |
| 426 | + <svg viewBox="0 0 16 16" className="size-3.5"> | |
| 427 | + <path d="M3 3l10 10M13 3L3 13" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" /> | |
| 428 | + </svg> | |
| 429 | + </button> | |
| 430 | + </div> | |
| 431 | + <SidebarContent | |
| 432 | + pathname={pathname} | |
| 433 | + onNavigate={() => setMobileSidebarOpen(false)} | |
| 434 | + showBrand={false} | |
| 435 | + updateAvailable={updateAvailable} | |
| 436 | + latestVersion={latestVersion} | |
| 437 | + channel={channel} | |
| 438 | + /> | |
| 439 | + </div> | |
| 440 | + </div> | |
| 441 | + )} | |
| 442 | + | |
| 443 | + {/* Main content */} | |
| 444 | + <main className="flex min-h-0 flex-1 flex-col min-w-0 overflow-hidden"> | |
| 445 | + {/* Mobile top bar */} | |
| 446 | + <div className="flex h-12 shrink-0 items-center justify-between border-b border-border bg-background px-4 md:hidden"> | |
| 447 | + <button | |
| 448 | + type="button" | |
| 449 | + aria-label="Open navigation" | |
| 450 | + onClick={() => setMobileSidebarOpen(true)} | |
| 451 | + className="size-8 flex items-center justify-center rounded-md border border-border bg-card hover:bg-accent/50" | |
| 452 | + > | |
| 453 | + <svg viewBox="0 0 16 16" className="size-4"> | |
| 454 | + <path d="M2 4h12M2 8h12M2 12h12" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" /> | |
| 455 | + </svg> | |
| 456 | + </button> | |
| 457 | + <Link to="/" className="flex items-center gap-1.5"> | |
| 458 | + <span className="font-display text-base tracking-tight text-foreground"> | |
| 459 | + executor | |
| 460 | + </span> | |
| 461 | + <span className="rounded bg-primary/15 px-1.5 py-0.5 text-[10px] font-medium text-primary"> | |
| 462 | + v4 | |
| 463 | + </span> | |
| 464 | + </Link> | |
| 465 | + <div className="w-8 shrink-0" /> | |
| 466 | + </div> | |
| 467 | + | |
| 468 | + {/* Outlet — pages control their own padding/scroll */} | |
| 469 | + <Outlet /> | |
| 470 | + </main> | |
| 471 | + </div> | |
| 472 | + ); | |
| 473 | +} | |
| @@ -1,123 +0,0 @@ | ||
| 1 | −import { Link } from "@tanstack/react-router"; | |
| 2 | −import { useSources } from "@executor/react"; | |
| 3 | −import { sourcePluginsIndexPath } from "@executor/react/plugins"; | |
| 4 | −import { LoadableBlock } from "../components/loadable"; | |
| 5 | −import { LocalMcpInstallCard } from "../components/local-mcp-install-card"; | |
| 6 | −import { SourceFavicon } from "../components/source-favicon"; | |
| 7 | −import { Alert, Badge, Button, Card } from "@executor/react/plugins"; | |
| 8 | −import { IconSources, IconPlus } from "../components/icons"; | |
| 9 | −import { | |
| 10 | − getSourceFrontendPaths, | |
| 11 | −} from "../plugins"; | |
| 12 | − | |
| 13 | −const statusVariant = (status: string) => | |
| 14 | − status === "connected" | |
| 15 | − ? "default" as const | |
| 16 | − : status === "error" | |
| 17 | − ? "destructive" as const | |
| 18 | − : "muted" as const; | |
| 19 | − | |
| 20 | −export function HomePage() { | |
| 21 | − const sources = useSources(); | |
| 22 | − | |
| 23 | − return ( | |
| 24 | − <div className="min-h-0 flex-1 overflow-y-auto"> | |
| 25 | − <div className="mx-auto max-w-4xl px-6 py-10 lg:px-10 lg:py-14"> | |
| 26 | − {/* Header */} | |
| 27 | − <div className="flex items-end justify-between mb-8"> | |
| 28 | − <div> | |
| 29 | − <h1 className="font-display text-3xl tracking-tight text-foreground lg:text-4xl"> | |
| 30 | − Sources | |
| 31 | − </h1> | |
| 32 | − <p className="mt-1.5 text-[14px] text-muted-foreground"> | |
| 33 | − Connected tool providers in this workspace. | |
| 34 | − </p> | |
| 35 | − </div> | |
| 36 | − <Link to={sourcePluginsIndexPath}> | |
| 37 | − <Button size="sm"> | |
| 38 | − <IconPlus className="size-3.5" /> | |
| 39 | − Add source | |
| 40 | − </Button> | |
| 41 | − </Link> | |
| 42 | − </div> | |
| 43 | − | |
| 44 | − <LocalMcpInstallCard className="mb-8" /> | |
| 45 | − | |
| 46 | − {/* Source list */} | |
| 47 | − <LoadableBlock loadable={sources} loading="Loading sources..."> | |
| 48 | − {(items) => | |
| 49 | − !Array.isArray(items) ? ( | |
| 50 | − <Alert variant="destructive" className="px-5 py-4"> | |
| 51 | − Sources returned an unexpected payload. | |
| 52 | − </Alert> | |
| 53 | − ) : items.length === 0 ? ( | |
| 54 | − <div className="flex flex-col items-center justify-center rounded-2xl border border-dashed border-border py-20"> | |
| 55 | − <div className="flex size-12 items-center justify-center rounded-2xl bg-muted text-muted-foreground mb-4"> | |
| 56 | − <IconSources className="size-5" /> | |
| 57 | − </div> | |
| 58 | − <p className="text-[14px] font-medium text-foreground/70 mb-1"> | |
| 59 | − No sources yet | |
| 60 | − </p> | |
| 61 | − <p className="text-[13px] text-muted-foreground/60 mb-5"> | |
| 62 | − Add a source to get started. | |
| 63 | − </p> | |
| 64 | − <Link to={sourcePluginsIndexPath}> | |
| 65 | − <Button size="sm"> | |
| 66 | − <IconPlus className="size-3.5" /> | |
| 67 | − Add source | |
| 68 | − </Button> | |
| 69 | − </Link> | |
| 70 | − </div> | |
| 71 | − ) : ( | |
| 72 | − <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3"> | |
| 73 | − {items.map((source) => { | |
| 74 | − const paths = getSourceFrontendPaths(source.kind); | |
| 75 | − const card = ( | |
| 76 | − <Card className="flex h-full flex-col rounded-2xl px-5 py-4 transition-colors hover:border-primary/25 hover:bg-card/90"> | |
| 77 | − <div className="flex items-start gap-3"> | |
| 78 | − <div className="flex size-9 shrink-0 items-center justify-center rounded-lg bg-muted text-muted-foreground"> | |
| 79 | − <SourceFavicon source={source} className="size-4" /> | |
| 80 | − </div> | |
| 81 | − <div className="min-w-0 flex-1"> | |
| 82 | − <div className="flex items-start justify-between gap-2"> | |
| 83 | − <div className="truncate text-sm font-semibold text-foreground"> | |
| 84 | − {source.name} | |
| 85 | − </div> | |
| 86 | − <Badge variant={statusVariant(source.status)} className="shrink-0"> | |
| 87 | − {source.status} | |
| 88 | − </Badge> | |
| 89 | − </div> | |
| 90 | − <div className="mt-0.5 text-xs text-muted-foreground"> | |
| 91 | − {source.kind} | |
| 92 | − </div> | |
| 93 | − </div> | |
| 94 | − </div> | |
| 95 | − </Card> | |
| 96 | − ); | |
| 97 | − | |
| 98 | − if (!paths) { | |
| 99 | − return ( | |
| 100 | − <div key={source.id}> | |
| 101 | − {card} | |
| 102 | − </div> | |
| 103 | − ); | |
| 104 | − } | |
| 105 | − | |
| 106 | − return ( | |
| 107 | − <Link | |
| 108 | − key={source.id} | |
| 109 | − to={paths.detail(source.id)} | |
| 110 | − search={{ tab: "model" }} | |
| 111 | − > | |
| 112 | − {card} | |
| 113 | − </Link> | |
| 114 | − ); | |
| 115 | − })} | |
| 116 | − </div> | |
| 117 | − ) | |
| 118 | − } | |
| 119 | − </LoadableBlock> | |
| 120 | − </div> | |
| 121 | − </div> | |
| 122 | − ); | |
| 123 | −} | |
| @@ -1,652 +0,0 @@ | ||
| 1 | −import { useState, type ReactNode } from "react"; | |
| 2 | −import { | |
| 3 | − type LocalScopePolicy, | |
| 4 | − type LocalScopePolicyApprovalMode, | |
| 5 | − type LocalScopePolicyEffect, | |
| 6 | − useCreatePolicy, | |
| 7 | − usePolicies, | |
| 8 | − useRemovePolicy, | |
| 9 | − useUpdatePolicy, | |
| 10 | −} from "@executor/react"; | |
| 11 | − | |
| 12 | −import { LoadableBlock } from "../components/loadable"; | |
| 13 | −import { | |
| 14 | − Alert, | |
| 15 | − Badge, | |
| 16 | − Button, | |
| 17 | − Card, | |
| 18 | − Input, | |
| 19 | − Label, | |
| 20 | − Select, | |
| 21 | −} from "@executor/react/plugins"; | |
| 22 | −import { | |
| 23 | − IconPencil, | |
| 24 | − IconPlus, | |
| 25 | − IconSpinner, | |
| 26 | − IconTrash, | |
| 27 | −} from "../components/icons"; | |
| 28 | −import { cn } from "../lib/utils"; | |
| 29 | − | |
| 30 | −// ── Permission state helpers ──────────────────────────────────────────── | |
| 31 | − | |
| 32 | −type PermissionLevel = "auto-run" | "requires-approval" | "denied"; | |
| 33 | − | |
| 34 | −const resolvePermissionLevel = ( | |
| 35 | − effect: LocalScopePolicyEffect, | |
| 36 | − approvalMode: LocalScopePolicyApprovalMode, | |
| 37 | −): PermissionLevel => { | |
| 38 | − if (effect === "deny") return "denied"; | |
| 39 | − if (approvalMode === "required") return "requires-approval"; | |
| 40 | − return "auto-run"; | |
| 41 | −}; | |
| 42 | − | |
| 43 | −const permissionConfig: Record< | |
| 44 | − PermissionLevel, | |
| 45 | − { label: string; className: string; dotClassName: string } | |
| 46 | −> = { | |
| 47 | − "auto-run": { | |
| 48 | − label: "Auto-run", | |
| 49 | − className: | |
| 50 | − "border-emerald-500/20 bg-emerald-500/10 text-emerald-600 dark:text-emerald-400", | |
| 51 | − dotClassName: "bg-emerald-500", | |
| 52 | − }, | |
| 53 | − "requires-approval": { | |
| 54 | − label: "Approval", | |
| 55 | − className: | |
| 56 | − "border-amber-500/20 bg-amber-500/10 text-amber-600 dark:text-amber-400", | |
| 57 | − dotClassName: "bg-amber-500", | |
| 58 | − }, | |
| 59 | − denied: { | |
| 60 | − label: "Denied", | |
| 61 | − className: | |
| 62 | − "border-red-500/20 bg-red-500/10 text-red-600 dark:text-red-400", | |
| 63 | − dotClassName: "bg-red-500", | |
| 64 | − }, | |
| 65 | −}; | |
| 66 | − | |
| 67 | −const PermissionBadge = (props: { | |
| 68 | − effect: LocalScopePolicyEffect; | |
| 69 | − approvalMode: LocalScopePolicyApprovalMode; | |
| 70 | −}) => { | |
| 71 | − const level = resolvePermissionLevel(props.effect, props.approvalMode); | |
| 72 | − const config = permissionConfig[level]; | |
| 73 | − | |
| 74 | − return ( | |
| 75 | − <span | |
| 76 | − className={cn( | |
| 77 | − "inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide", | |
| 78 | − config.className, | |
| 79 | − )} | |
| 80 | − > | |
| 81 | − <span className={cn("size-1.5 rounded-full", config.dotClassName)} /> | |
| 82 | − {config.label} | |
| 83 | − </span> | |
| 84 | − ); | |
| 85 | −}; | |
| 86 | − | |
| 87 | −// ── Page ──────────────────────────────────────────────────────────────── | |
| 88 | − | |
| 89 | −export function PoliciesPage() { | |
| 90 | − const policies = usePolicies(); | |
| 91 | − const [showCreate, setShowCreate] = useState(false); | |
| 92 | − const [editingId, setEditingId] = useState<string | null>(null); | |
| 93 | − | |
| 94 | − return ( | |
| 95 | − <div className="min-h-0 flex-1 overflow-y-auto"> | |
| 96 | − <div className="mx-auto flex max-w-4xl flex-col gap-8 px-6 py-10 lg:px-10 lg:py-14"> | |
| 97 | − <div className="flex flex-wrap items-end justify-between gap-4"> | |
| 98 | − <div> | |
| 99 | − <h1 className="font-display text-3xl tracking-tight text-foreground lg:text-4xl"> | |
| 100 | − Policies | |
| 101 | − </h1> | |
| 102 | − <p className="mt-1.5 text-[14px] text-muted-foreground"> | |
| 103 | − Control which tools can auto-run, require approval, or are | |
| 104 | − completely denied. | |
| 105 | − </p> | |
| 106 | − </div> | |
| 107 | − <Button | |
| 108 | − size="sm" | |
| 109 | − onClick={() => { | |
| 110 | − setShowCreate(true); | |
| 111 | − setEditingId(null); | |
| 112 | − }} | |
| 113 | − > | |
| 114 | − <IconPlus className="size-3.5" /> | |
| 115 | − Add policy | |
| 116 | − </Button> | |
| 117 | − </div> | |
| 118 | − | |
| 119 | − {showCreate && ( | |
| 120 | − <CreatePolicyForm | |
| 121 | − className="mb-2" | |
| 122 | − onClose={() => setShowCreate(false)} | |
| 123 | − /> | |
| 124 | − )} | |
| 125 | − | |
| 126 | − <section className="space-y-4"> | |
| 127 | − <div> | |
| 128 | − <h2 className="text-sm font-semibold text-foreground"> | |
| 129 | − Active Policies | |
| 130 | − </h2> | |
| 131 | − <p className="mt-1 text-[13px] text-muted-foreground"> | |
| 132 | − Policies are matched by resource pattern using glob syntax. | |
| 133 | − Higher priority rules take precedence. | |
| 134 | − </p> | |
| 135 | − </div> | |
| 136 | − | |
| 137 | − <LoadableBlock loadable={policies} loading="Loading policies..."> | |
| 138 | − {(items) => | |
| 139 | − items.length === 0 && !showCreate ? ( | |
| 140 | − <SectionEmptyState | |
| 141 | − title="No policies configured" | |
| 142 | − description="Add a policy to control tool permissions. By default all tools require approval." | |
| 143 | − actionLabel="Add policy" | |
| 144 | − onAction={() => { | |
| 145 | − setShowCreate(true); | |
| 146 | − setEditingId(null); | |
| 147 | − }} | |
| 148 | − /> | |
| 149 | − ) : ( | |
| 150 | − <Card className="overflow-hidden p-0"> | |
| 151 | − {[...items] | |
| 152 | − .sort((a, b) => b.priority - a.priority) | |
| 153 | − .map((policy, index) => ( | |
| 154 | − <div | |
| 155 | − key={policy.id} | |
| 156 | − className={cn( | |
| 157 | − "px-5 py-3.5", | |
| 158 | − index > 0 && "border-t border-border", | |
| 159 | − !policy.enabled && "opacity-50", | |
| 160 | − )} | |
| 161 | − > | |
| 162 | − <PolicyRow | |
| 163 | − policy={policy} | |
| 164 | − isEditing={editingId === policy.id} | |
| 165 | − onEdit={() => | |
| 166 | − setEditingId( | |
| 167 | − editingId === policy.id ? null : policy.id, | |
| 168 | − ) | |
| 169 | − } | |
| 170 | − onCancelEdit={() => setEditingId(null)} | |
| 171 | − /> | |
| 172 | − </div> | |
| 173 | − ))} | |
| 174 | − </Card> | |
| 175 | − ) | |
| 176 | − } | |
| 177 | − </LoadableBlock> | |
| 178 | − </section> | |
| 179 | − | |
| 180 | − <section className="space-y-3"> | |
| 181 | − <h2 className="text-sm font-semibold text-foreground"> | |
| 182 | − How policies work | |
| 183 | − </h2> | |
| 184 | − <div className="grid gap-3 md:grid-cols-3"> | |
| 185 | − <HelpCard level="auto-run"> | |
| 186 | − <strong>Auto-run</strong> tools execute immediately without | |
| 187 | − asking. Use for trusted, read-only operations. | |
| 188 | − </HelpCard> | |
| 189 | − <HelpCard level="requires-approval"> | |
| 190 | − <strong>Approval</strong> tools pause and ask before running. | |
| 191 | − The default for most tools. | |
| 192 | − </HelpCard> | |
| 193 | − <HelpCard level="denied"> | |
| 194 | − <strong>Denied</strong> tools are blocked completely and cannot | |
| 195 | − be invoked. | |
| 196 | − </HelpCard> | |
| 197 | − </div> | |
| 198 | − <p className="text-[12px] text-muted-foreground/60"> | |
| 199 | − Patterns use glob syntax: <code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px]">*</code> matches | |
| 200 | − all tools, <code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px]">github.*</code> matches all | |
| 201 | − GitHub tools, <code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px]">*.delete</code> matches | |
| 202 | − all delete operations. | |
| 203 | − </p> | |
| 204 | − </section> | |
| 205 | − </div> | |
| 206 | − </div> | |
| 207 | − ); | |
| 208 | −} | |
| 209 | − | |
| 210 | −// ── Create form ───────────────────────────────────────────────────────── | |
| 211 | − | |
| 212 | −function CreatePolicyForm(props: { className?: string; onClose: () => void }) { | |
| 213 | − const createPolicy = useCreatePolicy(); | |
| 214 | − const [pattern, setPattern] = useState("*"); | |
| 215 | − const [effect, setEffect] = useState<LocalScopePolicyEffect>("allow"); | |
| 216 | − const [approvalMode, setApprovalMode] = | |
| 217 | − useState<LocalScopePolicyApprovalMode>("auto"); | |
| 218 | − const [priority, setPriority] = useState("0"); | |
| 219 | − const [error, setError] = useState<string | null>(null); | |
| 220 | − | |
| 221 | − const handleSubmit = async () => { | |
| 222 | − setError(null); | |
| 223 | − | |
| 224 | − const trimmedPattern = pattern.trim(); | |
| 225 | − if (!trimmedPattern) { | |
| 226 | − setError("Resource pattern is required."); | |
| 227 | − return; | |
| 228 | − } | |
| 229 | − | |
| 230 | − try { | |
| 231 | − await createPolicy.mutateAsync({ | |
| 232 | − resourcePattern: trimmedPattern, | |
| 233 | − effect, | |
| 234 | − approvalMode, | |
| 235 | − priority: Number(priority) || 0, | |
| 236 | − enabled: true, | |
| 237 | − }); | |
| 238 | − props.onClose(); | |
| 239 | − } catch (cause) { | |
| 240 | − setError( | |
| 241 | − cause instanceof Error ? cause.message : "Failed creating policy.", | |
| 242 | − ); | |
| 243 | − } | |
| 244 | − }; | |
| 245 | − | |
| 246 | − return ( | |
| 247 | − <FormCard | |
| 248 | − className={props.className} | |
| 249 | − title="New policy" | |
| 250 | − onClose={props.onClose} | |
| 251 | − > | |
| 252 | − {error && <ErrorBanner>{error}</ErrorBanner>} | |
| 253 | − <div className="grid gap-4 sm:grid-cols-2"> | |
| 254 | − <div className="grid gap-2 sm:col-span-2"> | |
| 255 | − <Label>Resource pattern</Label> | |
| 256 | − <Input | |
| 257 | − value={pattern} | |
| 258 | − onChange={(event) => setPattern(event.target.value)} | |
| 259 | − placeholder="github.* or *.delete" | |
| 260 | − className="font-mono text-[12px]" | |
| 261 | − autoFocus | |
| 262 | − /> | |
| 263 | − <p className="text-[11px] text-muted-foreground/60"> | |
| 264 | − Glob pattern matched against tool paths. | |
| 265 | − </p> | |
| 266 | − </div> | |
| 267 | − <div className="grid gap-2"> | |
| 268 | − <Label>Permission</Label> | |
| 269 | − <Select | |
| 270 | − value={`${effect}:${approvalMode}`} | |
| 271 | − onChange={(event) => { | |
| 272 | − const [newEffect, newApproval] = event.target.value.split(":") as [ | |
| 273 | − LocalScopePolicyEffect, | |
| 274 | − LocalScopePolicyApprovalMode, | |
| 275 | − ]; | |
| 276 | − setEffect(newEffect); | |
| 277 | − setApprovalMode(newApproval); | |
| 278 | − }} | |
| 279 | − > | |
| 280 | − <option value="allow:auto">Auto-run</option> | |
| 281 | − <option value="allow:required">Requires approval</option> | |
| 282 | − <option value="deny:auto">Denied</option> | |
| 283 | − </Select> | |
| 284 | − </div> | |
| 285 | − <div className="grid gap-2"> | |
| 286 | − <Label>Priority</Label> | |
| 287 | − <Input | |
| 288 | − type="number" | |
| 289 | − value={priority} | |
| 290 | − onChange={(event) => setPriority(event.target.value)} | |
| 291 | − placeholder="0" | |
| 292 | − /> | |
| 293 | − <p className="text-[11px] text-muted-foreground/60"> | |
| 294 | − Higher priority rules win when multiple patterns match. | |
| 295 | − </p> | |
| 296 | − </div> | |
| 297 | − </div> | |
| 298 | − <div className="flex items-center justify-between"> | |
| 299 | − <PermissionBadge effect={effect} approvalMode={approvalMode} /> | |
| 300 | − <Button | |
| 301 | − size="sm" | |
| 302 | − onClick={handleSubmit} | |
| 303 | − disabled={createPolicy.status === "pending"} | |
| 304 | − > | |
| 305 | − {createPolicy.status === "pending" ? ( | |
| 306 | − <IconSpinner className="size-3.5" /> | |
| 307 | − ) : ( | |
| 308 | − <IconPlus className="size-3.5" /> | |
| 309 | − )} | |
| 310 | − Create policy | |
| 311 | − </Button> | |
| 312 | − </div> | |
| 313 | − </FormCard> | |
| 314 | − ); | |
| 315 | −} | |
| 316 | − | |
| 317 | −// ── Policy row ────────────────────────────────────────────────────────── | |
| 318 | − | |
| 319 | −function PolicyRow(props: { | |
| 320 | − policy: LocalScopePolicy; | |
| 321 | − isEditing: boolean; | |
| 322 | − onEdit: () => void; | |
| 323 | − onCancelEdit: () => void; | |
| 324 | −}) { | |
| 325 | − const removePolicy = useRemovePolicy(); | |
| 326 | − const [isDeleting, setIsDeleting] = useState(false); | |
| 327 | − const [confirmDelete, setConfirmDelete] = useState(false); | |
| 328 | − | |
| 329 | − const handleDelete = async () => { | |
| 330 | − setIsDeleting(true); | |
| 331 | − try { | |
| 332 | − await removePolicy.mutateAsync(props.policy.id); | |
| 333 | − } catch { | |
| 334 | − // refresh state will keep the policy visible | |
| 335 | − } finally { | |
| 336 | − setIsDeleting(false); | |
| 337 | − setConfirmDelete(false); | |
| 338 | − } | |
| 339 | − }; | |
| 340 | − | |
| 341 | − return ( | |
| 342 | − <> | |
| 343 | − <div className="flex items-center justify-between gap-4"> | |
| 344 | − <div className="min-w-0"> | |
| 345 | − <div className="flex flex-wrap items-center gap-2"> | |
| 346 | − <span className="truncate font-mono text-[13px] font-medium text-foreground"> | |
| 347 | − {props.policy.resourcePattern} | |
| 348 | − </span> | |
| 349 | − <PermissionBadge | |
| 350 | − effect={props.policy.effect} | |
| 351 | − approvalMode={props.policy.approvalMode} | |
| 352 | − /> | |
| 353 | − {!props.policy.enabled && ( | |
| 354 | − <Badge variant="outline" className="text-[9px] uppercase"> | |
| 355 | − disabled | |
| 356 | − </Badge> | |
| 357 | − )} | |
| 358 | − {props.policy.priority !== 0 && ( | |
| 359 | − <Badge variant="outline" className="text-[9px]"> | |
| 360 | − priority {props.policy.priority} | |
| 361 | − </Badge> | |
| 362 | − )} | |
| 363 | − </div> | |
| 364 | − <div className="mt-0.5 flex flex-wrap items-center gap-2 text-[11px] text-muted-foreground/50"> | |
| 365 | − <span className="font-mono">{props.policy.id}</span> | |
| 366 | − <span>{formatDate(props.policy.createdAt)}</span> | |
| 367 | − </div> | |
| 368 | − </div> | |
| 369 | − <div className="flex shrink-0 items-center gap-1.5"> | |
| 370 | − <Button | |
| 371 | − variant="ghost" | |
| 372 | − size="sm" | |
| 373 | − onClick={props.onEdit} | |
| 374 | − className={cn( | |
| 375 | − props.isEditing | |
| 376 | − ? "bg-primary/10 text-primary" | |
| 377 | − : "text-muted-foreground hover:bg-accent/50 hover:text-foreground", | |
| 378 | − )} | |
| 379 | − > | |
| 380 | − <IconPencil className="size-3" /> | |
| 381 | − Edit | |
| 382 | − </Button> | |
| 383 | − {confirmDelete ? ( | |
| 384 | − <> | |
| 385 | − <Button | |
| 386 | − variant="ghost" | |
| 387 | − size="sm" | |
| 388 | − onClick={() => setConfirmDelete(false)} | |
| 389 | − disabled={isDeleting} | |
| 390 | − > | |
| 391 | − Cancel | |
| 392 | − </Button> | |
| 393 | − <Button | |
| 394 | − variant="destructive-outline" | |
| 395 | − size="sm" | |
| 396 | − onClick={() => { | |
| 397 | − void handleDelete(); | |
| 398 | − }} | |
| 399 | − disabled={isDeleting} | |
| 400 | − > | |
| 401 | − {isDeleting ? ( | |
| 402 | − <IconSpinner className="size-3" /> | |
| 403 | − ) : ( | |
| 404 | − <IconTrash className="size-3" /> | |
| 405 | − )} | |
| 406 | − Delete | |
| 407 | − </Button> | |
| 408 | − </> | |
| 409 | − ) : ( | |
| 410 | − <Button | |
| 411 | − variant="ghost" | |
| 412 | − size="sm" | |
| 413 | − onClick={() => setConfirmDelete(true)} | |
| 414 | − disabled={isDeleting} | |
| 415 | − className="text-muted-foreground hover:bg-destructive/8 hover:text-destructive" | |
| 416 | − > | |
| 417 | − {isDeleting ? ( | |
| 418 | − <IconSpinner className="size-3" /> | |
| 419 | − ) : ( | |
| 420 | − <IconTrash className="size-3" /> | |
| 421 | − )} | |
| 422 | − Delete | |
| 423 | − </Button> | |
| 424 | − )} | |
| 425 | − </div> | |
| 426 | − </div> | |
| 427 | − | |
| 428 | − {props.isEditing && ( | |
| 429 | − <EditPolicyForm policy={props.policy} onClose={props.onCancelEdit} /> | |
| 430 | − )} | |
| 431 | − </> | |
| 432 | − ); | |
| 433 | −} | |
| 434 | − | |
| 435 | −// ── Edit form ─────────────────────────────────────────────────────────── | |
| 436 | − | |
| 437 | −function EditPolicyForm(props: { | |
| 438 | − policy: LocalScopePolicy; | |
| 439 | − onClose: () => void; | |
| 440 | −}) { | |
| 441 | − const updatePolicy = useUpdatePolicy(); | |
| 442 | − const [pattern, setPattern] = useState(props.policy.resourcePattern); | |
| 443 | − const [effect, setEffect] = useState<LocalScopePolicyEffect>( | |
| 444 | − props.policy.effect, | |
| 445 | − ); | |
| 446 | − const [approvalMode, setApprovalMode] = | |
| 447 | − useState<LocalScopePolicyApprovalMode>(props.policy.approvalMode); | |
| 448 | − const [priority, setPriority] = useState(String(props.policy.priority)); | |
| 449 | − const [enabled, setEnabled] = useState(props.policy.enabled); | |
| 450 | − const [error, setError] = useState<string | null>(null); | |
| 451 | − | |
| 452 | − const handleSubmit = async () => { | |
| 453 | − setError(null); | |
| 454 | − | |
| 455 | − const payload: Record<string, unknown> = {}; | |
| 456 | − const trimmedPattern = pattern.trim(); | |
| 457 | − | |
| 458 | − if (trimmedPattern && trimmedPattern !== props.policy.resourcePattern) { | |
| 459 | − payload.resourcePattern = trimmedPattern; | |
| 460 | − } | |
| 461 | − if (effect !== props.policy.effect) { | |
| 462 | − payload.effect = effect; | |
| 463 | − } | |
| 464 | − if (approvalMode !== props.policy.approvalMode) { | |
| 465 | − payload.approvalMode = approvalMode; | |
| 466 | − } | |
| 467 | − const numPriority = Number(priority) || 0; | |
| 468 | − if (numPriority !== props.policy.priority) { | |
| 469 | − payload.priority = numPriority; | |
| 470 | − } | |
| 471 | − if (enabled !== props.policy.enabled) { | |
| 472 | − payload.enabled = enabled; | |
| 473 | − } | |
| 474 | − | |
| 475 | − if (Object.keys(payload).length === 0) { | |
| 476 | − props.onClose(); | |
| 477 | − return; | |
| 478 | − } | |
| 479 | − | |
| 480 | − try { | |
| 481 | − await updatePolicy.mutateAsync({ | |
| 482 | − policyId: props.policy.id, | |
| 483 | − payload, | |
| 484 | − }); | |
| 485 | − props.onClose(); | |
| 486 | − } catch (cause) { | |
| 487 | − setError( | |
| 488 | − cause instanceof Error ? cause.message : "Failed updating policy.", | |
| 489 | − ); | |
| 490 | − } | |
| 491 | − }; | |
| 492 | − | |
| 493 | − return ( | |
| 494 | − <div className="mt-3 border-t border-border/50 pt-3"> | |
| 495 | − {error && <ErrorBanner className="mb-3">{error}</ErrorBanner>} | |
| 496 | − <div className="grid gap-3 sm:grid-cols-2"> | |
| 497 | − <div className="grid gap-2 sm:col-span-2"> | |
| 498 | − <Label>Resource pattern</Label> | |
| 499 | − <Input | |
| 500 | − value={pattern} | |
| 501 | − onChange={(event) => setPattern(event.target.value)} | |
| 502 | − placeholder="github.* or *.delete" | |
| 503 | − className="h-8 font-mono text-[12px]" | |
| 504 | − autoFocus | |
| 505 | − /> | |
| 506 | − </div> | |
| 507 | − <div className="grid gap-2"> | |
| 508 | − <Label>Permission</Label> | |
| 509 | − <Select | |
| 510 | − value={`${effect}:${approvalMode}`} | |
| 511 | − onChange={(event) => { | |
| 512 | − const [newEffect, newApproval] = event.target.value.split(":") as [ | |
| 513 | − LocalScopePolicyEffect, | |
| 514 | − LocalScopePolicyApprovalMode, | |
| 515 | − ]; | |
| 516 | − setEffect(newEffect); | |
| 517 | − setApprovalMode(newApproval); | |
| 518 | − }} | |
| 519 | − className="h-8 text-[12px]" | |
| 520 | − > | |
| 521 | − <option value="allow:auto">Auto-run</option> | |
| 522 | − <option value="allow:required">Requires approval</option> | |
| 523 | − <option value="deny:auto">Denied</option> | |
| 524 | − </Select> | |
| 525 | − </div> | |
| 526 | − <div className="grid gap-2"> | |
| 527 | − <Label>Priority</Label> | |
| 528 | − <Input | |
| 529 | − type="number" | |
| 530 | − value={priority} | |
| 531 | − onChange={(event) => setPriority(event.target.value)} | |
| 532 | − placeholder="0" | |
| 533 | − className="h-8 text-[12px]" | |
| 534 | − /> | |
| 535 | − </div> | |
| 536 | − </div> | |
| 537 | − <div className="mt-3 flex items-center justify-between"> | |
| 538 | − <label className="flex items-center gap-2 text-[12px] text-muted-foreground"> | |
| 539 | − <input | |
| 540 | − type="checkbox" | |
| 541 | − checked={enabled} | |
| 542 | − onChange={(event) => setEnabled(event.target.checked)} | |
| 543 | − className="rounded border-border" | |
| 544 | − /> | |
| 545 | − Enabled | |
| 546 | − </label> | |
| 547 | − <div className="flex items-center gap-2"> | |
| 548 | − <PermissionBadge effect={effect} approvalMode={approvalMode} /> | |
| 549 | − <Button variant="ghost" size="sm" onClick={props.onClose}> | |
| 550 | − Cancel | |
| 551 | − </Button> | |
| 552 | − <Button | |
| 553 | − size="sm" | |
| 554 | − onClick={handleSubmit} | |
| 555 | − disabled={updatePolicy.status === "pending"} | |
| 556 | − > | |
| 557 | − {updatePolicy.status === "pending" && ( | |
| 558 | − <IconSpinner className="size-3" /> | |
| 559 | − )} | |
| 560 | − Save | |
| 561 | − </Button> | |
| 562 | − </div> | |
| 563 | − </div> | |
| 564 | − </div> | |
| 565 | − ); | |
| 566 | −} | |
| 567 | − | |
| 568 | −// ── Shared components ─────────────────────────────────────────────────── | |
| 569 | − | |
| 570 | −function HelpCard(props: { level: PermissionLevel; children: ReactNode }) { | |
| 571 | − const config = permissionConfig[props.level]; | |
| 572 | − | |
| 573 | − return ( | |
| 574 | − <div | |
| 575 | − className={cn( | |
| 576 | − "rounded-xl border px-4 py-3 text-[12px] leading-relaxed", | |
| 577 | − config.className, | |
| 578 | − )} | |
| 579 | − > | |
| 580 | − <div className="mb-1.5 flex items-center gap-1.5"> | |
| 581 | − <span className={cn("size-2 rounded-full", config.dotClassName)} /> | |
| 582 | − <span className="text-[10px] font-semibold uppercase tracking-wide"> | |
| 583 | − {config.label} | |
| 584 | − </span> | |
| 585 | − </div> | |
| 586 | − <p className="text-foreground/70">{props.children}</p> | |
| 587 | − </div> | |
| 588 | − ); | |
| 589 | −} | |
| 590 | − | |
| 591 | −function FormCard(props: { | |
| 592 | − title: string; | |
| 593 | − onClose: () => void; | |
| 594 | − className?: string; | |
| 595 | − children: ReactNode; | |
| 596 | −}) { | |
| 597 | − return ( | |
| 598 | − <Card className={cn("border-primary/20 p-0", props.className)}> | |
| 599 | − <div className="flex items-center justify-between border-b border-border px-5 py-3"> | |
| 600 | − <h3 className="text-sm font-semibold text-foreground">{props.title}</h3> | |
| 601 | − <Button variant="ghost" size="sm" onClick={props.onClose}> | |
| 602 | − Cancel | |
| 603 | − </Button> | |
| 604 | − </div> | |
| 605 | − <div className="space-y-4 p-5">{props.children}</div> | |
| 606 | − </Card> | |
| 607 | − ); | |
| 608 | −} | |
| 609 | − | |
| 610 | −function ErrorBanner(props: { children: ReactNode; className?: string }) { | |
| 611 | − return ( | |
| 612 | − <Alert | |
| 613 | − variant="destructive" | |
| 614 | − className={cn("text-[13px]", props.className)} | |
| 615 | − > | |
| 616 | − {props.children} | |
| 617 | − </Alert> | |
| 618 | − ); | |
| 619 | −} | |
| 620 | − | |
| 621 | −function SectionEmptyState(props: { | |
| 622 | − title: string; | |
| 623 | − description: string; | |
| 624 | − actionLabel?: string; | |
| 625 | − onAction?: () => void; | |
| 626 | −}) { | |
| 627 | − return ( | |
| 628 | − <div className="rounded-xl border border-dashed border-border px-6 py-10 text-center"> | |
| 629 | − <p className="text-[14px] font-medium text-foreground/75"> | |
| 630 | − {props.title} | |
| 631 | − </p> | |
| 632 | − <p className="mt-1 text-[13px] text-muted-foreground"> | |
| 633 | − {props.description} | |
| 634 | − </p> | |
| 635 | − {props.actionLabel && props.onAction && ( | |
| 636 | − <div className="mt-4 flex justify-center"> | |
| 637 | − <Button size="sm" onClick={props.onAction}> | |
| 638 | − <IconPlus className="size-3.5" /> | |
| 639 | − {props.actionLabel} | |
| 640 | − </Button> | |
| 641 | − </div> | |
| 642 | − )} | |
| 643 | − </div> | |
| 644 | − ); | |
| 645 | −} | |
| 646 | − | |
| 647 | −const formatDate = (value: number): string => | |
| 648 | − new Date(value).toLocaleDateString(undefined, { | |
| 649 | − month: "short", | |
| 650 | − day: "numeric", | |
| 651 | − year: "numeric", | |
| 652 | − }); | |
| @@ -1,1073 +0,0 @@ | ||
| 1 | −import { useCallback, useEffect, useState, type ReactNode } from "react"; | |
| 2 | −import { | |
| 3 | − type BrowseSecretStoreResult, | |
| 4 | − getExecutorApiBaseUrl, | |
| 5 | − type InstanceConfig, | |
| 6 | − type Loadable, | |
| 7 | − type SecretListItem, | |
| 8 | − type SecretStore, | |
| 9 | − useCreateSecret, | |
| 10 | − useCreateSecretStore, | |
| 11 | − useDeleteSecret, | |
| 12 | − useDeleteSecretStore, | |
| 13 | − useExecutorMutation, | |
| 14 | − useInstanceConfig, | |
| 15 | − useRefreshSecrets, | |
| 16 | − useSecretStores, | |
| 17 | − useSecrets, | |
| 18 | − useUpdateSecret, | |
| 19 | −} from "@executor/react"; | |
| 20 | − | |
| 21 | −import { LoadableBlock } from "../components/loadable"; | |
| 22 | −import { Badge } from "@executor/react/plugins"; | |
| 23 | −import { | |
| 24 | − Alert, | |
| 25 | − Button, | |
| 26 | − Card, | |
| 27 | − Input, | |
| 28 | − Label, | |
| 29 | − Select, | |
| 30 | −} from "@executor/react/plugins"; | |
| 31 | −import { | |
| 32 | − IconPencil, | |
| 33 | − IconPlus, | |
| 34 | − IconSpinner, | |
| 35 | − IconTrash, | |
| 36 | −} from "../components/icons"; | |
| 37 | −import { cn } from "../lib/utils"; | |
| 38 | −import { getSecretStoreFrontendPlugin } from "../plugins"; | |
| 39 | − | |
| 40 | −const creatableStorePluginsFromConfig = (config: Loadable<InstanceConfig>) => | |
| 41 | − config.status === "ready" | |
| 42 | − ? config.data.secretStorePlugins.filter((plugin) => plugin.canCreate) | |
| 43 | − : []; | |
| 44 | − | |
| 45 | −const canManageStoreKind = ( | |
| 46 | − config: Loadable<InstanceConfig>, | |
| 47 | − kind: string, | |
| 48 | −): boolean => | |
| 49 | − config.status === "ready" | |
| 50 | − ? config.data.secretStorePlugins.some((plugin) => | |
| 51 | − plugin.kind === kind && plugin.canCreate | |
| 52 | − ) | |
| 53 | − : false; | |
| 54 | − | |
| 55 | −const defaultStoreLabel = ( | |
| 56 | − config: Loadable<InstanceConfig>, | |
| 57 | − stores: Loadable<ReadonlyArray<SecretStore>>, | |
| 58 | −): string | null => { | |
| 59 | − if ( | |
| 60 | − config.status !== "ready" | |
| 61 | − || stores.status !== "ready" | |
| 62 | − || config.data.defaultSecretStoreId === null | |
| 63 | − ) { | |
| 64 | − return null; | |
| 65 | − } | |
| 66 | − | |
| 67 | − return stores.data.find((store) => | |
| 68 | − store.id === config.data.defaultSecretStoreId | |
| 69 | − )?.name ?? null; | |
| 70 | −}; | |
| 71 | − | |
| 72 | −type SecretStoreBrowserEntry = BrowseSecretStoreResult["entries"][number]; | |
| 73 | −type SecretStoreBrowserCrumb = { | |
| 74 | − key: string; | |
| 75 | − label: string; | |
| 76 | −}; | |
| 77 | − | |
| 78 | −const canBrowseAndImportStore = (store: SecretStore | null): boolean => | |
| 79 | − store?.capabilities.canBrowseSecrets === true | |
| 80 | − && store.capabilities.canImportSecrets === true; | |
| 81 | − | |
| 82 | −export function SecretsPage() { | |
| 83 | − const instanceConfig = useInstanceConfig(); | |
| 84 | − const secretStores = useSecretStores(); | |
| 85 | − const secrets = useSecrets(); | |
| 86 | − const [showCreateStore, setShowCreateStore] = useState(false); | |
| 87 | − const [showCreateSecret, setShowCreateSecret] = useState(false); | |
| 88 | − const [editingId, setEditingId] = useState<string | null>(null); | |
| 89 | − | |
| 90 | − const creatableStorePlugins = creatableStorePluginsFromConfig(instanceConfig); | |
| 91 | − const defaultLabel = defaultStoreLabel(instanceConfig, secretStores); | |
| 92 | − | |
| 93 | − return ( | |
| 94 | − <div className="min-h-0 flex-1 overflow-y-auto"> | |
| 95 | − <div className="mx-auto flex max-w-4xl flex-col gap-8 px-6 py-10 lg:px-10 lg:py-14"> | |
| 96 | − <div className="flex flex-wrap items-end justify-between gap-4"> | |
| 97 | − <div> | |
| 98 | − <h1 className="font-display text-3xl tracking-tight text-foreground lg:text-4xl"> | |
| 99 | − Secrets | |
| 100 | − </h1> | |
| 101 | − <p className="mt-1.5 text-[14px] text-muted-foreground"> | |
| 102 | − Manage secret stores and the secrets linked into sources. | |
| 103 | − {defaultLabel ? ` New secrets default to ${defaultLabel}.` : ""} | |
| 104 | − </p> | |
| 105 | − </div> | |
| 106 | − <div className="flex gap-2"> | |
| 107 | − <Button | |
| 108 | − size="sm" | |
| 109 | − onClick={() => { | |
| 110 | − setShowCreateSecret(true); | |
| 111 | − setEditingId(null); | |
| 112 | − }} | |
| 113 | − > | |
| 114 | − <IconPlus className="size-3.5" /> | |
| 115 | − Add secret | |
| 116 | − </Button> | |
| 117 | − </div> | |
| 118 | − </div> | |
| 119 | − | |
| 120 | − <section className="space-y-4"> | |
| 121 | − <div> | |
| 122 | − <h2 className="text-sm font-semibold text-foreground">Stores</h2> | |
| 123 | − <p className="mt-1 text-[13px] text-muted-foreground"> | |
| 124 | − Local and external backends that hold managed secrets. | |
| 125 | − </p> | |
| 126 | − </div> | |
| 127 | − | |
| 128 | − {showCreateStore && ( | |
| 129 | − <CreateSecretStoreForm | |
| 130 | − className="mb-2" | |
| 131 | − onClose={() => setShowCreateStore(false)} | |
| 132 | − pluginOptions={creatableStorePlugins} | |
| 133 | − secrets={secrets} | |
| 134 | − /> | |
| 135 | − )} | |
| 136 | − | |
| 137 | − <LoadableBlock loadable={secretStores} loading="Loading stores..."> | |
| 138 | − {(items) => | |
| 139 | − items.length === 0 ? ( | |
| 140 | − <SectionEmptyState | |
| 141 | − title="No secret stores yet" | |
| 142 | − description="External secret stores are currently unavailable in this app." | |
| 143 | − /> | |
| 144 | − ) : ( | |
| 145 | − <div className="grid gap-3 md:grid-cols-2"> | |
| 146 | − {items.map((store) => ( | |
| 147 | − <SecretStoreCard | |
| 148 | − key={store.id} | |
| 149 | − store={store} | |
| 150 | − canManage={canManageStoreKind(instanceConfig, store.kind)} | |
| 151 | − /> | |
| 152 | − ))} | |
| 153 | − </div> | |
| 154 | − ) | |
| 155 | − } | |
| 156 | − </LoadableBlock> | |
| 157 | − </section> | |
| 158 | − | |
| 159 | − <section className="space-y-4"> | |
| 160 | − <div> | |
| 161 | − <h2 className="text-sm font-semibold text-foreground">Managed Secrets</h2> | |
| 162 | − <p className="mt-1 text-[13px] text-muted-foreground"> | |
| 163 | − Secret records stay stable even if their underlying store handle changes. | |
| 164 | − </p> | |
| 165 | − </div> | |
| 166 | − | |
| 167 | − {showCreateSecret && ( | |
| 168 | − <CreateSecretForm | |
| 169 | − className="mb-2" | |
| 170 | − onClose={() => setShowCreateSecret(false)} | |
| 171 | − storeOptions={secretStores.status === "ready" ? secretStores.data : []} | |
| 172 | − defaultStoreId={ | |
| 173 | − instanceConfig.status === "ready" | |
| 174 | − ? instanceConfig.data.defaultSecretStoreId | |
| 175 | − : null | |
| 176 | − } | |
| 177 | − /> | |
| 178 | − )} | |
| 179 | − | |
| 180 | − <LoadableBlock loadable={secrets} loading="Loading secrets..."> | |
| 181 | − {(items) => | |
| 182 | − items.length === 0 && !showCreateSecret ? ( | |
| 183 | − <SectionEmptyState | |
| 184 | − title="No secrets stored" | |
| 185 | − description="Add a secret to use it in source authentication and runtime resolution." | |
| 186 | − actionLabel="Add secret" | |
| 187 | − onAction={() => { | |
| 188 | − setShowCreateSecret(true); | |
| 189 | − setEditingId(null); | |
| 190 | − }} | |
| 191 | − /> | |
| 192 | − ) : ( | |
| 193 | − <Card className="overflow-hidden p-0"> | |
| 194 | − {items.map((secret, index) => ( | |
| 195 | − <div | |
| 196 | − key={secret.id} | |
| 197 | − className={cn( | |
| 198 | − "px-5 py-3.5", | |
| 199 | − index > 0 && "border-t border-border", | |
| 200 | − )} | |
| 201 | − > | |
| 202 | − <SecretRow | |
| 203 | − secret={secret} | |
| 204 | − isEditing={editingId === secret.id} | |
| 205 | − onEdit={() => | |
| 206 | − setEditingId(editingId === secret.id ? null : secret.id)} | |
| 207 | − onCancelEdit={() => setEditingId(null)} | |
| 208 | − /> | |
| 209 | − </div> | |
| 210 | − ))} | |
| 211 | − </Card> | |
| 212 | − ) | |
| 213 | − } | |
| 214 | − </LoadableBlock> | |
| 215 | − </section> | |
| 216 | − </div> | |
| 217 | − </div> | |
| 218 | − ); | |
| 219 | −} | |
| 220 | − | |
| 221 | −function CreateSecretStoreForm(props: { | |
| 222 | − className?: string; | |
| 223 | − onClose: () => void; | |
| 224 | − pluginOptions: ReadonlyArray<{ | |
| 225 | − kind: string; | |
| 226 | − displayName: string; | |
| 227 | − canCreate: boolean; | |
| 228 | − }>; | |
| 229 | − secrets: Loadable<ReadonlyArray<SecretListItem>>; | |
| 230 | −}) { | |
| 231 | − const createSecretStore = useCreateSecretStore(); | |
| 232 | − const [kind, setKind] = useState(props.pluginOptions[0]?.kind ?? ""); | |
| 233 | − const [name, setName] = useState(""); | |
| 234 | − const [error, setError] = useState<string | null>(null); | |
| 235 | − const selectedFrontendPlugin = getSecretStoreFrontendPlugin(kind); | |
| 236 | − const StoreCreateForm = selectedFrontendPlugin?.secretStore?.CreateStoreForm; | |
| 237 | − | |
| 238 | − useEffect(() => { | |
| 239 | − if (kind.length > 0 || props.pluginOptions.length === 0) { | |
| 240 | − return; | |
| 241 | − } | |
| 242 | − setKind(props.pluginOptions[0]!.kind); | |
| 243 | − }, [kind, props.pluginOptions]); | |
| 244 | − | |
| 245 | − const handleSubmit = async () => { | |
| 246 | − setError(null); | |
| 247 | − | |
| 248 | − const trimmedName = name.trim(); | |
| 249 | − if (!trimmedName) { | |
| 250 | − setError("Store name is required."); | |
| 251 | − return; | |
| 252 | − } | |
| 253 | − | |
| 254 | − try { | |
| 255 | − await createSecretStore.mutateAsync({ | |
| 256 | − kind, | |
| 257 | − name: trimmedName, | |
| 258 | − config: {}, | |
| 259 | − }); | |
| 260 | − props.onClose(); | |
| 261 | − } catch (cause) { | |
| 262 | − setError( | |
| 263 | − cause instanceof Error ? cause.message : "Failed creating secret store.", | |
| 264 | − ); | |
| 265 | − } | |
| 266 | − }; | |
| 267 | − | |
| 268 | − return ( | |
| 269 | − <FormCard | |
| 270 | − className={props.className} | |
| 271 | − title="New secret store" | |
| 272 | − onClose={props.onClose} | |
| 273 | − > | |
| 274 | − {error && <ErrorBanner>{error}</ErrorBanner>} | |
| 275 | − {props.pluginOptions.length === 0 ? ( | |
| 276 | − <div className="rounded-lg border border-border bg-background/40 px-4 py-3 text-[13px] text-muted-foreground"> | |
| 277 | − No external secret store plugins are available in this runtime. | |
| 278 | − </div> | |
| 279 | − ) : ( | |
| 280 | − <> | |
| 281 | − <div className="grid gap-4 sm:grid-cols-2"> | |
| 282 | − <div className="grid gap-2"> | |
| 283 | − <Label>Store type</Label> | |
| 284 | − <Select | |
| 285 | − value={kind} | |
| 286 | − onChange={(event) => setKind(event.target.value)} | |
| 287 | − > | |
| 288 | − {props.pluginOptions.map((plugin) => ( | |
| 289 | − <option key={plugin.kind} value={plugin.kind}> | |
| 290 | − {plugin.displayName} | |
| 291 | − </option> | |
| 292 | − ))} | |
| 293 | − </Select> | |
| 294 | − </div> | |
| 295 | − {!StoreCreateForm && ( | |
| 296 | − <div className="grid gap-2"> | |
| 297 | − <Label>Name</Label> | |
| 298 | − <Input | |
| 299 | − value={name} | |
| 300 | − onChange={(event) => setName(event.target.value)} | |
| 301 | − placeholder="Secret store" | |
| 302 | − autoFocus | |
| 303 | − /> | |
| 304 | − </div> | |
| 305 | − )} | |
| 306 | − </div> | |
| 307 | − | |
| 308 | − {StoreCreateForm ? ( | |
| 309 | − <StoreCreateForm | |
| 310 | − isSubmitting={createSecretStore.status === "pending"} | |
| 311 | − onCancel={props.onClose} | |
| 312 | − onSubmit={async (input) => { | |
| 313 | − await createSecretStore.mutateAsync({ | |
| 314 | − kind, | |
| 315 | − name: input.name, | |
| 316 | − config: input.config, | |
| 317 | − }); | |
| 318 | − props.onClose(); | |
| 319 | − }} | |
| 320 | − secrets={props.secrets} | |
| 321 | − /> | |
| 322 | − ) : ( | |
| 323 | − <div className="flex justify-end"> | |
| 324 | − <Button | |
| 325 | − size="sm" | |
| 326 | − onClick={handleSubmit} | |
| 327 | − disabled={createSecretStore.status === "pending"} | |
| 328 | − > | |
| 329 | − {createSecretStore.status === "pending" | |
| 330 | − ? <IconSpinner className="size-3.5" /> | |
| 331 | − : <IconPlus className="size-3.5" />} | |
| 332 | − Create store | |
| 333 | − </Button> | |
| 334 | − </div> | |
| 335 | − )} | |
| 336 | − </> | |
| 337 | − )} | |
| 338 | − </FormCard> | |
| 339 | − ); | |
| 340 | −} | |
| 341 | − | |
| 342 | −function CreateSecretForm(props: { | |
| 343 | − className?: string; | |
| 344 | − onClose: () => void; | |
| 345 | − storeOptions: ReadonlyArray<SecretStore>; | |
| 346 | − defaultStoreId: string | null; | |
| 347 | −}) { | |
| 348 | − const createSecret = useCreateSecret(); | |
| 349 | − const refreshSecrets = useRefreshSecrets(); | |
| 350 | − const [mode, setMode] = useState<"create" | "import">("create"); | |
| 351 | − const [name, setName] = useState(""); | |
| 352 | − const [value, setValue] = useState(""); | |
| 353 | − const [storeId, setStoreId] = useState(props.defaultStoreId ?? ""); | |
| 354 | − const [browserStack, setBrowserStack] = useState<ReadonlyArray<SecretStoreBrowserCrumb>>( | |
| 355 | − [], | |
| 356 | − ); | |
| 357 | − const [browserQuery, setBrowserQuery] = useState(""); | |
| 358 | − const [browserEntries, setBrowserEntries] = useState< | |
| 359 | − ReadonlyArray<SecretStoreBrowserEntry> | |
| 360 | − >([]); | |
| 361 | − const [browserStatus, setBrowserStatus] = useState<"idle" | "pending">("idle"); | |
| 362 | − const [browserError, setBrowserError] = useState<string | null>(null); | |
| 363 | − const [selectedImportKey, setSelectedImportKey] = useState(""); | |
| 364 | − const [selectedImportLabel, setSelectedImportLabel] = useState(""); | |
| 365 | − const [error, setError] = useState<string | null>(null); | |
| 366 | − const selectedStore = props.storeOptions.find((store) => store.id === storeId) ?? null; | |
| 367 | − const canImportSecrets = canBrowseAndImportStore(selectedStore); | |
| 368 | − const canCreateSecrets = selectedStore?.capabilities.canCreateSecrets !== false; | |
| 369 | − const currentParentKey = browserStack[browserStack.length - 1]?.key ?? null; | |
| 370 | − | |
| 371 | − const browseStore = useCallback( | |
| 372 | − async (input: { | |
| 373 | − storeId: string; | |
| 374 | − parentKey?: string | null; | |
| 375 | − query?: string | null; | |
| 376 | − }) => { | |
| 377 | − const response = await fetch( | |
| 378 | − `${getExecutorApiBaseUrl()}/v1/local/secret-stores/${input.storeId}/browse`, | |
| 379 | − { | |
| 380 | − method: "POST", | |
| 381 | − headers: { | |
| 382 | − "content-type": "application/json", | |
| 383 | − }, | |
| 384 | − body: JSON.stringify({ | |
| 385 | − ...(input.parentKey ? { parentKey: input.parentKey } : {}), | |
| 386 | − ...(input.query?.trim() ? { query: input.query.trim() } : {}), | |
| 387 | − }), | |
| 388 | − }, | |
| 389 | − ); | |
| 390 | − | |
| 391 | − if (!response.ok) { | |
| 392 | − let message = "Failed browsing secret store."; | |
| 393 | − try { | |
| 394 | − const payload = await response.json() as { | |
| 395 | − message?: string; | |
| 396 | − details?: string; | |
| 397 | − }; | |
| 398 | − message = payload.message ?? payload.details ?? message; | |
| 399 | − } catch { | |
| 400 | − // ignore response parsing errors | |
| 401 | − } | |
| 402 | − throw new Error(message); | |
| 403 | − } | |
| 404 | − | |
| 405 | − return await response.json() as BrowseSecretStoreResult; | |
| 406 | − }, | |
| 407 | − [], | |
| 408 | − ); | |
| 409 | − const importSecretMutation = useExecutorMutation<void, { id: string }>(async () => { | |
| 410 | − const response = await fetch( | |
| 411 | − `${getExecutorApiBaseUrl()}/v1/local/secret-stores/${storeId}/import`, | |
| 412 | − { | |
| 413 | − method: "POST", | |
| 414 | − headers: { | |
| 415 | − "content-type": "application/json", | |
| 416 | − }, | |
| 417 | − body: JSON.stringify({ | |
| 418 | − selectionKey: selectedImportKey, | |
| 419 | − ...(name.trim() ? { name: name.trim() } : {}), | |
| 420 | − }), | |
| 421 | − }, | |
| 422 | − ); | |
| 423 | − | |
| 424 | − if (!response.ok) { | |
| 425 | − let message = "Failed importing secret."; | |
| 426 | − try { | |
| 427 | − const payload = await response.json() as { | |
| 428 | − message?: string; | |
| 429 | − details?: string; | |
| 430 | − }; | |
| 431 | − message = payload.message ?? payload.details ?? message; | |
| 432 | − } catch { | |
| 433 | − // ignore response parsing errors | |
| 434 | − } | |
| 435 | − throw new Error(message); | |
| 436 | − } | |
| 437 | − | |
| 438 | − return await response.json() as { id: string }; | |
| 439 | − }); | |
| 440 | − | |
| 441 | − useEffect(() => { | |
| 442 | − if (storeId.length > 0) { | |
| 443 | − return; | |
| 444 | − } | |
| 445 | − if (props.defaultStoreId) { | |
| 446 | − setStoreId(props.defaultStoreId); | |
| 447 | − return; | |
| 448 | − } | |
| 449 | − if (props.storeOptions.length > 0) { | |
| 450 | − setStoreId(props.storeOptions[0]!.id); | |
| 451 | − } | |
| 452 | − }, [props.defaultStoreId, props.storeOptions, storeId]); | |
| 453 | − | |
| 454 | − useEffect(() => { | |
| 455 | − setBrowserStack([]); | |
| 456 | − setBrowserQuery(""); | |
| 457 | − setBrowserEntries([]); | |
| 458 | − setBrowserStatus("idle"); | |
| 459 | − setBrowserError(null); | |
| 460 | − setSelectedImportKey(""); | |
| 461 | − setSelectedImportLabel(""); | |
| 462 | − if (canImportSecrets && !canCreateSecrets) { | |
| 463 | − setMode("import"); | |
| 464 | − return; | |
| 465 | − } | |
| 466 | − if (!canImportSecrets && canCreateSecrets) { | |
| 467 | − setMode("create"); | |
| 468 | − return; | |
| 469 | − } | |
| 470 | − if (canImportSecrets) { | |
| 471 | − setMode("import"); | |
| 472 | − return; | |
| 473 | − } | |
| 474 | − setMode("create"); | |
| 475 | − }, [canCreateSecrets, canImportSecrets, selectedStore?.id]); | |
| 476 | − | |
| 477 | − useEffect(() => { | |
| 478 | − if (mode !== "import" || !canImportSecrets || !storeId) { | |
| 479 | − return; | |
| 480 | − } | |
| 481 | − | |
| 482 | − let active = true; | |
| 483 | − setBrowserStatus("pending"); | |
| 484 | − void browseStore({ | |
| 485 | − storeId, | |
| 486 | − parentKey: currentParentKey, | |
| 487 | − query: browserQuery, | |
| 488 | − }) | |
| 489 | − .then((result) => { | |
| 490 | − if (!active) { | |
| 491 | − return; | |
| 492 | − } | |
| 493 | − setBrowserEntries(result.entries); | |
| 494 | − setBrowserError(null); | |
| 495 | − setBrowserStatus("idle"); | |
| 496 | − }) | |
| 497 | − .catch((cause) => { | |
| 498 | − if (!active) { | |
| 499 | − return; | |
| 500 | − } | |
| 501 | − setBrowserEntries([]); | |
| 502 | − setBrowserError( | |
| 503 | − cause instanceof Error ? cause.message : "Failed browsing secret store.", | |
| 504 | − ); | |
| 505 | − setBrowserStatus("idle"); | |
| 506 | − }); | |
| 507 | − | |
| 508 | − return () => { | |
| 509 | − active = false; | |
| 510 | − }; | |
| 511 | − }, [browserQuery, browseStore, canImportSecrets, currentParentKey, mode, storeId]); | |
| 512 | − | |
| 513 | − useEffect(() => { | |
| 514 | − if (mode !== "import" || !selectedImportLabel || name.trim().length > 0) { | |
| 515 | − return; | |
| 516 | − } | |
| 517 | − setName(selectedImportLabel); | |
| 518 | − }, [mode, name, selectedImportLabel]); | |
| 519 | − | |
| 520 | − const handleBrowserEntryClick = (entry: SecretStoreBrowserEntry) => { | |
| 521 | − setError(null); | |
| 522 | − if (entry.kind === "group") { | |
| 523 | − setSelectedImportKey(""); | |
| 524 | − setSelectedImportLabel(""); | |
| 525 | − setBrowserStack((current) => [...current, { | |
| 526 | − key: entry.key, | |
| 527 | − label: entry.label, | |
| 528 | − }]); | |
| 529 | − setBrowserQuery(""); | |
| 530 | − return; | |
| 531 | − } | |
| 532 | − | |
| 533 | − setSelectedImportKey(entry.key); | |
| 534 | − setSelectedImportLabel(entry.label); | |
| 535 | − }; | |
| 536 | − | |
| 537 | − const handleSubmit = async () => { | |
| 538 | − setError(null); | |
| 539 | − const trimmedName = name.trim(); | |
| 540 | − | |
| 541 | − try { | |
| 542 | − if (mode === "import") { | |
| 543 | − if (!selectedImportKey) { | |
| 544 | − setError("Select a secret to import."); | |
| 545 | − return; | |
| 546 | − } | |
| 547 | − | |
| 548 | − await importSecretMutation.mutateAsync(); | |
| 549 | − refreshSecrets(); | |
| 550 | − } else { | |
| 551 | − if (!trimmedName) { | |
| 552 | − setError("Name is required."); | |
| 553 | − return; | |
| 554 | − } | |
| 555 | − if (!value) { | |
| 556 | − setError("Value is required."); | |
| 557 | − return; | |
| 558 | − } | |
| 559 | − | |
| 560 | − await createSecret.mutateAsync({ | |
| 561 | − name: trimmedName, | |
| 562 | − value, | |
| 563 | − ...(storeId ? { storeId } : {}), | |
| 564 | − }); | |
| 565 | − } | |
| 566 | − | |
| 567 | − props.onClose(); | |
| 568 | − } catch (cause) { | |
| 569 | − setError(cause instanceof Error ? cause.message : "Failed creating secret."); | |
| 570 | − } | |
| 571 | − }; | |
| 572 | − | |
| 573 | − return ( | |
| 574 | − <FormCard | |
| 575 | − className={props.className} | |
| 576 | − title="New managed secret" | |
| 577 | − onClose={props.onClose} | |
| 578 | − > | |
| 579 | − {error && <ErrorBanner>{error}</ErrorBanner>} | |
| 580 | − <div className="grid gap-4 sm:grid-cols-2"> | |
| 581 | − <div className="grid gap-2"> | |
| 582 | − <Label>Store</Label> | |
| 583 | − <Select | |
| 584 | − value={storeId} | |
| 585 | − onChange={(event) => setStoreId(event.target.value)} | |
| 586 | − > | |
| 587 | − {props.storeOptions.map((store) => ( | |
| 588 | − <option key={store.id} value={store.id}> | |
| 589 | − {store.name} | |
| 590 | − </option> | |
| 591 | − ))} | |
| 592 | − </Select> | |
| 593 | − </div> | |
| 594 | − {canImportSecrets && canCreateSecrets && ( | |
| 595 | − <div className="grid gap-2"> | |
| 596 | − <Label>Mode</Label> | |
| 597 | − <Select | |
| 598 | − value={mode} | |
| 599 | − onChange={(event) => setMode(event.target.value as "create" | "import")} | |
| 600 | − > | |
| 601 | − <option value="import">Import from store</option> | |
| 602 | − <option value="create">Create new secret</option> | |
| 603 | − </Select> | |
| 604 | − </div> | |
| 605 | − )} | |
| 606 | − <div className="grid gap-2"> | |
| 607 | − <Label>Name</Label> | |
| 608 | − <Input | |
| 609 | − value={name} | |
| 610 | − onChange={(event) => setName(event.target.value)} | |
| 611 | − placeholder={mode === "import" ? "Optional override name" : "GitHub PAT"} | |
| 612 | − autoFocus | |
| 613 | − /> | |
| 614 | − </div> | |
| 615 | − {mode === "create" && ( | |
| 616 | − <div className="grid gap-2"> | |
| 617 | − <Label>Value</Label> | |
| 618 | − <Input | |
| 619 | − type="password" | |
| 620 | − value={value} | |
| 621 | − onChange={(event) => setValue(event.target.value)} | |
| 622 | − placeholder="ghp_..." | |
| 623 | − className="font-mono text-[12px]" | |
| 624 | − /> | |
| 625 | − </div> | |
| 626 | − )} | |
| 627 | − </div> | |
| 628 | − {mode === "import" && canImportSecrets && ( | |
| 629 | − <div className="mt-4 space-y-4"> | |
| 630 | − <div className="flex flex-wrap items-center gap-2"> | |
| 631 | − {browserStack.length > 0 && ( | |
| 632 | − <Button | |
| 633 | − size="sm" | |
| 634 | − variant="outline" | |
| 635 | − onClick={() => { | |
| 636 | − setSelectedImportKey(""); | |
| 637 | − setSelectedImportLabel(""); | |
| 638 | − setBrowserStack((current) => current.slice(0, -1)); | |
| 639 | − }} | |
| 640 | − > | |
| 641 | − Back | |
| 642 | − </Button> | |
| 643 | − )} | |
| 644 | − <Input | |
| 645 | − value={browserQuery} | |
| 646 | − onChange={(event) => setBrowserQuery(event.target.value)} | |
| 647 | − placeholder="Search this store" | |
| 648 | − className="min-w-0 flex-1" | |
| 649 | − /> | |
| 650 | − </div> | |
| 651 | − {browserStack.length > 0 && ( | |
| 652 | − <div className="text-[11px] text-muted-foreground"> | |
| 653 | − {browserStack.map((crumb, index) => ( | |
| 654 | − <span key={crumb.key}> | |
| 655 | − {index > 0 ? " / " : ""} | |
| 656 | − {crumb.label} | |
| 657 | − </span> | |
| 658 | − ))} | |
| 659 | − </div> | |
| 660 | − )} | |
| 661 | − <div className="rounded-xl border border-border bg-background/40"> | |
| 662 | − {browserStatus === "pending" ? ( | |
| 663 | − <div className="flex items-center gap-2 px-4 py-3 text-[13px] text-muted-foreground"> | |
| 664 | − <IconSpinner className="size-3.5" /> | |
| 665 | − Loading store contents... | |
| 666 | − </div> | |
| 667 | − ) : browserEntries.length === 0 ? ( | |
| 668 | − <div className="px-4 py-3 text-[13px] text-muted-foreground"> | |
| 669 | − {browserError ?? "No importable secrets found here."} | |
| 670 | − </div> | |
| 671 | − ) : ( | |
| 672 | − browserEntries.map((entry, index) => ( | |
| 673 | − <Button | |
| 674 | − key={entry.key} | |
| 675 | − variant="ghost" | |
| 676 | − onClick={() => handleBrowserEntryClick(entry)} | |
| 677 | − className={cn( | |
| 678 | − "flex h-auto w-full items-center justify-between gap-3 rounded-none px-4 py-3 text-left", | |
| 679 | − index > 0 && "border-t border-border", | |
| 680 | − selectedImportKey === entry.key && "bg-accent/60", | |
| 681 | − )} | |
| 682 | − > | |
| 683 | − <div className="min-w-0"> | |
| 684 | − <div className="truncate text-[13px] font-medium text-foreground"> | |
| 685 | − {entry.label} | |
| 686 | − </div> | |
| 687 | − {entry.description && ( | |
| 688 | − <div className="truncate text-[11px] text-muted-foreground"> | |
| 689 | − {entry.description} | |
| 690 | − </div> | |
| 691 | − )} | |
| 692 | − </div> | |
| 693 | − <Badge variant="outline"> | |
| 694 | − {entry.kind === "group" ? "Open" : "Secret"} | |
| 695 | − </Badge> | |
| 696 | − </Button> | |
| 697 | − )) | |
| 698 | − )} | |
| 699 | − </div> | |
| 700 | − {browserError && browserEntries.length > 0 && ( | |
| 701 | − <div className="text-[12px] text-destructive">{browserError}</div> | |
| 702 | − )} | |
| 703 | − </div> | |
| 704 | − )} | |
| 705 | − <div className="flex justify-end"> | |
| 706 | − <Button | |
| 707 | − size="sm" | |
| 708 | − onClick={handleSubmit} | |
| 709 | − disabled={createSecret.status === "pending" || importSecretMutation.status === "pending"} | |
| 710 | − > | |
| 711 | − {(createSecret.status === "pending" || importSecretMutation.status === "pending") | |
| 712 | − ? <IconSpinner className="size-3.5" /> | |
| 713 | − : <IconPlus className="size-3.5" />} | |
| 714 | − {mode === "import" ? "Import secret" : "Store secret"} | |
| 715 | − </Button> | |
| 716 | − </div> | |
| 717 | − </FormCard> | |
| 718 | − ); | |
| 719 | −} | |
| 720 | − | |
| 721 | −function SecretStoreCard(props: { | |
| 722 | − store: SecretStore; | |
| 723 | − canManage: boolean; | |
| 724 | −}) { | |
| 725 | − const deleteSecretStore = useDeleteSecretStore(); | |
| 726 | − const [confirmDelete, setConfirmDelete] = useState(false); | |
| 727 | − const [isDeleting, setIsDeleting] = useState(false); | |
| 728 | − | |
| 729 | − const handleDelete = async () => { | |
| 730 | − setIsDeleting(true); | |
| 731 | − try { | |
| 732 | − await deleteSecretStore.mutateAsync(props.store.id); | |
| 733 | − } catch { | |
| 734 | − // refresh state will keep the store visible | |
| 735 | − } finally { | |
| 736 | − setIsDeleting(false); | |
| 737 | − setConfirmDelete(false); | |
| 738 | − } | |
| 739 | − }; | |
| 740 | − | |
| 741 | − return ( | |
| 742 | − <Card className="p-4"> | |
| 743 | − <div className="flex items-start justify-between gap-3"> | |
| 744 | − <div className="min-w-0"> | |
| 745 | − <div className="flex flex-wrap items-center gap-2"> | |
| 746 | − <span className="truncate text-[13px] font-medium text-foreground"> | |
| 747 | − {props.store.name} | |
| 748 | − </span> | |
| 749 | − <Badge variant="outline" className="text-[9px] uppercase"> | |
| 750 | − {props.store.kind} | |
| 751 | − </Badge> | |
| 752 | − <Badge variant="outline" className="text-[9px]"> | |
| 753 | − {props.store.status} | |
| 754 | − </Badge> | |
| 755 | − </div> | |
| 756 | − <div className="mt-1 flex flex-wrap items-center gap-2 text-[11px] text-muted-foreground/55"> | |
| 757 | − <span className="font-mono">{props.store.id}</span> | |
| 758 | − <span>Created {formatDate(props.store.createdAt)}</span> | |
| 759 | − </div> | |
| 760 | − </div> | |
| 761 | − {props.canManage ? ( | |
| 762 | − confirmDelete ? ( | |
| 763 | − <div className="flex items-center gap-1"> | |
| 764 | − <Button | |
| 765 | − variant="ghost" | |
| 766 | − size="sm" | |
| 767 | − onClick={() => setConfirmDelete(false)} | |
| 768 | − disabled={isDeleting} | |
| 769 | − > | |
| 770 | − Cancel | |
| 771 | − </Button> | |
| 772 | − <Button | |
| 773 | − variant="destructive-outline" | |
| 774 | − size="sm" | |
| 775 | − onClick={() => { | |
| 776 | − void handleDelete(); | |
| 777 | − }} | |
| 778 | − disabled={isDeleting} | |
| 779 | − > | |
| 780 | − {isDeleting | |
| 781 | − ? <IconSpinner className="size-3" /> | |
| 782 | − : <IconTrash className="size-3" />} | |
| 783 | − Delete | |
| 784 | − </Button> | |
| 785 | − </div> | |
| 786 | − ) : ( | |
| 787 | − <Button | |
| 788 | − variant="ghost" | |
| 789 | − size="sm" | |
| 790 | − onClick={() => setConfirmDelete(true)} | |
| 791 | − disabled={isDeleting} | |
| 792 | − className="text-muted-foreground hover:bg-destructive/8 hover:text-destructive" | |
| 793 | − > | |
| 794 | − {isDeleting | |
| 795 | − ? <IconSpinner className="size-3" /> | |
| 796 | − : <IconTrash className="size-3" />} | |
| 797 | − Remove | |
| 798 | − </Button> | |
| 799 | − ) | |
| 800 | − ) : ( | |
| 801 | − <span className="text-[10px] font-medium uppercase tracking-[0.12em] text-muted-foreground/45"> | |
| 802 | − Built-in | |
| 803 | − </span> | |
| 804 | − )} | |
| 805 | − </div> | |
| 806 | − </Card> | |
| 807 | − ); | |
| 808 | −} | |
| 809 | − | |
| 810 | −function SecretRow(props: { | |
| 811 | − secret: SecretListItem; | |
| 812 | − isEditing: boolean; | |
| 813 | − onEdit: () => void; | |
| 814 | − onCancelEdit: () => void; | |
| 815 | −}) { | |
| 816 | − const deleteSecret = useDeleteSecret(); | |
| 817 | − const [isDeleting, setIsDeleting] = useState(false); | |
| 818 | − const [confirmDelete, setConfirmDelete] = useState(false); | |
| 819 | − | |
| 820 | − const handleDelete = async () => { | |
| 821 | − setIsDeleting(true); | |
| 822 | − try { | |
| 823 | − await deleteSecret.mutateAsync(props.secret.id); | |
| 824 | − } catch { | |
| 825 | − // refresh state will keep the secret visible | |
| 826 | − } finally { | |
| 827 | − setIsDeleting(false); | |
| 828 | − setConfirmDelete(false); | |
| 829 | − } | |
| 830 | − }; | |
| 831 | − | |
| 832 | − return ( | |
| 833 | − <> | |
| 834 | − <div className="flex items-center justify-between gap-4"> | |
| 835 | − <div className="min-w-0"> | |
| 836 | − <div className="flex flex-wrap items-center gap-2"> | |
| 837 | − <span className="truncate text-[13px] font-medium text-foreground"> | |
| 838 | − {props.secret.name || "Unnamed secret"} | |
| 839 | − </span> | |
| 840 | − <Badge variant="outline" className="text-[9px] shrink-0"> | |
| 841 | − {props.secret.purpose.replace(/_/g, " ")} | |
| 842 | − </Badge> | |
| 843 | − <Badge variant="outline" className="text-[9px] shrink-0"> | |
| 844 | − {props.secret.storeName} | |
| 845 | − </Badge> | |
| 846 | − <Badge variant="outline" className="text-[9px] shrink-0 uppercase"> | |
| 847 | − {props.secret.storeKind} | |
| 848 | − </Badge> | |
| 849 | − </div> | |
| 850 | − <div className="mt-0.5 flex flex-wrap items-center gap-2 text-[11px] text-muted-foreground/50"> | |
| 851 | − <span className="font-mono">{props.secret.id}</span> | |
| 852 | − <span>{formatDate(props.secret.createdAt)}</span> | |
| 853 | − </div> | |
| 854 | − {props.secret.linkedSources.length > 0 && ( | |
| 855 | − <div className="mt-1 flex flex-wrap items-center gap-1.5"> | |
| 856 | − <span className="text-[10px] text-muted-foreground/50">Used by</span> | |
| 857 | − {props.secret.linkedSources.map((linkedSource) => ( | |
| 858 | − <span | |
| 859 | − key={linkedSource.sourceId} | |
| 860 | − className="inline-flex items-center rounded-md bg-accent/60 px-1.5 py-0.5 text-[10px] font-medium text-foreground/70" | |
| 861 | − > | |
| 862 | − {linkedSource.sourceName} | |
| 863 | − </span> | |
| 864 | − ))} | |
| 865 | − </div> | |
| 866 | − )} | |
| 867 | − </div> | |
| 868 | − <div className="flex shrink-0 items-center gap-1.5"> | |
| 869 | − <Button | |
| 870 | − variant="ghost" | |
| 871 | − size="sm" | |
| 872 | − onClick={props.onEdit} | |
| 873 | − className={cn( | |
| 874 | − props.isEditing | |
| 875 | − ? "bg-primary/10 text-primary" | |
| 876 | − : "text-muted-foreground hover:bg-accent/50 hover:text-foreground", | |
| 877 | − )} | |
| 878 | − > | |
| 879 | − <IconPencil className="size-3" /> | |
| 880 | − Edit | |
| 881 | − </Button> | |
| 882 | − {confirmDelete ? ( | |
| 883 | − <> | |
| 884 | − <Button | |
| 885 | − variant="ghost" | |
| 886 | − size="sm" | |
| 887 | − onClick={() => setConfirmDelete(false)} | |
| 888 | − disabled={isDeleting} | |
| 889 | − > | |
| 890 | − Cancel | |
| 891 | − </Button> | |
| 892 | − <Button | |
| 893 | − variant="destructive-outline" | |
| 894 | − size="sm" | |
| 895 | − onClick={() => { | |
| 896 | − void handleDelete(); | |
| 897 | − }} | |
| 898 | − disabled={isDeleting} | |
| 899 | − > | |
| 900 | − {isDeleting | |
| 901 | − ? <IconSpinner className="size-3" /> | |
| 902 | − : <IconTrash className="size-3" />} | |
| 903 | − Delete | |
| 904 | − </Button> | |
| 905 | − </> | |
| 906 | − ) : ( | |
| 907 | − <Button | |
| 908 | − variant="ghost" | |
| 909 | − size="sm" | |
| 910 | − onClick={() => setConfirmDelete(true)} | |
| 911 | − disabled={isDeleting} | |
| 912 | − className="text-muted-foreground hover:bg-destructive/8 hover:text-destructive" | |
| 913 | − > | |
| 914 | − {isDeleting | |
| 915 | − ? <IconSpinner className="size-3" /> | |
| 916 | − : <IconTrash className="size-3" />} | |
| 917 | − Delete | |
| 918 | − </Button> | |
| 919 | − )} | |
| 920 | − </div> | |
| 921 | − </div> | |
| 922 | − | |
| 923 | − {props.isEditing && ( | |
| 924 | − <EditSecretForm secret={props.secret} onClose={props.onCancelEdit} /> | |
| 925 | − )} | |
| 926 | − </> | |
| 927 | − ); | |
| 928 | −} | |
| 929 | − | |
| 930 | −function EditSecretForm(props: { | |
| 931 | − secret: SecretListItem; | |
| 932 | − onClose: () => void; | |
| 933 | −}) { | |
| 934 | − const updateSecret = useUpdateSecret(); | |
| 935 | − const [name, setName] = useState(props.secret.name ?? ""); | |
| 936 | − const [value, setValue] = useState(""); | |
| 937 | − const [error, setError] = useState<string | null>(null); | |
| 938 | − | |
| 939 | − const handleSubmit = async () => { | |
| 940 | − setError(null); | |
| 941 | − | |
| 942 | − const payload: { name?: string; value?: string } = {}; | |
| 943 | − const trimmedName = name.trim(); | |
| 944 | − if (trimmedName && trimmedName !== (props.secret.name ?? "")) { | |
| 945 | − payload.name = trimmedName; | |
| 946 | − } | |
| 947 | − if (value.length > 0) { | |
| 948 | − payload.value = value; | |
| 949 | − } | |
| 950 | − if (Object.keys(payload).length === 0) { | |
| 951 | − props.onClose(); | |
| 952 | − return; | |
| 953 | − } | |
| 954 | − | |
| 955 | − try { | |
| 956 | − await updateSecret.mutateAsync({ | |
| 957 | − secretId: props.secret.id, | |
| 958 | − payload, | |
| 959 | − }); | |
| 960 | − props.onClose(); | |
| 961 | − } catch (cause) { | |
| 962 | − setError(cause instanceof Error ? cause.message : "Failed updating secret."); | |
| 963 | − } | |
| 964 | − }; | |
| 965 | − | |
| 966 | − return ( | |
| 967 | − <div className="mt-3 border-t border-border/50 pt-3"> | |
| 968 | − {error && <ErrorBanner className="mb-3">{error}</ErrorBanner>} | |
| 969 | − <div className="grid gap-3 sm:grid-cols-2"> | |
| 970 | − <div className="grid gap-2"> | |
| 971 | − <Label>Name</Label> | |
| 972 | − <Input | |
| 973 | − value={name} | |
| 974 | − onChange={(event) => setName(event.target.value)} | |
| 975 | − placeholder="Secret name" | |
| 976 | − className="h-8 text-[12px]" | |
| 977 | − autoFocus | |
| 978 | − /> | |
| 979 | − </div> | |
| 980 | − <div className="grid gap-2"> | |
| 981 | − <Label>New value</Label> | |
| 982 | − <Input | |
| 983 | − type="password" | |
| 984 | − value={value} | |
| 985 | − onChange={(event) => setValue(event.target.value)} | |
| 986 | − placeholder="Leave empty to keep existing" | |
| 987 | − className="h-8 font-mono text-[11px]" | |
| 988 | − /> | |
| 989 | − </div> | |
| 990 | − </div> | |
| 991 | − <div className="mt-3 flex items-center justify-end gap-2"> | |
| 992 | − <Button | |
| 993 | − variant="ghost" | |
| 994 | − size="sm" | |
| 995 | − onClick={props.onClose} | |
| 996 | − > | |
| 997 | − Cancel | |
| 998 | − </Button> | |
| 999 | − <Button | |
| 1000 | − size="sm" | |
| 1001 | − onClick={handleSubmit} | |
| 1002 | − disabled={updateSecret.status === "pending"} | |
| 1003 | − > | |
| 1004 | − {updateSecret.status === "pending" && <IconSpinner className="size-3" />} | |
| 1005 | − Save | |
| 1006 | − </Button> | |
| 1007 | − </div> | |
| 1008 | − </div> | |
| 1009 | − ); | |
| 1010 | −} | |
| 1011 | − | |
| 1012 | −function FormCard(props: { | |
| 1013 | − title: string; | |
| 1014 | − onClose: () => void; | |
| 1015 | − className?: string; | |
| 1016 | − children: ReactNode; | |
| 1017 | −}) { | |
| 1018 | − return ( | |
| 1019 | − <Card className={cn("border-primary/20 p-0", props.className)}> | |
| 1020 | − <div className="flex items-center justify-between border-b border-border px-5 py-3"> | |
| 1021 | − <h3 className="text-sm font-semibold text-foreground">{props.title}</h3> | |
| 1022 | − <Button | |
| 1023 | − variant="ghost" | |
| 1024 | − size="sm" | |
| 1025 | − onClick={props.onClose} | |
| 1026 | − > | |
| 1027 | − Cancel | |
| 1028 | − </Button> | |
| 1029 | − </div> | |
| 1030 | − <div className="space-y-4 p-5">{props.children}</div> | |
| 1031 | − </Card> | |
| 1032 | − ); | |
| 1033 | −} | |
| 1034 | − | |
| 1035 | −function ErrorBanner(props: { | |
| 1036 | − children: ReactNode; | |
| 1037 | − className?: string; | |
| 1038 | −}) { | |
| 1039 | − return ( | |
| 1040 | − <Alert variant="destructive" className={cn("text-[13px]", props.className)}> | |
| 1041 | − {props.children} | |
| 1042 | − </Alert> | |
| 1043 | − ); | |
| 1044 | −} | |
| 1045 | − | |
| 1046 | −function SectionEmptyState(props: { | |
| 1047 | − title: string; | |
| 1048 | − description: string; | |
| 1049 | − actionLabel?: string; | |
| 1050 | − onAction?: () => void; | |
| 1051 | −}) { | |
| 1052 | − return ( | |
| 1053 | − <div className="rounded-xl border border-dashed border-border px-6 py-10 text-center"> | |
| 1054 | − <p className="text-[14px] font-medium text-foreground/75">{props.title}</p> | |
| 1055 | − <p className="mt-1 text-[13px] text-muted-foreground">{props.description}</p> | |
| 1056 | − {props.actionLabel && props.onAction && ( | |
| 1057 | − <div className="mt-4 flex justify-center"> | |
| 1058 | − <Button size="sm" onClick={props.onAction}> | |
| 1059 | − <IconPlus className="size-3.5" /> | |
| 1060 | − {props.actionLabel} | |
| 1061 | − </Button> | |
| 1062 | − </div> | |
| 1063 | − )} | |
| 1064 | − </div> | |
| 1065 | − ); | |
| 1066 | −} | |
| 1067 | − | |
| 1068 | −const formatDate = (value: number): string => | |
| 1069 | − new Date(value).toLocaleDateString(undefined, { | |
| 1070 | − month: "short", | |
| 1071 | − day: "numeric", | |
| 1072 | − year: "numeric", | |
| 1073 | − }); | |
| @@ -1,21 +1,19 @@ | ||
| 1 | 1 | { |
| 2 | 2 | "compilerOptions": { |
| 3 | − "target": "ES2022", | |
| 3 | + "target": "ESNext", | |
| 4 | 4 | "module": "ESNext", |
| 5 | − "moduleResolution": "Bundler", | |
| 5 | + "moduleResolution": "bundler", | |
| 6 | 6 | "strict": true, |
| 7 | + "esModuleInterop": true, | |
| 7 | 8 | "skipLibCheck": true, |
| 8 | − "noEmit": true, | |
| 9 | − "lib": ["ES2022", "DOM", "DOM.Iterable"], | |
| 9 | + "outDir": "dist", | |
| 10 | + "rootDir": ".", | |
| 10 | 11 | "jsx": "react-jsx", |
| 11 | − "types": ["bun-types"], | |
| 12 | − "baseUrl": ".", | |
| 13 | − "paths": { | |
| 14 | − "@/*": ["./src/*"] | |
| 15 | − } | |
| 12 | + "plugins": [ | |
| 13 | + { | |
| 14 | + "name": "@effect/language-service" | |
| 15 | + } | |
| 16 | + ] | |
| 16 | 17 | }, |
| 17 | − "include": [ | |
| 18 | − "src/**/*.ts", | |
| 19 | − "src/**/*.tsx" | |
| 20 | − ] | |
| 18 | + "include": ["src", "vite.config.ts"] | |
| 21 | 19 | } |
| @@ -1,99 +1,196 @@ | ||
| 1 | 1 | import { readFileSync } from "node:fs"; |
| 2 | −import path from "node:path"; | |
| 2 | +import { resolve } from "node:path"; | |
| 3 | 3 | import { defineConfig } from "vite"; |
| 4 | 4 | import react from "@vitejs/plugin-react"; |
| 5 | 5 | import tailwindcss from "@tailwindcss/vite"; |
| 6 | −import devServer from "@hono/vite-dev-server"; | |
| 7 | 6 | |
| 8 | −type ExecutorPackageMetadata = { | |
| 9 | − version: string; | |
| 10 | − homepage?: string; | |
| 11 | − repository?: string | { url?: string }; | |
| 7 | +type HotBackend = { | |
| 8 | + readonly api: { | |
| 9 | + readonly handler: (request: Request) => Promise<Response>; | |
| 10 | + readonly dispose: () => Promise<void>; | |
| 11 | + }; | |
| 12 | + readonly mcp: { | |
| 13 | + readonly handleRequest: (request: Request) => Promise<Response>; | |
| 14 | + readonly close: () => Promise<void>; | |
| 15 | + }; | |
| 16 | + readonly dispose: () => Promise<void>; | |
| 12 | 17 | }; |
| 13 | 18 | |
| 14 | −const executorPackage = JSON.parse( | |
| 15 | − readFileSync(new URL("../executor/package.json", import.meta.url), "utf8"), | |
| 16 | −) as ExecutorPackageMetadata; | |
| 19 | +const DEV_BACKEND_MODULE_ID = `/@fs/${resolve( | |
| 20 | + process.cwd(), | |
| 21 | + "../server/src/dev-backend.ts", | |
| 22 | +).replace(/\\/g, "/")}`; | |
| 17 | 23 | |
| 18 | −const repositoryUrl = | |
| 19 | − typeof executorPackage.repository === "string" | |
| 20 | − ? executorPackage.repository | |
| 21 | − : executorPackage.repository?.url; | |
| 24 | +// Build a Web Request from a Node IncomingMessage | |
| 25 | +const toWebRequest = async ( | |
| 26 | + req: import("http").IncomingMessage, | |
| 27 | +): Promise<Request> => { | |
| 28 | + const headers = new Headers(); | |
| 29 | + for (const [key, value] of Object.entries(req.headers)) { | |
| 30 | + if (value === undefined) continue; | |
| 31 | + if (Array.isArray(value)) { | |
| 32 | + for (const v of value) headers.append(key, v); | |
| 33 | + } else { | |
| 34 | + headers.set(key, value); | |
| 35 | + } | |
| 36 | + } | |
| 22 | 37 | |
| 23 | −const githubUrl = (executorPackage.homepage ?? repositoryUrl ?? "https://github.com/RhysSullivan/executor") | |
| 24 | − .replace(/^git\+/, "") | |
| 25 | − .replace(/\.git$/, ""); | |
| 38 | + const host = req.headers.host ?? "localhost"; | |
| 39 | + const url = `http://${host}${req.url}`; | |
| 26 | 40 | |
| 27 | −const webPackage = JSON.parse( | |
| 28 | − readFileSync(new URL("./package.json", import.meta.url), "utf8"), | |
| 29 | −) as { | |
| 30 | − dependencies?: Record<string, string>; | |
| 41 | + return new Request(url, { | |
| 42 | + method: req.method, | |
| 43 | + headers, | |
| 44 | + body: | |
| 45 | + req.method !== "GET" && req.method !== "HEAD" | |
| 46 | + ? (await new Promise<Buffer>((resolve) => { | |
| 47 | + const chunks: Buffer[] = []; | |
| 48 | + req.on("data", (c: Buffer) => chunks.push(c)); | |
| 49 | + req.on("end", () => resolve(Buffer.concat(chunks))); | |
| 50 | + }) as unknown as BodyInit) | |
| 51 | + : undefined, | |
| 52 | + duplex: "half" as const, | |
| 53 | + }); | |
| 31 | 54 | }; |
| 32 | 55 | |
| 33 | −const workspaceExecutorPackages = Object.keys(webPackage.dependencies ?? {}).filter( | |
| 34 | − (name) => name.startsWith("@executor/"), | |
| 35 | −); | |
| 56 | +// Pipe a Web Response back to a Node ServerResponse, streaming if needed | |
| 57 | +const sendWebResponse = async ( | |
| 58 | + webRes: Response, | |
| 59 | + nodeRes: import("http").ServerResponse, | |
| 60 | +) => { | |
| 61 | + nodeRes.statusCode = webRes.status; | |
| 62 | + webRes.headers.forEach((value, key) => nodeRes.setHeader(key, value)); | |
| 36 | 63 | |
| 37 | −const pluginsWorkspaceRoot = path.resolve(import.meta.dirname, "../../plugins") + path.sep; | |
| 64 | + if (!webRes.body) { | |
| 65 | + nodeRes.end(); | |
| 66 | + return; | |
| 67 | + } | |
| 38 | 68 | |
| 39 | −const reloadOnPluginChange = () => ({ | |
| 40 | − name: "executor-reload-on-plugin-change", | |
| 41 | − handleHotUpdate({ file, server }: { file: string; server: { hot: { send: (payload: { type: "full-reload" }) => void } } }) { | |
| 42 | − if (!file.startsWith(pluginsWorkspaceRoot)) { | |
| 43 | − return; | |
| 69 | + const reader = webRes.body.getReader(); | |
| 70 | + try { | |
| 71 | + for (;;) { | |
| 72 | + const { done, value } = await reader.read(); | |
| 73 | + if (done) break; | |
| 74 | + nodeRes.write(value); | |
| 44 | 75 | } |
| 76 | + } finally { | |
| 77 | + nodeRes.end(); | |
| 78 | + } | |
| 79 | +}; | |
| 45 | 80 | |
| 46 | − server.hot.send({ type: "full-reload" }); | |
| 47 | − return []; | |
| 48 | − }, | |
| 49 | −}); | |
| 81 | +const rootPackage = JSON.parse( | |
| 82 | + readFileSync(new URL("../../package.json", import.meta.url), "utf8"), | |
| 83 | +) as { version: string; homepage?: string; repository?: string | { url?: string } }; | |
| 84 | + | |
| 85 | +const cliPackage = JSON.parse( | |
| 86 | + readFileSync(new URL("../cli/package.json", import.meta.url), "utf8"), | |
| 87 | +) as { version?: string }; | |
| 88 | + | |
| 89 | +const repositoryUrl = | |
| 90 | + typeof rootPackage.repository === "string" | |
| 91 | + ? rootPackage.repository | |
| 92 | + : rootPackage.repository?.url; | |
| 93 | + | |
| 94 | +const EXECUTOR_VERSION = cliPackage.version ?? rootPackage.version; | |
| 95 | +const EXECUTOR_GITHUB_URL = (rootPackage.homepage ?? repositoryUrl ?? "https://github.com/RhysSullivan/executor") | |
| 96 | + .replace(/^git\+/, "") | |
| 97 | + .replace(/\.git$/, ""); | |
| 50 | 98 | |
| 51 | 99 | export default defineConfig({ |
| 52 | − root: "src", | |
| 53 | − resolve: { | |
| 54 | − alias: { | |
| 55 | − "@": path.resolve(import.meta.dirname, "./src"), | |
| 56 | − }, | |
| 100 | + define: { | |
| 101 | + "import.meta.env.VITE_APP_VERSION": JSON.stringify(EXECUTOR_VERSION), | |
| 102 | + "import.meta.env.VITE_GITHUB_URL": JSON.stringify(EXECUTOR_GITHUB_URL), | |
| 57 | 103 | }, |
| 58 | 104 | plugins: [ |
| 59 | − reloadOnPluginChange(), | |
| 60 | − tailwindcss(), | |
| 61 | 105 | react(), |
| 62 | − devServer({ | |
| 63 | − entry: "src/dev.ts", | |
| 64 | − exclude: [ | |
| 65 | − // Only let /v1 and /mcp requests reach the API handler | |
| 66 | − /^\/(?!(v1|mcp)(\/|$))/, | |
| 67 | − /^\/(src|node_modules|@vite|@id|@react-refresh)/, | |
| 68 | − /\.(css|ts|tsx|js|jsx|svg|png|jpg|gif|ico|woff2?|json|map)(\?.*)?$/, | |
| 69 | − ], | |
| 70 | − injectClientScript: false, | |
| 71 | − }), | |
| 72 | − ], | |
| 73 | − define: { | |
| 74 | − "import.meta.env.VITE_APP_VERSION": JSON.stringify(executorPackage.version), | |
| 75 | − "import.meta.env.VITE_GITHUB_URL": JSON.stringify(githubUrl), | |
| 76 | − }, | |
| 77 | − build: { | |
| 78 | − outDir: "../dist", | |
| 79 | − emptyOutDir: true, | |
| 80 | − }, | |
| 81 | − optimizeDeps: { | |
| 82 | − exclude: workspaceExecutorPackages, | |
| 83 | − }, | |
| 84 | − server: { | |
| 85 | − port: 8788, | |
| 86 | − allowedHosts: [ | |
| 87 | − "rhyss-laptop.tail5665af.ts.net", | |
| 88 | − ".tail5665af.ts.net", | |
| 89 | − ], | |
| 90 | − watch: { | |
| 91 | − ignored: [ | |
| 92 | − "!**/node_modules/@executor/**", | |
| 93 | − ], | |
| 94 | − // WSL2 inotify doesn't reliably detect changes through symlinked workspace packages | |
| 95 | − usePolling: true, | |
| 96 | − interval: 500, | |
| 106 | + tailwindcss(), | |
| 107 | + { | |
| 108 | + name: "executor-api", | |
| 109 | + configureServer(server) { | |
| 110 | + let backendPromise: Promise<HotBackend> | null = null; | |
| 111 | + let reloadPromise: Promise<void> | null = null; | |
| 112 | + | |
| 113 | + const loadBackend = () => | |
| 114 | + server | |
| 115 | + .ssrLoadModule(DEV_BACKEND_MODULE_ID) | |
| 116 | + .then((mod) => mod.createHotBackend() as Promise<HotBackend>); | |
| 117 | + | |
| 118 | + const getBackend = () => { | |
| 119 | + if (!backendPromise) { | |
| 120 | + backendPromise = loadBackend(); | |
| 121 | + } | |
| 122 | + return backendPromise; | |
| 123 | + }; | |
| 124 | + | |
| 125 | + const shouldReloadBackend = (file: string) => | |
| 126 | + /\.(ts|tsx)$/.test(file) && | |
| 127 | + !file.includes("/apps/web/") && | |
| 128 | + ( | |
| 129 | + file.includes("/apps/server/") || | |
| 130 | + file.includes("/packages/core/") || | |
| 131 | + file.includes("/packages/plugins/") || | |
| 132 | + file.includes("/packages/hosts/") | |
| 133 | + ); | |
| 134 | + | |
| 135 | + server.httpServer?.once("close", () => { | |
| 136 | + const pending = backendPromise; | |
| 137 | + backendPromise = null; | |
| 138 | + void pending?.then((backend) => backend.dispose()).catch(() => undefined); | |
| 139 | + }); | |
| 140 | + | |
| 141 | + server.watcher.on("change", (file) => { | |
| 142 | + if (!shouldReloadBackend(file) || reloadPromise) { | |
| 143 | + return; | |
| 144 | + } | |
| 145 | + | |
| 146 | + reloadPromise = (async () => { | |
| 147 | + server.config.logger.info(`[executor-api] hot reloading backend: ${file}`); | |
| 148 | + | |
| 149 | + const previous = await getBackend().catch(() => null); | |
| 150 | + | |
| 151 | + server.moduleGraph.invalidateAll(); | |
| 152 | + backendPromise = loadBackend(); | |
| 153 | + | |
| 154 | + await backendPromise; | |
| 155 | + await previous?.dispose().catch(() => undefined); | |
| 156 | + | |
| 157 | + server.ws.send({ | |
| 158 | + type: "custom", | |
| 159 | + event: "executor:backend-updated", | |
| 160 | + data: { file }, | |
| 161 | + }); | |
| 162 | + })() | |
| 163 | + .catch((error) => { | |
| 164 | + server.config.logger.error( | |
| 165 | + `[executor-api] backend reload failed: ${error instanceof Error ? error.message : String(error)}`, | |
| 166 | + ); | |
| 167 | + }) | |
| 168 | + .finally(() => { | |
| 169 | + reloadPromise = null; | |
| 170 | + }); | |
| 171 | + }); | |
| 172 | + | |
| 173 | + server.middlewares.use(async (req, res, next) => { | |
| 174 | + const url = req.url ?? "/"; | |
| 175 | + | |
| 176 | + const isApi = | |
| 177 | + url.startsWith("/v1/") || | |
| 178 | + url.startsWith("/docs") || | |
| 179 | + url === "/openapi.json"; | |
| 180 | + const isMcp = url.startsWith("/mcp"); | |
| 181 | + | |
| 182 | + if (!isApi && !isMcp) return next(); | |
| 183 | + | |
| 184 | + const backend = await getBackend(); | |
| 185 | + const request = await toWebRequest(req); | |
| 186 | + | |
| 187 | + const response = isMcp | |
| 188 | + ? await backend.mcp.handleRequest(request) | |
| 189 | + : await backend.api.handler(request); | |
| 190 | + | |
| 191 | + await sendWebResponse(response, res); | |
| 192 | + }); | |
| 193 | + }, | |
| 97 | 194 | }, |
| 98 | − }, | |
| 195 | + ], | |
| 99 | 196 | }); |
| @@ -1,124 +0,0 @@ | ||
| 1 | −# Notes on the architecture of Executor. | |
| 2 | − | |
| 3 | −## What is Executor? | |
| 4 | − | |
| 5 | −Executor is meant to be a replacement for how agents use bash and CLIs today, replacing it with code execution. | |
| 6 | − | |
| 7 | −The philosophy behind this is that bash + CLIs is a fundamentally flawed approach in that it is not going to be able to scale to organizations securely, is too dependant on having a vm to execute in, and has too many security flaws for things that can be generally run in a sandbox | |
| 8 | − | |
| 9 | −It is important to call out however what bash gets right, bash and CLIs are not bad primitives - they're the best approach agents have for calling services today | |
| 10 | − | |
| 11 | −### Why is bash the wrong primitive? | |
| 12 | − | |
| 13 | −Look at the attempts to make bash secure, namely [https://github.com/NVIDIA/OpenShell](https://github.com/NVIDIA/OpenShell) | |
| 14 | − | |
| 15 | −- Requires having docker running | |
| 16 | −- Single player | |
| 17 | − | |
| 18 | −### Why is code mode likely the right primitive? | |
| 19 | − | |
| 20 | −Portability, types, searchable index of all tools, unified interface | |
| 21 | − | |
| 22 | −[https://sunilpai.dev/posts/after-wimp/](https://sunilpai.dev/posts/after-wimp/) | |
| 23 | − | |
| 24 | −### What is Executor doing right that others haven't? | |
| 25 | − | |
| 26 | −Configuring itself, normalize to a TypeScript SDK but that's it, preserve complexity inside of plugins don't try to force a shared schema | |
| 27 | − | |
| 28 | −### What is going to be hard? | |
| 29 | − | |
| 30 | −- Distribution | |
| 31 | − | |
| 32 | −## Targets | |
| 33 | − | |
| 34 | −SaaS: | |
| 35 | − | |
| 36 | −- Organizations are able to use it to allow their employees to connect to services, examples: | |
| 37 | − - "Give all of my sales team access to Salesforce via just setting 1 API key and then they can OAuth" | |
| 38 | − - "All of my employees can OAuth with their own Google Workspace to setup their connections" | |
| 39 | −- Products embedding it inside of them, i.e "bring your own integrations" to another persons AI assistant | |
| 40 | − | |
| 41 | −Local: | |
| 42 | − | |
| 43 | −- Locally installable desktop application | |
| 44 | −- Be able to npx add-mcp executor and just start using it | |
| 45 | − | |
| 46 | −SDK: | |
| 47 | − | |
| 48 | −- Bring your AI SDK tools | |
| 49 | −- Leverage the plugin ecosystem to convert OpenAPI / GraphQL / etc into callable tools | |
| 50 | − | |
| 51 | −## Architecture | |
| 52 | − | |
| 53 | −All of these build on similar concepts and primitives | |
| 54 | − | |
| 55 | −The underlying concept is that you can generate a TypeScript SDK for literally anything you want to interact with, and the LLMs can call it | |
| 56 | − | |
| 57 | −Scope contains: | |
| 58 | − | |
| 59 | −- Secrets | |
| 60 | −- Policies | |
| 61 | −- Sources | |
| 62 | − - Tools | |
| 63 | − | |
| 64 | −### Scopes | |
| 65 | − | |
| 66 | −Scopes contain sources, sources contain tools | |
| 67 | −Scopes can be merged, for instance you may have: | |
| 68 | − | |
| 69 | −- Remote organization scope | |
| 70 | −- Remote workspace scope | |
| 71 | −- Local scope | |
| 72 | − | |
| 73 | −### Secrets | |
| 74 | − | |
| 75 | −#### Merging Scopes | |
| 76 | − | |
| 77 | −Q) How does merging secrets work with scopes? i.e I need to enforce people set their own tokens on sources | |
| 78 | − | |
| 79 | −A) TBD no idea | |
| 80 | − | |
| 81 | −Q) How does merging poliices work with scopes? i.e people can override | |
| 82 | − | |
| 83 | −A) TBD no idea | |
| 84 | − | |
| 85 | −### Tools | |
| 86 | − | |
| 87 | −A tool is a function call | |
| 88 | − | |
| 89 | −Requirements to think through: | |
| 90 | − | |
| 91 | −- Do tools have access to the full JS ecosystem? i.e streams | |
| 92 | −- Tools are seralizable in some form to enable workflow style use | |
| 93 | − | |
| 94 | −## Plugins | |
| 95 | − | |
| 96 | −Plugin list (non comphrensive): | |
| 97 | − | |
| 98 | −- Import / Manage OpenAPI | |
| 99 | −- Import / Manage GraphQL | |
| 100 | −- Import / Manage Google Discovery sources | |
| 101 | −- Import / Manage MCP | |
| 102 | −- Execution history | |
| 103 | −- 1password secrets | |
| 104 | −- Keychain secrets | |
| 105 | −- Storage backed secrets | |
| 106 | −- MCP apps | |
| 107 | −- Custom tools plugin | |
| 108 | − - Allows the agent to write .ts files w/ custom tools, plugs in to whatever relevant storage | |
| 109 | − - Agent gets install commands for packages, typecheck etc mini dev environment to work in | |
| 110 | − | |
| 111 | −Plugins: | |
| 112 | − | |
| 113 | −- Can register frontend routes | |
| 114 | −- Can register themselves in the app sidebar | |
| 115 | −- Can register HTTP routes | |
| 116 | −- Can extend the core sdk | |
| 117 | − | |
| 118 | −Plugins get access to the core sdk and so they are able to extend off of it | |
| 119 | − | |
| 120 | −## Is this work still relevant post AGI? | |
| 121 | − | |
| 122 | −While my day to day experience with the models begs to differ, if we assume the token sellers are correct most software is obsolete by 2028 | |
| 123 | − | |
| 124 | −Where I believe this is relevant still is that | |
| @@ -3,240 +3,212 @@ · 2 unmodified lines | ||
| 3 | 3 | "configVersion": 1, |
| 4 | 4 | "workspaces": { |
| 5 | 5 | "": { |
| 6 | − "name": "executor", | |
| 6 | + "name": "v4-executor", | |
| 7 | 7 | "devDependencies": { |
| 8 | 8 | "@changesets/cli": "^2.30.0", |
| 9 | − "@oxlint/plugins": "^1.57.0", | |
| 10 | − "knip": "^5.85.0", | |
| 9 | + "@effect/language-service": "^0.84.2", | |
| 10 | + "@effect/platform": "catalog:", | |
| 11 | + "@effect/vitest": "catalog:", | |
| 12 | + "effect": "catalog:", | |
| 11 | 13 | "oxlint": "^1.56.0", |
| 12 | 14 | "turbo": "^2.5.6", |
| 13 | 15 | "typescript": "^5.9.3", |
| 16 | + "vitest": "catalog:", | |
| 14 | 17 | }, |
| 15 | 18 | }, |
| 16 | − "apps/docs": { | |
| 17 | − "name": "@executor/docs", | |
| 18 | − "version": "0.0.0", | |
| 19 | − }, | |
| 20 | − "apps/executor": { | |
| 19 | + "apps/cli": { | |
| 21 | 20 | "name": "executor", |
| 22 | − "version": "1.3.0-beta.3", | |
| 21 | + "version": "1.4.0-beta.0", | |
| 23 | 22 | "bin": { |
| 24 | − "executor": "bin/executor", | |
| 23 | + "executor": "./bin/executor.ts", | |
| 25 | 24 | }, |
| 26 | 25 | "dependencies": { |
| 27 | 26 | "@effect/cli": "catalog:", |
| 28 | 27 | "@effect/platform": "catalog:", |
| 29 | − "@effect/platform-node": "catalog:", | |
| 30 | − "@executor/codemode-core": "workspace:*", | |
| 31 | − "@executor/executor-mcp": "workspace:*", | |
| 32 | − "@executor/platform-api": "workspace:*", | |
| 33 | − "@executor/platform-sdk": "workspace:*", | |
| 34 | − "@executor/platform-sdk-file": "workspace:*", | |
| 35 | − "@executor/plugin-google-discovery-sdk": "workspace:*", | |
| 36 | − "@executor/plugin-graphql-sdk": "workspace:*", | |
| 37 | − "@executor/plugin-keychain-secret-store-sdk": "workspace:*", | |
| 38 | − "@executor/plugin-local-secret-store-sdk": "workspace:*", | |
| 39 | − "@executor/plugin-local-tools-sdk": "workspace:*", | |
| 40 | − "@executor/plugin-mcp-sdk": "workspace:*", | |
| 41 | − "@executor/plugin-openapi-sdk": "workspace:*", | |
| 28 | + "@effect/platform-bun": "catalog:", | |
| 29 | + "@executor/api": "workspace:*", | |
| 30 | + "@executor/runtime-quickjs": "workspace:*", | |
| 42 | 31 | "@executor/server": "workspace:*", |
| 32 | + "@jitl/quickjs-wasmfile-release-sync": "*", | |
| 43 | 33 | "effect": "catalog:", |
| 34 | + "quickjs-emscripten": "*", | |
| 44 | 35 | }, |
| 45 | 36 | "devDependencies": { |
| 46 | − "@effect/vitest": "catalog:", | |
| 47 | − "@executor/effect-test-utils": "workspace:*", | |
| 48 | − "@executor/mcp-elicitation-demo": "workspace:*", | |
| 49 | − "@executor/runtime-ses": "workspace:*", | |
| 50 | − "@modelcontextprotocol/sdk": "^1.26.0", | |
| 51 | − "@types/node": "catalog:", | |
| 52 | 37 | "bun-types": "catalog:", |
| 53 | − "vitest": "catalog:", | |
| 54 | − "zod": "catalog:", | |
| 38 | + "typescript": "^5.9.3", | |
| 55 | 39 | }, |
| 56 | 40 | }, |
| 57 | − "apps/web": { | |
| 58 | − "name": "@executor/web", | |
| 59 | − "version": "0.0.0", | |
| 41 | + "apps/server": { | |
| 42 | + "name": "@executor/server", | |
| 43 | + "version": "1.4.0-beta.0", | |
| 60 | 44 | "dependencies": { |
| 61 | − "@base-ui/react": "^1.3.0", | |
| 62 | − "@executor/plugin-execution-history-react": "workspace:*", | |
| 63 | − "@executor/plugin-google-discovery-react": "workspace:*", | |
| 64 | − "@executor/plugin-graphql-react": "workspace:*", | |
| 65 | − "@executor/plugin-local-tools-react": "workspace:*", | |
| 66 | − "@executor/plugin-mcp-react": "workspace:*", | |
| 67 | − "@executor/plugin-onepassword-react": "workspace:*", | |
| 68 | − "@executor/plugin-openapi-react": "workspace:*", | |
| 69 | − "@executor/react": "workspace:*", | |
| 70 | − "@executor/server": "workspace:*", | |
| 71 | − "@executor/source-core": "workspace:*", | |
| 72 | − "@shikijs/langs": "^4.0.1", | |
| 73 | − "@shikijs/themes": "^4.0.1", | |
| 74 | − "@tanstack/react-router": "^1.132.7", | |
| 75 | − "class-variance-authority": "^0.7.1", | |
| 76 | − "clsx": "^2.1.1", | |
| 45 | + "@effect/platform": "catalog:", | |
| 46 | + "@effect/platform-node": "catalog:", | |
| 47 | + "@effect/sql": "catalog:", | |
| 48 | + "@effect/sql-sqlite-bun": "catalog:", | |
| 49 | + "@executor/api": "workspace:*", | |
| 50 | + "@executor/config": "workspace:*", | |
| 51 | + "@executor/execution": "workspace:*", | |
| 52 | + "@executor/host-mcp": "workspace:*", | |
| 53 | + "@executor/plugin-file-secrets": "workspace:*", | |
| 54 | + "@executor/plugin-google-discovery": "workspace:*", | |
| 55 | + "@executor/plugin-graphql": "workspace:*", | |
| 56 | + "@executor/plugin-keychain": "workspace:*", | |
| 57 | + "@executor/plugin-mcp": "workspace:*", | |
| 58 | + "@executor/plugin-onepassword": "workspace:*", | |
| 59 | + "@executor/plugin-openapi": "workspace:*", | |
| 60 | + "@executor/sdk": "workspace:*", | |
| 61 | + "@executor/storage-file": "workspace:*", | |
| 62 | + "@modelcontextprotocol/sdk": "^1.12.1", | |
| 77 | 63 | "effect": "catalog:", |
| 78 | − "lucide-react": "^1.7.0", | |
| 79 | − "react": "^19.2.0", | |
| 80 | − "react-dom": "^19.2.0", | |
| 81 | − "react-grab": "^0.1.26", | |
| 82 | − "shadcn": "^4.1.1", | |
| 83 | − "shiki": "^4.0.1", | |
| 84 | − "streamdown": "^2.3.0", | |
| 85 | − "tailwind-merge": "^3.5.0", | |
| 86 | − "tldts": "^7.0.23", | |
| 87 | 64 | }, |
| 88 | 65 | "devDependencies": { |
| 89 | − "@hono/vite-dev-server": "^0.25.0", | |
| 90 | − "@tailwindcss/vite": "^4.2.1", | |
| 91 | − "@types/react": "^19.2.10", | |
| 92 | − "@types/react-dom": "^19.2.3", | |
| 93 | − "@vitejs/plugin-react": "^5.1.4", | |
| 66 | + "@types/node": "catalog:", | |
| 94 | 67 | "bun-types": "catalog:", |
| 95 | − "tailwindcss": "^4.2.1", | |
| 96 | − "tw-animate-css": "^1.4.0", | |
| 97 | − "vite": "^7.3.1", | |
| 68 | + "typescript": "^5.9.3", | |
| 98 | 69 | }, |
| 99 | 70 | }, |
| 100 | − "examples/mcp-elicitation-demo": { | |
| 101 | − "name": "@executor/mcp-elicitation-demo", | |
| 102 | − "version": "0.0.0", | |
| 71 | + "apps/web": { | |
| 72 | + "name": "@executor/web", | |
| 73 | + "version": "1.4.0-beta.0", | |
| 103 | 74 | "dependencies": { |
| 104 | − "@modelcontextprotocol/sdk": "^1.26.0", | |
| 105 | − "zod": "catalog:", | |
| 75 | + "@executor/plugin-google-discovery": "workspace:*", | |
| 76 | + "@executor/plugin-graphql": "workspace:*", | |
| 77 | + "@executor/plugin-mcp": "workspace:*", | |
| 78 | + "@executor/plugin-onepassword": "workspace:*", | |
| 79 | + "@executor/plugin-openapi": "workspace:*", | |
| 80 | + "@executor/react": "workspace:*", | |
| 81 | + "@executor/sdk": "workspace:*", | |
| 82 | + "@executor/server": "workspace:*", | |
| 83 | + "@executor/ui": "workspace:*", | |
| 84 | + "@shikijs/langs": "^4.0.2", | |
| 85 | + "@shikijs/themes": "^4.0.2", | |
| 86 | + "@tanstack/react-router": "^1.168.10", | |
| 87 | + "react": "^19.1.0", | |
| 88 | + "react-dom": "^19.1.0", | |
| 89 | + "shiki": "^4.0.2", | |
| 90 | + "streamdown": "^2.5.0", | |
| 91 | + "tailwindcss": "^4.1.10", | |
| 106 | 92 | }, |
| 107 | 93 | "devDependencies": { |
| 94 | + "@tailwindcss/vite": "^4.1.10", | |
| 108 | 95 | "@types/node": "catalog:", |
| 109 | − "bun-types": "catalog:", | |
| 96 | + "@types/react": "^19.1.0", | |
| 97 | + "@types/react-dom": "^19.1.0", | |
| 98 | + "@vitejs/plugin-react": "^4.5.2", | |
| 99 | + "typescript": "^5.9.3", | |
| 100 | + "vite": "^6.3.5", | |
| 110 | 101 | }, |
| 111 | 102 | }, |
| 112 | − "examples/serve-skills-via-mcp": { | |
| 113 | − "name": "@executor/serve-skills-via-mcp-demo", | |
| 114 | − "version": "0.0.0", | |
| 103 | + "packages/clients/react": { | |
| 104 | + "name": "@executor/react", | |
| 105 | + "version": "1.4.0-beta.0", | |
| 115 | 106 | "dependencies": { |
| 116 | − "@modelcontextprotocol/sdk": "^1.26.0", | |
| 107 | + "@effect-atom/atom": "^0.5.3", | |
| 108 | + "@effect-atom/atom-react": "^0.5.0", | |
| 109 | + "@effect/platform": "catalog:", | |
| 110 | + "@executor/api": "workspace:*", | |
| 111 | + "@executor/sdk": "workspace:*", | |
| 112 | + "@executor/ui": "workspace:*", | |
| 113 | + "effect": "catalog:", | |
| 114 | + "react": "^19.1.0", | |
| 117 | 115 | }, |
| 118 | 116 | "devDependencies": { |
| 119 | 117 | "@types/node": "catalog:", |
| 120 | − "bun-types": "catalog:", | |
| 118 | + "@types/react": "^19.1.0", | |
| 119 | + "typescript": "^5.9.3", | |
| 121 | 120 | }, |
| 122 | 121 | }, |
| 123 | − "examples/sqlite-sdk-consumer": { | |
| 124 | − "name": "@executor/sqlite-sdk-consumer-example", | |
| 125 | − "version": "0.0.0", | |
| 122 | + "packages/core/api": { | |
| 123 | + "name": "@executor/api", | |
| 124 | + "version": "1.4.0-beta.0", | |
| 126 | 125 | "dependencies": { |
| 127 | − "@executor/platform-sdk": "workspace:*", | |
| 128 | − "@executor/source-core": "workspace:*", | |
| 129 | − "drizzle-orm": "^0.44.5", | |
| 126 | + "@effect/platform": "catalog:", | |
| 127 | + "@executor/sdk": "workspace:*", | |
| 128 | + "effect": "catalog:", | |
| 130 | 129 | }, |
| 131 | 130 | "devDependencies": { |
| 132 | 131 | "@types/node": "catalog:", |
| 133 | 132 | "bun-types": "catalog:", |
| 133 | + "typescript": "^5.9.3", | |
| 134 | 134 | }, |
| 135 | 135 | }, |
| 136 | − "packages/clients/react": { | |
| 137 | − "name": "@executor/react", | |
| 138 | − "version": "0.0.0", | |
| 136 | + "packages/core/config": { | |
| 137 | + "name": "@executor/config", | |
| 138 | + "version": "1.4.0-beta.0", | |
| 139 | 139 | "dependencies": { |
| 140 | − "@base-ui/react": "^1.3.0", | |
| 141 | − "@effect-atom/atom": "0.5.3", | |
| 142 | − "@effect-atom/atom-react": "0.5.0", | |
| 143 | 140 | "@effect/platform": "catalog:", |
| 144 | − "@executor/platform-api": "workspace:*", | |
| 145 | − "@executor/platform-sdk": "workspace:*", | |
| 146 | − "@shikijs/langs": "^4.0.1", | |
| 147 | − "@shikijs/themes": "^4.0.1", | |
| 148 | − "class-variance-authority": "^0.7.1", | |
| 149 | − "clsx": "^2.1.1", | |
| 150 | − "cmdk": "^1.1.1", | |
| 141 | + "@executor/sdk": "workspace:*", | |
| 151 | 142 | "effect": "catalog:", |
| 152 | − "shiki": "^4.0.1", | |
| 153 | − "streamdown": "^2.3.0", | |
| 154 | − "tailwind-merge": "^3.5.0", | |
| 143 | + "jsonc-parser": "^3.3.1", | |
| 155 | 144 | }, |
| 156 | 145 | "devDependencies": { |
| 157 | 146 | "@effect/platform-node": "catalog:", |
| 158 | 147 | "@effect/vitest": "catalog:", |
| 159 | − "@executor/effect-test-utils": "workspace:*", | |
| 160 | − "@executor/platform-sdk-file": "workspace:*", | |
| 161 | − "@types/jsdom": "^21.1.7", | |
| 162 | − "@types/node": "catalog:", | |
| 163 | − "@types/react": "^19.2.10", | |
| 164 | − "@types/react-dom": "^19.2.3", | |
| 165 | − "bun-types": "catalog:", | |
| 166 | − "jsdom": "^26.1.0", | |
| 167 | − "react-dom": "^19.2.0", | |
| 148 | + "typescript": "latest", | |
| 168 | 149 | "vitest": "catalog:", |
| 169 | 150 | }, |
| 170 | − "peerDependencies": { | |
| 171 | − "react": ">=18 <20", | |
| 172 | − }, | |
| 173 | 151 | }, |
| 174 | − "packages/dev/effect-test-utils": { | |
| 175 | − "name": "@executor/effect-test-utils", | |
| 176 | − "version": "0.0.0", | |
| 152 | + "packages/core/execution": { | |
| 153 | + "name": "@executor/execution", | |
| 154 | + "version": "1.4.0-beta.0", | |
| 177 | 155 | "dependencies": { |
| 178 | − "@effect/platform": "catalog:", | |
| 179 | − "@effect/platform-node": "catalog:", | |
| 156 | + "@executor/codemode-core": "workspace:*", | |
| 157 | + "@executor/runtime-quickjs": "workspace:*", | |
| 158 | + "@executor/sdk": "workspace:*", | |
| 180 | 159 | "effect": "catalog:", |
| 181 | 160 | }, |
| 182 | 161 | "devDependencies": { |
| 183 | 162 | "@types/node": "catalog:", |
| 184 | 163 | "bun-types": "catalog:", |
| 185 | − "typescript": "^5.9.3", | |
| 186 | 164 | }, |
| 187 | 165 | }, |
| 188 | − "packages/dev/kitchen-sink": { | |
| 189 | − "name": "@executor/kitchen-sink", | |
| 190 | − "version": "0.0.0", | |
| 166 | + "packages/core/sdk": { | |
| 167 | + "name": "@executor/sdk", | |
| 168 | + "version": "1.4.0-beta.0", | |
| 191 | 169 | "dependencies": { |
| 192 | − "@effect/platform": "catalog:", | |
| 193 | − "@executor/ai-sdk-adapter": "workspace:*", | |
| 194 | − "@executor/codemode-core": "workspace:*", | |
| 195 | − "@executor/platform-sdk": "workspace:*", | |
| 196 | − "@executor/runtime-ses": "workspace:*", | |
| 197 | 170 | "effect": "catalog:", |
| 198 | 171 | }, |
| 199 | 172 | "devDependencies": { |
| 200 | 173 | "@effect/vitest": "catalog:", |
| 201 | − "@types/node": "catalog:", | |
| 202 | − "bun-types": "catalog:", | |
| 174 | + "typescript": "latest", | |
| 203 | 175 | "vitest": "catalog:", |
| 204 | 176 | }, |
| 205 | 177 | }, |
| 206 | − "packages/hosts/ai-sdk": { | |
| 207 | − "name": "@executor/ai-sdk-adapter", | |
| 208 | − "version": "0.0.0", | |
| 178 | + "packages/core/storage-file": { | |
| 179 | + "name": "@executor/storage-file", | |
| 180 | + "version": "1.4.0-beta.0", | |
| 209 | 181 | "dependencies": { |
| 210 | − "@executor/codemode-core": "workspace:*", | |
| 211 | − "@executor/runtime-ses": "workspace:*", | |
| 212 | − "ai": "^6.0.0", | |
| 182 | + "@effect/sql": "catalog:", | |
| 183 | + "@executor/sdk": "workspace:*", | |
| 213 | 184 | "effect": "catalog:", |
| 214 | − "zod": "catalog:", | |
| 215 | 185 | }, |
| 216 | 186 | "devDependencies": { |
| 217 | − "@types/node": "catalog:", | |
| 218 | − "bun-types": "catalog:", | |
| 187 | + "@effect/experimental": "catalog:", | |
| 188 | + "@effect/sql-sqlite-node": "catalog:", | |
| 189 | + "@effect/vitest": "catalog:", | |
| 190 | + "typescript": "^5.9.3", | |
| 191 | + "vitest": "catalog:", | |
| 219 | 192 | }, |
| 220 | 193 | }, |
| 221 | 194 | "packages/hosts/mcp": { |
| 222 | − "name": "@executor/executor-mcp", | |
| 223 | − "version": "0.0.0", | |
| 195 | + "name": "@executor/host-mcp", | |
| 196 | + "version": "1.4.0-beta.0", | |
| 224 | 197 | "dependencies": { |
| 225 | − "@executor/platform-sdk": "workspace:*", | |
| 226 | − "@modelcontextprotocol/sdk": "^1.26.0", | |
| 198 | + "@executor/execution": "workspace:*", | |
| 199 | + "@executor/sdk": "workspace:*", | |
| 200 | + "@modelcontextprotocol/sdk": "^1.12.1", | |
| 227 | 201 | "effect": "catalog:", |
| 228 | − "zod": "catalog:", | |
| 202 | + "zod": "^4.3.0", | |
| 229 | 203 | }, |
| 230 | 204 | "devDependencies": { |
| 231 | − "@effect/vitest": "catalog:", | |
| 232 | 205 | "@types/node": "catalog:", |
| 233 | 206 | "bun-types": "catalog:", |
| 234 | − "vitest": "catalog:", | |
| 235 | 207 | }, |
| 236 | 208 | }, |
| 237 | 209 | "packages/kernel/core": { |
| 238 | 210 | "name": "@executor/codemode-core", |
| 239 | − "version": "0.0.0", | |
| 211 | + "version": "1.4.0-beta.0", | |
| 240 | 212 | "dependencies": { |
| 241 | 213 | "@standard-schema/spec": "^1.0.0", |
| 242 | 214 | "ajv": "^8.17.1", |
| @@ -252,9 +224,8 @@ · 9 unmodified lines | ||
| 252 | 224 | }, |
| 253 | 225 | "packages/kernel/ir": { |
| 254 | 226 | "name": "@executor/ir", |
| 255 | − "version": "0.0.0", | |
| 227 | + "version": "1.4.0-beta.0", | |
| 256 | 228 | "dependencies": { |
| 257 | − "@executor/codemode-core": "workspace:*", | |
| 258 | 229 | "effect": "catalog:", |
| 259 | 230 | }, |
| 260 | 231 | "devDependencies": { |
| @@ -280,7 +251,7 @@ · 19 unmodified lines | ||
| 280 | 251 | }, |
| 281 | 252 | "packages/kernel/runtime-quickjs": { |
| 282 | 253 | "name": "@executor/runtime-quickjs", |
| 283 | − "version": "0.0.0", | |
| 254 | + "version": "1.4.0-beta.0", | |
| 284 | 255 | "dependencies": { |
| 285 | 256 | "@executor/codemode-core": "workspace:*", |
| 286 | 257 | "effect": "catalog:", |
| @@ -293,199 +264,99 @@ · 6 unmodified lines | ||
| 293 | 264 | "vitest": "catalog:", |
| 294 | 265 | }, |
| 295 | 266 | }, |
| 296 | − "packages/kernel/runtime-ses": { | |
| 297 | − "name": "@executor/runtime-ses", | |
| 298 | − "version": "0.0.0", | |
| 299 | − "dependencies": { | |
| 300 | − "@executor/codemode-core": "workspace:*", | |
| 301 | − "effect": "catalog:", | |
| 302 | − "ses": "^1.15.0", | |
| 303 | − }, | |
| 304 | − "devDependencies": { | |
| 305 | − "@types/node": "catalog:", | |
| 306 | − "bun-types": "catalog:", | |
| 307 | − }, | |
| 308 | − }, | |
| 309 | − "packages/platform/api": { | |
| 310 | − "name": "@executor/platform-api", | |
| 311 | − "version": "0.0.0", | |
| 312 | − "dependencies": { | |
| 313 | − "@effect/platform": "catalog:", | |
| 314 | − "@executor/platform-sdk": "workspace:*", | |
| 315 | − "effect": "catalog:", | |
| 316 | − }, | |
| 317 | − "devDependencies": { | |
| 318 | − "@effect/vitest": "catalog:", | |
| 319 | − "bun-types": "catalog:", | |
| 320 | − "typescript": "^5.9.3", | |
| 321 | − "vitest": "catalog:", | |
| 322 | − }, | |
| 323 | − }, | |
| 324 | − "packages/platform/sdk": { | |
| 325 | − "name": "@executor/platform-sdk", | |
| 326 | − "version": "0.0.0", | |
| 267 | + "packages/plugins/file-secrets": { | |
| 268 | + "name": "@executor/plugin-file-secrets", | |
| 269 | + "version": "1.4.0-beta.0", | |
| 327 | 270 | "dependencies": { |
| 328 | − "@effect/platform": "catalog:", | |
| 329 | − "@effect/platform-node": "catalog:", | |
| 330 | − "@executor/codemode-core": "workspace:*", | |
| 331 | − "@executor/ir": "workspace:*", | |
| 332 | − "@executor/runtime-deno-subprocess": "workspace:*", | |
| 333 | − "@executor/runtime-quickjs": "workspace:*", | |
| 334 | − "@executor/runtime-ses": "workspace:*", | |
| 335 | − "@executor/source-core": "workspace:*", | |
| 271 | + "@executor/sdk": "workspace:*", | |
| 336 | 272 | "effect": "catalog:", |
| 337 | 273 | }, |
| 338 | 274 | "devDependencies": { |
| 339 | 275 | "@effect/vitest": "catalog:", |
| 340 | − "@executor/effect-test-utils": "workspace:*", | |
| 341 | − "@modelcontextprotocol/sdk": "^1.26.0", | |
| 342 | 276 | "@types/node": "catalog:", |
| 343 | 277 | "bun-types": "catalog:", |
| 344 | − "jsonc-parser": "3.3.1", | |
| 345 | − "prettier": "^3.8.1", | |
| 346 | − "typescript": "^5.9.3", | |
| 347 | 278 | "vitest": "catalog:", |
| 348 | − "zod": "catalog:", | |
| 349 | 279 | }, |
| 350 | 280 | }, |
| 351 | − "packages/platform/sdk-file": { | |
| 352 | − "name": "@executor/platform-sdk-file", | |
| 353 | − "version": "0.0.0", | |
| 281 | + "packages/plugins/google-discovery": { | |
| 282 | + "name": "@executor/plugin-google-discovery", | |
| 283 | + "version": "1.4.0-beta.0", | |
| 354 | 284 | "dependencies": { |
| 355 | 285 | "@effect/platform": "catalog:", |
| 356 | − "@effect/platform-node": "catalog:", | |
| 357 | − "@executor/codemode-core": "workspace:*", | |
| 358 | − "@executor/ir": "workspace:*", | |
| 359 | − "@executor/platform-sdk": "workspace:*", | |
| 360 | − "@executor/source-core": "workspace:*", | |
| 286 | + "@executor/api": "workspace:*", | |
| 287 | + "@executor/sdk": "workspace:*", | |
| 361 | 288 | "effect": "catalog:", |
| 362 | − "jsonc-parser": "3.3.1", | |
| 363 | 289 | }, |
| 364 | 290 | "devDependencies": { |
| 291 | + "@effect-atom/atom-react": "^0.5.0", | |
| 365 | 292 | "@effect/vitest": "catalog:", |
| 293 | + "@executor/react": "workspace:*", | |
| 294 | + "@executor/ui": "workspace:*", | |
| 366 | 295 | "@types/node": "catalog:", |
| 296 | + "@types/react": "^19.1.0", | |
| 367 | 297 | "bun-types": "catalog:", |
| 368 | − "typescript": "^5.9.3", | |
| 298 | + "react": "^19.1.0", | |
| 369 | 299 | "vitest": "catalog:", |
| 370 | 300 | }, |
| 301 | + "peerDependencies": { | |
| 302 | + "@effect-atom/atom-react": "^0.5.0", | |
| 303 | + "@executor/react": "workspace:*", | |
| 304 | + "@executor/ui": "workspace:*", | |
| 305 | + "@tanstack/react-router": "^1.168.10", | |
| 306 | + "react": "^19.1.0", | |
| 307 | + }, | |
| 308 | + "optionalPeers": [ | |
| 309 | + "@effect-atom/atom-react", | |
| 310 | + "@executor/react", | |
| 311 | + "@executor/ui", | |
| 312 | + "@tanstack/react-router", | |
| 313 | + "react", | |
| 314 | + ], | |
| 371 | 315 | }, |
| 372 | − "packages/platform/server": { | |
| 373 | − "name": "@executor/server", | |
| 374 | − "version": "0.0.0", | |
| 316 | + "packages/plugins/graphql": { | |
| 317 | + "name": "@executor/plugin-graphql", | |
| 318 | + "version": "1.4.0-beta.0", | |
| 375 | 319 | "dependencies": { |
| 376 | − "@effect/opentelemetry": "^0.61.0", | |
| 377 | 320 | "@effect/platform": "catalog:", |
| 378 | 321 | "@effect/platform-node": "catalog:", |
| 379 | − "@executor/executor-mcp": "workspace:*", | |
| 380 | − "@executor/platform-api": "workspace:*", | |
| 381 | − "@executor/platform-sdk": "workspace:*", | |
| 382 | − "@executor/platform-sdk-file": "workspace:*", | |
| 383 | − "@executor/plugin-google-discovery-http": "workspace:*", | |
| 384 | − "@executor/plugin-google-discovery-sdk": "workspace:*", | |
| 385 | − "@executor/plugin-google-discovery-shared": "workspace:*", | |
| 386 | − "@executor/plugin-graphql-http": "workspace:*", | |
| 387 | − "@executor/plugin-graphql-sdk": "workspace:*", | |
| 388 | − "@executor/plugin-graphql-shared": "workspace:*", | |
| 389 | − "@executor/plugin-keychain-secret-store-sdk": "workspace:*", | |
| 390 | − "@executor/plugin-local-secret-store-sdk": "workspace:*", | |
| 391 | − "@executor/plugin-local-tools-sdk": "workspace:*", | |
| 392 | − "@executor/plugin-mcp-http": "workspace:*", | |
| 393 | − "@executor/plugin-mcp-sdk": "workspace:*", | |
| 394 | − "@executor/plugin-mcp-shared": "workspace:*", | |
| 395 | − "@executor/plugin-onepassword-http": "workspace:*", | |
| 396 | − "@executor/plugin-onepassword-sdk": "workspace:*", | |
| 397 | − "@executor/plugin-onepassword-shared": "workspace:*", | |
| 398 | − "@executor/plugin-openapi-http": "workspace:*", | |
| 399 | − "@executor/plugin-openapi-sdk": "workspace:*", | |
| 400 | − "@executor/plugin-openapi-shared": "workspace:*", | |
| 401 | − "@opentelemetry/api": "^1.9.0", | |
| 402 | − "@opentelemetry/exporter-trace-otlp-grpc": "^0.213.0", | |
| 403 | − "@opentelemetry/resources": "^2.6.0", | |
| 404 | − "@opentelemetry/sdk-trace-base": "^2.6.0", | |
| 405 | − "@opentelemetry/sdk-trace-node": "^2.6.0", | |
| 406 | − "@opentelemetry/semantic-conventions": "^1.40.0", | |
| 322 | + "@executor/sdk": "workspace:*", | |
| 407 | 323 | "effect": "catalog:", |
| 408 | 324 | }, |
| 409 | 325 | "devDependencies": { |
| 326 | + "@effect-atom/atom-react": "^0.5.0", | |
| 410 | 327 | "@effect/vitest": "catalog:", |
| 411 | − "@executor/effect-test-utils": "workspace:*", | |
| 412 | − "@executor/mcp-elicitation-demo": "workspace:*", | |
| 413 | − "@executor/runtime-ses": "workspace:*", | |
| 414 | − "@modelcontextprotocol/sdk": "^1.26.0", | |
| 415 | − "@types/node": "catalog:", | |
| 416 | − "bun-types": "catalog:", | |
| 417 | − "vitest": "catalog:", | |
| 418 | − "zod": "catalog:", | |
| 419 | − }, | |
| 420 | − }, | |
| 421 | − "packages/sources/core": { | |
| 422 | − "name": "@executor/source-core", | |
| 423 | − "version": "0.0.0", | |
| 424 | − "dependencies": { | |
| 425 | − "@executor/codemode-core": "workspace:*", | |
| 426 | − "@executor/ir": "workspace:*", | |
| 427 | − "@modelcontextprotocol/sdk": "^1.26.0", | |
| 428 | − "effect": "catalog:", | |
| 429 | − "tldts": "^7.0.27", | |
| 430 | − }, | |
| 431 | − "devDependencies": { | |
| 432 | − "@types/node": "catalog:", | |
| 433 | − "bun-types": "catalog:", | |
| 434 | − }, | |
| 435 | − }, | |
| 436 | − "plugins/execution-history/react": { | |
| 437 | − "name": "@executor/plugin-execution-history-react", | |
| 438 | − "version": "0.0.0", | |
| 439 | − "dependencies": { | |
| 328 | + "@executor/api": "workspace:*", | |
| 440 | 329 | "@executor/react": "workspace:*", |
| 441 | − "react": "^19.2.0", | |
| 442 | − }, | |
| 443 | − "devDependencies": { | |
| 444 | − "@types/node": "catalog:", | |
| 445 | − "@types/react": "^19.2.10", | |
| 446 | − "bun-types": "catalog:", | |
| 447 | − }, | |
| 448 | − }, | |
| 449 | − "plugins/google-discovery/http": { | |
| 450 | − "name": "@executor/plugin-google-discovery-http", | |
| 451 | − "version": "0.0.0", | |
| 452 | − "dependencies": { | |
| 453 | − "@effect/platform": "catalog:", | |
| 454 | − "@executor/platform-api": "workspace:*", | |
| 455 | − "@executor/platform-sdk": "workspace:*", | |
| 456 | − "@executor/plugin-google-discovery-shared": "workspace:*", | |
| 457 | − "effect": "catalog:", | |
| 458 | − }, | |
| 459 | − "devDependencies": { | |
| 330 | + "@executor/ui": "workspace:*", | |
| 460 | 331 | "@types/node": "catalog:", |
| 332 | + "@types/react": "^19.1.0", | |
| 461 | 333 | "bun-types": "catalog:", |
| 334 | + "react": "^19.1.0", | |
| 335 | + "vitest": "catalog:", | |
| 462 | 336 | }, |
| 463 | − }, | |
| 464 | − "plugins/google-discovery/react": { | |
| 465 | − "name": "@executor/plugin-google-discovery-react", | |
| 466 | − "version": "0.0.0", | |
| 467 | − "dependencies": { | |
| 468 | − "@executor/plugin-google-discovery-http": "workspace:*", | |
| 469 | − "@executor/plugin-google-discovery-shared": "workspace:*", | |
| 337 | + "peerDependencies": { | |
| 338 | + "@effect-atom/atom-react": "^0.5.0", | |
| 339 | + "@executor/api": "workspace:*", | |
| 470 | 340 | "@executor/react": "workspace:*", |
| 471 | − "react": "^19.2.0", | |
| 472 | − }, | |
| 473 | − "devDependencies": { | |
| 474 | − "@types/node": "catalog:", | |
| 475 | − "@types/react": "^19.2.10", | |
| 476 | − "bun-types": "catalog:", | |
| 477 | − }, | |
| 341 | + "@executor/ui": "workspace:*", | |
| 342 | + "@tanstack/react-router": "^1.168.10", | |
| 343 | + "react": "^19.1.0", | |
| 344 | + }, | |
| 345 | + "optionalPeers": [ | |
| 346 | + "@effect-atom/atom-react", | |
| 347 | + "@executor/api", | |
| 348 | + "@executor/react", | |
| 349 | + "@executor/ui", | |
| 350 | + "@tanstack/react-router", | |
| 351 | + "react", | |
| 352 | + ], | |
| 478 | 353 | }, |
| 479 | − "plugins/google-discovery/sdk": { | |
| 480 | − "name": "@executor/plugin-google-discovery-sdk", | |
| 481 | − "version": "0.0.0", | |
| 354 | + "packages/plugins/keychain": { | |
| 355 | + "name": "@executor/plugin-keychain", | |
| 356 | + "version": "1.4.0-beta.0", | |
| 482 | 357 | "dependencies": { |
| 483 | − "@effect/platform": "catalog:", | |
| 484 | − "@executor/codemode-core": "workspace:*", | |
| 485 | − "@executor/ir": "workspace:*", | |
| 486 | − "@executor/platform-sdk": "workspace:*", | |
| 487 | − "@executor/plugin-google-discovery-shared": "workspace:*", | |
| 488 | − "@executor/source-core": "workspace:*", | |
| 358 | + "@executor/sdk": "workspace:*", | |
| 359 | + "@napi-rs/keyring": "^1.2.0", | |
| 489 | 360 | "effect": "catalog:", |
| 490 | 361 | }, |
| 491 | 362 | "devDependencies": { |
| @@ -495,345 +366,186 @@ · 3 unmodified lines | ||
| 495 | 366 | "vitest": "catalog:", |
| 496 | 367 | }, |
| 497 | 368 | }, |
| 498 | − "plugins/google-discovery/shared": { | |
| 499 | − "name": "@executor/plugin-google-discovery-shared", | |
| 500 | − "version": "0.0.0", | |
| 501 | − "dependencies": { | |
| 502 | − "@executor/platform-sdk": "workspace:*", | |
| 503 | − "@executor/source-core": "workspace:*", | |
| 504 | − "effect": "catalog:", | |
| 505 | − }, | |
| 506 | − "devDependencies": { | |
| 507 | − "@types/node": "catalog:", | |
| 508 | − "bun-types": "catalog:", | |
| 509 | − }, | |
| 510 | − }, | |
| 511 | − "plugins/graphql/http": { | |
| 512 | − "name": "@executor/plugin-graphql-http", | |
| 513 | − "version": "0.0.0", | |
| 369 | + "packages/plugins/mcp": { | |
| 370 | + "name": "@executor/plugin-mcp", | |
| 371 | + "version": "1.4.0-beta.0", | |
| 514 | 372 | "dependencies": { |
| 515 | 373 | "@effect/platform": "catalog:", |
| 516 | − "@executor/platform-api": "workspace:*", | |
| 517 | − "@executor/platform-sdk": "workspace:*", | |
| 518 | − "@executor/plugin-graphql-shared": "workspace:*", | |
| 519 | − "effect": "catalog:", | |
| 520 | − }, | |
| 521 | − "devDependencies": { | |
| 522 | − "@types/node": "catalog:", | |
| 523 | − "bun-types": "catalog:", | |
| 524 | − }, | |
| 525 | − }, | |
| 526 | − "plugins/graphql/react": { | |
| 527 | − "name": "@executor/plugin-graphql-react", | |
| 528 | − "version": "0.0.0", | |
| 529 | − "dependencies": { | |
| 530 | − "@executor/plugin-graphql-http": "workspace:*", | |
| 531 | − "@executor/plugin-graphql-shared": "workspace:*", | |
| 532 | − "@executor/react": "workspace:*", | |
| 533 | − "react": "^19.2.0", | |
| 534 | − }, | |
| 535 | − "devDependencies": { | |
| 536 | − "@types/node": "catalog:", | |
| 537 | − "@types/react": "^19.2.10", | |
| 538 | − "bun-types": "catalog:", | |
| 539 | − }, | |
| 540 | − }, | |
| 541 | − "plugins/graphql/sdk": { | |
| 542 | − "name": "@executor/plugin-graphql-sdk", | |
| 543 | − "version": "0.0.0", | |
| 544 | − "dependencies": { | |
| 545 | − "@executor/codemode-core": "workspace:*", | |
| 546 | − "@executor/ir": "workspace:*", | |
| 547 | − "@executor/platform-sdk": "workspace:*", | |
| 548 | − "@executor/plugin-graphql-shared": "workspace:*", | |
| 549 | − "@executor/source-core": "workspace:*", | |
| 374 | + "@effect/platform-node": "catalog:", | |
| 375 | + "@executor/sdk": "workspace:*", | |
| 376 | + "@modelcontextprotocol/sdk": "^1.29.0", | |
| 550 | 377 | "effect": "catalog:", |
| 551 | − "graphql": "^16.12.0", | |
| 552 | 378 | }, |
| 553 | 379 | "devDependencies": { |
| 380 | + "@effect-atom/atom-react": "^0.5.0", | |
| 554 | 381 | "@effect/vitest": "catalog:", |
| 382 | + "@executor/api": "workspace:*", | |
| 383 | + "@executor/react": "workspace:*", | |
| 384 | + "@executor/ui": "workspace:*", | |
| 555 | 385 | "@types/node": "catalog:", |
| 386 | + "@types/react": "^19.1.0", | |
| 556 | 387 | "bun-types": "catalog:", |
| 388 | + "react": "^19.1.0", | |
| 557 | 389 | "vitest": "catalog:", |
| 558 | 390 | }, |
| 559 | − }, | |
| 560 | − "plugins/graphql/shared": { | |
| 561 | − "name": "@executor/plugin-graphql-shared", | |
| 562 | − "version": "0.0.0", | |
| 563 | − "dependencies": { | |
| 564 | − "@executor/platform-sdk": "workspace:*", | |
| 565 | − "@executor/source-core": "workspace:*", | |
| 566 | − "effect": "catalog:", | |
| 567 | − }, | |
| 568 | − "devDependencies": { | |
| 569 | − "@types/node": "catalog:", | |
| 570 | − "bun-types": "catalog:", | |
| 571 | − }, | |
| 572 | − }, | |
| 573 | − "plugins/keychain-secret-store/sdk": { | |
| 574 | − "name": "@executor/plugin-keychain-secret-store-sdk", | |
| 575 | − "version": "0.0.0", | |
| 576 | − "dependencies": { | |
| 577 | − "@executor/platform-sdk": "workspace:*", | |
| 578 | − "@napi-rs/keyring": "^1.2.0", | |
| 579 | − "effect": "catalog:", | |
| 580 | − }, | |
| 581 | − "devDependencies": { | |
| 582 | − "@types/node": "catalog:", | |
| 583 | − "bun-types": "catalog:", | |
| 584 | − }, | |
| 585 | − }, | |
| 586 | − "plugins/local-secret-store/sdk": { | |
| 587 | − "name": "@executor/plugin-local-secret-store-sdk", | |
| 588 | − "version": "0.0.0", | |
| 589 | − "dependencies": { | |
| 590 | − "@executor/platform-sdk": "workspace:*", | |
| 591 | − "effect": "catalog:", | |
| 592 | − }, | |
| 593 | − "devDependencies": { | |
| 594 | − "@types/node": "catalog:", | |
| 595 | − "bun-types": "catalog:", | |
| 596 | − }, | |
| 597 | − }, | |
| 598 | − "plugins/local-tools/react": { | |
| 599 | − "name": "@executor/plugin-local-tools-react", | |
| 600 | − "version": "0.0.0", | |
| 601 | − "dependencies": { | |
| 391 | + "peerDependencies": { | |
| 392 | + "@effect-atom/atom-react": "^0.5.0", | |
| 393 | + "@executor/api": "workspace:*", | |
| 602 | 394 | "@executor/react": "workspace:*", |
| 603 | − "react": "^19.2.0", | |
| 604 | − }, | |
| 605 | − "devDependencies": { | |
| 606 | − "@types/node": "catalog:", | |
| 607 | − "@types/react": "^19.2.10", | |
| 608 | − "bun-types": "catalog:", | |
| 609 | − }, | |
| 610 | − }, | |
| 611 | − "plugins/local-tools/sdk": { | |
| 612 | − "name": "@executor/plugin-local-tools-sdk", | |
| 613 | − "version": "0.0.0", | |
| 614 | − "dependencies": { | |
| 615 | − "@executor/codemode-core": "workspace:*", | |
| 616 | − "@executor/ir": "workspace:*", | |
| 617 | − "@executor/platform-sdk": "workspace:*", | |
| 618 | − "@executor/source-core": "workspace:*", | |
| 619 | − "effect": "catalog:", | |
| 620 | − }, | |
| 621 | − "devDependencies": { | |
| 622 | − "@types/node": "catalog:", | |
| 623 | − "bun-types": "catalog:", | |
| 624 | − }, | |
| 395 | + "@executor/ui": "workspace:*", | |
| 396 | + "@tanstack/react-router": "^1.168.10", | |
| 397 | + "react": "^19.1.0", | |
| 398 | + }, | |
| 399 | + "optionalPeers": [ | |
| 400 | + "@effect-atom/atom-react", | |
| 401 | + "@executor/api", | |
| 402 | + "@executor/react", | |
| 403 | + "@executor/ui", | |
| 404 | + "@tanstack/react-router", | |
| 405 | + "react", | |
| 406 | + ], | |
| 625 | 407 | }, |
| 626 | − "plugins/mcp/http": { | |
| 627 | − "name": "@executor/plugin-mcp-http", | |
| 628 | − "version": "0.0.0", | |
| 408 | + "packages/plugins/onepassword": { | |
| 409 | + "name": "@executor/plugin-onepassword", | |
| 410 | + "version": "1.4.0-beta.0", | |
| 629 | 411 | "dependencies": { |
| 412 | + "@1password/op-js": "^0.1.13", | |
| 413 | + "@1password/sdk": "^0.4.1-beta.1", | |
| 414 | + "@effect-atom/atom-react": "^0.5.0", | |
| 630 | 415 | "@effect/platform": "catalog:", |
| 631 | − "@executor/platform-api": "workspace:*", | |
| 632 | − "@executor/platform-sdk": "workspace:*", | |
| 633 | − "@executor/plugin-mcp-shared": "workspace:*", | |
| 634 | − "effect": "catalog:", | |
| 635 | − }, | |
| 636 | − "devDependencies": { | |
| 637 | − "@types/node": "catalog:", | |
| 638 | − "bun-types": "catalog:", | |
| 639 | − }, | |
| 640 | − }, | |
| 641 | − "plugins/mcp/react": { | |
| 642 | − "name": "@executor/plugin-mcp-react", | |
| 643 | − "version": "0.0.0", | |
| 644 | − "dependencies": { | |
| 645 | − "@executor/plugin-mcp-http": "workspace:*", | |
| 646 | − "@executor/plugin-mcp-shared": "workspace:*", | |
| 647 | − "@executor/react": "workspace:*", | |
| 648 | − "react": "^19.2.0", | |
| 649 | − }, | |
| 650 | − "devDependencies": { | |
| 651 | − "@types/node": "catalog:", | |
| 652 | − "@types/react": "^19.2.10", | |
| 653 | − "bun-types": "catalog:", | |
| 654 | − }, | |
| 655 | − }, | |
| 656 | − "plugins/mcp/sdk": { | |
| 657 | − "name": "@executor/plugin-mcp-sdk", | |
| 658 | − "version": "0.0.0", | |
| 659 | − "dependencies": { | |
| 660 | − "@executor/codemode-core": "workspace:*", | |
| 661 | − "@executor/ir": "workspace:*", | |
| 662 | − "@executor/platform-sdk": "workspace:*", | |
| 663 | − "@executor/plugin-mcp-shared": "workspace:*", | |
| 664 | − "@executor/source-core": "workspace:*", | |
| 665 | − "@modelcontextprotocol/sdk": "^1.26.0", | |
| 416 | + "@executor/api": "workspace:*", | |
| 417 | + "@executor/sdk": "workspace:*", | |
| 666 | 418 | "effect": "catalog:", |
| 667 | 419 | }, |
| 668 | 420 | "devDependencies": { |
| 669 | 421 | "@effect/vitest": "catalog:", |
| 670 | − "@executor/runtime-ses": "workspace:*", | |
| 671 | 422 | "@types/node": "catalog:", |
| 672 | 423 | "bun-types": "catalog:", |
| 673 | 424 | "vitest": "catalog:", |
| 674 | − "zod": "catalog:", | |
| 675 | − }, | |
| 676 | − }, | |
| 677 | − "plugins/mcp/shared": { | |
| 678 | − "name": "@executor/plugin-mcp-shared", | |
| 679 | − "version": "0.0.0", | |
| 680 | − "dependencies": { | |
| 681 | − "@executor/platform-sdk": "workspace:*", | |
| 682 | − "@executor/source-core": "workspace:*", | |
| 683 | − "effect": "catalog:", | |
| 684 | − }, | |
| 685 | − "devDependencies": { | |
| 686 | − "@types/node": "catalog:", | |
| 687 | − "bun-types": "catalog:", | |
| 688 | 425 | }, |
| 689 | − }, | |
| 690 | − "plugins/onepassword/http": { | |
| 691 | − "name": "@executor/plugin-onepassword-http", | |
| 692 | − "version": "0.0.0", | |
| 693 | − "dependencies": { | |
| 694 | − "@effect/platform": "catalog:", | |
| 695 | − "@executor/platform-api": "workspace:*", | |
| 696 | − "@executor/platform-sdk": "workspace:*", | |
| 697 | − "@executor/plugin-onepassword-shared": "workspace:*", | |
| 698 | − "effect": "catalog:", | |
| 699 | − }, | |
| 700 | − "devDependencies": { | |
| 701 | − "@types/node": "catalog:", | |
| 702 | − "bun-types": "catalog:", | |
| 703 | − }, | |
| 704 | − }, | |
| 705 | − "plugins/onepassword/react": { | |
| 706 | − "name": "@executor/plugin-onepassword-react", | |
| 707 | − "version": "0.0.0", | |
| 708 | − "dependencies": { | |
| 709 | − "@executor/plugin-onepassword-shared": "workspace:*", | |
| 426 | + "peerDependencies": { | |
| 427 | + "@effect-atom/atom-react": "^0.5.0", | |
| 710 | 428 | "@executor/react": "workspace:*", |
| 711 | − "react": "^19.2.0", | |
| 712 | − }, | |
| 713 | − "devDependencies": { | |
| 714 | − "@types/node": "catalog:", | |
| 715 | − "@types/react": "^19.2.10", | |
| 716 | − "bun-types": "catalog:", | |
| 717 | − }, | |
| 718 | − }, | |
| 719 | − "plugins/onepassword/sdk": { | |
| 720 | − "name": "@executor/plugin-onepassword-sdk", | |
| 721 | − "version": "0.0.0", | |
| 722 | − "dependencies": { | |
| 723 | − "@1password/sdk": "0.4.1-beta.1", | |
| 724 | − "@executor/platform-sdk": "workspace:*", | |
| 725 | − "@executor/plugin-onepassword-shared": "workspace:*", | |
| 726 | − "effect": "catalog:", | |
| 727 | − }, | |
| 728 | − "devDependencies": { | |
| 729 | − "@types/node": "catalog:", | |
| 730 | − "bun-types": "catalog:", | |
| 731 | − }, | |
| 429 | + "@executor/ui": "workspace:*", | |
| 430 | + "react": ">=18", | |
| 431 | + }, | |
| 432 | + "optionalPeers": [ | |
| 433 | + "@effect-atom/atom-react", | |
| 434 | + "@executor/react", | |
| 435 | + "@executor/ui", | |
| 436 | + "react", | |
| 437 | + ], | |
| 732 | 438 | }, |
| 733 | − "plugins/onepassword/shared": { | |
| 734 | − "name": "@executor/plugin-onepassword-shared", | |
| 735 | − "version": "0.0.0", | |
| 439 | + "packages/plugins/openapi": { | |
| 440 | + "name": "@executor/plugin-openapi", | |
| 441 | + "version": "1.4.0-beta.0", | |
| 736 | 442 | "dependencies": { |
| 443 | + "@apidevtools/swagger-parser": "^12.1.0", | |
| 737 | 444 | "@effect/platform": "catalog:", |
| 738 | − "@executor/platform-sdk": "workspace:*", | |
| 739 | − "effect": "catalog:", | |
| 740 | − }, | |
| 741 | − "devDependencies": { | |
| 742 | − "@types/node": "catalog:", | |
| 743 | − "bun-types": "catalog:", | |
| 744 | − }, | |
| 745 | − }, | |
| 746 | − "plugins/openapi/http": { | |
| 747 | − "name": "@executor/plugin-openapi-http", | |
| 748 | − "version": "0.0.0", | |
| 749 | − "dependencies": { | |
| 750 | − "@effect/platform": "catalog:", | |
| 751 | − "@executor/platform-api": "workspace:*", | |
| 752 | − "@executor/platform-sdk": "workspace:*", | |
| 753 | − "@executor/plugin-openapi-shared": "workspace:*", | |
| 445 | + "@effect/platform-node": "catalog:", | |
| 446 | + "@executor/sdk": "workspace:*", | |
| 754 | 447 | "effect": "catalog:", |
| 448 | + "openapi-types": "^12.1.3", | |
| 449 | + "yaml": "^2.7.1", | |
| 755 | 450 | }, |
| 756 | 451 | "devDependencies": { |
| 757 | − "@types/node": "catalog:", | |
| 758 | − "bun-types": "catalog:", | |
| 759 | − }, | |
| 760 | − }, | |
| 761 | − "plugins/openapi/react": { | |
| 762 | − "name": "@executor/plugin-openapi-react", | |
| 763 | − "version": "0.0.0", | |
| 764 | − "dependencies": { | |
| 765 | − "@executor/plugin-openapi-http": "workspace:*", | |
| 766 | − "@executor/plugin-openapi-shared": "workspace:*", | |
| 452 | + "@effect-atom/atom-react": "^0.5.0", | |
| 453 | + "@effect/vitest": "catalog:", | |
| 454 | + "@executor/api": "workspace:*", | |
| 767 | 455 | "@executor/react": "workspace:*", |
| 768 | − "react": "^19.2.0", | |
| 769 | − }, | |
| 770 | − "devDependencies": { | |
| 771 | − "@types/node": "catalog:", | |
| 772 | − "@types/react": "^19.2.10", | |
| 773 | − "bun-types": "catalog:", | |
| 774 | − }, | |
| 775 | − }, | |
| 776 | − "plugins/openapi/sdk": { | |
| 777 | − "name": "@executor/plugin-openapi-sdk", | |
| 778 | − "version": "0.0.0", | |
| 779 | − "dependencies": { | |
| 780 | − "@executor/codemode-core": "workspace:*", | |
| 781 | − "@executor/ir": "workspace:*", | |
| 782 | − "@executor/platform-sdk": "workspace:*", | |
| 783 | − "@executor/plugin-openapi-shared": "workspace:*", | |
| 784 | − "@executor/source-core": "workspace:*", | |
| 785 | − "effect": "catalog:", | |
| 786 | − "yaml": "^2.8.1", | |
| 787 | − }, | |
| 788 | − "devDependencies": { | |
| 789 | − "@effect/platform": "catalog:", | |
| 790 | − "@effect/platform-node": "catalog:", | |
| 791 | − "@executor/effect-test-utils": "workspace:*", | |
| 456 | + "@executor/ui": "workspace:*", | |
| 792 | 457 | "@types/node": "catalog:", |
| 458 | + "@types/react": "^19.1.0", | |
| 793 | 459 | "bun-types": "catalog:", |
| 460 | + "react": "^19.1.0", | |
| 794 | 461 | "vitest": "catalog:", |
| 795 | 462 | }, |
| 463 | + "peerDependencies": { | |
| 464 | + "@effect-atom/atom-react": "^0.5.0", | |
| 465 | + "@executor/api": "workspace:*", | |
| 466 | + "@executor/react": "workspace:*", | |
| 467 | + "@executor/ui": "workspace:*", | |
| 468 | + "@tanstack/react-router": "^1.168.10", | |
| 469 | + "react": "^19.1.0", | |
| 470 | + }, | |
| 471 | + "optionalPeers": [ | |
| 472 | + "@effect-atom/atom-react", | |
| 473 | + "@executor/api", | |
| 474 | + "@executor/react", | |
| 475 | + "@executor/ui", | |
| 476 | + "@tanstack/react-router", | |
| 477 | + "react", | |
| 478 | + ], | |
| 796 | 479 | }, |
| 797 | − "plugins/openapi/shared": { | |
| 798 | − "name": "@executor/plugin-openapi-shared", | |
| 799 | − "version": "0.0.0", | |
| 480 | + "packages/ui": { | |
| 481 | + "name": "@executor/ui", | |
| 482 | + "version": "1.4.0-beta.0", | |
| 800 | 483 | "dependencies": { |
| 801 | − "@executor/platform-sdk": "workspace:*", | |
| 802 | − "@executor/source-core": "workspace:*", | |
| 803 | − "effect": "catalog:", | |
| 804 | − "yaml": "^2.8.1", | |
| 484 | + "@base-ui/react": "^1.3.0", | |
| 485 | + "@hookform/resolvers": "^5.2.2", | |
| 486 | + "@shikijs/langs": "^4.0.2", | |
| 487 | + "@shikijs/themes": "^4.0.2", | |
| 488 | + "class-variance-authority": "^0.7.1", | |
| 489 | + "clsx": "^2.1.1", | |
| 490 | + "cmdk": "^1.1.1", | |
| 491 | + "date-fns": "^4.1.0", | |
| 492 | + "embla-carousel-react": "^8.6.0", | |
| 493 | + "input-otp": "^1.4.2", | |
| 494 | + "lucide-react": "^1.7.0", | |
| 495 | + "next-themes": "^0.4.6", | |
| 496 | + "radix-ui": "^1.4.3", | |
| 497 | + "react": "^19.1.0", | |
| 498 | + "react-day-picker": "^9.14.0", | |
| 499 | + "react-hook-form": "^7.72.0", | |
| 500 | + "react-resizable-panels": "^4", | |
| 501 | + "recharts": "3.8.0", | |
| 502 | + "shiki": "^4.0.2", | |
| 503 | + "sonner": "^2.0.7", | |
| 504 | + "streamdown": "^2.5.0", | |
| 505 | + "tailwind-merge": "^3.3.0", | |
| 506 | + "vaul": "^1.1.2", | |
| 507 | + "zod": "^4.3.6", | |
| 805 | 508 | }, |
| 806 | 509 | "devDependencies": { |
| 807 | − "@types/node": "catalog:", | |
| 808 | − "bun-types": "catalog:", | |
| 510 | + "@types/react": "^19.1.0", | |
| 511 | + "hast-util-to-jsx-runtime": "^2.3.6", | |
| 512 | + "tailwindcss": "^4.1.10", | |
| 513 | + "typescript": "^5.9.3", | |
| 809 | 514 | }, |
| 810 | 515 | }, |
| 811 | 516 | }, |
| 812 | 517 | "catalog": { |
| 813 | 518 | "@effect/cli": "^0.73.2", |
| 814 | − "@effect/platform": "^0.94.5", | |
| 815 | − "@effect/platform-node": "^0.104.1", | |
| 519 | + "@effect/cluster": "^0.58.0", | |
| 520 | + "@effect/experimental": "^0.60.0", | |
| 521 | + "@effect/platform": "^0.96.0", | |
| 522 | + "@effect/platform-bun": "^0.89.0", | |
| 523 | + "@effect/platform-node": "^0.106.0", | |
| 524 | + "@effect/sql": "^0.51.0", | |
| 525 | + "@effect/sql-sqlite-bun": "^0.52.0", | |
| 526 | + "@effect/sql-sqlite-node": "^0.52.0", | |
| 816 | 527 | "@effect/vitest": "^0.27.0", |
| 817 | 528 | "@types/node": "^24.3.1", |
| 818 | 529 | "bun-types": "^1.2.22", |
| 819 | − "effect": "^3.19.19", | |
| 530 | + "effect": "^3.21.0", | |
| 820 | 531 | "vitest": "^3.2.4", |
| 821 | − "zod": "^4.3.6", | |
| 822 | 532 | }, |
| 823 | 533 | "packages": { |
| 534 | + "@1password/op-js": ["@1password/op-js@0.1.13", "", { "dependencies": { "lookpath": "^1.2.2", "semver": "^7.6.2" } }, "sha512-ZZBLxVqywFdvIbLv2xWw2N1ImSi183rRKf90vV19KRMReNyLwuD0dv6IrKrIdrJU33IuV3Gz85Z4K2a1PJTBDg=="], | |
| 535 | + | |
| 824 | 536 | "@1password/sdk": ["@1password/sdk@0.4.1-beta.1", "", { "dependencies": { "@1password/sdk-core": "0.4.1-beta.1" } }, "sha512-QWY6eIIEs9at6kAFbgjZ1vVxg7ygp/MwXJ6/BoBdPkqIk8vfulXu4pjDsVQ87HhddJAD5LVGBXSbQIa+svI3bA=="], |
| 825 | 537 | |
| 826 | 538 | "@1password/sdk-core": ["@1password/sdk-core@0.4.1-beta.1", "", {}, "sha512-/otbg1JVhsEn6oUIeReoT9TmFr8J7KBwr9UuRVfJFwwGG3bHPF8ewT+LhRimQeJtypqQ69ZVuOYkxknD4iQHxw=="], |
| 827 | 539 | |
| 828 | − "@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.66", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.19", "@vercel/oidc": "3.1.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-SIQ0YY0iMuv+07HLsZ+bB990zUJ6S4ujORAh+Jv1V2KGNn73qQKnGO0JBk+w+Res8YqOFSycwDoWcFlQrVxS4A=="], | |
| 540 | + "@antfu/install-pkg": ["@antfu/install-pkg@1.1.0", "", { "dependencies": { "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" } }, "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ=="], | |
| 829 | 541 | |
| 830 | − "@ai-sdk/provider": ["@ai-sdk/provider@3.0.8", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ=="], | |
| 542 | + "@apidevtools/json-schema-ref-parser": ["@apidevtools/json-schema-ref-parser@14.0.1", "", { "dependencies": { "@types/json-schema": "^7.0.15", "js-yaml": "^4.1.0" } }, "sha512-Oc96zvmxx1fqoSEdUmfmvvb59/KDOnUoJ7s2t7bISyAn0XEz57LCCw8k2Y4Pf3mwKaZLMciESALORLgfe2frCw=="], | |
| 831 | 543 | |
| 832 | − "@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.19", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-3eG55CrSWCu2SXlqq2QCsFjo3+E7+Gmg7i/oRVoSZzIodTuDSfLb3MRje67xE9RFea73Zao7Lm4mADIfUETKGg=="], | |
| 544 | + "@apidevtools/openapi-schemas": ["@apidevtools/openapi-schemas@2.1.0", "", {}, "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ=="], | |
| 833 | 545 | |
| 834 | − "@antfu/ni": ["@antfu/ni@0.23.2", "", { "bin": { "na": "bin/na.mjs", "ni": "bin/ni.mjs", "nr": "bin/nr.mjs", "nu": "bin/nu.mjs", "nci": "bin/nci.mjs", "nlx": "bin/nlx.mjs", "nun": "bin/nun.mjs" } }, "sha512-FSEVWXvwroExDXUu8qV6Wqp2X3D1nJ0Li4LFymCyvCVrm7I3lNfG0zZWSWvGU1RE7891eTnFTyh31L3igOwNKQ=="], | |
| 546 | + "@apidevtools/swagger-methods": ["@apidevtools/swagger-methods@3.0.2", "", {}, "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg=="], | |
| 835 | 547 | |
| 836 | − "@asamuzakjp/css-color": ["@asamuzakjp/css-color@3.2.0", "", { "dependencies": { "@csstools/css-calc": "^2.1.3", "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", "lru-cache": "^10.4.3" } }, "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw=="], | |
| 548 | + "@apidevtools/swagger-parser": ["@apidevtools/swagger-parser@12.1.0", "", { "dependencies": { "@apidevtools/json-schema-ref-parser": "14.0.1", "@apidevtools/openapi-schemas": "^2.1.0", "@apidevtools/swagger-methods": "^3.0.2", "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", "call-me-maybe": "^1.0.2" }, "peerDependencies": { "openapi-types": ">=7" } }, "sha512-e5mJoswsnAX0jG+J09xHFYQXb/bUc5S3pLpMxUuRUA2H8T2kni3yEoyz2R3Dltw5f4A6j6rPNMpWTK+iVDFlng=="], | |
| 837 | 549 | |
| 838 | 550 | "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], |
| 839 | 551 | |
| @@ -843,53 +555,31 @@ · 3 unmodified lines | ||
| 843 | 555 | |
| 844 | 556 | "@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="], |
| 845 | 557 | |
| 846 | − "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="], | |
| 847 | − | |
| 848 | 558 | "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="], |
| 849 | 559 | |
| 850 | − "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.6", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow=="], | |
| 851 | − | |
| 852 | 560 | "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], |
| 853 | 561 | |
| 854 | − "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="], | |
| 855 | − | |
| 856 | 562 | "@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="], |
| 857 | 563 | |
| 858 | 564 | "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="], |
| 859 | 565 | |
| 860 | − "@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="], | |
| 861 | − | |
| 862 | 566 | "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], |
| 863 | 567 | |
| 864 | − "@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.28.6", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg=="], | |
| 865 | − | |
| 866 | − "@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="], | |
| 867 | − | |
| 868 | 568 | "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], |
| 869 | 569 | |
| 870 | 570 | "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], |
| 871 | 571 | |
| 872 | 572 | "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], |
| 873 | 573 | |
| 874 | − "@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="], | |
| 875 | − | |
| 876 | − "@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="], | |
| 877 | − | |
| 878 | − "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w=="], | |
| 879 | − | |
| 880 | − "@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A=="], | |
| 574 | + "@babel/helpers": ["@babel/helpers@7.29.2", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.29.0" } }, "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw=="], | |
| 881 | 575 | |
| 882 | − "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.28.6", "", { "dependencies": { "@babel/helper-module-transforms": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA=="], | |
| 576 | + "@babel/parser": ["@babel/parser@7.29.2", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA=="], | |
| 883 | 577 | |
| 884 | 578 | "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="], |
| 885 | 579 | |
| 886 | 580 | "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="], |
| 887 | 581 | |
| 888 | − "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw=="], | |
| 889 | − | |
| 890 | − "@babel/preset-typescript": ["@babel/preset-typescript@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g=="], | |
| 891 | − | |
| 892 | − "@babel/runtime": ["@babel/runtime@7.28.6", "", {}, "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA=="], | |
| 582 | + "@babel/runtime": ["@babel/runtime@7.29.2", "", {}, "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g=="], | |
| 893 | 583 | |
| 894 | 584 | "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="], |
| 895 | 585 | |
| @@ -901,6 +591,8 @@ · 5 unmodified lines | ||
| 901 | 591 | |
| 902 | 592 | "@base-ui/utils": ["@base-ui/utils@0.2.6", "", { "dependencies": { "@babel/runtime": "^7.28.6", "@floating-ui/utils": "^0.2.11", "reselect": "^5.1.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-yQ+qeuqohwhsNpoYDqqXaLllYAkPCP4vYdDrVo8FQXaAPfHWm1pG/Vm+jmGTA5JFS0BAIjookyapuJFY8F9PIw=="], |
| 903 | 593 | |
| 594 | + "@braintree/sanitize-url": ["@braintree/sanitize-url@7.1.2", "", {}, "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA=="], | |
| 595 | + | |
| 904 | 596 | "@changesets/apply-release-plan": ["@changesets/apply-release-plan@7.1.0", "", { "dependencies": { "@changesets/config": "^3.1.3", "@changesets/get-version-range-type": "^0.4.0", "@changesets/git": "^3.0.4", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "detect-indent": "^6.0.0", "fs-extra": "^7.0.1", "lodash.startcase": "^4.4.0", "outdent": "^0.5.0", "prettier": "^2.7.1", "resolve-from": "^5.0.0", "semver": "^7.5.3" } }, "sha512-yq8ML3YS7koKQ/9bk1PqO0HMzApIFNwjlwCnwFEXMzNe8NpzeeYYKCmnhWJGkN8g7E51MnWaSbqRcTcdIxUgnQ=="], |
| 905 | 597 | |
| 906 | 598 | "@changesets/assemble-release-plan": ["@changesets/assemble-release-plan@6.0.9", "", { "dependencies": { "@changesets/errors": "^0.2.0", "@changesets/get-dependents-graph": "^2.1.3", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "semver": "^7.5.3" } }, "sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ=="], |
| @@ -935,19 +627,17 @@ · 28 unmodified lines | ||
| 935 | 627 | |
| 936 | 628 | "@changesets/write": ["@changesets/write@0.4.0", "", { "dependencies": { "@changesets/types": "^6.1.0", "fs-extra": "^7.0.1", "human-id": "^4.1.1", "prettier": "^2.7.1" } }, "sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q=="], |
| 937 | 629 | |
| 938 | − "@csstools/color-helpers": ["@csstools/color-helpers@5.1.0", "", {}, "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA=="], | |
| 939 | − | |
| 940 | − "@csstools/css-calc": ["@csstools/css-calc@2.1.4", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4" } }, "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ=="], | |
| 630 | + "@chevrotain/cst-dts-gen": ["@chevrotain/cst-dts-gen@11.1.2", "", { "dependencies": { "@chevrotain/gast": "11.1.2", "@chevrotain/types": "11.1.2", "lodash-es": "4.17.23" } }, "sha512-XTsjvDVB5nDZBQB8o0o/0ozNelQtn2KrUVteIHSlPd2VAV2utEb6JzyCJaJ8tGxACR4RiBNWy5uYUHX2eji88Q=="], | |
| 941 | 631 | |
| 942 | − "@csstools/css-color-parser": ["@csstools/css-color-parser@3.1.0", "", { "dependencies": { "@csstools/color-helpers": "^5.1.0", "@csstools/css-calc": "^2.1.4" }, "peerDependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4" } }, "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA=="], | |
| 632 | + "@chevrotain/gast": ["@chevrotain/gast@11.1.2", "", { "dependencies": { "@chevrotain/types": "11.1.2", "lodash-es": "4.17.23" } }, "sha512-Z9zfXR5jNZb1Hlsd/p+4XWeUFugrHirq36bKzPWDSIacV+GPSVXdk+ahVWZTwjhNwofAWg/sZg58fyucKSQx5g=="], | |
| 943 | 633 | |
| 944 | − "@csstools/css-parser-algorithms": ["@csstools/css-parser-algorithms@3.0.5", "", { "peerDependencies": { "@csstools/css-tokenizer": "^3.0.4" } }, "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ=="], | |
| 634 | + "@chevrotain/regexp-to-ast": ["@chevrotain/regexp-to-ast@11.1.2", "", {}, "sha512-nMU3Uj8naWer7xpZTYJdxbAs6RIv/dxYzkYU8GSwgUtcAAlzjcPfX1w+RKRcYG8POlzMeayOQ/znfwxEGo5ulw=="], | |
| 945 | 635 | |
| 946 | − "@csstools/css-tokenizer": ["@csstools/css-tokenizer@3.0.4", "", {}, "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw=="], | |
| 636 | + "@chevrotain/types": ["@chevrotain/types@11.1.2", "", {}, "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw=="], | |
| 947 | 637 | |
| 948 | − "@dotenvx/dotenvx": ["@dotenvx/dotenvx@1.59.1", "", { "dependencies": { "commander": "^11.1.0", "dotenv": "^17.2.1", "eciesjs": "^0.4.10", "execa": "^5.1.1", "fdir": "^6.2.0", "ignore": "^5.3.0", "object-treeify": "1.1.33", "picomatch": "^4.0.2", "which": "^4.0.0" }, "bin": { "dotenvx": "src/cli/dotenvx.js" } }, "sha512-Qg+meC+XFxliuVSDlEPkKnaUjdaJKK6FNx/Wwl2UxhQR8pyPIuLhMavsF7ePdB9qFZUWV1jEK3ckbJir/WmF4w=="], | |
| 638 | + "@chevrotain/utils": ["@chevrotain/utils@11.1.2", "", {}, "sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA=="], | |
| 949 | 639 | |
| 950 | − "@ecies/ciphers": ["@ecies/ciphers@0.2.5", "", { "peerDependencies": { "@noble/ciphers": "^1.0.0" } }, "sha512-GalEZH4JgOMHYYcYmVqnFirFsjZHeoGMDt9IxEnM9F7GRUUyUksJ7Ou53L83WHJq3RWKD3AcBpo0iQh0oMpf8A=="], | |
| 640 | + "@date-fns/tz": ["@date-fns/tz@1.4.1", "", {}, "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA=="], | |
| 951 | 641 | |
| 952 | 642 | "@effect-atom/atom": ["@effect-atom/atom@0.5.3", "", { "peerDependencies": { "@effect/experimental": "^0.58.0", "@effect/platform": "^0.94.2", "@effect/rpc": "^0.73.0", "effect": "^3.19.15" } }, "sha512-TRZv/i+YT3TtnN0oFORJqXdxSs1fc7lrJlH+1xZvDFyjC9hgoVnrcKbeZsDFmr6r0wYRqVo7U3IftxiQNjpNZA=="], |
| 953 | 643 | |
| @@ -955,167 +645,115 @@ · 1 unmodified line | ||
| 955 | 645 | |
| 956 | 646 | "@effect/cli": ["@effect/cli@0.73.2", "", { "dependencies": { "ini": "^4.1.3", "toml": "^3.0.0", "yaml": "^2.5.0" }, "peerDependencies": { "@effect/platform": "^0.94.3", "@effect/printer": "^0.47.0", "@effect/printer-ansi": "^0.47.0", "effect": "^3.19.16" } }, "sha512-K8IJo81+qa1LU8dhxcDU4QO/bIjL/dPd3zUOSCpLiuUNz8Y3/T+WNs3GqIXEhMfCFMSlRZERN0YgmtRlEZUREA=="], |
| 957 | 647 | |
| 958 | − "@effect/cluster": ["@effect/cluster@0.56.4", "", { "dependencies": { "kubernetes-types": "^1.30.0" }, "peerDependencies": { "@effect/platform": "^0.94.5", "@effect/rpc": "^0.73.1", "@effect/sql": "^0.49.0", "@effect/workflow": "^0.16.0", "effect": "^3.19.17" } }, "sha512-7Je5/JlbZOlsSxsbKjr97dJed2cNGWsb+TLNgMcr5mRDbcWlFOTUGvsrisEJV6waosYLIg+2omPdvnvRoYKdhA=="], | |
| 648 | + "@effect/cluster": ["@effect/cluster@0.58.0", "", { "dependencies": { "kubernetes-types": "^1.30.0" }, "peerDependencies": { "@effect/platform": "^0.96.0", "@effect/rpc": "^0.75.0", "@effect/sql": "^0.51.0", "@effect/workflow": "^0.18.0", "effect": "^3.21.0" } }, "sha512-0Zog7s7XdntWcTqdqWPoj6nc7hPaWIzp0k0DsFUWyCynXNPK9dAtgFrSce04NhddNqqbhtZck/lhuqJwNBrprQ=="], | |
| 959 | 649 | |
| 960 | − "@effect/experimental": ["@effect/experimental@0.58.0", "", { "dependencies": { "uuid": "^11.0.3" }, "peerDependencies": { "@effect/platform": "^0.94.0", "effect": "^3.19.13", "ioredis": "^5", "lmdb": "^3" }, "optionalPeers": ["ioredis", "lmdb"] }, "sha512-IEP9sapjF6rFy5TkoqDPc86st/fnqUfjT7Xa3pWJrFGr1hzaMXHo+mWsYOZS9LAOVKnpHuVziDK97EP5qsCHVA=="], | |
| 650 | + "@effect/experimental": ["@effect/experimental@0.60.0", "", { "dependencies": { "uuid": "^11.0.3" }, "peerDependencies": { "@effect/platform": "^0.96.0", "effect": "^3.21.0", "ioredis": "^5", "lmdb": "^3" }, "optionalPeers": ["ioredis", "lmdb"] }, "sha512-i5zIg7Xup2KgHyqHlYtkgqSE1bNzCL0GbbTQxrpIzKF0q/ebknOk/ox8B/gIq2vImjoEE81h/oxU+6i1NH210g=="], | |
| 961 | 651 | |
| 962 | − "@effect/opentelemetry": ["@effect/opentelemetry@0.61.0", "", { "peerDependencies": { "@effect/platform": "^0.94.2", "@opentelemetry/api": "^1.9", "@opentelemetry/resources": "^2.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": "^2.0.0", "@opentelemetry/sdk-trace-base": "^2.0.0", "@opentelemetry/sdk-trace-node": "^2.0.0", "@opentelemetry/sdk-trace-web": "^2.0.0", "@opentelemetry/semantic-conventions": "^1.33.0", "effect": "^3.19.15" } }, "sha512-aTg4qWzMxGDoUZKSyws/dMZqVNoSCQIvHaPDJnWitUAVuWDAPOXiaiHJDWO39cwDlySBTCSF6rEanm3+nR/2Mg=="], | |
| 652 | + "@effect/language-service": ["@effect/language-service@0.84.2", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-l04qNxpiA8rY5yXWckRPJ7Mk5MNerXuNymSFf+IdflfI5i8jgL1bpBNLuP6ijg7wgjdHc/KmTnCj2kT0SCntuA=="], | |
| 963 | 653 | |
| 964 | − "@effect/platform": ["@effect/platform@0.94.5", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.19.17" } }, "sha512-z05APUiDDPbodhTkH/RJqOLoCU11bU2IZLfcwLFrld03+ob1VeqRnELQlmueLIYm6NZifHAtjl32V+GRt34y4A=="], | |
| 654 | + "@effect/platform": ["@effect/platform@0.96.0", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.21.0" } }, "sha512-U7PLhkVzg7zzrgFvyWATOzD6reL87KG/fcdOxgLWBQ/J5CCU6qdPAVG+0o6o+IxcsLoqGwxs+rFxaFzrdtDV1A=="], | |
| 965 | 655 | |
| 966 | − "@effect/platform-node": ["@effect/platform-node@0.104.1", "", { "dependencies": { "@effect/platform-node-shared": "^0.57.1", "mime": "^3.0.0", "undici": "^7.10.0", "ws": "^8.18.2" }, "peerDependencies": { "@effect/cluster": "^0.56.1", "@effect/platform": "^0.94.2", "@effect/rpc": "^0.73.0", "@effect/sql": "^0.49.0", "effect": "^3.19.15" } }, "sha512-jT1a/z98niK6fnEU8pWHPPCdJMVDRCIdB65lolcOjse5rsTwVbczMjvKkhVQpF63mNWoOnol7OTRNkw5L54llg=="], | |
| 656 | + "@effect/platform-bun": ["@effect/platform-bun@0.89.0", "", { "dependencies": { "@effect/platform-node-shared": "^0.59.0", "multipasta": "^0.2.7" }, "peerDependencies": { "@effect/cluster": "^0.58.0", "@effect/platform": "^0.96.0", "@effect/rpc": "^0.75.0", "@effect/sql": "^0.51.0", "effect": "^3.21.0" } }, "sha512-ReT5f2vujJfffMOBexrgwJd2RLxgfr2G0c1FyCsoflcjdQJ7RZE3cwHDp1M3hAzmG67wWAssMHqLsX6H/n27sQ=="], | |
| 967 | 657 | |
| 968 | − "@effect/platform-node-shared": ["@effect/platform-node-shared@0.57.1", "", { "dependencies": { "@parcel/watcher": "^2.5.1", "multipasta": "^0.2.7", "ws": "^8.18.2" }, "peerDependencies": { "@effect/cluster": "^0.56.1", "@effect/platform": "^0.94.2", "@effect/rpc": "^0.73.0", "@effect/sql": "^0.49.0", "effect": "^3.19.15" } }, "sha512-oX/bApMdoKsyrDiNdJxo7U9Rz1RXsjRv+ecfAPp1qGlSdGIo32wVRvJ2XCHqYj0sqaYJS0pU0/GCulRfVGuJag=="], | |
| 658 | + "@effect/platform-node": ["@effect/platform-node@0.106.0", "", { "dependencies": { "@effect/platform-node-shared": "^0.59.0", "mime": "^3.0.0", "undici": "^7.10.0", "ws": "^8.18.2" }, "peerDependencies": { "@effect/cluster": "^0.58.0", "@effect/platform": "^0.96.0", "@effect/rpc": "^0.75.0", "@effect/sql": "^0.51.0", "effect": "^3.21.0" } }, "sha512-mpsJK2jNLVd0jQAjHKBo8j3wdKWznSGvfnKBcAuG/9Rr4mb8bMRZFLXHHT9wUP7EvnZ0tDZJgEDxkC+j+ByRag=="], | |
| 659 | + | |
| 660 | + "@effect/platform-node-shared": ["@effect/platform-node-shared@0.59.0", "", { "dependencies": { "@parcel/watcher": "^2.5.1", "multipasta": "^0.2.7", "ws": "^8.18.2" }, "peerDependencies": { "@effect/cluster": "^0.58.0", "@effect/platform": "^0.96.0", "@effect/rpc": "^0.75.0", "@effect/sql": "^0.51.0", "effect": "^3.21.0" } }, "sha512-3bq2YKKfLY7UFauZSxqZUneCXoA3SMSls82V+0RKunvRlfPuPQW0hVn6t1RkvEdh0PDoygWG2mZXYQa6Iqgp9A=="], | |
| 969 | 661 | |
| 970 | 662 | "@effect/printer": ["@effect/printer@0.47.0", "", { "peerDependencies": { "@effect/typeclass": "^0.38.0", "effect": "^3.19.0" } }, "sha512-VgR8e+YWWhMEAh9qFOjwiZ3OXluAbcVLIOtvp2S5di1nSrPOZxj78g8LE77JSvyfp5y5bS2gmFW+G7xD5uU+2Q=="], |
| 971 | 663 | |
| 972 | 664 | "@effect/printer-ansi": ["@effect/printer-ansi@0.47.0", "", { "dependencies": { "@effect/printer": "^0.47.0" }, "peerDependencies": { "@effect/typeclass": "^0.38.0", "effect": "^3.19.0" } }, "sha512-tDEQ9XJpXDNYoWMQJHFRMxKGmEOu6z32x3Kb8YLOV5nkauEKnKmWNs7NBp8iio/pqoJbaSwqDwUg9jXVquxfWQ=="], |
| 973 | 665 | |
| 974 | − "@effect/rpc": ["@effect/rpc@0.73.2", "", { "dependencies": { "msgpackr": "^1.11.4" }, "peerDependencies": { "@effect/platform": "^0.94.5", "effect": "^3.19.18" } }, "sha512-td7LHDgBOYKg+VgGWEelD8rSAmvjXz7am17vfxZROX5qIYuvH7drL/z4p5xQFadhHZ7DYdlFpqdO9ggc77OCIw=="], | |
| 975 | − | |
| 976 | − "@effect/sql": ["@effect/sql@0.49.0", "", { "dependencies": { "uuid": "^11.0.3" }, "peerDependencies": { "@effect/experimental": "^0.58.0", "@effect/platform": "^0.94.0", "effect": "^3.19.13" } }, "sha512-9UEKR+z+MrI/qMAmSvb/RiD9KlgIazjZUCDSpwNgm0lEK9/Q6ExEyfziiYFVCPiptp52cBw8uBHRic8hHnwqXA=="], | |
| 977 | − | |
| 978 | − "@effect/typeclass": ["@effect/typeclass@0.38.0", "", { "peerDependencies": { "effect": "^3.19.0" } }, "sha512-lMUcJTRtG8KXhXoczapZDxbLK5os7M6rn0zkvOgncJW++A0UyelZfMVMKdT5R+fgpZcsAU/1diaqw3uqLJwGxA=="], | |
| 979 | − | |
| 980 | − "@effect/vitest": ["@effect/vitest@0.27.0", "", { "peerDependencies": { "effect": "^3.19.0", "vitest": "^3.2.0" } }, "sha512-8bM7n9xlMUYw9GqPIVgXFwFm2jf27m/R7psI64PGpwU5+26iwyxp9eAXEsfT5S6lqztYfpQQ1Ubp5o6HfNYzJQ=="], | |
| 981 | − | |
| 982 | − "@effect/workflow": ["@effect/workflow@0.16.0", "", { "peerDependencies": { "@effect/experimental": "^0.58.0", "@effect/platform": "^0.94.0", "@effect/rpc": "^0.73.0", "effect": "^3.19.13" } }, "sha512-MiAdlxx3TixkgHdbw+Yf1Z3tHAAE0rOQga12kIydJqj05Fnod+W/I+kQGRMY/XWRg+QUsVxhmh1qTr7Ype6lrw=="], | |
| 666 | + "@effect/rpc": ["@effect/rpc@0.75.0", "", { "dependencies": { "msgpackr": "^1.11.4" }, "peerDependencies": { "@effect/platform": "^0.96.0", "effect": "^3.21.0" } }, "sha512-VFeJ16cZUXqiIzG9UHOVKGuiBPJ7fV+0lEbJU6xi12JnnxXe/19BQPpOwiRawCUbPOR3/xIURDUgGxU+Ft0pvQ=="], | |
| 983 | 667 | |
| 984 | − "@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], | |
| 668 | + "@effect/sql": ["@effect/sql@0.51.0", "", { "dependencies": { "uuid": "^11.0.3" }, "peerDependencies": { "@effect/experimental": "^0.60.0", "@effect/platform": "^0.96.0", "effect": "^3.21.0" } }, "sha512-e7hWe46QD15eMCr4kNBMVdItIVK/WLHJG+d8DLL1FjVf5Ra82k2mwUYIXplJewVbHjt3my6GSKPPd1ZrQjVd5A=="], | |
| 985 | 669 | |
| 986 | − "@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], | |
| 670 | + "@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@0.52.0", "", { "peerDependencies": { "@effect/experimental": "^0.60.0", "@effect/platform": "^0.96.0", "@effect/sql": "^0.51.0", "effect": "^3.21.0" } }, "sha512-iqQ7SvSNxq0HLjKW5IQ29FsCTzOD1CuX1wuBEuPLLgPCvuEykEHLn4zDrs2qJ+O3CBEUm4kiCy29tmfHE7uAdw=="], | |
| 987 | 671 | |
| 988 | − "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], | |
| 672 | + "@effect/sql-sqlite-node": ["@effect/sql-sqlite-node@0.52.0", "", { "dependencies": { "better-sqlite3": "^12.6.2" }, "peerDependencies": { "@effect/experimental": "^0.60.0", "@effect/platform": "^0.96.0", "@effect/sql": "^0.51.0", "effect": "^3.21.0" } }, "sha512-yijDbly4MwxAPebvd2ZBI62qDpGdXKL96drMzflXDnjEh2JiVr/xVyy1VB0JsVxqw8IJ9TUIgOvAJWQ88oVMXA=="], | |
| 989 | 673 | |
| 990 | − "@endo/cache-map": ["@endo/cache-map@1.1.0", "", {}, "sha512-owFGshs/97PDw9oguZqU/px8Lv1d0KjAUtDUiPwKHNXRVUE/jyettEbRoTbNJR1OaI8biMn6bHr9kVJsOh6dXw=="], | |
| 674 | + "@effect/typeclass": ["@effect/typeclass@0.38.0", "", { "peerDependencies": { "effect": "^3.19.0" } }, "sha512-lMUcJTRtG8KXhXoczapZDxbLK5os7M6rn0zkvOgncJW++A0UyelZfMVMKdT5R+fgpZcsAU/1diaqw3uqLJwGxA=="], | |
| 991 | 675 | |
| 992 | − "@endo/env-options": ["@endo/env-options@1.1.11", "", {}, "sha512-p9OnAPsdqoX4YJsE98e3NBVhIr2iW9gNZxHhAI2/Ul5TdRfoOViItzHzTqrgUVopw6XxA1u1uS6CykLMDUxarA=="], | |
| 676 | + "@effect/vitest": ["@effect/vitest@0.27.0", "", { "peerDependencies": { "effect": "^3.19.0", "vitest": "^3.2.0" } }, "sha512-8bM7n9xlMUYw9GqPIVgXFwFm2jf27m/R7psI64PGpwU5+26iwyxp9eAXEsfT5S6lqztYfpQQ1Ubp5o6HfNYzJQ=="], | |
| 993 | 677 | |
| 994 | − "@endo/immutable-arraybuffer": ["@endo/immutable-arraybuffer@1.1.2", "", {}, "sha512-u+NaYB2aqEugQ3u7w3c5QNkPogf8q/xGgsPaqdY6pUiGWtYiTiFspKFcha6+oeZhWXWQ23rf0KrUq0kfuzqYyQ=="], | |
| 678 | + "@effect/workflow": ["@effect/workflow@0.18.0", "", { "peerDependencies": { "@effect/experimental": "^0.60.0", "@effect/platform": "^0.96.0", "@effect/rpc": "^0.75.0", "effect": "^3.21.0" } }, "sha512-9Zp+x9ADtR0H6CRhU6wLyPcIRjO1PXjvSpUlFlBQ8piw7ldjPmnUWEY8YQuH6eExV2dalQ4z2LMiZ5Bd7XAJbA=="], | |
| 995 | 679 | |
| 996 | − "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="], | |
| 680 | + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], | |
| 997 | 681 | |
| 998 | − "@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="], | |
| 682 | + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], | |
| 999 | 683 | |
| 1000 | − "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="], | |
| 684 | + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], | |
| 1001 | 685 | |
| 1002 | − "@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="], | |
| 686 | + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], | |
| 1003 | 687 | |
| 1004 | − "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="], | |
| 688 | + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], | |
| 1005 | 689 | |
| 1006 | − "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="], | |
| 690 | + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], | |
| 1007 | 691 | |
| 1008 | − "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="], | |
| 692 | + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], | |
| 1009 | 693 | |
| 1010 | − "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="], | |
| 694 | + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], | |
| 1011 | 695 | |
| 1012 | − "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="], | |
| 696 | + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], | |
| 1013 | 697 | |
| 1014 | − "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="], | |
| 698 | + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], | |
| 1015 | 699 | |
| 1016 | − "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="], | |
| 700 | + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], | |
| 1017 | 701 | |
| 1018 | − "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="], | |
| 702 | + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], | |
| 1019 | 703 | |
| 1020 | − "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="], | |
| 704 | + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], | |
| 1021 | 705 | |
| 1022 | − "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="], | |
| 706 | + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], | |
| 1023 | 707 | |
| 1024 | − "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="], | |
| 708 | + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], | |
| 1025 | 709 | |
| 1026 | − "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="], | |
| 710 | + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], | |
| 1027 | 711 | |
| 1028 | − "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="], | |
| 712 | + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], | |
| 1029 | 713 | |
| 1030 | − "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="], | |
| 714 | + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], | |
| 1031 | 715 | |
| 1032 | − "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="], | |
| 716 | + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], | |
| 1033 | 717 | |
| 1034 | − "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="], | |
| 718 | + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], | |
| 1035 | 719 | |
| 1036 | − "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="], | |
| 720 | + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], | |
| 1037 | 721 | |
| 1038 | − "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="], | |
| 722 | + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], | |
| 1039 | 723 | |
| 1040 | − "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="], | |
| 724 | + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], | |
| 1041 | 725 | |
| 1042 | − "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="], | |
| 726 | + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], | |
| 1043 | 727 | |
| 1044 | − "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="], | |
| 728 | + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], | |
| 1045 | 729 | |
| 1046 | − "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="], | |
| 730 | + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], | |
| 1047 | 731 | |
| 1048 | − "@executor/ai-sdk-adapter": ["@executor/ai-sdk-adapter@workspace:packages/hosts/ai-sdk"], | |
| 732 | + "@executor/api": ["@executor/api@workspace:packages/core/api"], | |
| 1049 | 733 | |
| 1050 | 734 | "@executor/codemode-core": ["@executor/codemode-core@workspace:packages/kernel/core"], |
| 1051 | 735 | |
| 1052 | − "@executor/docs": ["@executor/docs@workspace:apps/docs"], | |
| 736 | + "@executor/config": ["@executor/config@workspace:packages/core/config"], | |
| 1053 | 737 | |
| 1054 | − "@executor/effect-test-utils": ["@executor/effect-test-utils@workspace:packages/dev/effect-test-utils"], | |
| 738 | + "@executor/execution": ["@executor/execution@workspace:packages/core/execution"], | |
| 1055 | 739 | |
| 1056 | − "@executor/executor-mcp": ["@executor/executor-mcp@workspace:packages/hosts/mcp"], | |
| 740 | + "@executor/host-mcp": ["@executor/host-mcp@workspace:packages/hosts/mcp"], | |
| 1057 | 741 | |
| 1058 | 742 | "@executor/ir": ["@executor/ir@workspace:packages/kernel/ir"], |
| 1059 | 743 | |
| 1060 | − "@executor/kitchen-sink": ["@executor/kitchen-sink@workspace:packages/dev/kitchen-sink"], | |
| 1061 | − | |
| 1062 | − "@executor/mcp-elicitation-demo": ["@executor/mcp-elicitation-demo@workspace:examples/mcp-elicitation-demo"], | |
| 1063 | − | |
| 1064 | − "@executor/platform-api": ["@executor/platform-api@workspace:packages/platform/api"], | |
| 1065 | − | |
| 1066 | − "@executor/platform-sdk": ["@executor/platform-sdk@workspace:packages/platform/sdk"], | |
| 1067 | − | |
| 1068 | − "@executor/platform-sdk-file": ["@executor/platform-sdk-file@workspace:packages/platform/sdk-file"], | |
| 1069 | − | |
| 1070 | − "@executor/plugin-execution-history-react": ["@executor/plugin-execution-history-react@workspace:plugins/execution-history/react"], | |
| 1071 | − | |
| 1072 | − "@executor/plugin-google-discovery-http": ["@executor/plugin-google-discovery-http@workspace:plugins/google-discovery/http"], | |
| 1073 | − | |
| 1074 | − "@executor/plugin-google-discovery-react": ["@executor/plugin-google-discovery-react@workspace:plugins/google-discovery/react"], | |
| 1075 | − | |
| 1076 | − "@executor/plugin-google-discovery-sdk": ["@executor/plugin-google-discovery-sdk@workspace:plugins/google-discovery/sdk"], | |
| 1077 | − | |
| 1078 | − "@executor/plugin-google-discovery-shared": ["@executor/plugin-google-discovery-shared@workspace:plugins/google-discovery/shared"], | |
| 1079 | − | |
| 1080 | − "@executor/plugin-graphql-http": ["@executor/plugin-graphql-http@workspace:plugins/graphql/http"], | |
| 1081 | − | |
| 1082 | − "@executor/plugin-graphql-react": ["@executor/plugin-graphql-react@workspace:plugins/graphql/react"], | |
| 1083 | − | |
| 1084 | − "@executor/plugin-graphql-sdk": ["@executor/plugin-graphql-sdk@workspace:plugins/graphql/sdk"], | |
| 744 | + "@executor/plugin-file-secrets": ["@executor/plugin-file-secrets@workspace:packages/plugins/file-secrets"], | |
| 1085 | 745 | |
| 1086 | − "@executor/plugin-graphql-shared": ["@executor/plugin-graphql-shared@workspace:plugins/graphql/shared"], | |
| 746 | + "@executor/plugin-google-discovery": ["@executor/plugin-google-discovery@workspace:packages/plugins/google-discovery"], | |
| 1087 | 747 | |
| 1088 | − "@executor/plugin-keychain-secret-store-sdk": ["@executor/plugin-keychain-secret-store-sdk@workspace:plugins/keychain-secret-store/sdk"], | |
| 748 | + "@executor/plugin-graphql": ["@executor/plugin-graphql@workspace:packages/plugins/graphql"], | |
| 1089 | 749 | |
| 1090 | − "@executor/plugin-local-secret-store-sdk": ["@executor/plugin-local-secret-store-sdk@workspace:plugins/local-secret-store/sdk"], | |
| 750 | + "@executor/plugin-keychain": ["@executor/plugin-keychain@workspace:packages/plugins/keychain"], | |
| 1091 | 751 | |
| 1092 | − "@executor/plugin-local-tools-react": ["@executor/plugin-local-tools-react@workspace:plugins/local-tools/react"], | |
| 752 | + "@executor/plugin-mcp": ["@executor/plugin-mcp@workspace:packages/plugins/mcp"], | |
| 1093 | 753 | |
| 1094 | − "@executor/plugin-local-tools-sdk": ["@executor/plugin-local-tools-sdk@workspace:plugins/local-tools/sdk"], | |
| 754 | + "@executor/plugin-onepassword": ["@executor/plugin-onepassword@workspace:packages/plugins/onepassword"], | |
| 1095 | 755 | |
| 1096 | − "@executor/plugin-mcp-http": ["@executor/plugin-mcp-http@workspace:plugins/mcp/http"], | |
| 1097 | − | |
| 1098 | − "@executor/plugin-mcp-react": ["@executor/plugin-mcp-react@workspace:plugins/mcp/react"], | |
| 1099 | − | |
| 1100 | − "@executor/plugin-mcp-sdk": ["@executor/plugin-mcp-sdk@workspace:plugins/mcp/sdk"], | |
| 1101 | − | |
| 1102 | − "@executor/plugin-mcp-shared": ["@executor/plugin-mcp-shared@workspace:plugins/mcp/shared"], | |
| 1103 | − | |
| 1104 | − "@executor/plugin-onepassword-http": ["@executor/plugin-onepassword-http@workspace:plugins/onepassword/http"], | |
| 1105 | − | |
| 1106 | − "@executor/plugin-onepassword-react": ["@executor/plugin-onepassword-react@workspace:plugins/onepassword/react"], | |
| 1107 | − | |
| 1108 | − "@executor/plugin-onepassword-sdk": ["@executor/plugin-onepassword-sdk@workspace:plugins/onepassword/sdk"], | |
| 1109 | − | |
| 1110 | − "@executor/plugin-onepassword-shared": ["@executor/plugin-onepassword-shared@workspace:plugins/onepassword/shared"], | |
| 1111 | − | |
| 1112 | − "@executor/plugin-openapi-http": ["@executor/plugin-openapi-http@workspace:plugins/openapi/http"], | |
| 1113 | − | |
| 1114 | − "@executor/plugin-openapi-react": ["@executor/plugin-openapi-react@workspace:plugins/openapi/react"], | |
| 1115 | − | |
| 1116 | − "@executor/plugin-openapi-sdk": ["@executor/plugin-openapi-sdk@workspace:plugins/openapi/sdk"], | |
| 1117 | − | |
| 1118 | − "@executor/plugin-openapi-shared": ["@executor/plugin-openapi-shared@workspace:plugins/openapi/shared"], | |
| 756 | + "@executor/plugin-openapi": ["@executor/plugin-openapi@workspace:packages/plugins/openapi"], | |
| 1119 | 757 | |
| 1120 | 758 | "@executor/react": ["@executor/react@workspace:packages/clients/react"], |
| 1121 | 759 | |
| @@ -1123,15 +761,13 @@ · 1 unmodified line | ||
| 1123 | 761 | |
| 1124 | 762 | "@executor/runtime-quickjs": ["@executor/runtime-quickjs@workspace:packages/kernel/runtime-quickjs"], |
| 1125 | 763 | |
| 1126 | − "@executor/runtime-ses": ["@executor/runtime-ses@workspace:packages/kernel/runtime-ses"], | |
| 1127 | − | |
| 1128 | − "@executor/serve-skills-via-mcp-demo": ["@executor/serve-skills-via-mcp-demo@workspace:examples/serve-skills-via-mcp"], | |
| 764 | + "@executor/sdk": ["@executor/sdk@workspace:packages/core/sdk"], | |
| 1129 | 765 | |
| 1130 | − "@executor/server": ["@executor/server@workspace:packages/platform/server"], | |
| 766 | + "@executor/server": ["@executor/server@workspace:apps/server"], | |
| 1131 | 767 | |
| 1132 | − "@executor/source-core": ["@executor/source-core@workspace:packages/sources/core"], | |
| 768 | + "@executor/storage-file": ["@executor/storage-file@workspace:packages/core/storage-file"], | |
| 1133 | 769 | |
| 1134 | − "@executor/sqlite-sdk-consumer-example": ["@executor/sqlite-sdk-consumer-example@workspace:examples/sqlite-sdk-consumer"], | |
| 770 | + "@executor/ui": ["@executor/ui@workspace:packages/ui"], | |
| 1135 | 771 | |
| 1136 | 772 | "@executor/web": ["@executor/web@workspace:apps/web"], |
| 1137 | 773 | |
| @@ -1143,26 +779,16 @@ · 5 unmodified lines | ||
| 1143 | 779 | |
| 1144 | 780 | "@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="], |
| 1145 | 781 | |
| 1146 | − "@grpc/grpc-js": ["@grpc/grpc-js@1.14.3", "", { "dependencies": { "@grpc/proto-loader": "^0.8.0", "@js-sdsl/ordered-map": "^4.4.2" } }, "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA=="], | |
| 1147 | − | |
| 1148 | − "@grpc/proto-loader": ["@grpc/proto-loader@0.8.0", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.5.3", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ=="], | |
| 1149 | − | |
| 1150 | − "@hono/node-server": ["@hono/node-server@1.19.11", "", { "peerDependencies": { "hono": "^4" } }, "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g=="], | |
| 1151 | − | |
| 1152 | − "@hono/vite-dev-server": ["@hono/vite-dev-server@0.25.0", "", { "dependencies": { "@hono/node-server": "^1.14.2", "minimatch": "^9.0.3" }, "peerDependencies": { "hono": "*", "miniflare": "*", "wrangler": "*" }, "optionalPeers": ["miniflare", "wrangler"] }, "sha512-4j5rs7yUTOObU2/yCEHeWbf3C8m95SD9lhdUUE6CJ462Emp9vS94yiza2dsA8+ly5pdaIQW0cd4nhNVcwYL5tA=="], | |
| 782 | + "@hono/node-server": ["@hono/node-server@1.19.12", "", { "peerDependencies": { "hono": "^4" } }, "sha512-txsUW4SQ1iilgE0l9/e9VQWmELXifEFvmdA1j6WFh/aFPj99hIntrSsq/if0UWyGVkmrRPKA1wCeP+UCr1B9Uw=="], | |
| 1153 | 783 | |
| 1154 | − "@inquirer/ansi": ["@inquirer/ansi@1.0.2", "", {}, "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ=="], | |
| 784 | + "@hookform/resolvers": ["@hookform/resolvers@5.2.2", "", { "dependencies": { "@standard-schema/utils": "^0.3.0" }, "peerDependencies": { "react-hook-form": "^7.55.0" } }, "sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA=="], | |
| 1155 | 785 | |
| 1156 | − "@inquirer/confirm": ["@inquirer/confirm@5.1.21", "", { "dependencies": { "@inquirer/core": "^10.3.2", "@inquirer/type": "^3.0.10" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ=="], | |
| 786 | + "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], | |
| 1157 | 787 | |
| 1158 | − "@inquirer/core": ["@inquirer/core@10.3.2", "", { "dependencies": { "@inquirer/ansi": "^1.0.2", "@inquirer/figures": "^1.0.15", "@inquirer/type": "^3.0.10", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", "wrap-ansi": "^6.2.0", "yoctocolors-cjs": "^2.1.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A=="], | |
| 788 | + "@iconify/utils": ["@iconify/utils@3.1.0", "", { "dependencies": { "@antfu/install-pkg": "^1.1.0", "@iconify/types": "^2.0.0", "mlly": "^1.8.0" } }, "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw=="], | |
| 1159 | 789 | |
| 1160 | 790 | "@inquirer/external-editor": ["@inquirer/external-editor@1.0.3", "", { "dependencies": { "chardet": "^2.1.1", "iconv-lite": "^0.7.0" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA=="], |
| 1161 | 791 | |
| 1162 | − "@inquirer/figures": ["@inquirer/figures@1.0.15", "", {}, "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g=="], | |
| 1163 | − | |
| 1164 | − "@inquirer/type": ["@inquirer/type@3.0.10", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA=="], | |
| 1165 | − | |
| 1166 | 792 | "@jitl/quickjs-ffi-types": ["@jitl/quickjs-ffi-types@0.31.0", "", {}, "sha512-1yrgvXlmXH2oNj3eFTrkwacGJbmM0crwipA3ohCrjv52gBeDaD7PsTvFYinlAnqU8iPME3LGP437yk05a2oejw=="], |
| 1167 | 793 | |
| 1168 | 794 | "@jitl/quickjs-wasmfile-debug-asyncify": ["@jitl/quickjs-wasmfile-debug-asyncify@0.31.0", "", { "dependencies": { "@jitl/quickjs-ffi-types": "0.31.0" } }, "sha512-YkdzQdr1uaftFhgEnTRjTTZHk2SFZdpWO7XhOmRVbi6CEVsH9g5oNF8Ta1q3OuSJHRwwT8YsuR1YzEiEIJEk6w=="], |
| @@ -1183,15 +809,13 @@ · 14 unmodified lines | ||
| 1183 | 809 | |
| 1184 | 810 | "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], |
| 1185 | 811 | |
| 1186 | − "@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="], | |
| 1187 | − | |
| 1188 | 812 | "@manypkg/find-root": ["@manypkg/find-root@1.1.0", "", { "dependencies": { "@babel/runtime": "^7.5.5", "@types/node": "^12.7.1", "find-up": "^4.1.0", "fs-extra": "^8.1.0" } }, "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA=="], |
| 1189 | 813 | |
| 1190 | 814 | "@manypkg/get-packages": ["@manypkg/get-packages@1.1.3", "", { "dependencies": { "@babel/runtime": "^7.5.5", "@changesets/types": "^4.0.1", "@manypkg/find-root": "^1.1.0", "fs-extra": "^8.1.0", "globby": "^11.0.0", "read-yaml-file": "^1.1.0" } }, "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A=="], |
| 1191 | 815 | |
| 1192 | − "@medv/finder": ["@medv/finder@4.0.2", "", {}, "sha512-RraNY9SCcx4KZV0Dh6BEW6XEW2swkqYca74pkFFRw6hHItSHiy+O/xMnpbofjYbzXj0tSpBGthUF1hHTsr3vIQ=="], | |
| 816 | + "@mermaid-js/parser": ["@mermaid-js/parser@1.1.0", "", { "dependencies": { "langium": "^4.0.0" } }, "sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw=="], | |
| 1193 | 817 | |
| 1194 | − "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.27.1", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA=="], | |
| 818 | + "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="], | |
| 1195 | 819 | |
| 1196 | 820 | "@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw=="], |
| 1197 | 821 | |
| @@ -1205,8 +829,6 @@ · 7 unmodified lines | ||
| 1205 | 829 | |
| 1206 | 830 | "@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3", "", { "os": "win32", "cpu": "x64" }, "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ=="], |
| 1207 | 831 | |
| 1208 | − "@mswjs/interceptors": ["@mswjs/interceptors@0.41.3", "", { "dependencies": { "@open-draft/deferred-promise": "^2.2.0", "@open-draft/logger": "^0.3.0", "@open-draft/until": "^2.0.0", "is-node-process": "^1.2.0", "outvariant": "^1.4.3", "strict-event-emitter": "^0.5.1" } }, "sha512-cXu86tF4VQVfwz8W1SPbhoRyHJkti6mjH/XJIxp40jhO4j2k1m4KYrEykxqWPkFF3vrK4rgQppBh//AwyGSXPA=="], | |
| 1209 | − | |
| 1210 | 832 | "@napi-rs/keyring": ["@napi-rs/keyring@1.2.0", "", { "optionalDependencies": { "@napi-rs/keyring-darwin-arm64": "1.2.0", "@napi-rs/keyring-darwin-x64": "1.2.0", "@napi-rs/keyring-freebsd-x64": "1.2.0", "@napi-rs/keyring-linux-arm-gnueabihf": "1.2.0", "@napi-rs/keyring-linux-arm64-gnu": "1.2.0", "@napi-rs/keyring-linux-arm64-musl": "1.2.0", "@napi-rs/keyring-linux-riscv64-gnu": "1.2.0", "@napi-rs/keyring-linux-x64-gnu": "1.2.0", "@napi-rs/keyring-linux-x64-musl": "1.2.0", "@napi-rs/keyring-win32-arm64-msvc": "1.2.0", "@napi-rs/keyring-win32-ia32-msvc": "1.2.0", "@napi-rs/keyring-win32-x64-msvc": "1.2.0" } }, "sha512-d0d4Oyxm+v980PEq1ZH2PmS6cvpMIRc17eYpiU47KgW+lzxklMu6+HOEOPmxrpnF/XQZ0+Q78I2mgMhbIIo/dg=="], |
| 1211 | 833 | |
| 1212 | 834 | "@napi-rs/keyring-darwin-arm64": ["@napi-rs/keyring-darwin-arm64@1.2.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-CA83rDeyONDADO25JLZsh3eHY8yTEtm/RS6ecPsY+1v+dSawzT9GywBMu2r6uOp1IEhQs/xAfxgybGAFr17lSA=="], |
| @@ -1233,349 +855,399 @@ · 20 unmodified lines | ||
| 1233 | 855 | |
| 1234 | 856 | "@napi-rs/keyring-win32-x64-msvc": ["@napi-rs/keyring-win32-x64-msvc@1.2.0", "", { "os": "win32", "cpu": "x64" }, "sha512-xFlx/TsmqmCwNU9v+AVnEJgoEAlBYgzFF5Ihz1rMpPAt4qQWWkMd4sCyM1gMJ1A/GnRqRegDiQpwaxGUHFtFbA=="], |
| 1235 | 857 | |
| 1236 | − "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="], | |
| 858 | + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], | |
| 859 | + | |
| 860 | + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], | |
| 861 | + | |
| 862 | + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], | |
| 1237 | 863 | |
| 1238 | − "@noble/ciphers": ["@noble/ciphers@1.3.0", "", {}, "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw=="], | |
| 864 | + "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.58.0", "", { "os": "android", "cpu": "arm" }, "sha512-1T7UN3SsWWxpWyWGn1cT3ASNJOo+pI3eUkmEl7HgtowapcV8kslYpFQcYn431VuxghXakPNlbjRwhqmR37PFOg=="], | |
| 1239 | 865 | |
| 1240 | − "@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], | |
| 866 | + "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.58.0", "", { "os": "android", "cpu": "arm64" }, "sha512-GryzujxuiRv2YFF7bRy8mKcxlbuAN+euVUtGJt9KKbLT8JBUIosamVhcthLh+VEr6KE6cjeVMAQxKAzJcoN7dg=="], | |
| 1241 | 867 | |
| 1242 | − "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], | |
| 868 | + "@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.58.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-7/bRSJIwl4GxeZL9rPZ11anNTyUO9epZrfEJH/ZMla3+/gbQ6xZixh9nOhsZ0QwsTW7/5J2A/fHbD1udC5DQQA=="], | |
| 1243 | 869 | |
| 1244 | − "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], | |
| 870 | + "@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.58.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-EqdtJSiHweS2vfILNrpyJ6HUwpEq2g7+4Zx1FPi4hu3Hu7tC3znF6ufbXO8Ub2LD4mGgznjI7kSdku9NDD1Mkg=="], | |
| 1245 | 871 | |
| 1246 | − "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], | |
| 872 | + "@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.58.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-VQt5TH4M42mY20F545G637RKxV/yjwVtKk2vfXuazfReSIiuvWBnv+FVSvIV5fKVTJNjt3GSJibh6JecbhGdBw=="], | |
| 1247 | 873 | |
| 1248 | − "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], | |
| 874 | + "@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.58.0", "", { "os": "linux", "cpu": "arm" }, "sha512-fBYcj4ucwpAtjJT3oeBdFBYKvNyjRSK+cyuvBOTQjh0jvKp4yeA4S/D0IsCHus/VPaNG5L48qQkh+Vjy3HL2/Q=="], | |
| 875 | + | |
| 876 | + "@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.58.0", "", { "os": "linux", "cpu": "arm" }, "sha512-0BeuFfwlUHlJ1xpEdSD1YO3vByEFGPg36uLjK1JgFaxFb4W6w17F8ET8sz5cheZ4+x5f2xzdnRrrWv83E3Yd8g=="], | |
| 877 | + | |
| 878 | + "@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.58.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-TXlZgnPTlxrQzxG9ZXU7BNwx1Ilrr17P3GwZY0If2EzrinqRH3zXPc3HrRcBJgcsoZNMuNL5YivtkJYgp467UQ=="], | |
| 1249 | 879 | |
| 1250 | − "@open-draft/deferred-promise": ["@open-draft/deferred-promise@2.2.0", "", {}, "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA=="], | |
| 880 | + "@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.58.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-zSoYRo5dxHLcUx93Stl2hW3hSNjPt99O70eRVWt5A1zwJ+FPjeCCANCD2a9R4JbHsdcl11TIQOjyigcRVOH2mw=="], | |
| 1251 | 881 | |
| 1252 | − "@open-draft/logger": ["@open-draft/logger@0.3.0", "", { "dependencies": { "is-node-process": "^1.2.0", "outvariant": "^1.4.0" } }, "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ=="], | |
| 882 | + "@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.58.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NQ0U/lqxH2/VxBYeAIvMNUK1y0a1bJ3ZicqkF2c6wfakbEciP9jvIE4yNzCFpZaqeIeRYaV7AVGqEO1yrfVPjA=="], | |
| 1253 | 883 | |
| 1254 | − "@open-draft/until": ["@open-draft/until@2.1.0", "", {}, "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg=="], | |
| 884 | + "@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.58.0", "", { "os": "linux", "cpu": "none" }, "sha512-X9J+kr3gIC9FT8GuZt0ekzpNUtkBVzMVU4KiKDSlocyQuEgi3gBbXYN8UkQiV77FTusLDPsovjo95YedHr+3yg=="], | |
| 1255 | 885 | |
| 1256 | − "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], | |
| 886 | + "@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.58.0", "", { "os": "linux", "cpu": "none" }, "sha512-CDze3pi1OO3Wvb/QsXjmLEY4XPKGM6kIo82ssNOgmcl1IdndF9VSGAE38YLhADWmOac7fjqhBw82LozuUVxD0Q=="], | |
| 1257 | 887 | |
| 1258 | − "@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.213.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-zRM5/Qj6G84Ej3F1yt33xBVY/3tnMxtL1fiDIxYbDWYaZ/eudVw3/PBiZ8G7JwUxXxjW8gU4g6LnOyfGKYHYgw=="], | |
| 888 | + "@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.58.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-b/89glbxFaEAcA6Uf1FvCNecBJEgcUTsV1quzrqXM/o4R1M4u+2KCVuyGCayN2UpsRWtGGLb+Ver0tBBpxaPog=="], | |
| 1259 | 889 | |
| 1260 | − "@opentelemetry/context-async-hooks": ["@opentelemetry/context-async-hooks@2.6.0", "", { "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-L8UyDwqpTcbkIK5cgwDRDYDoEhQoj8wp8BwsO19w3LB1Z41yEQm2VJyNfAi9DrLP/YTqXqWpKHyZfR9/tFYo1Q=="], | |
| 890 | + "@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.58.0", "", { "os": "linux", "cpu": "x64" }, "sha512-0/yYpkq9VJFCEcuRlrViGj8pJUFFvNS4EkEREaN7CB1EcLXJIaVSSa5eCihwBGXtOZxhnblWgxks9juRdNQI7w=="], | |
| 1261 | 891 | |
| 1262 | − "@opentelemetry/core": ["@opentelemetry/core@2.6.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-HLM1v2cbZ4TgYN6KEOj+Bbj8rAKriOdkF9Ed3tG25FoprSiQl7kYc+RRT6fUZGOvx0oMi5U67GoFdT+XUn8zEg=="], | |
| 892 | + "@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.58.0", "", { "os": "linux", "cpu": "x64" }, "sha512-hr6FNvmcAXiH+JxSvaJ4SJ1HofkdqEElXICW9sm3/Rd5eC3t7kzvmLyRAB3NngKO2wzXRCAm4Z/mGWfrsS4X8w=="], | |
| 1263 | 893 | |
| 1264 | − "@opentelemetry/exporter-trace-otlp-grpc": ["@opentelemetry/exporter-trace-otlp-grpc@0.213.0", "", { "dependencies": { "@grpc/grpc-js": "^1.14.3", "@opentelemetry/core": "2.6.0", "@opentelemetry/otlp-exporter-base": "0.213.0", "@opentelemetry/otlp-grpc-exporter-base": "0.213.0", "@opentelemetry/otlp-transformer": "0.213.0", "@opentelemetry/resources": "2.6.0", "@opentelemetry/sdk-trace-base": "2.6.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-L8y6piP4jBIIx1Nv7/9hkx25ql6/Cro/kQrs+f9e8bPF0Ar5Dm991v7PnbtubKz6Q4fT872H56QXUWVnz/Cs4Q=="], | |
| 894 | + "@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.58.0", "", { "os": "none", "cpu": "arm64" }, "sha512-R+O368VXgRql1K6Xar+FEo7NEwfo13EibPMoTv3sesYQedRXd6m30Dh/7lZMxnrQVFfeo4EOfYIP4FpcgWQNHg=="], | |
| 1265 | 895 | |
| 1266 | − "@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.213.0", "", { "dependencies": { "@opentelemetry/core": "2.6.0", "@opentelemetry/otlp-transformer": "0.213.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-MegxAP1/n09Ob2dQvY5NBDVjAFkZRuKtWKxYev1R2M8hrsgXzQGkaMgoEKeUOyQ0FUyYcO29UOnYdQWmWa0PXg=="], | |
| 896 | + "@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.58.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Q0FZiAY/3c4YRj4z3h9K1PgaByrifrfbBoODSeX7gy97UtB7pySPUQfC2B/GbxWU6k7CzQrRy5gME10PltLAFQ=="], | |
| 1267 | 897 | |
| 1268 | − "@opentelemetry/otlp-grpc-exporter-base": ["@opentelemetry/otlp-grpc-exporter-base@0.213.0", "", { "dependencies": { "@grpc/grpc-js": "^1.14.3", "@opentelemetry/core": "2.6.0", "@opentelemetry/otlp-exporter-base": "0.213.0", "@opentelemetry/otlp-transformer": "0.213.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-XgRGuLE9usFNlnw2lgMIM4HTwpcIyjdU/xPoJ8v3LbBLBfjaDkIugjc9HoWa7ZSJ/9Bhzgvm/aD0bGdYUFgnTw=="], | |
| 898 | + "@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.58.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-Y8FKBABrSPp9H0QkRLHDHOSUgM/309a3IvOVgPcVxYcX70wxJrk608CuTg7w+C6vEd724X5wJoNkBcGYfH7nNQ=="], | |
| 1269 | 899 | |
| 1270 | − "@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.213.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.213.0", "@opentelemetry/core": "2.6.0", "@opentelemetry/resources": "2.6.0", "@opentelemetry/sdk-logs": "0.213.0", "@opentelemetry/sdk-metrics": "2.6.0", "@opentelemetry/sdk-trace-base": "2.6.0", "protobufjs": "^7.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-RSuAlxFFPjeK4d5Y6ps8L2WhaQI6CXWllIjvo5nkAlBpmq2XdYWEBGiAbOF4nDs8CX4QblJDv5BbMUft3sEfDw=="], | |
| 900 | + "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.58.0", "", { "os": "win32", "cpu": "x64" }, "sha512-bCn5rbiz5My+Bj7M09sDcnqW0QJyINRVxdZ65x1/Y2tGrMwherwK/lpk+HRQCKvXa8pcaQdF5KY5j54VGZLwNg=="], | |
| 1271 | 901 | |
| 1272 | − "@opentelemetry/resources": ["@opentelemetry/resources@2.6.0", "", { "dependencies": { "@opentelemetry/core": "2.6.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-D4y/+OGe3JSuYUCBxtH5T9DSAWNcvCb/nQWIga8HNtXTVPQn59j0nTBAgaAXxUVBDl40mG3Tc76b46wPlZaiJQ=="], | |
| 902 | + "@parcel/watcher": ["@parcel/watcher@2.5.6", "", { "dependencies": { "detect-libc": "^2.0.3", "is-glob": "^4.0.3", "node-addon-api": "^7.0.0", "picomatch": "^4.0.3" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.6", "@parcel/watcher-darwin-arm64": "2.5.6", "@parcel/watcher-darwin-x64": "2.5.6", "@parcel/watcher-freebsd-x64": "2.5.6", "@parcel/watcher-linux-arm-glibc": "2.5.6", "@parcel/watcher-linux-arm-musl": "2.5.6", "@parcel/watcher-linux-arm64-glibc": "2.5.6", "@parcel/watcher-linux-arm64-musl": "2.5.6", "@parcel/watcher-linux-x64-glibc": "2.5.6", "@parcel/watcher-linux-x64-musl": "2.5.6", "@parcel/watcher-win32-arm64": "2.5.6", "@parcel/watcher-win32-ia32": "2.5.6", "@parcel/watcher-win32-x64": "2.5.6" } }, "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ=="], | |
| 1273 | 903 | |
| 1274 | − "@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.213.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.213.0", "@opentelemetry/core": "2.6.0", "@opentelemetry/resources": "2.6.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-00xlU3GZXo3kXKve4DLdrAL0NAFUaZ9appU/mn00S/5kSUdAvyYsORaDUfR04Mp2CLagAOhrzfUvYozY/EZX2g=="], | |
| 904 | + "@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.6", "", { "os": "android", "cpu": "arm64" }, "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A=="], | |
| 1275 | 905 | |
| 1276 | − "@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.6.0", "", { "dependencies": { "@opentelemetry/core": "2.6.0", "@opentelemetry/resources": "2.6.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-CicxWZxX6z35HR83jl+PLgtFgUrKRQ9LCXyxgenMnz5A1lgYWfAog7VtdOvGkJYyQgMNPhXQwkYrDLujk7z1Iw=="], | |
| 906 | + "@parcel/watcher-darwin-arm64": ["@parcel/watcher-darwin-arm64@2.5.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA=="], | |
| 1277 | 907 | |
| 1278 | − "@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.6.0", "", { "dependencies": { "@opentelemetry/core": "2.6.0", "@opentelemetry/resources": "2.6.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-g/OZVkqlxllgFM7qMKqbPV9c1DUPhQ7d4n3pgZFcrnrNft9eJXZM2TNHTPYREJBrtNdRytYyvwjgL5geDKl3EQ=="], | |
| 908 | + "@parcel/watcher-darwin-x64": ["@parcel/watcher-darwin-x64@2.5.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg=="], | |
| 1279 | 909 | |
| 1280 | − "@opentelemetry/sdk-trace-node": ["@opentelemetry/sdk-trace-node@2.6.0", "", { "dependencies": { "@opentelemetry/context-async-hooks": "2.6.0", "@opentelemetry/core": "2.6.0", "@opentelemetry/sdk-trace-base": "2.6.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-YhswtasmsbIGEFvLGvR9p/y3PVRTfFf+mgY8van4Ygpnv4sA3vooAjvh+qAn9PNWxs4/IwGGqiQS0PPsaRJ0vQ=="], | |
| 910 | + "@parcel/watcher-freebsd-x64": ["@parcel/watcher-freebsd-x64@2.5.6", "", { "os": "freebsd", "cpu": "x64" }, "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng=="], | |
| 1281 | 911 | |
| 1282 | − "@opentelemetry/sdk-trace-web": ["@opentelemetry/sdk-trace-web@2.6.0", "", { "dependencies": { "@opentelemetry/core": "2.6.0", "@opentelemetry/sdk-trace-base": "2.6.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-xyYmLFatwUeYnB7NtQ2Ydl9Y8uiblN+EDo5YEjnk7ZRMhGFyt1wgPqb8EYvATLuDiRVtxid1fJsL6RH1fCQMIA=="], | |
| 912 | + "@parcel/watcher-linux-arm-glibc": ["@parcel/watcher-linux-arm-glibc@2.5.6", "", { "os": "linux", "cpu": "arm" }, "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ=="], | |
| 1283 | 913 | |
| 1284 | − "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="], | |
| 914 | + "@parcel/watcher-linux-arm-musl": ["@parcel/watcher-linux-arm-musl@2.5.6", "", { "os": "linux", "cpu": "arm" }, "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg=="], | |
| 1285 | 915 | |
| 1286 | − "@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.19.1", "", { "os": "android", "cpu": "arm" }, "sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg=="], | |
| 916 | + "@parcel/watcher-linux-arm64-glibc": ["@parcel/watcher-linux-arm64-glibc@2.5.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA=="], | |
| 1287 | 917 | |
| 1288 | − "@oxc-resolver/binding-android-arm64": ["@oxc-resolver/binding-android-arm64@11.19.1", "", { "os": "android", "cpu": "arm64" }, "sha512-oolbkRX+m7Pq2LNjr/kKgYeC7bRDMVTWPgxBGMjSpZi/+UskVo4jsMU3MLheZV55jL6c3rNelPl4oD60ggYmqA=="], | |
| 918 | + "@parcel/watcher-linux-arm64-musl": ["@parcel/watcher-linux-arm64-musl@2.5.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA=="], | |
| 1289 | 919 | |
| 1290 | − "@oxc-resolver/binding-darwin-arm64": ["@oxc-resolver/binding-darwin-arm64@11.19.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-nUC6d2i3R5B12sUW4O646qD5cnMXf2oBGPLIIeaRfU9doJRORAbE2SGv4eW6rMqhD+G7nf2Y8TTJTLiiO3Q/dQ=="], | |
| 920 | + "@parcel/watcher-linux-x64-glibc": ["@parcel/watcher-linux-x64-glibc@2.5.6", "", { "os": "linux", "cpu": "x64" }, "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ=="], | |
| 1291 | 921 | |
| 1292 | − "@oxc-resolver/binding-darwin-x64": ["@oxc-resolver/binding-darwin-x64@11.19.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-cV50vE5+uAgNcFa3QY1JOeKDSkM/9ReIcc/9wn4TavhW/itkDGrXhw9jaKnkQnGbjJ198Yh5nbX/Gr2mr4Z5jQ=="], | |
| 922 | + "@parcel/watcher-linux-x64-musl": ["@parcel/watcher-linux-x64-musl@2.5.6", "", { "os": "linux", "cpu": "x64" }, "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg=="], | |
| 1293 | 923 | |
| 1294 | − "@oxc-resolver/binding-freebsd-x64": ["@oxc-resolver/binding-freebsd-x64@11.19.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-xZOQiYGFxtk48PBKff+Zwoym7ScPAIVp4c14lfLxizO2LTTTJe5sx9vQNGrBymrf/vatSPNMD4FgsaaRigPkqw=="], | |
| 924 | + "@parcel/watcher-win32-arm64": ["@parcel/watcher-win32-arm64@2.5.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q=="], | |
| 1295 | 925 | |
| 1296 | − "@oxc-resolver/binding-linux-arm-gnueabihf": ["@oxc-resolver/binding-linux-arm-gnueabihf@11.19.1", "", { "os": "linux", "cpu": "arm" }, "sha512-lXZYWAC6kaGe/ky2su94e9jN9t6M0/6c+GrSlCqL//XO1cxi5lpAhnJYdyrKfm0ZEr/c7RNyAx3P7FSBcBd5+A=="], | |
| 926 | + "@parcel/watcher-win32-ia32": ["@parcel/watcher-win32-ia32@2.5.6", "", { "os": "win32", "cpu": "ia32" }, "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g=="], | |
| 1297 | 927 | |
| 1298 | − "@oxc-resolver/binding-linux-arm-musleabihf": ["@oxc-resolver/binding-linux-arm-musleabihf@11.19.1", "", { "os": "linux", "cpu": "arm" }, "sha512-veG1kKsuK5+t2IsO9q0DErYVSw2azvCVvWHnfTOS73WE0STdLLB7Q1bB9WR+yHPQM76ASkFyRbogWo1GR1+WbQ=="], | |
| 928 | + "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw=="], | |
| 1299 | 929 | |
| 1300 | − "@oxc-resolver/binding-linux-arm64-gnu": ["@oxc-resolver/binding-linux-arm64-gnu@11.19.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-heV2+jmXyYnUrpUXSPugqWDRpnsQcDm2AX4wzTuvgdlZfoNYO0O3W2AVpJYaDn9AG4JdM6Kxom8+foE7/BcSig=="], | |
| 930 | + "@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="], | |
| 1301 | 931 | |
| 1302 | − "@oxc-resolver/binding-linux-arm64-musl": ["@oxc-resolver/binding-linux-arm64-musl@11.19.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jvo2Pjs1c9KPxMuMPIeQsgu0mOJF9rEb3y3TdpsrqwxRM+AN6/nDDwv45n5ZrUnQMsdBy5gIabioMKnQfWo9ew=="], | |
| 932 | + "@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="], | |
| 1303 | 933 | |
| 1304 | − "@oxc-resolver/binding-linux-ppc64-gnu": ["@oxc-resolver/binding-linux-ppc64-gnu@11.19.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-vLmdNxWCdN7Uo5suays6A/+ywBby2PWBBPXctWPg5V0+eVuzsJxgAn6MMB4mPlshskYbppjpN2Zg83ArHze9gQ=="], | |
| 934 | + "@radix-ui/react-accessible-icon": ["@radix-ui/react-accessible-icon@1.1.7", "", { "dependencies": { "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A=="], | |
| 1305 | 935 | |
| 1306 | − "@oxc-resolver/binding-linux-riscv64-gnu": ["@oxc-resolver/binding-linux-riscv64-gnu@11.19.1", "", { "os": "linux", "cpu": "none" }, "sha512-/b+WgR+VTSBxzgOhDO7TlMXC1ufPIMR6Vj1zN+/x+MnyXGW7prTLzU9eW85Aj7Th7CCEG9ArCbTeqxCzFWdg2w=="], | |
| 936 | + "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA=="], | |
| 1307 | 937 | |
| 1308 | − "@oxc-resolver/binding-linux-riscv64-musl": ["@oxc-resolver/binding-linux-riscv64-musl@11.19.1", "", { "os": "linux", "cpu": "none" }, "sha512-YlRdeWb9j42p29ROh+h4eg/OQ3dTJlpHSa+84pUM9+p6i3djtPz1q55yLJhgW9XfDch7FN1pQ/Vd6YP+xfRIuw=="], | |
| 938 | + "@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw=="], | |
| 1309 | 939 | |
| 1310 | − "@oxc-resolver/binding-linux-s390x-gnu": ["@oxc-resolver/binding-linux-s390x-gnu@11.19.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-EDpafVOQWF8/MJynsjOGFThcqhRHy417sRyLfQmeiamJ8qVhSKAn2Dn2VVKUGCjVB9C46VGjhNo7nOPUi1x6uA=="], | |
| 940 | + "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="], | |
| 1311 | 941 | |
| 1312 | − "@oxc-resolver/binding-linux-x64-gnu": ["@oxc-resolver/binding-linux-x64-gnu@11.19.1", "", { "os": "linux", "cpu": "x64" }, "sha512-NxjZe+rqWhr+RT8/Ik+5ptA3oz7tUw361Wa5RWQXKnfqwSSHdHyrw6IdcTfYuml9dM856AlKWZIUXDmA9kkiBQ=="], | |
| 942 | + "@radix-ui/react-aspect-ratio": ["@radix-ui/react-aspect-ratio@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g=="], | |
| 1313 | 943 | |
| 1314 | − "@oxc-resolver/binding-linux-x64-musl": ["@oxc-resolver/binding-linux-x64-musl@11.19.1", "", { "os": "linux", "cpu": "x64" }, "sha512-cM/hQwsO3ReJg5kR+SpI69DMfvNCp+A/eVR4b4YClE5bVZwz8rh2Nh05InhwI5HR/9cArbEkzMjcKgTHS6UaNw=="], | |
| 944 | + "@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.10", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog=="], | |
| 1315 | 945 | |
| 1316 | − "@oxc-resolver/binding-openharmony-arm64": ["@oxc-resolver/binding-openharmony-arm64@11.19.1", "", { "os": "none", "cpu": "arm64" }, "sha512-QF080IowFB0+9Rh6RcD19bdgh49BpQHUW5TajG1qvWHvmrQznTZZjYlgE2ltLXyKY+qs4F/v5xuX1XS7Is+3qA=="], | |
| 946 | + "@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw=="], | |
| 1317 | 947 | |
| 1318 | − "@oxc-resolver/binding-wasm32-wasi": ["@oxc-resolver/binding-wasm32-wasi@11.19.1", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-w8UCKhX826cP/ZLokXDS6+milN8y4X7zidsAttEdWlVoamTNf6lhBJldaWr3ukTDiye7s4HRcuPEPOXNC432Vg=="], | |
| 948 | + "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA=="], | |
| 1319 | 949 | |
| 1320 | − "@oxc-resolver/binding-win32-arm64-msvc": ["@oxc-resolver/binding-win32-arm64-msvc@11.19.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-nJ4AsUVZrVKwnU/QRdzPCCrO0TrabBqgJ8pJhXITdZGYOV28TIYystV1VFLbQ7DtAcaBHpocT5/ZJnF78YJPtQ=="], | |
| 950 | + "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="], | |
| 1321 | 951 | |
| 1322 | − "@oxc-resolver/binding-win32-ia32-msvc": ["@oxc-resolver/binding-win32-ia32-msvc@11.19.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-EW+ND5q2Tl+a3pH81l1QbfgbF3HmqgwLfDfVithRFheac8OTcnbXt/JxqD2GbDkb7xYEqy1zNaVFRr3oeG8npA=="], | |
| 952 | + "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="], | |
| 1323 | 953 | |
| 1324 | − "@oxc-resolver/binding-win32-x64-msvc": ["@oxc-resolver/binding-win32-x64-msvc@11.19.1", "", { "os": "win32", "cpu": "x64" }, "sha512-6hIU3RQu45B+VNTY4Ru8ppFwjVS/S5qwYyGhBotmjxfEKk41I2DlGtRfGJndZ5+6lneE2pwloqunlOyZuX/XAw=="], | |
| 954 | + "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="], | |
| 1325 | 955 | |
| 1326 | − "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.56.0", "", { "os": "android", "cpu": "arm" }, "sha512-IyfYPthZyiSKwAv/dLjeO18SaK8MxLI9Yss2JrRDyweQAkuL3LhEy7pwIwI7uA3KQc1Vdn20kdmj3q0oUIQL6A=="], | |
| 956 | + "@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.2.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww=="], | |
| 1327 | 957 | |
| 1328 | − "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.56.0", "", { "os": "android", "cpu": "arm64" }, "sha512-Ga5zYrzH6vc/VFxhn6MmyUnYEfy9vRpwTIks99mY3j6Nz30yYpIkWryI0QKPCgvGUtDSXVLEaMum5nA+WrNOSg=="], | |
| 958 | + "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="], | |
| 1329 | 959 | |
| 1330 | − "@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.56.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ogmbdJysnw/D4bDcpf1sPLpFThZ48lYp4aKYm10Z/6Nh1SON6NtnNhTNOlhEY296tDFItsZUz+2tgcSYqh8Eyw=="], | |
| 960 | + "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="], | |
| 1331 | 961 | |
| 1332 | − "@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.56.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-x8QE1h+RAtQ2g+3KPsP6Fk/tdz6zJQUv5c7fTrJxXV3GHOo+Ry5p/PsogU4U+iUZg0rj6hS+E4xi+mnwwlDCWQ=="], | |
| 962 | + "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="], | |
| 1333 | 963 | |
| 1334 | − "@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.56.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-6G+WMZvwJpMvY7my+/SHEjb7BTk/PFbePqLpmVmUJRIsJMy/UlyYqjpuh0RCgYYkPLcnXm1rUM04kbTk8yS1Yg=="], | |
| 964 | + "@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw=="], | |
| 1335 | 965 | |
| 1336 | − "@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.56.0", "", { "os": "linux", "cpu": "arm" }, "sha512-YYHBsk/sl7fYwQOok+6W5lBPeUEvisznV/HZD2IfZmF3Bns6cPC3Z0vCtSEOaAWTjYWN3jVsdu55jMxKlsdlhg=="], | |
| 966 | + "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="], | |
| 1337 | 967 | |
| 1338 | − "@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.56.0", "", { "os": "linux", "cpu": "arm" }, "sha512-+AZK8rOUr78y8WT6XkDb04IbMRqauNV+vgT6f8ZLOH8wnpQ9i7Nol0XLxAu+Cq7Sb+J9wC0j6Km5hG8rj47/yQ=="], | |
| 968 | + "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="], | |
| 1339 | 969 | |
| 1340 | − "@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.56.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-urse2SnugwJRojUkGSSeH2LPMaje5Q50yQtvtL9HFckiyeqXzoFwOAZqD5TR29R2lq7UHidfFDM9EGcchcbb8A=="], | |
| 970 | + "@radix-ui/react-form": ["@radix-ui/react-form@0.1.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ=="], | |
| 1341 | 971 | |
| 1342 | − "@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.56.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-rkTZkBfJ4TYLjansjSzL6mgZOdN5IvUnSq3oNJSLwBcNvy3dlgQtpHPrRxrCEbbcp7oQ6If0tkNaqfOsphYZ9g=="], | |
| 972 | + "@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg=="], | |
| 1343 | 973 | |
| 1344 | − "@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.56.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-uqL1kMH3u69/e1CH2EJhP3CP28jw2ExLsku4o8RVAZ7fySo9zOyI2fy9pVlTAp4voBLVgzndXi3SgtdyCTa2aA=="], | |
| 974 | + "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="], | |
| 1345 | 975 | |
| 1346 | − "@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.56.0", "", { "os": "linux", "cpu": "none" }, "sha512-j0CcMBOgV6KsRaBdsebIeiy7hCjEvq2KdEsiULf2LZqAq0v1M1lWjelhCV57LxsqaIGChXFuFJ0RiFrSRHPhSg=="], | |
| 976 | + "@radix-ui/react-label": ["@radix-ui/react-label@2.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="], | |
| 1347 | 977 | |
| 1348 | − "@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.56.0", "", { "os": "linux", "cpu": "none" }, "sha512-7VDOiL8cDG3DQ/CY3yKjbV1c4YPvc4vH8qW09Vv+5ukq3l/Kcyr6XGCd5NvxUmxqDb2vjMpM+eW/4JrEEsUetA=="], | |
| 978 | + "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="], | |
| 1349 | 979 | |
| 1350 | − "@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.56.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-JGRpX0M+ikD3WpwJ7vKcHKV6Kg0dT52BW2Eu2BupXotYeqGXBrbY+QPkAyKO6MNgKozyTNaRh3r7g+VWgyAQYQ=="], | |
| 980 | + "@radix-ui/react-menubar": ["@radix-ui/react-menubar@1.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA=="], | |
| 1351 | 981 | |
| 1352 | − "@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.56.0", "", { "os": "linux", "cpu": "x64" }, "sha512-dNaICPvtmuxFP/VbqdofrLqdS3bM/AKJN3LMJD52si44ea7Be1cBk6NpfIahaysG9Uo+L98QKddU9CD5L8UHnQ=="], | |
| 982 | + "@radix-ui/react-navigation-menu": ["@radix-ui/react-navigation-menu@1.2.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w=="], | |
| 1353 | 983 | |
| 1354 | − "@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.56.0", "", { "os": "linux", "cpu": "x64" }, "sha512-pF1vOtM+GuXmbklM1hV8WMsn6tCNPvkUzklj/Ej98JhlanbmA2RB1BILgOpwSuCTRTIYx2MXssmEyQQ90QF5aA=="], | |
| 984 | + "@radix-ui/react-one-time-password-field": ["@radix-ui/react-one-time-password-field@0.1.8", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg=="], | |
| 1355 | 985 | |
| 1356 | − "@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.56.0", "", { "os": "none", "cpu": "arm64" }, "sha512-bp8NQ4RE6fDIFLa4bdBiOA+TAvkNkg+rslR+AvvjlLTYXLy9/uKAYLQudaQouWihLD/hgkrXIKKzXi5IXOewwg=="], | |
| 986 | + "@radix-ui/react-password-toggle-field": ["@radix-ui/react-password-toggle-field@0.1.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw=="], | |
| 1357 | 987 | |
| 1358 | − "@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.56.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-PxT4OJDfMOQBzo3OlzFb9gkoSD+n8qSBxyVq2wQSZIHFQYGEqIRTo9M0ZStvZm5fdhMqaVYpOnJvH2hUMEDk/g=="], | |
| 988 | + "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA=="], | |
| 1359 | 989 | |
| 1360 | − "@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.56.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-PTRy6sIEPqy2x8PTP1baBNReN/BNEFmde0L+mYeHmjXE1Vlcc9+I5nsqENsB2yAm5wLkzPoTNCMY/7AnabT4/A=="], | |
| 990 | + "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="], | |
| 1361 | 991 | |
| 1362 | − "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.56.0", "", { "os": "win32", "cpu": "x64" }, "sha512-ZHa0clocjLmIDr+1LwoWtxRcoYniAvERotvwKUYKhH41NVfl0Y4LNbyQkwMZzwDvKklKGvGZ5+DAG58/Ik47tQ=="], | |
| 992 | + "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="], | |
| 1363 | 993 | |
| 1364 | − "@oxlint/plugins": ["@oxlint/plugins@1.57.0", "", {}, "sha512-4mAGdfUZNQSZwUbHs0xoUcKjByrdBSJ9iaCI3STn/d1ZVRKhW/82oCA6rdfSzO4vxrWH3/l+qYWh/tyrwPSpag=="], | |
| 994 | + "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="], | |
| 1365 | 995 | |
| 1366 | − "@parcel/watcher": ["@parcel/watcher@2.5.6", "", { "dependencies": { "detect-libc": "^2.0.3", "is-glob": "^4.0.3", "node-addon-api": "^7.0.0", "picomatch": "^4.0.3" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.6", "@parcel/watcher-darwin-arm64": "2.5.6", "@parcel/watcher-darwin-x64": "2.5.6", "@parcel/watcher-freebsd-x64": "2.5.6", "@parcel/watcher-linux-arm-glibc": "2.5.6", "@parcel/watcher-linux-arm-musl": "2.5.6", "@parcel/watcher-linux-arm64-glibc": "2.5.6", "@parcel/watcher-linux-arm64-musl": "2.5.6", "@parcel/watcher-linux-x64-glibc": "2.5.6", "@parcel/watcher-linux-x64-musl": "2.5.6", "@parcel/watcher-win32-arm64": "2.5.6", "@parcel/watcher-win32-ia32": "2.5.6", "@parcel/watcher-win32-x64": "2.5.6" } }, "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ=="], | |
| 996 | + "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], | |
| 1367 | 997 | |
| 1368 | − "@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.6", "", { "os": "android", "cpu": "arm64" }, "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A=="], | |
| 998 | + "@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.7", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg=="], | |
| 1369 | 999 | |
| 1370 | − "@parcel/watcher-darwin-arm64": ["@parcel/watcher-darwin-arm64@2.5.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA=="], | |
| 1000 | + "@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.3.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ=="], | |
| 1371 | 1001 | |
| 1372 | − "@parcel/watcher-darwin-x64": ["@parcel/watcher-darwin-x64@2.5.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg=="], | |
| 1002 | + "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="], | |
| 1373 | 1003 | |
| 1374 | − "@parcel/watcher-freebsd-x64": ["@parcel/watcher-freebsd-x64@2.5.6", "", { "os": "freebsd", "cpu": "x64" }, "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng=="], | |
| 1004 | + "@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.10", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="], | |
| 1375 | 1005 | |
| 1376 | − "@parcel/watcher-linux-arm-glibc": ["@parcel/watcher-linux-arm-glibc@2.5.6", "", { "os": "linux", "cpu": "arm" }, "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ=="], | |
| 1006 | + "@radix-ui/react-select": ["@radix-ui/react-select@2.2.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ=="], | |
| 1377 | 1007 | |
| 1378 | − "@parcel/watcher-linux-arm-musl": ["@parcel/watcher-linux-arm-musl@2.5.6", "", { "os": "linux", "cpu": "arm" }, "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg=="], | |
| 1008 | + "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="], | |
| 1009 | + | |
| 1010 | + "@radix-ui/react-slider": ["@radix-ui/react-slider@1.3.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw=="], | |
| 1011 | + | |
| 1012 | + "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], | |
| 1013 | + | |
| 1014 | + "@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ=="], | |
| 1015 | + | |
| 1016 | + "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="], | |
| 1017 | + | |
| 1018 | + "@radix-ui/react-toast": ["@radix-ui/react-toast@1.2.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g=="], | |
| 1019 | + | |
| 1020 | + "@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ=="], | |
| 1021 | + | |
| 1022 | + "@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q=="], | |
| 1023 | + | |
| 1024 | + "@radix-ui/react-toolbar": ["@radix-ui/react-toolbar@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-toggle-group": "1.1.11" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg=="], | |
| 1025 | + | |
| 1026 | + "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg=="], | |
| 1027 | + | |
| 1028 | + "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="], | |
| 1029 | + | |
| 1030 | + "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="], | |
| 1031 | + | |
| 1032 | + "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="], | |
| 1033 | + | |
| 1034 | + "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="], | |
| 1035 | + | |
| 1036 | + "@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.0", "", { "dependencies": { "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA=="], | |
| 1037 | + | |
| 1038 | + "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="], | |
| 1039 | + | |
| 1040 | + "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="], | |
| 1041 | + | |
| 1042 | + "@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.1", "", { "dependencies": { "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w=="], | |
| 1043 | + | |
| 1044 | + "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="], | |
| 1045 | + | |
| 1046 | + "@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.3", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug=="], | |
| 1047 | + | |
| 1048 | + "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="], | |
| 1049 | + | |
| 1050 | + "@reduxjs/toolkit": ["@reduxjs/toolkit@2.11.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@standard-schema/utils": "^0.3.0", "immer": "^11.0.0", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "optionalPeers": ["react", "react-redux"] }, "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ=="], | |
| 1379 | 1051 | |
| 1380 | − "@parcel/watcher-linux-arm64-glibc": ["@parcel/watcher-linux-arm64-glibc@2.5.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA=="], | |
| 1052 | + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="], | |
| 1381 | 1053 | |
| 1382 | − "@parcel/watcher-linux-arm64-musl": ["@parcel/watcher-linux-arm64-musl@2.5.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA=="], | |
| 1054 | + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.60.1", "", { "os": "android", "cpu": "arm" }, "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA=="], | |
| 1383 | 1055 | |
| 1384 | − "@parcel/watcher-linux-x64-glibc": ["@parcel/watcher-linux-x64-glibc@2.5.6", "", { "os": "linux", "cpu": "x64" }, "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ=="], | |
| 1056 | + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.60.1", "", { "os": "android", "cpu": "arm64" }, "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA=="], | |
| 1385 | 1057 | |
| 1386 | − "@parcel/watcher-linux-x64-musl": ["@parcel/watcher-linux-x64-musl@2.5.6", "", { "os": "linux", "cpu": "x64" }, "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg=="], | |
| 1058 | + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.60.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw=="], | |
| 1387 | 1059 | |
| 1388 | − "@parcel/watcher-win32-arm64": ["@parcel/watcher-win32-arm64@2.5.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q=="], | |
| 1060 | + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.60.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew=="], | |
| 1389 | 1061 | |
| 1390 | − "@parcel/watcher-win32-ia32": ["@parcel/watcher-win32-ia32@2.5.6", "", { "os": "win32", "cpu": "ia32" }, "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g=="], | |
| 1062 | + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.60.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w=="], | |
| 1391 | 1063 | |
| 1392 | − "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw=="], | |
| 1064 | + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.60.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g=="], | |
| 1393 | 1065 | |
| 1394 | − "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="], | |
| 1066 | + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.60.1", "", { "os": "linux", "cpu": "arm" }, "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g=="], | |
| 1395 | 1067 | |
| 1396 | − "@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="], | |
| 1068 | + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.60.1", "", { "os": "linux", "cpu": "arm" }, "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg=="], | |
| 1397 | 1069 | |
| 1398 | − "@protobufjs/codegen": ["@protobufjs/codegen@2.0.4", "", {}, "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="], | |
| 1070 | + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.60.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ=="], | |
| 1399 | 1071 | |
| 1400 | − "@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="], | |
| 1072 | + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.60.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA=="], | |
| 1401 | 1073 | |
| 1402 | − "@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="], | |
| 1074 | + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.60.1", "", { "os": "linux", "cpu": "none" }, "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ=="], | |
| 1403 | 1075 | |
| 1404 | − "@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="], | |
| 1076 | + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.60.1", "", { "os": "linux", "cpu": "none" }, "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw=="], | |
| 1405 | 1077 | |
| 1406 | − "@protobufjs/inquire": ["@protobufjs/inquire@1.1.0", "", {}, "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="], | |
| 1078 | + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.60.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw=="], | |
| 1407 | 1079 | |
| 1408 | − "@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="], | |
| 1080 | + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.60.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg=="], | |
| 1409 | 1081 | |
| 1410 | − "@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="], | |
| 1082 | + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.60.1", "", { "os": "linux", "cpu": "none" }, "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg=="], | |
| 1411 | 1083 | |
| 1412 | − "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="], | |
| 1084 | + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.60.1", "", { "os": "linux", "cpu": "none" }, "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg=="], | |
| 1413 | 1085 | |
| 1414 | − "@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="], | |
| 1086 | + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.60.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ=="], | |
| 1415 | 1087 | |
| 1416 | − "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="], | |
| 1088 | + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.60.1", "", { "os": "linux", "cpu": "x64" }, "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg=="], | |
| 1417 | 1089 | |
| 1418 | − "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="], | |
| 1090 | + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.60.1", "", { "os": "linux", "cpu": "x64" }, "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w=="], | |
| 1419 | 1091 | |
| 1420 | − "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="], | |
| 1092 | + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.60.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw=="], | |
| 1421 | 1093 | |
| 1422 | − "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="], | |
| 1094 | + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.60.1", "", { "os": "none", "cpu": "arm64" }, "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA=="], | |
| 1423 | 1095 | |
| 1424 | − "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="], | |
| 1096 | + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.60.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g=="], | |
| 1425 | 1097 | |
| 1426 | − "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="], | |
| 1098 | + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.60.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg=="], | |
| 1427 | 1099 | |
| 1428 | − "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="], | |
| 1100 | + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.60.1", "", { "os": "win32", "cpu": "x64" }, "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg=="], | |
| 1429 | 1101 | |
| 1430 | − "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="], | |
| 1102 | + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.60.1", "", { "os": "win32", "cpu": "x64" }, "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ=="], | |
| 1431 | 1103 | |
| 1432 | − "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="], | |
| 1104 | + "@shikijs/core": ["@shikijs/core@4.0.2", "", { "dependencies": { "@shikijs/primitive": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw=="], | |
| 1433 | 1105 | |
| 1434 | − "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="], | |
| 1106 | + "@shikijs/engine-javascript": ["@shikijs/engine-javascript@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag=="], | |
| 1435 | 1107 | |
| 1436 | − "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], | |
| 1108 | + "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg=="], | |
| 1437 | 1109 | |
| 1438 | − "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="], | |
| 1110 | + "@shikijs/langs": ["@shikijs/langs@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg=="], | |
| 1439 | 1111 | |
| 1440 | − "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="], | |
| 1112 | + "@shikijs/primitive": ["@shikijs/primitive@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw=="], | |
| 1441 | 1113 | |
| 1442 | − "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="], | |
| 1114 | + "@shikijs/themes": ["@shikijs/themes@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA=="], | |
| 1443 | 1115 | |
| 1444 | − "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="], | |
| 1116 | + "@shikijs/types": ["@shikijs/types@4.0.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg=="], | |
| 1445 | 1117 | |
| 1446 | − "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="], | |
| 1118 | + "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], | |
| 1447 | 1119 | |
| 1448 | − "@react-grab/cli": ["@react-grab/cli@0.1.26", "", { "dependencies": { "@antfu/ni": "^0.23.0", "commander": "^14.0.0", "ignore": "^7.0.5", "jsonc-parser": "^3.3.1", "ora": "^8.2.0", "picocolors": "^1.1.1", "prompts": "^2.4.2", "smol-toml": "^1.6.0" }, "bin": { "react-grab": "dist/cli.js" } }, "sha512-nNOBdrJ2K7jji6L/X9ARCpU1o/CQ33KYZUtW7vAtrfDM2hyvAIA224ps+Syl97FxhS7pO8b59Bnhc7YLG6h3nA=="], | |
| 1120 | + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], | |
| 1449 | 1121 | |
| 1450 | − "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.3", "", {}, "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q=="], | |
| 1122 | + "@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="], | |
| 1451 | 1123 | |
| 1452 | − "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.59.0", "", { "os": "android", "cpu": "arm" }, "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg=="], | |
| 1124 | + "@tabby_ai/hijri-converter": ["@tabby_ai/hijri-converter@1.0.5", "", {}, "sha512-r5bClKrcIusDoo049dSL8CawnHR6mRdDwhlQuIgZRNty68q0x8k3Lf1BtPAMxRf/GgnHBnIO4ujd3+GQdLWzxQ=="], | |
| 1453 | 1125 | |
| 1454 | − "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.59.0", "", { "os": "android", "cpu": "arm64" }, "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q=="], | |
| 1126 | + "@tailwindcss/node": ["@tailwindcss/node@4.2.2", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.2" } }, "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA=="], | |
| 1455 | 1127 | |
| 1456 | − "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.59.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg=="], | |
| 1128 | + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.2", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.2", "@tailwindcss/oxide-darwin-arm64": "4.2.2", "@tailwindcss/oxide-darwin-x64": "4.2.2", "@tailwindcss/oxide-freebsd-x64": "4.2.2", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", "@tailwindcss/oxide-linux-x64-musl": "4.2.2", "@tailwindcss/oxide-wasm32-wasi": "4.2.2", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" } }, "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg=="], | |
| 1457 | 1129 | |
| 1458 | − "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.59.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w=="], | |
| 1130 | + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.2.2", "", { "os": "android", "cpu": "arm64" }, "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg=="], | |
| 1459 | 1131 | |
| 1460 | − "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.59.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA=="], | |
| 1132 | + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.2.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg=="], | |
| 1461 | 1133 | |
| 1462 | − "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.59.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg=="], | |
| 1134 | + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.2.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw=="], | |
| 1463 | 1135 | |
| 1464 | − "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw=="], | |
| 1136 | + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.2.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ=="], | |
| 1465 | 1137 | |
| 1466 | − "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA=="], | |
| 1138 | + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2", "", { "os": "linux", "cpu": "arm" }, "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ=="], | |
| 1467 | 1139 | |
| 1468 | − "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA=="], | |
| 1140 | + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.2.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw=="], | |
| 1469 | 1141 | |
| 1470 | − "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA=="], | |
| 1142 | + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.2.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag=="], | |
| 1471 | 1143 | |
| 1472 | − "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg=="], | |
| 1144 | + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.2.2", "", { "os": "linux", "cpu": "x64" }, "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg=="], | |
| 1473 | 1145 | |
| 1474 | − "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q=="], | |
| 1146 | + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.2.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ=="], | |
| 1475 | 1147 | |
| 1476 | − "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA=="], | |
| 1148 | + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.2.2", "", { "dependencies": { "@emnapi/core": "^1.8.1", "@emnapi/runtime": "^1.8.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.1", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q=="], | |
| 1477 | 1149 | |
| 1478 | − "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA=="], | |
| 1150 | + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.2.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ=="], | |
| 1479 | 1151 | |
| 1480 | − "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg=="], | |
| 1152 | + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.2", "", { "os": "win32", "cpu": "x64" }, "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA=="], | |
| 1481 | 1153 | |
| 1482 | − "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg=="], | |
| 1154 | + "@tailwindcss/vite": ["@tailwindcss/vite@4.2.2", "", { "dependencies": { "@tailwindcss/node": "4.2.2", "@tailwindcss/oxide": "4.2.2", "tailwindcss": "4.2.2" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "sha512-mEiF5HO1QqCLXoNEfXVA1Tzo+cYsrqV7w9Juj2wdUFyW07JRenqMG225MvPwr3ZD9N1bFQj46X7r33iHxLUW0w=="], | |
| 1483 | 1155 | |
| 1484 | − "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.59.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w=="], | |
| 1156 | + "@tanstack/history": ["@tanstack/history@1.161.6", "", {}, "sha512-NaOGLRrddszbQj9upGat6HG/4TKvXLvu+osAIgfxPYA+eIvYKv8GKDJOrY2D3/U9MRnKfMWD7bU4jeD4xmqyIg=="], | |
| 1485 | 1157 | |
| 1486 | − "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg=="], | |
| 1158 | + "@tanstack/react-router": ["@tanstack/react-router@1.168.10", "", { "dependencies": { "@tanstack/history": "1.161.6", "@tanstack/react-store": "^0.9.3", "@tanstack/router-core": "1.168.9", "isbot": "^5.1.22" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-/RmDlOwDkCug609KdPB3U+U1zmrtadJpvsmRg2zEn8TRCKRNri7dYZIjQZbNg8PgUiRL4T6njrZBV1ChzblNaA=="], | |
| 1487 | 1159 | |
| 1488 | − "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg=="], | |
| 1160 | + "@tanstack/react-store": ["@tanstack/react-store@0.9.3", "", { "dependencies": { "@tanstack/store": "0.9.3", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg=="], | |
| 1489 | 1161 | |
| 1490 | − "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.59.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ=="], | |
| 1162 | + "@tanstack/router-core": ["@tanstack/router-core@1.168.9", "", { "dependencies": { "@tanstack/history": "1.161.6", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2" }, "bin": { "intent": "bin/intent.js" } }, "sha512-18oeEwEDyXOIuO1VBP9ACaK7tYHZUjynGDCoUh/5c/BNhia9vCJCp9O0LfhZXOorDc/PmLSgvmweFhVmIxF10g=="], | |
| 1491 | 1163 | |
| 1492 | − "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.59.0", "", { "os": "none", "cpu": "arm64" }, "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA=="], | |
| 1164 | + "@tanstack/store": ["@tanstack/store@0.9.3", "", {}, "sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw=="], | |
| 1493 | 1165 | |
| 1494 | − "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.59.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A=="], | |
| 1166 | + "@turbo/darwin-64": ["@turbo/darwin-64@2.9.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-yg0qdthTUuV/K0oJB9t8YGweW1hOefQ+NTiSA6gw/mwAqqifCvAXH/kDkvVj/fFP9+wzoQ4WjyAF5/syDbCIHA=="], | |
| 1495 | 1167 | |
| 1496 | − "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.59.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA=="], | |
| 1168 | + "@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.9.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-x4H9U8cXZob3oqTleKOEdY89OCWwLX3qVRpW0NeZg+CHDXemYD+PhACjwjvh7orIlhmmq2Lk+7iO7b34kphFig=="], | |
| 1497 | 1169 | |
| 1498 | − "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA=="], | |
| 1170 | + "@turbo/linux-64": ["@turbo/linux-64@2.9.2", "", { "os": "linux", "cpu": "x64" }, "sha512-fxbpor8zvRtaf75sfloNTaBkl487JECSVDrXXMGlwR3+Qmq7yStUE+ccQddPu+nKqYD46QxDspk8KZvT78SBSg=="], | |
| 1499 | 1171 | |
| 1500 | − "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA=="], | |
| 1172 | + "@turbo/linux-arm64": ["@turbo/linux-arm64@2.9.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-ufMQcCQMi8kzHbEA+FihPaRdrPQC1vUO0LQ9oU/LGWlnc+RVyDlvH9l9x0BWoS7HLyHK8hbqLf3O2ml/ZLMEIw=="], | |
| 1501 | 1173 | |
| 1502 | − "@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="], | |
| 1174 | + "@turbo/windows-64": ["@turbo/windows-64@2.9.2", "", { "os": "win32", "cpu": "x64" }, "sha512-SOELKum/pjdJWKQb+RU/OEAlNtWJKfjjYUA9QhYxBvIT26SyfWgY+ecZ7QlVWt+xnEdQyC6BkYlWR546KxPO5w=="], | |
| 1503 | 1175 | |
| 1504 | − "@shikijs/core": ["@shikijs/core@4.0.1", "", { "dependencies": { "@shikijs/primitive": "4.0.1", "@shikijs/types": "4.0.1", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-vWvqi9JNgz1dRL9Nvog5wtx7RuNkf7MEPl2mU/cyUUxJeH1CAr3t+81h8zO8zs7DK6cKLMoU9TvukWIDjP4Lzg=="], | |
| 1176 | + "@turbo/windows-arm64": ["@turbo/windows-arm64@2.9.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-qPFjErR4MrKo71lNfqgUNaajftZN2nyaOsSxMSb2NI+5r/zlB26yjXUKYvADGg4EWvaLTJPIzgZDT9ZX+WN9bw=="], | |
| 1505 | 1177 | |
| 1506 | − "@shikijs/engine-javascript": ["@shikijs/engine-javascript@4.0.1", "", { "dependencies": { "@shikijs/types": "4.0.1", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-DJK9NiwtGYqMuKCRO4Ip0FKNDQpmaiS+K5bFjJ7DWFn4zHueDWgaUG8kAofkrnXF6zPPYYQY7J5FYVW9MbZyBg=="], | |
| 1178 | + "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], | |
| 1507 | 1179 | |
| 1508 | − "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@4.0.1", "", { "dependencies": { "@shikijs/types": "4.0.1", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-oCWdCTDch3J8Kc0OZJ98KuUPC02O1VqIE3W/e2uvrHqTxYRR21RGEJMtchrgrxhsoJJCzmIciKsqG+q/yD+Cxg=="], | |
| 1180 | + "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], | |
| 1509 | 1181 | |
| 1510 | − "@shikijs/langs": ["@shikijs/langs@4.0.1", "", { "dependencies": { "@shikijs/types": "4.0.1" } }, "sha512-v/mluaybWdnGJR4GqAR6zh8qAZohW9k+cGYT28Y7M8+jLbC0l4yG085O1A+WkseHTn+awd+P3UBymb2+MXFc8w=="], | |
| 1182 | + "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], | |
| 1511 | 1183 | |
| 1512 | − "@shikijs/primitive": ["@shikijs/primitive@4.0.1", "", { "dependencies": { "@shikijs/types": "4.0.1", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-ns0hHZc5eWZuvuIEJz2pTx3Qecz0aRVYumVQJ8JgWY2tq/dH8WxdcVM49Fc2NsHEILNIT6vfdW9MF26RANWiTA=="], | |
| 1184 | + "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], | |
| 1513 | 1185 | |
| 1514 | − "@shikijs/themes": ["@shikijs/themes@4.0.1", "", { "dependencies": { "@shikijs/types": "4.0.1" } }, "sha512-FW41C/D6j/yKQkzVdjrRPiJCtgeDaYRJFEyCKFCINuRJRj9WcmubhP4KQHPZ4+9eT87jruSrYPyoblNRyDFzvA=="], | |
| 1186 | + "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="], | |
| 1515 | 1187 | |
| 1516 | − "@shikijs/types": ["@shikijs/types@4.0.1", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-EaygPEn57+jJ76mw+nTLvIpJMAcMPokFbrF8lufsZP7Ukk+ToJYEcswN1G0e49nUZAq7aCQtoeW219A8HK1ZOw=="], | |
| 1188 | + "@types/d3": ["@types/d3@7.4.3", "", { "dependencies": { "@types/d3-array": "*", "@types/d3-axis": "*", "@types/d3-brush": "*", "@types/d3-chord": "*", "@types/d3-color": "*", "@types/d3-contour": "*", "@types/d3-delaunay": "*", "@types/d3-dispatch": "*", "@types/d3-drag": "*", "@types/d3-dsv": "*", "@types/d3-ease": "*", "@types/d3-fetch": "*", "@types/d3-force": "*", "@types/d3-format": "*", "@types/d3-geo": "*", "@types/d3-hierarchy": "*", "@types/d3-interpolate": "*", "@types/d3-path": "*", "@types/d3-polygon": "*", "@types/d3-quadtree": "*", "@types/d3-random": "*", "@types/d3-scale": "*", "@types/d3-scale-chromatic": "*", "@types/d3-selection": "*", "@types/d3-shape": "*", "@types/d3-time": "*", "@types/d3-time-format": "*", "@types/d3-timer": "*", "@types/d3-transition": "*", "@types/d3-zoom": "*" } }, "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww=="], | |
| 1517 | 1189 | |
| 1518 | − "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], | |
| 1190 | + "@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="], | |
| 1519 | 1191 | |
| 1520 | − "@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="], | |
| 1192 | + "@types/d3-axis": ["@types/d3-axis@3.0.6", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw=="], | |
| 1521 | 1193 | |
| 1522 | − "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], | |
| 1194 | + "@types/d3-brush": ["@types/d3-brush@3.0.6", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A=="], | |
| 1523 | 1195 | |
| 1524 | − "@tailwindcss/node": ["@tailwindcss/node@4.2.1", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.31.1", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.1" } }, "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg=="], | |
| 1196 | + "@types/d3-chord": ["@types/d3-chord@3.0.6", "", {}, "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg=="], | |
| 1525 | 1197 | |
| 1526 | − "@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.1", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.1", "@tailwindcss/oxide-darwin-arm64": "4.2.1", "@tailwindcss/oxide-darwin-x64": "4.2.1", "@tailwindcss/oxide-freebsd-x64": "4.2.1", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", "@tailwindcss/oxide-linux-x64-musl": "4.2.1", "@tailwindcss/oxide-wasm32-wasi": "4.2.1", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" } }, "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw=="], | |
| 1198 | + "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="], | |
| 1527 | 1199 | |
| 1528 | − "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.2.1", "", { "os": "android", "cpu": "arm64" }, "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg=="], | |
| 1200 | + "@types/d3-contour": ["@types/d3-contour@3.0.6", "", { "dependencies": { "@types/d3-array": "*", "@types/geojson": "*" } }, "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg=="], | |
| 1529 | 1201 | |
| 1530 | − "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.2.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw=="], | |
| 1202 | + "@types/d3-delaunay": ["@types/d3-delaunay@6.0.4", "", {}, "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw=="], | |
| 1531 | 1203 | |
| 1532 | − "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.2.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw=="], | |
| 1204 | + "@types/d3-dispatch": ["@types/d3-dispatch@3.0.7", "", {}, "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA=="], | |
| 1533 | 1205 | |
| 1534 | − "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.2.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA=="], | |
| 1206 | + "@types/d3-drag": ["@types/d3-drag@3.0.7", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ=="], | |
| 1535 | 1207 | |
| 1536 | − "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1", "", { "os": "linux", "cpu": "arm" }, "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw=="], | |
| 1208 | + "@types/d3-dsv": ["@types/d3-dsv@3.0.7", "", {}, "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g=="], | |
| 1537 | 1209 | |
| 1538 | − "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.2.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ=="], | |
| 1210 | + "@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="], | |
| 1539 | 1211 | |
| 1540 | − "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.2.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ=="], | |
| 1212 | + "@types/d3-fetch": ["@types/d3-fetch@3.0.7", "", { "dependencies": { "@types/d3-dsv": "*" } }, "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA=="], | |
| 1541 | 1213 | |
| 1542 | − "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.2.1", "", { "os": "linux", "cpu": "x64" }, "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g=="], | |
| 1214 | + "@types/d3-force": ["@types/d3-force@3.0.10", "", {}, "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw=="], | |
| 1543 | 1215 | |
| 1544 | − "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.2.1", "", { "os": "linux", "cpu": "x64" }, "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g=="], | |
| 1216 | + "@types/d3-format": ["@types/d3-format@3.0.4", "", {}, "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g=="], | |
| 1545 | 1217 | |
| 1546 | − "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.2.1", "", { "dependencies": { "@emnapi/core": "^1.8.1", "@emnapi/runtime": "^1.8.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.1", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q=="], | |
| 1218 | + "@types/d3-geo": ["@types/d3-geo@3.1.0", "", { "dependencies": { "@types/geojson": "*" } }, "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ=="], | |
| 1547 | 1219 | |
| 1548 | − "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.2.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA=="], | |
| 1220 | + "@types/d3-hierarchy": ["@types/d3-hierarchy@3.1.7", "", {}, "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg=="], | |
| 1549 | 1221 | |
| 1550 | − "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.1", "", { "os": "win32", "cpu": "x64" }, "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ=="], | |
| 1222 | + "@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "*" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="], | |
| 1551 | 1223 | |
| 1552 | − "@tailwindcss/vite": ["@tailwindcss/vite@4.2.1", "", { "dependencies": { "@tailwindcss/node": "4.2.1", "@tailwindcss/oxide": "4.2.1", "tailwindcss": "4.2.1" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w=="], | |
| 1224 | + "@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="], | |
| 1553 | 1225 | |
| 1554 | − "@tanstack/history": ["@tanstack/history@1.161.4", "", {}, "sha512-Kp/WSt411ZWYvgXy6uiv5RmhHrz9cAml05AQPrtdAp7eUqvIDbMGPnML25OKbzR3RJ1q4wgENxDTvlGPa9+Mww=="], | |
| 1226 | + "@types/d3-polygon": ["@types/d3-polygon@3.0.2", "", {}, "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA=="], | |
| 1555 | 1227 | |
| 1556 | − "@tanstack/react-router": ["@tanstack/react-router@1.166.2", "", { "dependencies": { "@tanstack/history": "1.161.4", "@tanstack/react-store": "^0.9.1", "@tanstack/router-core": "1.166.2", "isbot": "^5.1.22", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-pKhUtrvVLlhjWhsHkJSuIzh1J4LcP+8ErbIqRLORX9Js8dUFMKoT0+8oFpi+P8QRpuhm/7rzjYiWfcyTsqQZtA=="], | |
| 1228 | + "@types/d3-quadtree": ["@types/d3-quadtree@3.0.6", "", {}, "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg=="], | |
| 1557 | 1229 | |
| 1558 | − "@tanstack/react-store": ["@tanstack/react-store@0.9.2", "", { "dependencies": { "@tanstack/store": "0.9.2", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Vt5usJE5sHG/cMechQfmwvwne6ktGCELe89Lmvoxe3LKRoFrhPa8OCKWs0NliG8HTJElEIj7PLtaBQIcux5pAQ=="], | |
| 1230 | + "@types/d3-random": ["@types/d3-random@3.0.3", "", {}, "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ=="], | |
| 1559 | 1231 | |
| 1560 | − "@tanstack/router-core": ["@tanstack/router-core@1.166.2", "", { "dependencies": { "@tanstack/history": "1.161.4", "@tanstack/store": "^0.9.1", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-zn3NhENOAX9ToQiX077UV2OH3aJKOvV2ZMNZZxZ3gDG3i3WqL8NfWfEgetEAfMN37/Mnt90PpotYgf7IyuoKqQ=="], | |
| 1232 | + "@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "*" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="], | |
| 1561 | 1233 | |
| 1562 | − "@tanstack/store": ["@tanstack/store@0.9.2", "", {}, "sha512-K013lUJEFJK2ofFQ/hZKJUmCnpcV00ebLyOyFOWQvyQHUOZp/iYO84BM6aOGiV81JzwbX0APTVmW8YI7yiG5oA=="], | |
| 1234 | + "@types/d3-scale-chromatic": ["@types/d3-scale-chromatic@3.1.0", "", {}, "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ=="], | |
| 1563 | 1235 | |
| 1564 | − "@ts-morph/common": ["@ts-morph/common@0.27.0", "", { "dependencies": { "fast-glob": "^3.3.3", "minimatch": "^10.0.1", "path-browserify": "^1.0.1" } }, "sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ=="], | |
| 1236 | + "@types/d3-selection": ["@types/d3-selection@3.0.11", "", {}, "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w=="], | |
| 1565 | 1237 | |
| 1566 | − "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], | |
| 1238 | + "@types/d3-shape": ["@types/d3-shape@3.1.8", "", { "dependencies": { "@types/d3-path": "*" } }, "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w=="], | |
| 1567 | 1239 | |
| 1568 | − "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], | |
| 1240 | + "@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="], | |
| 1569 | 1241 | |
| 1570 | − "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], | |
| 1242 | + "@types/d3-time-format": ["@types/d3-time-format@4.0.3", "", {}, "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg=="], | |
| 1571 | 1243 | |
| 1572 | − "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], | |
| 1244 | + "@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="], | |
| 1573 | 1245 | |
| 1574 | − "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], | |
| 1246 | + "@types/d3-transition": ["@types/d3-transition@3.0.9", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg=="], | |
| 1575 | 1247 | |
| 1576 | − "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="], | |
| 1248 | + "@types/d3-zoom": ["@types/d3-zoom@3.0.8", "", { "dependencies": { "@types/d3-interpolate": "*", "@types/d3-selection": "*" } }, "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw=="], | |
| 1577 | 1249 | |
| 1578 | − "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], | |
| 1250 | + "@types/debug": ["@types/debug@4.1.13", "", { "dependencies": { "@types/ms": "*" } }, "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw=="], | |
| 1579 | 1251 | |
| 1580 | 1252 | "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], |
| 1581 | 1253 | |
| @@ -1583,35 +1255,33 @@ · 1 unmodified line | ||
| 1583 | 1255 | |
| 1584 | 1256 | "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="], |
| 1585 | 1257 | |
| 1258 | + "@types/geojson": ["@types/geojson@7946.0.16", "", {}, "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg=="], | |
| 1259 | + | |
| 1586 | 1260 | "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], |
| 1587 | 1261 | |
| 1588 | − "@types/jsdom": ["@types/jsdom@21.1.7", "", { "dependencies": { "@types/node": "*", "@types/tough-cookie": "*", "parse5": "^7.0.0" } }, "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA=="], | |
| 1262 | + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], | |
| 1589 | 1263 | |
| 1590 | 1264 | "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], |
| 1591 | 1265 | |
| 1592 | 1266 | "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], |
| 1593 | 1267 | |
| 1594 | − "@types/node": ["@types/node@24.11.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-fPxQqz4VTgPI/IQ+lj9r0h+fDR66bzoeMGHp8ASee+32OSGIkeASsoZuJixsQoVef1QJbeubcPBxKk22QVoWdw=="], | |
| 1268 | + "@types/node": ["@types/node@24.12.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ=="], | |
| 1595 | 1269 | |
| 1596 | 1270 | "@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="], |
| 1597 | 1271 | |
| 1598 | 1272 | "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], |
| 1599 | 1273 | |
| 1600 | − "@types/react-reconciler": ["@types/react-reconciler@0.28.9", "", { "peerDependencies": { "@types/react": "*" } }, "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg=="], | |
| 1601 | − | |
| 1602 | − "@types/statuses": ["@types/statuses@2.0.6", "", {}, "sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA=="], | |
| 1603 | − | |
| 1604 | − "@types/tough-cookie": ["@types/tough-cookie@4.0.5", "", {}, "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA=="], | |
| 1274 | + "@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="], | |
| 1605 | 1275 | |
| 1606 | 1276 | "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], |
| 1607 | 1277 | |
| 1608 | − "@types/validate-npm-package-name": ["@types/validate-npm-package-name@4.0.2", "", {}, "sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw=="], | |
| 1278 | + "@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="], | |
| 1609 | 1279 | |
| 1610 | 1280 | "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], |
| 1611 | 1281 | |
| 1612 | − "@vercel/oidc": ["@vercel/oidc@3.1.0", "", {}, "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w=="], | |
| 1282 | + "@upsetjs/venn.js": ["@upsetjs/venn.js@2.0.0", "", { "optionalDependencies": { "d3-selection": "^3.0.0", "d3-transition": "^3.0.1" } }, "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw=="], | |
| 1613 | 1283 | |
| 1614 | − "@vitejs/plugin-react": ["@vitejs/plugin-react@5.1.4", "", { "dependencies": { "@babel/core": "^7.29.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-rc.3", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA=="], | |
| 1284 | + "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="], | |
| 1615 | 1285 | |
| 1616 | 1286 | "@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="], |
| 1617 | 1287 | |
| @@ -1629,20 +1299,18 @@ · 11 unmodified lines | ||
| 1629 | 1299 | |
| 1630 | 1300 | "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], |
| 1631 | 1301 | |
| 1632 | − "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], | |
| 1633 | − | |
| 1634 | − "ai": ["ai@6.0.116", "", { "dependencies": { "@ai-sdk/gateway": "3.0.66", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.19", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-7yM+cTmyRLeNIXwt4Vj+mrrJgVQ9RMIW5WO0ydoLoYkewIvsMcvUmqS4j2RJTUXaF1HphwmSKUMQ/HypNRGOmA=="], | |
| 1302 | + "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], | |
| 1635 | 1303 | |
| 1636 | 1304 | "ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="], |
| 1637 | 1305 | |
| 1306 | + "ajv-draft-04": ["ajv-draft-04@1.0.0", "", { "peerDependencies": { "ajv": "^8.5.0" }, "optionalPeers": ["ajv"] }, "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw=="], | |
| 1307 | + | |
| 1638 | 1308 | "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], |
| 1639 | 1309 | |
| 1640 | 1310 | "ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="], |
| 1641 | 1311 | |
| 1642 | 1312 | "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], |
| 1643 | 1313 | |
| 1644 | − "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], | |
| 1645 | − | |
| 1646 | 1314 | "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], |
| 1647 | 1315 | |
| 1648 | 1316 | "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], |
| @@ -1651,29 +1319,29 @@ · 2 unmodified lines | ||
| 1651 | 1319 | |
| 1652 | 1320 | "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], |
| 1653 | 1321 | |
| 1654 | − "ast-types": ["ast-types@0.16.1", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg=="], | |
| 1655 | − | |
| 1656 | 1322 | "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], |
| 1657 | 1323 | |
| 1658 | − "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], | |
| 1324 | + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], | |
| 1659 | 1325 | |
| 1660 | − "baseline-browser-mapping": ["baseline-browser-mapping@2.10.0", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA=="], | |
| 1326 | + "baseline-browser-mapping": ["baseline-browser-mapping@2.10.13", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw=="], | |
| 1661 | 1327 | |
| 1662 | 1328 | "better-path-resolve": ["better-path-resolve@1.0.0", "", { "dependencies": { "is-windows": "^1.0.0" } }, "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g=="], |
| 1663 | 1329 | |
| 1664 | − "bippy": ["bippy@0.5.32", "", { "dependencies": { "@types/react-reconciler": "^0.28.9" }, "peerDependencies": { "react": ">=17.0.1" } }, "sha512-yt1mC8eReTxjfg41YBZdN4PvsDwHFWxltoiQX0Q+Htlbf41aSniopb7ECZits01HwNAvXEh69RGk/ImlswDTEw=="], | |
| 1330 | + "better-sqlite3": ["better-sqlite3@12.8.0", "", { "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" } }, "sha512-RxD2Vd96sQDjQr20kdP+F+dK/1OUNiVOl200vKBZY8u0vTwysfolF6Hq+3ZK2+h8My9YvZhHsF+RSGZW2VYrPQ=="], | |
| 1665 | 1331 | |
| 1666 | − "body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], | |
| 1332 | + "bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="], | |
| 1333 | + | |
| 1334 | + "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], | |
| 1667 | 1335 | |
| 1668 | − "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], | |
| 1336 | + "body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], | |
| 1669 | 1337 | |
| 1670 | 1338 | "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], |
| 1671 | 1339 | |
| 1672 | − "browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="], | |
| 1340 | + "browserslist": ["browserslist@4.28.2", "", { "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", "electron-to-chromium": "^1.5.328", "node-releases": "^2.0.36", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="], | |
| 1673 | 1341 | |
| 1674 | − "bun-types": ["bun-types@1.3.10", "", { "dependencies": { "@types/node": "*" } }, "sha512-tcpfCCl6XWo6nCVnpcVrxQ+9AYN1iqMIzgrSKYMB/fjLtV2eyAVEg7AxQJuCq/26R6HpKWykQXuSOq/21RYcbg=="], | |
| 1342 | + "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], | |
| 1675 | 1343 | |
| 1676 | − "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], | |
| 1344 | + "bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="], | |
| 1677 | 1345 | |
| 1678 | 1346 | "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], |
| 1679 | 1347 | |
| @@ -1683,16 +1351,14 @@ · 3 unmodified lines | ||
| 1683 | 1351 | |
| 1684 | 1352 | "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], |
| 1685 | 1353 | |
| 1686 | − "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], | |
| 1354 | + "call-me-maybe": ["call-me-maybe@1.0.2", "", {}, "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ=="], | |
| 1687 | 1355 | |
| 1688 | − "caniuse-lite": ["caniuse-lite@1.0.30001777", "", {}, "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ=="], | |
| 1356 | + "caniuse-lite": ["caniuse-lite@1.0.30001784", "", {}, "sha512-WU346nBTklUV9YfUl60fqRbU5ZqyXlqvo1SgigE1OAXK5bFL8LL9q1K7aap3N739l4BvNqnkm3YrGHiY9sfUQw=="], | |
| 1689 | 1357 | |
| 1690 | 1358 | "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], |
| 1691 | 1359 | |
| 1692 | 1360 | "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], |
| 1693 | 1361 | |
| 1694 | − "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], | |
| 1695 | − | |
| 1696 | 1362 | "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], |
| 1697 | 1363 | |
| 1698 | 1364 | "character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="], |
| @@ -1705,29 +1371,23 @@ · 6 unmodified lines | ||
| 1705 | 1371 | |
| 1706 | 1372 | "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="], |
| 1707 | 1373 | |
| 1708 | − "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], | |
| 1709 | − | |
| 1710 | − "cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="], | |
| 1374 | + "chevrotain": ["chevrotain@11.1.2", "", { "dependencies": { "@chevrotain/cst-dts-gen": "11.1.2", "@chevrotain/gast": "11.1.2", "@chevrotain/regexp-to-ast": "11.1.2", "@chevrotain/types": "11.1.2", "@chevrotain/utils": "11.1.2", "lodash-es": "4.17.23" } }, "sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg=="], | |
| 1711 | 1375 | |
| 1712 | − "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="], | |
| 1376 | + "chevrotain-allstar": ["chevrotain-allstar@0.3.1", "", { "dependencies": { "lodash-es": "^4.17.21" }, "peerDependencies": { "chevrotain": "^11.0.0" } }, "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw=="], | |
| 1713 | 1377 | |
| 1714 | − "cli-width": ["cli-width@4.1.0", "", {}, "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ=="], | |
| 1378 | + "chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], | |
| 1715 | 1379 | |
| 1716 | − "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], | |
| 1380 | + "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], | |
| 1717 | 1381 | |
| 1718 | 1382 | "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], |
| 1719 | 1383 | |
| 1720 | 1384 | "cmdk": ["cmdk@1.1.1", "", { "dependencies": { "@radix-ui/react-compose-refs": "^1.1.1", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-id": "^1.1.0", "@radix-ui/react-primitive": "^2.0.2" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg=="], |
| 1721 | 1385 | |
| 1722 | − "code-block-writer": ["code-block-writer@13.0.3", "", {}, "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg=="], | |
| 1723 | − | |
| 1724 | − "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], | |
| 1725 | − | |
| 1726 | − "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], | |
| 1727 | − | |
| 1728 | 1386 | "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], |
| 1729 | 1387 | |
| 1730 | − "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], | |
| 1388 | + "commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], | |
| 1389 | + | |
| 1390 | + "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], | |
| 1731 | 1391 | |
| 1732 | 1392 | "content-disposition": ["content-disposition@1.0.1", "", {}, "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q=="], |
| 1733 | 1393 | |
| @@ -1743,37 +1403,103 @@ · 9 unmodified lines | ||
| 1743 | 1403 | |
| 1744 | 1404 | "cors": ["cors@2.8.6", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="], |
| 1745 | 1405 | |
| 1746 | − "cosmiconfig": ["cosmiconfig@9.0.1", "", { "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", "parse-json": "^5.2.0" }, "peerDependencies": { "typescript": ">=4.9.5" }, "optionalPeers": ["typescript"] }, "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ=="], | |
| 1406 | + "cose-base": ["cose-base@1.0.3", "", { "dependencies": { "layout-base": "^1.0.0" } }, "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg=="], | |
| 1747 | 1407 | |
| 1748 | 1408 | "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], |
| 1749 | 1409 | |
| 1750 | − "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], | |
| 1410 | + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], | |
| 1411 | + | |
| 1412 | + "cytoscape": ["cytoscape@3.33.1", "", {}, "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ=="], | |
| 1751 | 1413 | |
| 1752 | − "cssstyle": ["cssstyle@4.6.0", "", { "dependencies": { "@asamuzakjp/css-color": "^3.2.0", "rrweb-cssom": "^0.8.0" } }, "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg=="], | |
| 1414 | + "cytoscape-cose-bilkent": ["cytoscape-cose-bilkent@4.1.0", "", { "dependencies": { "cose-base": "^1.0.0" }, "peerDependencies": { "cytoscape": "^3.2.0" } }, "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ=="], | |
| 1753 | 1415 | |
| 1754 | − "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], | |
| 1416 | + "cytoscape-fcose": ["cytoscape-fcose@2.2.0", "", { "dependencies": { "cose-base": "^2.2.0" }, "peerDependencies": { "cytoscape": "^3.2.0" } }, "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ=="], | |
| 1417 | + | |
| 1418 | + "d3": ["d3@7.9.0", "", { "dependencies": { "d3-array": "3", "d3-axis": "3", "d3-brush": "3", "d3-chord": "3", "d3-color": "3", "d3-contour": "4", "d3-delaunay": "6", "d3-dispatch": "3", "d3-drag": "3", "d3-dsv": "3", "d3-ease": "3", "d3-fetch": "3", "d3-force": "3", "d3-format": "3", "d3-geo": "3", "d3-hierarchy": "3", "d3-interpolate": "3", "d3-path": "3", "d3-polygon": "3", "d3-quadtree": "3", "d3-random": "3", "d3-scale": "4", "d3-scale-chromatic": "3", "d3-selection": "3", "d3-shape": "3", "d3-time": "3", "d3-time-format": "4", "d3-timer": "3", "d3-transition": "3", "d3-zoom": "3" } }, "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA=="], | |
| 1419 | + | |
| 1420 | + "d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="], | |
| 1421 | + | |
| 1422 | + "d3-axis": ["d3-axis@3.0.0", "", {}, "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw=="], | |
| 1423 | + | |
| 1424 | + "d3-brush": ["d3-brush@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", "d3-interpolate": "1 - 3", "d3-selection": "3", "d3-transition": "3" } }, "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ=="], | |
| 1425 | + | |
| 1426 | + "d3-chord": ["d3-chord@3.0.1", "", { "dependencies": { "d3-path": "1 - 3" } }, "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g=="], | |
| 1427 | + | |
| 1428 | + "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="], | |
| 1755 | 1429 | |
| 1756 | − "data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="], | |
| 1430 | + "d3-contour": ["d3-contour@4.0.2", "", { "dependencies": { "d3-array": "^3.2.0" } }, "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA=="], | |
| 1757 | 1431 | |
| 1758 | − "data-urls": ["data-urls@5.0.0", "", { "dependencies": { "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0" } }, "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg=="], | |
| 1432 | + "d3-delaunay": ["d3-delaunay@6.0.4", "", { "dependencies": { "delaunator": "5" } }, "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A=="], | |
| 1433 | + | |
| 1434 | + "d3-dispatch": ["d3-dispatch@3.0.1", "", {}, "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg=="], | |
| 1435 | + | |
| 1436 | + "d3-drag": ["d3-drag@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-selection": "3" } }, "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg=="], | |
| 1437 | + | |
| 1438 | + "d3-dsv": ["d3-dsv@3.0.1", "", { "dependencies": { "commander": "7", "iconv-lite": "0.6", "rw": "1" }, "bin": { "csv2json": "bin/dsv2json.js", "csv2tsv": "bin/dsv2dsv.js", "dsv2dsv": "bin/dsv2dsv.js", "dsv2json": "bin/dsv2json.js", "json2csv": "bin/json2dsv.js", "json2dsv": "bin/json2dsv.js", "json2tsv": "bin/json2dsv.js", "tsv2csv": "bin/dsv2dsv.js", "tsv2json": "bin/dsv2json.js" } }, "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q=="], | |
| 1439 | + | |
| 1440 | + "d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="], | |
| 1441 | + | |
| 1442 | + "d3-fetch": ["d3-fetch@3.0.1", "", { "dependencies": { "d3-dsv": "1 - 3" } }, "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw=="], | |
| 1443 | + | |
| 1444 | + "d3-force": ["d3-force@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-quadtree": "1 - 3", "d3-timer": "1 - 3" } }, "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg=="], | |
| 1445 | + | |
| 1446 | + "d3-format": ["d3-format@3.1.2", "", {}, "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg=="], | |
| 1447 | + | |
| 1448 | + "d3-geo": ["d3-geo@3.1.1", "", { "dependencies": { "d3-array": "2.5.0 - 3" } }, "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q=="], | |
| 1449 | + | |
| 1450 | + "d3-hierarchy": ["d3-hierarchy@3.1.2", "", {}, "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA=="], | |
| 1451 | + | |
| 1452 | + "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="], | |
| 1453 | + | |
| 1454 | + "d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="], | |
| 1455 | + | |
| 1456 | + "d3-polygon": ["d3-polygon@3.0.1", "", {}, "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg=="], | |
| 1457 | + | |
| 1458 | + "d3-quadtree": ["d3-quadtree@3.0.1", "", {}, "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw=="], | |
| 1459 | + | |
| 1460 | + "d3-random": ["d3-random@3.0.1", "", {}, "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ=="], | |
| 1461 | + | |
| 1462 | + "d3-sankey": ["d3-sankey@0.12.3", "", { "dependencies": { "d3-array": "1 - 2", "d3-shape": "^1.2.0" } }, "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ=="], | |
| 1463 | + | |
| 1464 | + "d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", "d3-interpolate": "1.2.0 - 3", "d3-time": "2.1.1 - 3", "d3-time-format": "2 - 4" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="], | |
| 1465 | + | |
| 1466 | + "d3-scale-chromatic": ["d3-scale-chromatic@3.1.0", "", { "dependencies": { "d3-color": "1 - 3", "d3-interpolate": "1 - 3" } }, "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ=="], | |
| 1467 | + | |
| 1468 | + "d3-selection": ["d3-selection@3.0.0", "", {}, "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="], | |
| 1469 | + | |
| 1470 | + "d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "^3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="], | |
| 1471 | + | |
| 1472 | + "d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "2 - 3" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="], | |
| 1473 | + | |
| 1474 | + "d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "1 - 3" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="], | |
| 1475 | + | |
| 1476 | + "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="], | |
| 1477 | + | |
| 1478 | + "d3-transition": ["d3-transition@3.0.1", "", { "dependencies": { "d3-color": "1 - 3", "d3-dispatch": "1 - 3", "d3-ease": "1 - 3", "d3-interpolate": "1 - 3", "d3-timer": "1 - 3" }, "peerDependencies": { "d3-selection": "2 - 3" } }, "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w=="], | |
| 1479 | + | |
| 1480 | + "d3-zoom": ["d3-zoom@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", "d3-interpolate": "1 - 3", "d3-selection": "2 - 3", "d3-transition": "2 - 3" } }, "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw=="], | |
| 1481 | + | |
| 1482 | + "dagre-d3-es": ["dagre-d3-es@7.0.14", "", { "dependencies": { "d3": "^7.9.0", "lodash-es": "^4.17.21" } }, "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg=="], | |
| 1483 | + | |
| 1484 | + "date-fns": ["date-fns@4.1.0", "", {}, "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg=="], | |
| 1485 | + | |
| 1486 | + "date-fns-jalali": ["date-fns-jalali@4.1.0-0", "", {}, "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg=="], | |
| 1487 | + | |
| 1488 | + "dayjs": ["dayjs@1.11.20", "", {}, "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ=="], | |
| 1759 | 1489 | |
| 1760 | 1490 | "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], |
| 1761 | 1491 | |
| 1762 | − "decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="], | |
| 1492 | + "decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="], | |
| 1763 | 1493 | |
| 1764 | 1494 | "decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="], |
| 1765 | 1495 | |
| 1766 | − "dedent": ["dedent@1.7.2", "", { "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, "optionalPeers": ["babel-plugin-macros"] }, "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA=="], | |
| 1496 | + "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="], | |
| 1767 | 1497 | |
| 1768 | 1498 | "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="], |
| 1769 | 1499 | |
| 1770 | − "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], | |
| 1500 | + "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], | |
| 1771 | 1501 | |
| 1772 | − "default-browser": ["default-browser@5.5.0", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw=="], | |
| 1773 | − | |
| 1774 | − "default-browser-id": ["default-browser-id@5.0.1", "", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="], | |
| 1775 | − | |
| 1776 | − "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], | |
| 1502 | + "delaunator": ["delaunator@5.1.0", "", { "dependencies": { "robust-predicates": "^3.0.2" } }, "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ=="], | |
| 1777 | 1503 | |
| 1778 | 1504 | "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], |
| 1779 | 1505 | |
| @@ -1787,38 +1513,34 @@ · 7 unmodified lines | ||
| 1787 | 1513 | |
| 1788 | 1514 | "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], |
| 1789 | 1515 | |
| 1790 | − "diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], | |
| 1791 | − | |
| 1792 | 1516 | "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="], |
| 1793 | 1517 | |
| 1794 | − "dotenv": ["dotenv@17.3.1", "", {}, "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA=="], | |
| 1795 | − | |
| 1796 | − "drizzle-orm": ["drizzle-orm@0.44.7", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-quIpnYznjU9lHshEOAYLoZ9s3jweleHlZIAWR/jX9gAWNg/JhQ1wj0KGRf7/Zm+obRrYd9GjPVJg790QY9N5AQ=="], | |
| 1518 | + "dompurify": ["dompurify@3.3.3", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA=="], | |
| 1797 | 1519 | |
| 1798 | 1520 | "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], |
| 1799 | 1521 | |
| 1800 | − "eciesjs": ["eciesjs@0.4.18", "", { "dependencies": { "@ecies/ciphers": "^0.2.5", "@noble/ciphers": "^1.3.0", "@noble/curves": "^1.9.7", "@noble/hashes": "^1.8.0" } }, "sha512-wG99Zcfcys9fZux7Cft8BAX/YrOJLJSZ3jyYPfhZHqN2E+Ffx+QXBDsv3gubEgPtV6dTzJMSQUwk1H98/t/0wQ=="], | |
| 1801 | − | |
| 1802 | 1522 | "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], |
| 1803 | 1523 | |
| 1804 | − "effect": ["effect@3.19.19", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-Yc8U/SVXo2dHnaP7zNBlAo83h/nzSJpi7vph6Hzyl4ulgMBIgPmz3UzOjb9sBgpFE00gC0iETR244sfXDNLHRg=="], | |
| 1524 | + "effect": ["effect@3.21.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-PPN80qRokCd1f015IANNhrwOnLO7GrrMQfk4/lnZRE/8j7UPWrNNjPV0uBrZutI/nHzernbW+J0hdqQysHiSnQ=="], | |
| 1525 | + | |
| 1526 | + "electron-to-chromium": ["electron-to-chromium@1.5.330", "", {}, "sha512-jFNydB5kFtYUobh4IkWUnXeyDbjf/r9gcUEXe1xcrcUxIGfTdzPXA+ld6zBRbwvgIGVzDll/LTIiDztEtckSnA=="], | |
| 1805 | 1527 | |
| 1806 | − "electron-to-chromium": ["electron-to-chromium@1.5.307", "", {}, "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg=="], | |
| 1528 | + "embla-carousel": ["embla-carousel@8.6.0", "", {}, "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA=="], | |
| 1807 | 1529 | |
| 1808 | − "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], | |
| 1530 | + "embla-carousel-react": ["embla-carousel-react@8.6.0", "", { "dependencies": { "embla-carousel": "8.6.0", "embla-carousel-reactive-utils": "8.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA=="], | |
| 1531 | + | |
| 1532 | + "embla-carousel-reactive-utils": ["embla-carousel-reactive-utils@8.6.0", "", { "peerDependencies": { "embla-carousel": "8.6.0" } }, "sha512-fMVUDUEx0/uIEDM0Mz3dHznDhfX+znCCDCeIophYb1QGVM7YThSWX+wz11zlYwWFOr74b4QLGg0hrGPJeG2s4A=="], | |
| 1809 | 1533 | |
| 1810 | 1534 | "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], |
| 1811 | 1535 | |
| 1812 | − "enhanced-resolve": ["enhanced-resolve@5.20.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ=="], | |
| 1536 | + "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], | |
| 1537 | + | |
| 1538 | + "enhanced-resolve": ["enhanced-resolve@5.20.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA=="], | |
| 1813 | 1539 | |
| 1814 | 1540 | "enquirer": ["enquirer@2.4.1", "", { "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" } }, "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ=="], |
| 1815 | 1541 | |
| 1816 | 1542 | "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], |
| 1817 | 1543 | |
| 1818 | − "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], | |
| 1819 | − | |
| 1820 | − "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], | |
| 1821 | − | |
| 1822 | 1544 | "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], |
| 1823 | 1545 | |
| 1824 | 1546 | "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], |
| @@ -1827,7 +1549,9 @@ · 2 unmodified lines | ||
| 1827 | 1549 | |
| 1828 | 1550 | "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], |
| 1829 | 1551 | |
| 1830 | − "esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="], | |
| 1552 | + "es-toolkit": ["es-toolkit@1.45.1", "", {}, "sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw=="], | |
| 1553 | + | |
| 1554 | + "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], | |
| 1831 | 1555 | |
| 1832 | 1556 | "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], |
| 1833 | 1557 | |
| @@ -1843,19 +1567,21 @@ · 9 unmodified lines | ||
| 1843 | 1567 | |
| 1844 | 1568 | "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], |
| 1845 | 1569 | |
| 1570 | + "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="], | |
| 1571 | + | |
| 1846 | 1572 | "eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="], |
| 1847 | 1573 | |
| 1848 | 1574 | "eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="], |
| 1849 | 1575 | |
| 1850 | − "execa": ["execa@9.6.1", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.6", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.2.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.1.1" } }, "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA=="], | |
| 1576 | + "executor": ["executor@workspace:apps/cli"], | |
| 1851 | 1577 | |
| 1852 | − "executor": ["executor@workspace:apps/executor"], | |
| 1578 | + "expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="], | |
| 1853 | 1579 | |
| 1854 | 1580 | "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="], |
| 1855 | 1581 | |
| 1856 | 1582 | "express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], |
| 1857 | 1583 | |
| 1858 | − "express-rate-limit": ["express-rate-limit@8.2.1", "", { "dependencies": { "ip-address": "10.0.1" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g=="], | |
| 1584 | + "express-rate-limit": ["express-rate-limit@8.3.2", "", { "dependencies": { "ip-address": "10.1.0" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg=="], | |
| 1859 | 1585 | |
| 1860 | 1586 | "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], |
| 1861 | 1587 | |
| @@ -1871,13 +1597,9 @@ · 9 unmodified lines | ||
| 1871 | 1597 | |
| 1872 | 1598 | "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], |
| 1873 | 1599 | |
| 1874 | − "fd-package-json": ["fd-package-json@2.0.0", "", { "dependencies": { "walk-up-path": "^4.0.0" } }, "sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ=="], | |
| 1875 | − | |
| 1876 | 1600 | "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], |
| 1877 | 1601 | |
| 1878 | − "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="], | |
| 1879 | − | |
| 1880 | − "figures": ["figures@6.1.0", "", { "dependencies": { "is-unicode-supported": "^2.0.0" } }, "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg=="], | |
| 1602 | + "file-uri-to-path": ["file-uri-to-path@1.0.0", "", {}, "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="], | |
| 1881 | 1603 | |
| 1882 | 1604 | "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], |
| 1883 | 1605 | |
| @@ -1887,37 +1609,27 @@ · 3 unmodified lines | ||
| 1887 | 1609 | |
| 1888 | 1610 | "find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], |
| 1889 | 1611 | |
| 1890 | − "formatly": ["formatly@0.3.0", "", { "dependencies": { "fd-package-json": "^2.0.0" }, "bin": { "formatly": "bin/index.mjs" } }, "sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w=="], | |
| 1891 | − | |
| 1892 | − "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="], | |
| 1893 | − | |
| 1894 | 1612 | "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], |
| 1895 | 1613 | |
| 1896 | 1614 | "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], |
| 1897 | 1615 | |
| 1616 | + "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], | |
| 1617 | + | |
| 1898 | 1618 | "fs-extra": ["fs-extra@7.0.1", "", { "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw=="], |
| 1899 | 1619 | |
| 1900 | 1620 | "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], |
| 1901 | 1621 | |
| 1902 | 1622 | "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], |
| 1903 | 1623 | |
| 1904 | − "fuzzysort": ["fuzzysort@3.1.0", "", {}, "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ=="], | |
| 1905 | − | |
| 1906 | 1624 | "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], |
| 1907 | 1625 | |
| 1908 | − "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], | |
| 1909 | − | |
| 1910 | − "get-east-asian-width": ["get-east-asian-width@1.5.0", "", {}, "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA=="], | |
| 1911 | − | |
| 1912 | 1626 | "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], |
| 1913 | 1627 | |
| 1914 | 1628 | "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], |
| 1915 | 1629 | |
| 1916 | − "get-own-enumerable-keys": ["get-own-enumerable-keys@1.0.0", "", {}, "sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA=="], | |
| 1917 | − | |
| 1918 | 1630 | "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], |
| 1919 | 1631 | |
| 1920 | − "get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="], | |
| 1632 | + "github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="], | |
| 1921 | 1633 | |
| 1922 | 1634 | "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], |
| 1923 | 1635 | |
| @@ -1927,7 +1639,7 @@ · 3 unmodified lines | ||
| 1927 | 1639 | |
| 1928 | 1640 | "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], |
| 1929 | 1641 | |
| 1930 | − "graphql": ["graphql@16.13.1", "", {}, "sha512-gGgrVCoDKlIZ8fIqXBBb0pPKqDgki0Z/FSKNiQzSGj2uEYHr1tq5wmBegGwJx6QB5S5cM0khSBpi/JFHMCvsmQ=="], | |
| 1642 | + "hachure-fill": ["hachure-fill@0.5.2", "", {}, "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg=="], | |
| 1931 | 1643 | |
| 1932 | 1644 | "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], |
| 1933 | 1645 | |
| @@ -1951,11 +1663,7 @@ · 17 unmodified lines | ||
| 1951 | 1663 | |
| 1952 | 1664 | "hastscript": ["hastscript@9.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-parse-selector": "^4.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0" } }, "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w=="], |
| 1953 | 1665 | |
| 1954 | − "headers-polyfill": ["headers-polyfill@4.0.3", "", {}, "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ=="], | |
| 1955 | − | |
| 1956 | − "hono": ["hono@4.12.5", "", {}, "sha512-3qq+FUBtlTHhtYxbxheZgY8NIFnkkC/MR8u5TTsr7YZ3wixryQ3cCwn3iZbg8p8B88iDBBAYSfZDS75t8MN7Vg=="], | |
| 1957 | − | |
| 1958 | − "html-encoding-sniffer": ["html-encoding-sniffer@4.0.0", "", { "dependencies": { "whatwg-encoding": "^3.1.1" } }, "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ=="], | |
| 1666 | + "hono": ["hono@4.12.9", "", {}, "sha512-wy3T8Zm2bsEvxKZM5w21VdHDDcwVS1yUFFY6i8UobSsKfFceT7TOwhbhfKsDyx7tYQlmRM5FLpIuYvNFyjctiA=="], | |
| 1959 | 1667 | |
| 1960 | 1668 | "html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="], |
| 1961 | 1669 | |
| @@ -1963,19 +1671,15 @@ · 1 unmodified line | ||
| 1963 | 1671 | |
| 1964 | 1672 | "http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], |
| 1965 | 1673 | |
| 1966 | − "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], | |
| 1967 | − | |
| 1968 | − "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], | |
| 1969 | − | |
| 1970 | 1674 | "human-id": ["human-id@4.1.3", "", { "bin": { "human-id": "dist/cli.js" } }, "sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q=="], |
| 1971 | 1675 | |
| 1972 | − "human-signals": ["human-signals@8.0.1", "", {}, "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ=="], | |
| 1973 | − | |
| 1974 | 1676 | "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], |
| 1975 | 1677 | |
| 1976 | − "ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], | |
| 1678 | + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], | |
| 1977 | 1679 | |
| 1978 | − "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], | |
| 1680 | + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], | |
| 1681 | + | |
| 1682 | + "immer": ["immer@10.2.0", "", {}, "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw=="], | |
| 1979 | 1683 | |
| 1980 | 1684 | "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], |
| 1981 | 1685 | |
| @@ -1983,7 +1687,11 @@ · 1 unmodified line | ||
| 1983 | 1687 | |
| 1984 | 1688 | "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="], |
| 1985 | 1689 | |
| 1986 | − "ip-address": ["ip-address@10.0.1", "", {}, "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA=="], | |
| 1690 | + "input-otp": ["input-otp@1.4.2", "", { "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA=="], | |
| 1691 | + | |
| 1692 | + "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], | |
| 1693 | + | |
| 1694 | + "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="], | |
| 1987 | 1695 | |
| 1988 | 1696 | "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], |
| 1989 | 1697 | |
| @@ -1991,70 +1699,38 @@ · 1 unmodified line | ||
| 1991 | 1699 | |
| 1992 | 1700 | "is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="], |
| 1993 | 1701 | |
| 1994 | − "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], | |
| 1995 | − | |
| 1996 | 1702 | "is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="], |
| 1997 | 1703 | |
| 1998 | − "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], | |
| 1999 | − | |
| 2000 | 1704 | "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], |
| 2001 | 1705 | |
| 2002 | − "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], | |
| 2003 | − | |
| 2004 | 1706 | "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], |
| 2005 | 1707 | |
| 2006 | 1708 | "is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="], |
| 2007 | 1709 | |
| 2008 | − "is-in-ssh": ["is-in-ssh@1.0.0", "", {}, "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw=="], | |
| 2009 | − | |
| 2010 | − "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], | |
| 2011 | − | |
| 2012 | − "is-interactive": ["is-interactive@2.0.0", "", {}, "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ=="], | |
| 2013 | − | |
| 2014 | − "is-node-process": ["is-node-process@1.2.0", "", {}, "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw=="], | |
| 2015 | − | |
| 2016 | 1710 | "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], |
| 2017 | 1711 | |
| 2018 | − "is-obj": ["is-obj@3.0.0", "", {}, "sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ=="], | |
| 2019 | − | |
| 2020 | 1712 | "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], |
| 2021 | 1713 | |
| 2022 | − "is-potential-custom-element-name": ["is-potential-custom-element-name@1.0.1", "", {}, "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="], | |
| 2023 | − | |
| 2024 | 1714 | "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], |
| 2025 | 1715 | |
| 2026 | − "is-regexp": ["is-regexp@3.1.0", "", {}, "sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA=="], | |
| 2027 | − | |
| 2028 | − "is-stream": ["is-stream@4.0.1", "", {}, "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A=="], | |
| 2029 | − | |
| 2030 | 1716 | "is-subdir": ["is-subdir@1.2.0", "", { "dependencies": { "better-path-resolve": "1.0.0" } }, "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw=="], |
| 2031 | 1717 | |
| 2032 | − "is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="], | |
| 2033 | − | |
| 2034 | 1718 | "is-windows": ["is-windows@1.0.2", "", {}, "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="], |
| 2035 | 1719 | |
| 2036 | − "is-wsl": ["is-wsl@3.1.1", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="], | |
| 2037 | − | |
| 2038 | − "isbot": ["isbot@5.1.35", "", {}, "sha512-waFfC72ZNfwLLuJ2iLaoVaqcNo+CAaLR7xCpAn0Y5WfGzkNHv7ZN39Vbi1y+kb+Zs46XHOX3tZNExroFUPX+Kg=="], | |
| 1720 | + "isbot": ["isbot@5.1.37", "", {}, "sha512-5bcicX81xf6NlTEV8rWdg7Pk01LFizDetuYGHx6d/f6y3lR2/oo8IfxjzJqn1UdDEyCcwT9e7NRloj8DwCYujQ=="], | |
| 2039 | 1721 | |
| 2040 | 1722 | "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], |
| 2041 | 1723 | |
| 2042 | 1724 | "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], |
| 2043 | 1725 | |
| 2044 | − "jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="], | |
| 1726 | + "jose": ["jose@6.2.2", "", {}, "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ=="], | |
| 2045 | 1727 | |
| 2046 | 1728 | "js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], |
| 2047 | 1729 | |
| 2048 | 1730 | "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], |
| 2049 | 1731 | |
| 2050 | − "jsdom": ["jsdom@26.1.0", "", { "dependencies": { "cssstyle": "^4.2.1", "data-urls": "^5.0.0", "decimal.js": "^10.5.0", "html-encoding-sniffer": "^4.0.0", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.6", "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.16", "parse5": "^7.2.1", "rrweb-cssom": "^0.8.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^5.1.1", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^7.0.0", "whatwg-encoding": "^3.1.1", "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.1.1", "ws": "^8.18.0", "xml-name-validator": "^5.0.0" }, "peerDependencies": { "canvas": "^3.0.0" }, "optionalPeers": ["canvas"] }, "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg=="], | |
| 2051 | − | |
| 2052 | 1732 | "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], |
| 2053 | 1733 | |
| 2054 | − "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="], | |
| 2055 | − | |
| 2056 | − "json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="], | |
| 2057 | − | |
| 2058 | 1734 | "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], |
| 2059 | 1735 | |
| 2060 | 1736 | "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="], |
| @@ -2065,53 +1741,53 @@ · 4 unmodified lines | ||
| 2065 | 1741 | |
| 2066 | 1742 | "jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], |
| 2067 | 1743 | |
| 2068 | − "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], | |
| 1744 | + "katex": ["katex@0.16.44", "", { "dependencies": { "commander": "^8.3.0" }, "bin": { "katex": "cli.js" } }, "sha512-EkxoDTk8ufHqHlf9QxGwcxeLkWRR3iOuYfRpfORgYfqc8s13bgb+YtRY59NK5ZpRaCwq1kqA6a5lpX8C/eLphQ=="], | |
| 2069 | 1745 | |
| 2070 | − "knip": ["knip@5.85.0", "", { "dependencies": { "@nodelib/fs.walk": "^1.2.3", "fast-glob": "^3.3.3", "formatly": "^0.3.0", "jiti": "^2.6.0", "js-yaml": "^4.1.1", "minimist": "^1.2.8", "oxc-resolver": "^11.15.0", "picocolors": "^1.1.1", "picomatch": "^4.0.1", "smol-toml": "^1.5.2", "strip-json-comments": "5.0.3", "zod": "^4.1.11" }, "peerDependencies": { "@types/node": ">=18", "typescript": ">=5.0.4 <7" }, "bin": { "knip": "bin/knip.js", "knip-bun": "bin/knip-bun.js" } }, "sha512-V2kyON+DZiYdNNdY6GALseiNCwX7dYdpz9Pv85AUn69Gk0UKCts+glOKWfe5KmaMByRjM9q17Mzj/KinTVOyxg=="], | |
| 1746 | + "khroma": ["khroma@2.1.0", "", {}, "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw=="], | |
| 2071 | 1747 | |
| 2072 | 1748 | "kubernetes-types": ["kubernetes-types@1.30.0", "", {}, "sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q=="], |
| 2073 | 1749 | |
| 2074 | − "lightningcss": ["lightningcss@1.31.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.31.1", "lightningcss-darwin-arm64": "1.31.1", "lightningcss-darwin-x64": "1.31.1", "lightningcss-freebsd-x64": "1.31.1", "lightningcss-linux-arm-gnueabihf": "1.31.1", "lightningcss-linux-arm64-gnu": "1.31.1", "lightningcss-linux-arm64-musl": "1.31.1", "lightningcss-linux-x64-gnu": "1.31.1", "lightningcss-linux-x64-musl": "1.31.1", "lightningcss-win32-arm64-msvc": "1.31.1", "lightningcss-win32-x64-msvc": "1.31.1" } }, "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ=="], | |
| 1750 | + "langium": ["langium@4.2.1", "", { "dependencies": { "chevrotain": "~11.1.1", "chevrotain-allstar": "~0.3.1", "vscode-languageserver": "~9.0.1", "vscode-languageserver-textdocument": "~1.0.11", "vscode-uri": "~3.1.0" } }, "sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ=="], | |
| 1751 | + | |
| 1752 | + "layout-base": ["layout-base@1.0.2", "", {}, "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg=="], | |
| 2075 | 1753 | |
| 2076 | − "lightningcss-android-arm64": ["lightningcss-android-arm64@1.31.1", "", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="], | |
| 1754 | + "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "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" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], | |
| 2077 | 1755 | |
| 2078 | − "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.31.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg=="], | |
| 1756 | + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], | |
| 2079 | 1757 | |
| 2080 | − "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.31.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA=="], | |
| 1758 | + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="], | |
| 2081 | 1759 | |
| 2082 | − "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.31.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A=="], | |
| 1760 | + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="], | |
| 2083 | 1761 | |
| 2084 | − "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.31.1", "", { "os": "linux", "cpu": "arm" }, "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g=="], | |
| 1762 | + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="], | |
| 2085 | 1763 | |
| 2086 | − "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg=="], | |
| 1764 | + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="], | |
| 2087 | 1765 | |
| 2088 | − "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg=="], | |
| 1766 | + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="], | |
| 2089 | 1767 | |
| 2090 | − "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA=="], | |
| 1768 | + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="], | |
| 2091 | 1769 | |
| 2092 | − "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA=="], | |
| 1770 | + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="], | |
| 2093 | 1771 | |
| 2094 | − "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.31.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w=="], | |
| 1772 | + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="], | |
| 2095 | 1773 | |
| 2096 | − "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="], | |
| 1774 | + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="], | |
| 2097 | 1775 | |
| 2098 | − "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], | |
| 1776 | + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], | |
| 2099 | 1777 | |
| 2100 | 1778 | "locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], |
| 2101 | 1779 | |
| 2102 | − "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="], | |
| 1780 | + "lodash-es": ["lodash-es@4.17.23", "", {}, "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg=="], | |
| 2103 | 1781 | |
| 2104 | 1782 | "lodash.startcase": ["lodash.startcase@4.4.0", "", {}, "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg=="], |
| 2105 | 1783 | |
| 2106 | − "log-symbols": ["log-symbols@6.0.0", "", { "dependencies": { "chalk": "^5.3.0", "is-unicode-supported": "^1.3.0" } }, "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw=="], | |
| 2107 | − | |
| 2108 | − "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], | |
| 2109 | − | |
| 2110 | 1784 | "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], |
| 2111 | 1785 | |
| 1786 | + "lookpath": ["lookpath@1.2.3", "", { "bin": { "lookpath": "bin/lookpath.js" } }, "sha512-kthRVhf4kH4+HW3anM4UBHxsw/XFESf13euCEldhXr6GpBdmBoa7rDd7WO5G0Mhd4G5XtKTcEy8OR0iRZXpS3Q=="], | |
| 1787 | + | |
| 2112 | 1788 | "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="], |
| 2113 | 1789 | |
| 2114 | − "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], | |
| 1790 | + "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], | |
| 2115 | 1791 | |
| 2116 | 1792 | "lucide-react": ["lucide-react@1.7.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-yI7BeItCLZJTXikmK4KNUGCKoGzSvbKlfCvw44bU4fXAL6v3gYS4uHD1jzsLkfwODYwI6Drw5Tu9Z5ulDe0TSg=="], |
| 2117 | 1793 | |
| @@ -2119,7 +1795,7 @@ · 1 unmodified line | ||
| 2119 | 1795 | |
| 2120 | 1796 | "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], |
| 2121 | 1797 | |
| 2122 | − "marked": ["marked@17.0.4", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-NOmVMM+KAokHMvjWmC5N/ZOvgmSWuqJB8FoYI019j4ogb/PeRMKoKIjReZ2w3376kkA8dSJIP8uD993Kxc0iRQ=="], | |
| 1798 | + "marked": ["marked@17.0.5", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-6hLvc0/JEbRjRgzI6wnT2P1XuM1/RrrDEX0kPt0N7jGm1133g6X7DlxFasUIx+72aKAr904GTxhSLDrd5DIlZg=="], | |
| 2123 | 1799 | |
| 2124 | 1800 | "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], |
| 2125 | 1801 | |
| @@ -2157,10 +1833,10 @@ · 31 unmodified lines | ||
| 2157 | 1833 | |
| 2158 | 1834 | "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], |
| 2159 | 1835 | |
| 2160 | − "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], | |
| 2161 | − | |
| 2162 | 1836 | "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], |
| 2163 | 1837 | |
| 1838 | + "mermaid": ["mermaid@11.14.0", "", { "dependencies": { "@braintree/sanitize-url": "^7.1.1", "@iconify/utils": "^3.0.2", "@mermaid-js/parser": "^1.1.0", "@types/d3": "^7.4.3", "@upsetjs/venn.js": "^2.0.0", "cytoscape": "^3.33.1", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", "d3": "^7.9.0", "d3-sankey": "^0.12.3", "dagre-d3-es": "7.0.14", "dayjs": "^1.11.19", "dompurify": "^3.3.1", "katex": "^0.16.25", "khroma": "^2.1.0", "lodash-es": "^4.17.23", "marked": "^16.3.0", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", "uuid": "^11.1.0" } }, "sha512-GSGloRsBs+JINmmhl0JDwjpuezCsHB4WGI4NASHxL3fHo3o/BRXTxhDLKnln8/Q0lRFRyDdEjmk1/d5Sn1Xz8g=="], | |
| 1839 | + | |
| 2164 | 1840 | "micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="], |
| 2165 | 1841 | |
| 2166 | 1842 | "micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="], |
| @@ -2225,73 +1901,57 @@ · 58 unmodified lines | ||
| 2225 | 1901 | |
| 2226 | 1902 | "mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], |
| 2227 | 1903 | |
| 2228 | − "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], | |
| 1904 | + "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], | |
| 2229 | 1905 | |
| 2230 | − "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="], | |
| 1906 | + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], | |
| 2231 | 1907 | |
| 2232 | − "minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], | |
| 1908 | + "mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="], | |
| 2233 | 1909 | |
| 2234 | − "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], | |
| 1910 | + "mlly": ["mlly@1.8.2", "", { "dependencies": { "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.3" } }, "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA=="], | |
| 2235 | 1911 | |
| 2236 | 1912 | "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], |
| 2237 | 1913 | |
| 2238 | 1914 | "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], |
| 2239 | 1915 | |
| 2240 | − "msgpackr": ["msgpackr@1.11.8", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "sha512-bC4UGzHhVvgDNS7kn9tV8fAucIYUBuGojcaLiz7v+P63Lmtm0Xeji8B/8tYKddALXxJLpwIeBmUN3u64C4YkRA=="], | |
| 1916 | + "msgpackr": ["msgpackr@1.11.9", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "sha512-FkoAAyyA6HM8wL882EcEyFZ9s7hVADSwG9xrVx3dxxNQAtgADTrJoEWivID82Iv1zWDsv/OtbrrcZAzGzOMdNw=="], | |
| 2241 | 1917 | |
| 2242 | 1918 | "msgpackr-extract": ["msgpackr-extract@3.0.3", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA=="], |
| 2243 | 1919 | |
| 2244 | − "msw": ["msw@2.12.14", "", { "dependencies": { "@inquirer/confirm": "^5.0.0", "@mswjs/interceptors": "^0.41.2", "@open-draft/deferred-promise": "^2.2.0", "@types/statuses": "^2.0.6", "cookie": "^1.0.2", "graphql": "^16.12.0", "headers-polyfill": "^4.0.2", "is-node-process": "^1.2.0", "outvariant": "^1.4.3", "path-to-regexp": "^6.3.0", "picocolors": "^1.1.1", "rettime": "^0.10.1", "statuses": "^2.0.2", "strict-event-emitter": "^0.5.1", "tough-cookie": "^6.0.0", "type-fest": "^5.2.0", "until-async": "^3.0.2", "yargs": "^17.7.2" }, "peerDependencies": { "typescript": ">= 4.8.x" }, "optionalPeers": ["typescript"], "bin": { "msw": "cli/index.js" } }, "sha512-4KXa4nVBIBjbDbd7vfQNuQ25eFxug0aropCQFoI0JdOBuJWamkT1yLVIWReFI8SiTRc+H1hKzaNk+cLk2N9rtQ=="], | |
| 2245 | − | |
| 2246 | 1920 | "multipasta": ["multipasta@0.2.7", "", {}, "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA=="], |
| 2247 | 1921 | |
| 2248 | − "mute-stream": ["mute-stream@2.0.0", "", {}, "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA=="], | |
| 2249 | − | |
| 2250 | 1922 | "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], |
| 2251 | 1923 | |
| 1924 | + "napi-build-utils": ["napi-build-utils@2.0.0", "", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="], | |
| 1925 | + | |
| 2252 | 1926 | "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], |
| 2253 | 1927 | |
| 2254 | − "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], | |
| 1928 | + "next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="], | |
| 2255 | 1929 | |
| 2256 | − "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], | |
| 1930 | + "node-abi": ["node-abi@3.89.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA=="], | |
| 2257 | 1931 | |
| 2258 | − "node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], | |
| 1932 | + "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], | |
| 2259 | 1933 | |
| 2260 | 1934 | "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="], |
| 2261 | 1935 | |
| 2262 | 1936 | "node-releases": ["node-releases@2.0.36", "", {}, "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA=="], |
| 2263 | 1937 | |
| 2264 | − "npm-run-path": ["npm-run-path@6.0.0", "", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="], | |
| 2265 | − | |
| 2266 | − "nwsapi": ["nwsapi@2.2.23", "", {}, "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ=="], | |
| 2267 | − | |
| 2268 | 1938 | "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], |
| 2269 | 1939 | |
| 2270 | 1940 | "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], |
| 2271 | 1941 | |
| 2272 | − "object-treeify": ["object-treeify@1.1.33", "", {}, "sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A=="], | |
| 2273 | − | |
| 2274 | 1942 | "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], |
| 2275 | 1943 | |
| 2276 | 1944 | "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], |
| 2277 | 1945 | |
| 2278 | − "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], | |
| 2279 | − | |
| 2280 | 1946 | "oniguruma-parser": ["oniguruma-parser@0.12.1", "", {}, "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w=="], |
| 2281 | 1947 | |
| 2282 | − "oniguruma-to-es": ["oniguruma-to-es@4.3.4", "", { "dependencies": { "oniguruma-parser": "^0.12.1", "regex": "^6.0.1", "regex-recursion": "^6.0.2" } }, "sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA=="], | |
| 1948 | + "oniguruma-to-es": ["oniguruma-to-es@4.3.5", "", { "dependencies": { "oniguruma-parser": "^0.12.1", "regex": "^6.1.0", "regex-recursion": "^6.0.2" } }, "sha512-Zjygswjpsewa0NLTsiizVuMQZbp0MDyM6lIt66OxsF21npUDlzpHi1Mgb/qhQdkb+dWFTzJmFbEWdvZgRho8eQ=="], | |
| 2283 | 1949 | |
| 2284 | − "open": ["open@11.0.0", "", { "dependencies": { "default-browser": "^5.4.0", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", "powershell-utils": "^0.1.0", "wsl-utils": "^0.3.0" } }, "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw=="], | |
| 2285 | − | |
| 2286 | − "ora": ["ora@8.2.0", "", { "dependencies": { "chalk": "^5.3.0", "cli-cursor": "^5.0.0", "cli-spinners": "^2.9.2", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.0.0", "log-symbols": "^6.0.0", "stdin-discarder": "^0.2.2", "string-width": "^7.2.0", "strip-ansi": "^7.1.0" } }, "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw=="], | |
| 1950 | + "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], | |
| 2287 | 1951 | |
| 2288 | 1952 | "outdent": ["outdent@0.5.0", "", {}, "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q=="], |
| 2289 | 1953 | |
| 2290 | − "outvariant": ["outvariant@1.4.3", "", {}, "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA=="], | |
| 2291 | − | |
| 2292 | − "oxc-resolver": ["oxc-resolver@11.19.1", "", { "optionalDependencies": { "@oxc-resolver/binding-android-arm-eabi": "11.19.1", "@oxc-resolver/binding-android-arm64": "11.19.1", "@oxc-resolver/binding-darwin-arm64": "11.19.1", "@oxc-resolver/binding-darwin-x64": "11.19.1", "@oxc-resolver/binding-freebsd-x64": "11.19.1", "@oxc-resolver/binding-linux-arm-gnueabihf": "11.19.1", "@oxc-resolver/binding-linux-arm-musleabihf": "11.19.1", "@oxc-resolver/binding-linux-arm64-gnu": "11.19.1", "@oxc-resolver/binding-linux-arm64-musl": "11.19.1", "@oxc-resolver/binding-linux-ppc64-gnu": "11.19.1", "@oxc-resolver/binding-linux-riscv64-gnu": "11.19.1", "@oxc-resolver/binding-linux-riscv64-musl": "11.19.1", "@oxc-resolver/binding-linux-s390x-gnu": "11.19.1", "@oxc-resolver/binding-linux-x64-gnu": "11.19.1", "@oxc-resolver/binding-linux-x64-musl": "11.19.1", "@oxc-resolver/binding-openharmony-arm64": "11.19.1", "@oxc-resolver/binding-wasm32-wasi": "11.19.1", "@oxc-resolver/binding-win32-arm64-msvc": "11.19.1", "@oxc-resolver/binding-win32-ia32-msvc": "11.19.1", "@oxc-resolver/binding-win32-x64-msvc": "11.19.1" } }, "sha512-qE/CIg/spwrTBFt5aKmwe3ifeDdLfA2NESN30E42X/lII5ClF8V7Wt6WIJhcGZjp0/Q+nQ+9vgxGk//xZNX2hg=="], | |
| 2293 | − | |
| 2294 | − "oxlint": ["oxlint@1.56.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.56.0", "@oxlint/binding-android-arm64": "1.56.0", "@oxlint/binding-darwin-arm64": "1.56.0", "@oxlint/binding-darwin-x64": "1.56.0", "@oxlint/binding-freebsd-x64": "1.56.0", "@oxlint/binding-linux-arm-gnueabihf": "1.56.0", "@oxlint/binding-linux-arm-musleabihf": "1.56.0", "@oxlint/binding-linux-arm64-gnu": "1.56.0", "@oxlint/binding-linux-arm64-musl": "1.56.0", "@oxlint/binding-linux-ppc64-gnu": "1.56.0", "@oxlint/binding-linux-riscv64-gnu": "1.56.0", "@oxlint/binding-linux-riscv64-musl": "1.56.0", "@oxlint/binding-linux-s390x-gnu": "1.56.0", "@oxlint/binding-linux-x64-gnu": "1.56.0", "@oxlint/binding-linux-x64-musl": "1.56.0", "@oxlint/binding-openharmony-arm64": "1.56.0", "@oxlint/binding-win32-arm64-msvc": "1.56.0", "@oxlint/binding-win32-ia32-msvc": "1.56.0", "@oxlint/binding-win32-x64-msvc": "1.56.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.15.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-Q+5Mj5PVaH/R6/fhMMFzw4dT+KPB+kQW4kaL8FOIq7tfhlnEVp6+3lcWqFruuTNlUo9srZUW3qH7Id4pskeR6g=="], | |
| 1954 | + "oxlint": ["oxlint@1.58.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.58.0", "@oxlint/binding-android-arm64": "1.58.0", "@oxlint/binding-darwin-arm64": "1.58.0", "@oxlint/binding-darwin-x64": "1.58.0", "@oxlint/binding-freebsd-x64": "1.58.0", "@oxlint/binding-linux-arm-gnueabihf": "1.58.0", "@oxlint/binding-linux-arm-musleabihf": "1.58.0", "@oxlint/binding-linux-arm64-gnu": "1.58.0", "@oxlint/binding-linux-arm64-musl": "1.58.0", "@oxlint/binding-linux-ppc64-gnu": "1.58.0", "@oxlint/binding-linux-riscv64-gnu": "1.58.0", "@oxlint/binding-linux-riscv64-musl": "1.58.0", "@oxlint/binding-linux-s390x-gnu": "1.58.0", "@oxlint/binding-linux-x64-gnu": "1.58.0", "@oxlint/binding-linux-x64-musl": "1.58.0", "@oxlint/binding-openharmony-arm64": "1.58.0", "@oxlint/binding-win32-arm64-msvc": "1.58.0", "@oxlint/binding-win32-ia32-msvc": "1.58.0", "@oxlint/binding-win32-x64-msvc": "1.58.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.18.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-t4s9leczDMqlvOSjnbCQe7gtoLkWgBGZ7sBdCJ9EOj5IXFSG/X7OAzK4yuH4iW+4cAYe8kLFbC8tuYMwWZm+Cg=="], | |
| 2295 | 1955 | |
| 2296 | 1956 | "p-filter": ["p-filter@2.1.0", "", { "dependencies": { "p-map": "^2.0.0" } }, "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw=="], |
| 2297 | 1957 | |
| @@ -2305,25 +1965,19 @@ · 7 unmodified lines | ||
| 2305 | 1965 | |
| 2306 | 1966 | "package-manager-detector": ["package-manager-detector@0.2.11", "", { "dependencies": { "quansync": "^0.2.7" } }, "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ=="], |
| 2307 | 1967 | |
| 2308 | − "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], | |
| 2309 | − | |
| 2310 | 1968 | "parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="], |
| 2311 | 1969 | |
| 2312 | − "parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="], | |
| 2313 | − | |
| 2314 | − "parse-ms": ["parse-ms@4.0.0", "", {}, "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw=="], | |
| 2315 | − | |
| 2316 | 1970 | "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], |
| 2317 | 1971 | |
| 2318 | 1972 | "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], |
| 2319 | 1973 | |
| 2320 | − "path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="], | |
| 1974 | + "path-data-parser": ["path-data-parser@0.1.0", "", {}, "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w=="], | |
| 2321 | 1975 | |
| 2322 | 1976 | "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], |
| 2323 | 1977 | |
| 2324 | 1978 | "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], |
| 2325 | 1979 | |
| 2326 | − "path-to-regexp": ["path-to-regexp@6.3.0", "", {}, "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="], | |
| 1980 | + "path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="], | |
| 2327 | 1981 | |
| 2328 | 1982 | "path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="], |
| 2329 | 1983 | |
| @@ -2333,31 +1987,29 @@ · 3 unmodified lines | ||
| 2333 | 1987 | |
| 2334 | 1988 | "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], |
| 2335 | 1989 | |
| 2336 | − "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], | |
| 1990 | + "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], | |
| 2337 | 1991 | |
| 2338 | 1992 | "pify": ["pify@4.0.1", "", {}, "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="], |
| 2339 | 1993 | |
| 2340 | 1994 | "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], |
| 2341 | 1995 | |
| 2342 | − "postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="], | |
| 1996 | + "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], | |
| 2343 | 1997 | |
| 2344 | − "postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="], | |
| 1998 | + "points-on-curve": ["points-on-curve@0.2.0", "", {}, "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A=="], | |
| 2345 | 1999 | |
| 2346 | − "powershell-utils": ["powershell-utils@0.1.0", "", {}, "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A=="], | |
| 2000 | + "points-on-path": ["points-on-path@0.2.1", "", { "dependencies": { "path-data-parser": "0.1.0", "points-on-curve": "0.2.0" } }, "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g=="], | |
| 2347 | 2001 | |
| 2348 | − "prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="], | |
| 2002 | + "postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="], | |
| 2349 | 2003 | |
| 2350 | − "pretty-ms": ["pretty-ms@9.3.0", "", { "dependencies": { "parse-ms": "^4.0.0" } }, "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ=="], | |
| 2004 | + "prebuild-install": ["prebuild-install@7.1.3", "", { "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^2.0.0", "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^4.0.0", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug=="], | |
| 2351 | 2005 | |
| 2352 | − "prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="], | |
| 2006 | + "prettier": ["prettier@2.8.8", "", { "bin": { "prettier": "bin-prettier.js" } }, "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q=="], | |
| 2353 | 2007 | |
| 2354 | 2008 | "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], |
| 2355 | 2009 | |
| 2356 | − "protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg=="], | |
| 2357 | − | |
| 2358 | 2010 | "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], |
| 2359 | 2011 | |
| 2360 | − "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], | |
| 2012 | + "pump": ["pump@3.0.4", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA=="], | |
| 2361 | 2013 | |
| 2362 | 2014 | "pure-rand": ["pure-rand@6.1.0", "", {}, "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA=="], |
| 2363 | 2015 | |
| @@ -2371,27 +2023,45 @@ · 7 unmodified lines | ||
| 2371 | 2023 | |
| 2372 | 2024 | "quickjs-emscripten-core": ["quickjs-emscripten-core@0.31.0", "", { "dependencies": { "@jitl/quickjs-ffi-types": "0.31.0" } }, "sha512-oQz8p0SiKDBc1TC7ZBK2fr0GoSHZKA0jZIeXxsnCyCs4y32FStzCW4d1h6E1sE0uHDMbGITbk2zhNaytaoJwXQ=="], |
| 2373 | 2025 | |
| 2026 | + "radix-ui": ["radix-ui@1.4.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-accessible-icon": "1.1.7", "@radix-ui/react-accordion": "1.2.12", "@radix-ui/react-alert-dialog": "1.1.15", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-aspect-ratio": "1.1.7", "@radix-ui/react-avatar": "1.1.10", "@radix-ui/react-checkbox": "1.3.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-context-menu": "2.2.16", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-dropdown-menu": "2.1.16", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-form": "0.1.8", "@radix-ui/react-hover-card": "1.1.15", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-menubar": "1.1.16", "@radix-ui/react-navigation-menu": "1.2.14", "@radix-ui/react-one-time-password-field": "0.1.8", "@radix-ui/react-password-toggle-field": "0.1.3", "@radix-ui/react-popover": "1.1.15", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-progress": "1.1.7", "@radix-ui/react-radio-group": "1.3.8", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-scroll-area": "1.2.10", "@radix-ui/react-select": "2.2.6", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-slider": "1.3.6", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-switch": "1.2.6", "@radix-ui/react-tabs": "1.1.13", "@radix-ui/react-toast": "1.2.15", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-toggle-group": "1.1.11", "@radix-ui/react-toolbar": "1.1.11", "@radix-ui/react-tooltip": "1.2.8", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-escape-keydown": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA=="], | |
| 2027 | + | |
| 2374 | 2028 | "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], |
| 2375 | 2029 | |
| 2376 | 2030 | "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], |
| 2377 | 2031 | |
| 2032 | + "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], | |
| 2033 | + | |
| 2378 | 2034 | "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], |
| 2379 | 2035 | |
| 2036 | + "react-day-picker": ["react-day-picker@9.14.0", "", { "dependencies": { "@date-fns/tz": "^1.4.1", "@tabby_ai/hijri-converter": "1.0.5", "date-fns": "^4.1.0", "date-fns-jalali": "4.1.0-0" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-tBaoDWjPwe0M5pGrum4H0SR6Lyk+BO9oHnp9JbKpGKW2mlraNPgP9BMfsg5pWpwrssARmeqk7YBl2oXutZTaHA=="], | |
| 2037 | + | |
| 2380 | 2038 | "react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="], |
| 2381 | 2039 | |
| 2382 | − "react-grab": ["react-grab@0.1.26", "", { "dependencies": { "@medv/finder": "^4.0.2", "@react-grab/cli": "0.1.26", "bippy": "^0.5.32", "solid-js": "^1.9.10" }, "peerDependencies": { "react": ">=17.0.0" }, "optionalPeers": ["react"], "bin": { "react-grab": "bin/cli.js" } }, "sha512-ubpS3jvxuO47J3/GGYYXVQ0L/EfIojpLg8a+2Ii+8doGJmnZw0nw2Ez1cGpNaZeSHbmY4+8qADWoIFOMWD008A=="], | |
| 2040 | + "react-hook-form": ["react-hook-form@7.72.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-V4v6jubaf6JAurEaVnT9aUPKFbNtDgohj5CIgVGyPHvT9wRx5OZHVjz31GsxnPNI278XMu+ruFz+wGOscHaLKw=="], | |
| 2041 | + | |
| 2042 | + "react-is": ["react-is@19.2.4", "", {}, "sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA=="], | |
| 2043 | + | |
| 2044 | + "react-redux": ["react-redux@9.2.0", "", { "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "@types/react": "^18.2.25 || ^19", "react": "^18.0 || ^19", "redux": "^5.0.0" }, "optionalPeers": ["@types/react", "redux"] }, "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g=="], | |
| 2383 | 2045 | |
| 2384 | − "react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="], | |
| 2046 | + "react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="], | |
| 2385 | 2047 | |
| 2386 | 2048 | "react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="], |
| 2387 | 2049 | |
| 2388 | 2050 | "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], |
| 2389 | 2051 | |
| 2052 | + "react-resizable-panels": ["react-resizable-panels@4.8.0", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-2uEABkewb3ky/ZgIlAUxWa1W/LjsK494fdV1QsXxst7CDRHCzo7h22tWWu3NNaBjmiuriOCt3CvhipnaYcpoIw=="], | |
| 2053 | + | |
| 2390 | 2054 | "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], |
| 2391 | 2055 | |
| 2392 | 2056 | "read-yaml-file": ["read-yaml-file@1.1.0", "", { "dependencies": { "graceful-fs": "^4.1.5", "js-yaml": "^3.6.1", "pify": "^4.0.1", "strip-bom": "^3.0.0" } }, "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA=="], |
| 2393 | 2057 | |
| 2394 | − "recast": ["recast@0.23.11", "", { "dependencies": { "ast-types": "^0.16.1", "esprima": "~4.0.0", "source-map": "~0.6.1", "tiny-invariant": "^1.3.3", "tslib": "^2.0.1" } }, "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA=="], | |
| 2058 | + "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], | |
| 2059 | + | |
| 2060 | + "recharts": ["recharts@3.8.0", "", { "dependencies": { "@reduxjs/toolkit": "^1.9.0 || 2.x.x", "clsx": "^2.1.1", "decimal.js-light": "^2.5.1", "es-toolkit": "^1.39.3", "eventemitter3": "^5.0.1", "immer": "^10.1.1", "react-redux": "8.x.x || 9.x.x", "reselect": "5.1.1", "tiny-invariant": "^1.3.3", "use-sync-external-store": "^1.2.2", "victory-vendor": "^37.0.2" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Z/m38DX3L73ExO4Tpc9/iZWHmHnlzWG4njQbxsF5aSjwqmHNDDIm0rdEBArkwsBvR8U6EirlEHiQNYWCVh9sGQ=="], | |
| 2061 | + | |
| 2062 | + "redux": ["redux@5.0.1", "", {}, "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="], | |
| 2063 | + | |
| 2064 | + "redux-thunk": ["redux-thunk@3.1.0", "", { "peerDependencies": { "redux": "^5.0.0" } }, "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw=="], | |
| 2395 | 2065 | |
| 2396 | 2066 | "regex": ["regex@6.1.0", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg=="], |
| 2397 | 2067 | |
| @@ -2413,9 +2083,7 @@ · 15 unmodified lines | ||
| 2413 | 2083 | |
| 2414 | 2084 | "remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="], |
| 2415 | 2085 | |
| 2416 | − "remend": ["remend@1.2.2", "", {}, "sha512-4ZJgIB9EG9fQE41mOJCRHMmnxDTKHWawQoJWZyUbZuj680wVyogu2ihnj8Edqm7vh2mo/TWHyEZpn2kqeDvS7w=="], | |
| 2417 | − | |
| 2418 | − "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], | |
| 2086 | + "remend": ["remend@1.3.0", "", {}, "sha512-iIhggPkhW3hFImKtB10w0dz4EZbs28mV/dmbcYVonWEJ6UGHHpP+bFZnTh6GNWJONg5m+U56JrL+8IxZRdgWjw=="], | |
| 2419 | 2087 | |
| 2420 | 2088 | "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], |
| 2421 | 2089 | |
| @@ -2423,49 +2091,43 @@ · 1 unmodified line | ||
| 2423 | 2091 | |
| 2424 | 2092 | "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], |
| 2425 | 2093 | |
| 2426 | − "restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="], | |
| 2094 | + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], | |
| 2427 | 2095 | |
| 2428 | − "rettime": ["rettime@0.10.1", "", {}, "sha512-uyDrIlUEH37cinabq0AX4QbgV4HbFZ/gqoiunWQ1UqBtRvTTytwhNYjE++pO/MjPTZL5KQCf2bEoJ/BJNVQ5Kw=="], | |
| 2096 | + "robust-predicates": ["robust-predicates@3.0.3", "", {}, "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA=="], | |
| 2429 | 2097 | |
| 2430 | − "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], | |
| 2098 | + "rollup": ["rollup@4.60.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.1", "@rollup/rollup-android-arm64": "4.60.1", "@rollup/rollup-darwin-arm64": "4.60.1", "@rollup/rollup-darwin-x64": "4.60.1", "@rollup/rollup-freebsd-arm64": "4.60.1", "@rollup/rollup-freebsd-x64": "4.60.1", "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", "@rollup/rollup-linux-arm-musleabihf": "4.60.1", "@rollup/rollup-linux-arm64-gnu": "4.60.1", "@rollup/rollup-linux-arm64-musl": "4.60.1", "@rollup/rollup-linux-loong64-gnu": "4.60.1", "@rollup/rollup-linux-loong64-musl": "4.60.1", "@rollup/rollup-linux-ppc64-gnu": "4.60.1", "@rollup/rollup-linux-ppc64-musl": "4.60.1", "@rollup/rollup-linux-riscv64-gnu": "4.60.1", "@rollup/rollup-linux-riscv64-musl": "4.60.1", "@rollup/rollup-linux-s390x-gnu": "4.60.1", "@rollup/rollup-linux-x64-gnu": "4.60.1", "@rollup/rollup-linux-x64-musl": "4.60.1", "@rollup/rollup-openbsd-x64": "4.60.1", "@rollup/rollup-openharmony-arm64": "4.60.1", "@rollup/rollup-win32-arm64-msvc": "4.60.1", "@rollup/rollup-win32-ia32-msvc": "4.60.1", "@rollup/rollup-win32-x64-gnu": "4.60.1", "@rollup/rollup-win32-x64-msvc": "4.60.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w=="], | |
| 2431 | 2099 | |
| 2432 | − "rollup": ["rollup@4.59.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.59.0", "@rollup/rollup-android-arm64": "4.59.0", "@rollup/rollup-darwin-arm64": "4.59.0", "@rollup/rollup-darwin-x64": "4.59.0", "@rollup/rollup-freebsd-arm64": "4.59.0", "@rollup/rollup-freebsd-x64": "4.59.0", "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", "@rollup/rollup-linux-arm-musleabihf": "4.59.0", "@rollup/rollup-linux-arm64-gnu": "4.59.0", "@rollup/rollup-linux-arm64-musl": "4.59.0", "@rollup/rollup-linux-loong64-gnu": "4.59.0", "@rollup/rollup-linux-loong64-musl": "4.59.0", "@rollup/rollup-linux-ppc64-gnu": "4.59.0", "@rollup/rollup-linux-ppc64-musl": "4.59.0", "@rollup/rollup-linux-riscv64-gnu": "4.59.0", "@rollup/rollup-linux-riscv64-musl": "4.59.0", "@rollup/rollup-linux-s390x-gnu": "4.59.0", "@rollup/rollup-linux-x64-gnu": "4.59.0", "@rollup/rollup-linux-x64-musl": "4.59.0", "@rollup/rollup-openbsd-x64": "4.59.0", "@rollup/rollup-openharmony-arm64": "4.59.0", "@rollup/rollup-win32-arm64-msvc": "4.59.0", "@rollup/rollup-win32-ia32-msvc": "4.59.0", "@rollup/rollup-win32-x64-gnu": "4.59.0", "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg=="], | |
| 2100 | + "roughjs": ["roughjs@4.6.6", "", { "dependencies": { "hachure-fill": "^0.5.2", "path-data-parser": "^0.1.0", "points-on-curve": "^0.2.0", "points-on-path": "^0.2.1" } }, "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ=="], | |
| 2433 | 2101 | |
| 2434 | 2102 | "router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], |
| 2435 | 2103 | |
| 2436 | − "rrweb-cssom": ["rrweb-cssom@0.8.0", "", {}, "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw=="], | |
| 2104 | + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], | |
| 2437 | 2105 | |
| 2438 | − "run-applescript": ["run-applescript@7.1.0", "", {}, "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q=="], | |
| 2106 | + "rw": ["rw@1.3.3", "", {}, "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="], | |
| 2439 | 2107 | |
| 2440 | − "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], | |
| 2108 | + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], | |
| 2441 | 2109 | |
| 2442 | 2110 | "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], |
| 2443 | 2111 | |
| 2444 | − "saxes": ["saxes@6.0.0", "", { "dependencies": { "xmlchars": "^2.2.0" } }, "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA=="], | |
| 2445 | − | |
| 2446 | 2112 | "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], |
| 2447 | 2113 | |
| 2448 | 2114 | "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], |
| 2449 | 2115 | |
| 2450 | 2116 | "send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], |
| 2451 | 2117 | |
| 2452 | − "seroval": ["seroval@1.5.0", "", {}, "sha512-OE4cvmJ1uSPrKorFIH9/w/Qwuvi/IMcGbv5RKgcJ/zjA/IohDLU6SVaxFN9FwajbP7nsX0dQqMDes1whk3y+yw=="], | |
| 2118 | + "seroval": ["seroval@1.5.1", "", {}, "sha512-OwrZRZAfhHww0WEnKHDY8OM0U/Qs8OTfIDWhUD4BLpNJUfXK4cGmjiagGze086m+mhI+V2nD0gfbHEnJjb9STA=="], | |
| 2453 | 2119 | |
| 2454 | − "seroval-plugins": ["seroval-plugins@1.5.0", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-EAHqADIQondwRZIdeW2I636zgsODzoBDwb3PT/+7TLDWyw1Dy/Xv7iGUIEXXav7usHDE9HVhOU61irI3EnyyHA=="], | |
| 2120 | + "seroval-plugins": ["seroval-plugins@1.5.1", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-4FbuZ/TMl02sqv0RTFexu0SP6V+ywaIe5bAWCCEik0fk17BhALgwvUDVF7e3Uvf9pxmwCEJsRPmlkUE6HdzLAw=="], | |
| 2455 | 2121 | |
| 2456 | 2122 | "serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="], |
| 2457 | 2123 | |
| 2458 | − "ses": ["ses@1.15.0", "", { "dependencies": { "@endo/cache-map": "^1.1.0", "@endo/env-options": "^1.1.11", "@endo/immutable-arraybuffer": "^1.1.2" } }, "sha512-Y7RvgVXhkwQEqVActNn44QBxB2BCUbPfexAaMiUFjbJkDXDnxPisQC5jYQeWOZ3QBOfecnmLfPn0sQKLiYGBAQ=="], | |
| 2459 | − | |
| 2460 | 2124 | "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], |
| 2461 | 2125 | |
| 2462 | − "shadcn": ["shadcn@4.1.1", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/parser": "^7.28.0", "@babel/plugin-transform-typescript": "^7.28.0", "@babel/preset-typescript": "^7.27.1", "@dotenvx/dotenvx": "^1.48.4", "@modelcontextprotocol/sdk": "^1.26.0", "@types/validate-npm-package-name": "^4.0.2", "browserslist": "^4.26.2", "commander": "^14.0.0", "cosmiconfig": "^9.0.0", "dedent": "^1.6.0", "deepmerge": "^4.3.1", "diff": "^8.0.2", "execa": "^9.6.0", "fast-glob": "^3.3.3", "fs-extra": "^11.3.1", "fuzzysort": "^3.1.0", "https-proxy-agent": "^7.0.6", "kleur": "^4.1.5", "msw": "^2.10.4", "node-fetch": "^3.3.2", "open": "^11.0.0", "ora": "^8.2.0", "postcss": "^8.5.6", "postcss-selector-parser": "^7.1.0", "prompts": "^2.4.2", "recast": "^0.23.11", "stringify-object": "^5.0.0", "tailwind-merge": "^3.0.1", "ts-morph": "^26.0.0", "tsconfig-paths": "^4.2.0", "validate-npm-package-name": "^7.0.1", "zod": "^3.24.1", "zod-to-json-schema": "^3.24.6" }, "bin": { "shadcn": "dist/index.js" } }, "sha512-nBj+7LYC9kzV9v9QmRPpoOhfW4KctJVQejywdAt/K+K+z4RYlJOcO2a4AaF7elrRWkfCbgXeGK02liV0KB9HvQ=="], | |
| 2463 | − | |
| 2464 | 2126 | "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], |
| 2465 | 2127 | |
| 2466 | 2128 | "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], |
| 2467 | 2129 | |
| 2468 | − "shiki": ["shiki@4.0.1", "", { "dependencies": { "@shikijs/core": "4.0.1", "@shikijs/engine-javascript": "4.0.1", "@shikijs/engine-oniguruma": "4.0.1", "@shikijs/langs": "4.0.1", "@shikijs/themes": "4.0.1", "@shikijs/types": "4.0.1", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-EkAEhDTN5WhpoQFXFw79OHIrSAfHhlImeCdSyg4u4XvrpxKEmdo/9x/HWSowujAnUrFsGOwWiE58a6GVentMnQ=="], | |
| 2130 | + "shiki": ["shiki@4.0.2", "", { "dependencies": { "@shikijs/core": "4.0.2", "@shikijs/engine-javascript": "4.0.2", "@shikijs/engine-oniguruma": "4.0.2", "@shikijs/langs": "4.0.2", "@shikijs/themes": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ=="], | |
| 2469 | 2131 | |
| 2470 | 2132 | "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], |
| 2471 | 2133 | |
| @@ -2479,15 +2141,13 @@ · 7 unmodified lines | ||
| 2479 | 2141 | |
| 2480 | 2142 | "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], |
| 2481 | 2143 | |
| 2482 | − "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], | |
| 2144 | + "simple-concat": ["simple-concat@1.0.1", "", {}, "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="], | |
| 2483 | 2145 | |
| 2484 | − "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], | |
| 2485 | − | |
| 2486 | − "smol-toml": ["smol-toml@1.6.0", "", {}, "sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw=="], | |
| 2146 | + "simple-get": ["simple-get@4.0.1", "", { "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA=="], | |
| 2487 | 2147 | |
| 2488 | − "solid-js": ["solid-js@1.9.11", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.5.0", "seroval-plugins": "~1.5.0" } }, "sha512-WEJtcc5mkh/BnHA6Yrg4whlF8g6QwpmXXRg4P2ztPmcKeHHlH4+djYecBLhSpecZY2RRECXYUwIc/C2r3yzQ4Q=="], | |
| 2148 | + "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], | |
| 2489 | 2149 | |
| 2490 | − "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], | |
| 2150 | + "sonner": ["sonner@2.0.7", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w=="], | |
| 2491 | 2151 | |
| 2492 | 2152 | "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], |
| 2493 | 2153 | |
| @@ -2503,25 +2163,17 @@ · 9 unmodified lines | ||
| 2503 | 2163 | |
| 2504 | 2164 | "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], |
| 2505 | 2165 | |
| 2506 | − "stdin-discarder": ["stdin-discarder@0.2.2", "", {}, "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ=="], | |
| 2507 | − | |
| 2508 | − "streamdown": ["streamdown@2.4.0", "", { "dependencies": { "clsx": "^2.1.1", "hast-util-to-jsx-runtime": "^2.3.6", "html-url-attributes": "^3.0.1", "marked": "^17.0.1", "rehype-harden": "^1.1.8", "rehype-raw": "^7.0.0", "rehype-sanitize": "^6.0.0", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remend": "1.2.2", "tailwind-merge": "^3.4.0", "unified": "^11.0.5", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-fRk4HEYNznRLmxoVeT8wsGBwHF6/Yrdey6k+ZrE1Qtp4NyKwm7G/6e2Iw8penY4yLx31TlAHWT5Bsg1weZ9FZg=="], | |
| 2166 | + "streamdown": ["streamdown@2.5.0", "", { "dependencies": { "clsx": "^2.1.1", "hast-util-to-jsx-runtime": "^2.3.6", "html-url-attributes": "^3.0.1", "marked": "^17.0.1", "mermaid": "^11.12.2", "rehype-harden": "^1.1.8", "rehype-raw": "^7.0.0", "rehype-sanitize": "^6.0.0", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remend": "1.3.0", "tailwind-merge": "^3.4.0", "unified": "^11.0.5", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-/tTnURfIOxZK/pqJAxsfCvETG/XCJHoWnk3jq9xLcuz6CSpnjjuxSRBTTL4PKGhxiZQf0lqPxGhImdpwcZ2XwA=="], | |
| 2509 | 2167 | |
| 2510 | − "strict-event-emitter": ["strict-event-emitter@0.5.1", "", {}, "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ=="], | |
| 2511 | − | |
| 2512 | − "string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], | |
| 2168 | + "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], | |
| 2513 | 2169 | |
| 2514 | 2170 | "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], |
| 2515 | 2171 | |
| 2516 | − "stringify-object": ["stringify-object@5.0.0", "", { "dependencies": { "get-own-enumerable-keys": "^1.0.0", "is-obj": "^3.0.0", "is-regexp": "^3.1.0" } }, "sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg=="], | |
| 2517 | − | |
| 2518 | 2172 | "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], |
| 2519 | 2173 | |
| 2520 | 2174 | "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="], |
| 2521 | 2175 | |
| 2522 | − "strip-final-newline": ["strip-final-newline@4.0.0", "", {}, "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw=="], | |
| 2523 | − | |
| 2524 | − "strip-json-comments": ["strip-json-comments@5.0.3", "", {}, "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw=="], | |
| 2176 | + "strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], | |
| 2525 | 2177 | |
| 2526 | 2178 | "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], |
| 2527 | 2179 | |
| @@ -2529,24 +2181,24 @@ · 1 unmodified line | ||
| 2529 | 2181 | |
| 2530 | 2182 | "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="], |
| 2531 | 2183 | |
| 2532 | − "symbol-tree": ["symbol-tree@3.2.4", "", {}, "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="], | |
| 2184 | + "stylis": ["stylis@4.3.6", "", {}, "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ=="], | |
| 2533 | 2185 | |
| 2534 | 2186 | "tabbable": ["tabbable@6.4.0", "", {}, "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg=="], |
| 2535 | 2187 | |
| 2536 | − "tagged-tag": ["tagged-tag@1.0.0", "", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="], | |
| 2537 | − | |
| 2538 | 2188 | "tailwind-merge": ["tailwind-merge@3.5.0", "", {}, "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A=="], |
| 2539 | 2189 | |
| 2540 | − "tailwindcss": ["tailwindcss@4.2.1", "", {}, "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw=="], | |
| 2190 | + "tailwindcss": ["tailwindcss@4.2.2", "", {}, "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q=="], | |
| 2541 | 2191 | |
| 2542 | − "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], | |
| 2192 | + "tapable": ["tapable@2.3.2", "", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="], | |
| 2193 | + | |
| 2194 | + "tar-fs": ["tar-fs@2.1.4", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ=="], | |
| 2195 | + | |
| 2196 | + "tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], | |
| 2543 | 2197 | |
| 2544 | 2198 | "term-size": ["term-size@2.2.1", "", {}, "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg=="], |
| 2545 | 2199 | |
| 2546 | 2200 | "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="], |
| 2547 | 2201 | |
| 2548 | − "tiny-warning": ["tiny-warning@1.0.3", "", {}, "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="], | |
| 2549 | − | |
| 2550 | 2202 | "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], |
| 2551 | 2203 | |
| 2552 | 2204 | "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], |
| @@ -2559,57 +2211,33 @@ · 6 unmodified lines | ||
| 2559 | 2211 | |
| 2560 | 2212 | "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="], |
| 2561 | 2213 | |
| 2562 | − "tldts": ["tldts@7.0.27", "", { "dependencies": { "tldts-core": "^7.0.27" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-I4FZcVFcqCRuT0ph6dCDpPuO4Xgzvh+spkcTr1gK7peIvxWauoloVO0vuy1FQnijT63ss6AsHB6+OIM4aXHbPg=="], | |
| 2563 | − | |
| 2564 | − "tldts-core": ["tldts-core@7.0.27", "", {}, "sha512-YQ7uPjgWUibIK6DW5lrKujGwUKhLevU4hcGbP5O6TcIUb+oTjJYJVWPS4nZsIHrEEEG6myk/oqAJUEQmpZrHsg=="], | |
| 2565 | − | |
| 2566 | 2214 | "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], |
| 2567 | 2215 | |
| 2568 | 2216 | "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], |
| 2569 | 2217 | |
| 2570 | 2218 | "toml": ["toml@3.0.0", "", {}, "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w=="], |
| 2571 | 2219 | |
| 2572 | − "tough-cookie": ["tough-cookie@5.1.2", "", { "dependencies": { "tldts": "^6.1.32" } }, "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A=="], | |
| 2573 | − | |
| 2574 | − "tr46": ["tr46@5.1.1", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw=="], | |
| 2575 | − | |
| 2576 | 2220 | "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], |
| 2577 | 2221 | |
| 2578 | 2222 | "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="], |
| 2579 | 2223 | |
| 2580 | − "ts-morph": ["ts-morph@26.0.0", "", { "dependencies": { "@ts-morph/common": "~0.27.0", "code-block-writer": "^13.0.3" } }, "sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug=="], | |
| 2581 | − | |
| 2582 | − "tsconfig-paths": ["tsconfig-paths@4.2.0", "", { "dependencies": { "json5": "^2.2.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg=="], | |
| 2224 | + "ts-dedent": ["ts-dedent@2.2.0", "", {}, "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ=="], | |
| 2583 | 2225 | |
| 2584 | 2226 | "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], |
| 2585 | 2227 | |
| 2586 | − "turbo": ["turbo@2.8.14", "", { "optionalDependencies": { "turbo-darwin-64": "2.8.14", "turbo-darwin-arm64": "2.8.14", "turbo-linux-64": "2.8.14", "turbo-linux-arm64": "2.8.14", "turbo-windows-64": "2.8.14", "turbo-windows-arm64": "2.8.14" }, "bin": { "turbo": "bin/turbo" } }, "sha512-UCTxeMNYT1cKaHiIFdLCQ7ulI+jw5i5uOnJOrRXsgUD7G3+OjlUjwVd7JfeVt2McWSVGjYA3EVW/v1FSsJ5DtA=="], | |
| 2587 | − | |
| 2588 | − "turbo-darwin-64": ["turbo-darwin-64@2.8.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-9sFi7n2lLfEsGWi5OEoA/eTtQU2BPKtzSYKqufMtDeRmqMT9vKjbv9gJCRkllSVE9BOXA0qXC3diyX8V8rKIKw=="], | |
| 2589 | − | |
| 2590 | − "turbo-darwin-arm64": ["turbo-darwin-arm64@2.8.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-aS4yJuy6A1PCLws+PJpZP0qCURG8Y5iVx13z/WAbKyeDTY6W6PiGgcEllSaeLGxyn++382ztN/EZH85n2zZ6VQ=="], | |
| 2591 | − | |
| 2592 | − "turbo-linux-64": ["turbo-linux-64@2.8.14", "", { "os": "linux", "cpu": "x64" }, "sha512-XC6wPUDJkakjhNLaS0NrHDMiujRVjH+naEAwvKLArgqRaFkNxjmyNDRM4eu3soMMFmjym6NTxYaF74rvET+Orw=="], | |
| 2593 | − | |
| 2594 | − "turbo-linux-arm64": ["turbo-linux-arm64@2.8.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-ChfE7isyVNjZrVSPDwcfqcHLG/FuIBbOFxnt1FM8vSuBGzHAs8AlTdwFNIxlEMJfZ8Ad9mdMxdmsCUPIWiQ6cg=="], | |
| 2228 | + "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], | |
| 2595 | 2229 | |
| 2596 | − "turbo-windows-64": ["turbo-windows-64@2.8.14", "", { "os": "win32", "cpu": "x64" }, "sha512-FTbIeQL1ycLFW2t9uQNMy+bRSzi3Xhwun/e7ZhFBdM+U0VZxxrtfYEBM9CHOejlfqomk6Jh7aRz0sJoqYn39Hg=="], | |
| 2597 | − | |
| 2598 | − "turbo-windows-arm64": ["turbo-windows-arm64@2.8.14", "", { "os": "win32", "cpu": "arm64" }, "sha512-KgZX12cTyhY030qS7ieT8zRkhZZE2VWJasDFVUSVVn17nR7IShpv68/7j5UqJNeRLIGF1XPK0phsP5V5yw3how=="], | |
| 2599 | − | |
| 2600 | − "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="], | |
| 2601 | − | |
| 2602 | − "type-fest": ["type-fest@5.5.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-PlBfpQwiUvGViBNX84Yxwjsdhd1TUlXr6zjX7eoirtCPIr08NAmxwa+fcYBTeRQxHo9YC9wwF3m9i700sHma8g=="], | |
| 2230 | + "turbo": ["turbo@2.9.2", "", { "optionalDependencies": { "@turbo/darwin-64": "2.9.2", "@turbo/darwin-arm64": "2.9.2", "@turbo/linux-64": "2.9.2", "@turbo/linux-arm64": "2.9.2", "@turbo/windows-64": "2.9.2", "@turbo/windows-arm64": "2.9.2" }, "bin": { "turbo": "bin/turbo" } }, "sha512-DUUWysctg/vax8W05UJcyrHm4LvxtX0umAT4bZB5lab4inNXTbwoYSFpdgqzBxON23j8ls3xGxvx0kwQz6Q8wQ=="], | |
| 2603 | 2231 | |
| 2604 | 2232 | "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], |
| 2605 | 2233 | |
| 2606 | 2234 | "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], |
| 2607 | 2235 | |
| 2608 | − "undici": ["undici@7.22.0", "", {}, "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg=="], | |
| 2236 | + "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], | |
| 2609 | 2237 | |
| 2610 | − "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], | |
| 2238 | + "undici": ["undici@7.24.6", "", {}, "sha512-Xi4agocCbRzt0yYMZGMA6ApD7gvtUFaxm4ZmeacWI4cZxaF6C+8I8QfofC20NAePiB/IcvZmzkJ7XPa471AEtA=="], | |
| 2611 | 2239 | |
| 2612 | − "unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="], | |
| 2240 | + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], | |
| 2613 | 2241 | |
| 2614 | 2242 | "unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="], |
| 2615 | 2243 | |
| @@ -2627,8 +2255,6 @@ · 11 unmodified lines | ||
| 2627 | 2255 | |
| 2628 | 2256 | "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], |
| 2629 | 2257 | |
| 2630 | − "until-async": ["until-async@3.0.2", "", {}, "sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw=="], | |
| 2631 | − | |
| 2632 | 2258 | "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], |
| 2633 | 2259 | |
| 2634 | 2260 | "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], |
| @@ -2641,210 +2267,234 @@ · 6 unmodified lines | ||
| 2641 | 2267 | |
| 2642 | 2268 | "uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="], |
| 2643 | 2269 | |
| 2644 | − "validate-npm-package-name": ["validate-npm-package-name@7.0.2", "", {}, "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A=="], | |
| 2645 | − | |
| 2646 | 2270 | "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], |
| 2647 | 2271 | |
| 2272 | + "vaul": ["vaul@1.1.2", "", { "dependencies": { "@radix-ui/react-dialog": "^1.1.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA=="], | |
| 2273 | + | |
| 2648 | 2274 | "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], |
| 2649 | 2275 | |
| 2650 | 2276 | "vfile-location": ["vfile-location@5.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg=="], |
| 2651 | 2277 | |
| 2652 | 2278 | "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], |
| 2653 | 2279 | |
| 2654 | − "vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.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", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], | |
| 2280 | + "victory-vendor": ["victory-vendor@37.3.6", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ=="], | |
| 2281 | + | |
| 2282 | + "vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="], | |
| 2655 | 2283 | |
| 2656 | 2284 | "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="], |
| 2657 | 2285 | |
| 2658 | 2286 | "vitest": ["vitest@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", "@vitest/mocker": "3.2.4", "@vitest/pretty-format": "^3.2.4", "@vitest/runner": "3.2.4", "@vitest/snapshot": "3.2.4", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "debug": "^4.4.1", "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", "picomatch": "^4.0.2", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.14", "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.2.4", "@vitest/ui": "3.2.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A=="], |
| 2659 | 2287 | |
| 2660 | − "w3c-xmlserializer": ["w3c-xmlserializer@5.0.0", "", { "dependencies": { "xml-name-validator": "^5.0.0" } }, "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA=="], | |
| 2661 | − | |
| 2662 | − "walk-up-path": ["walk-up-path@4.0.0", "", {}, "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A=="], | |
| 2288 | + "vscode-jsonrpc": ["vscode-jsonrpc@8.2.0", "", {}, "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="], | |
| 2663 | 2289 | |
| 2664 | − "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], | |
| 2290 | + "vscode-languageserver": ["vscode-languageserver@9.0.1", "", { "dependencies": { "vscode-languageserver-protocol": "3.17.5" }, "bin": { "installServerIntoExtension": "bin/installServerIntoExtension" } }, "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g=="], | |
| 2665 | 2291 | |
| 2666 | − "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], | |
| 2292 | + "vscode-languageserver-protocol": ["vscode-languageserver-protocol@3.17.5", "", { "dependencies": { "vscode-jsonrpc": "8.2.0", "vscode-languageserver-types": "3.17.5" } }, "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg=="], | |
| 2667 | 2293 | |
| 2668 | − "webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="], | |
| 2294 | + "vscode-languageserver-textdocument": ["vscode-languageserver-textdocument@1.0.12", "", {}, "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA=="], | |
| 2669 | 2295 | |
| 2670 | − "whatwg-encoding": ["whatwg-encoding@3.1.1", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ=="], | |
| 2296 | + "vscode-languageserver-types": ["vscode-languageserver-types@3.17.5", "", {}, "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="], | |
| 2671 | 2297 | |
| 2672 | − "whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="], | |
| 2298 | + "vscode-uri": ["vscode-uri@3.1.0", "", {}, "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ=="], | |
| 2673 | 2299 | |
| 2674 | − "whatwg-url": ["whatwg-url@14.2.0", "", { "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" } }, "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw=="], | |
| 2300 | + "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], | |
| 2675 | 2301 | |
| 2676 | 2302 | "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], |
| 2677 | 2303 | |
| 2678 | 2304 | "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="], |
| 2679 | 2305 | |
| 2680 | − "wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], | |
| 2681 | − | |
| 2682 | 2306 | "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], |
| 2683 | 2307 | |
| 2684 | − "ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], | |
| 2308 | + "ws": ["ws@8.20.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA=="], | |
| 2685 | 2309 | |
| 2686 | − "wsl-utils": ["wsl-utils@0.3.1", "", { "dependencies": { "is-wsl": "^3.1.0", "powershell-utils": "^0.1.0" } }, "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg=="], | |
| 2310 | + "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], | |
| 2687 | 2311 | |
| 2688 | − "xml-name-validator": ["xml-name-validator@5.0.0", "", {}, "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg=="], | |
| 2312 | + "yaml": ["yaml@2.8.3", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg=="], | |
| 2689 | 2313 | |
| 2690 | − "xmlchars": ["xmlchars@2.2.0", "", {}, "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="], | |
| 2314 | + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], | |
| 2691 | 2315 | |
| 2692 | − "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], | |
| 2316 | + "zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="], | |
| 2693 | 2317 | |
| 2694 | − "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], | |
| 2318 | + "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], | |
| 2695 | 2319 | |
| 2696 | − "yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="], | |
| 2320 | + "@antfu/install-pkg/package-manager-detector": ["package-manager-detector@1.6.0", "", {}, "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA=="], | |
| 2697 | 2321 | |
| 2698 | − "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], | |
| 2322 | + "@antfu/install-pkg/tinyexec": ["tinyexec@1.0.4", "", {}, "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw=="], | |
| 2699 | 2323 | |
| 2700 | − "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], | |
| 2324 | + "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], | |
| 2701 | 2325 | |
| 2702 | − "yoctocolors": ["yoctocolors@2.1.2", "", {}, "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug=="], | |
| 2326 | + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], | |
| 2703 | 2327 | |
| 2704 | − "yoctocolors-cjs": ["yoctocolors-cjs@2.1.3", "", {}, "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw=="], | |
| 2328 | + "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], | |
| 2705 | 2329 | |
| 2706 | − "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], | |
| 2330 | + "@executor/config/typescript": ["typescript@6.0.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="], | |
| 2707 | 2331 | |
| 2708 | − "zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="], | |
| 2332 | + "@executor/sdk/typescript": ["typescript@6.0.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="], | |
| 2709 | 2333 | |
| 2710 | − "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], | |
| 2334 | + "@manypkg/find-root/@types/node": ["@types/node@12.20.55", "", {}, "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="], | |
| 2711 | 2335 | |
| 2712 | − "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], | |
| 2336 | + "@manypkg/find-root/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], | |
| 2713 | 2337 | |
| 2714 | − "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], | |
| 2338 | + "@manypkg/get-packages/@changesets/types": ["@changesets/types@4.1.0", "", {}, "sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw=="], | |
| 2715 | 2339 | |
| 2716 | − "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], | |
| 2340 | + "@manypkg/get-packages/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], | |
| 2717 | 2341 | |
| 2718 | − "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], | |
| 2342 | + "@reduxjs/toolkit/immer": ["immer@11.1.4", "", {}, "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw=="], | |
| 2719 | 2343 | |
| 2720 | − "@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], | |
| 2344 | + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="], | |
| 2721 | 2345 | |
| 2722 | − "@changesets/apply-release-plan/prettier": ["prettier@2.8.8", "", { "bin": { "prettier": "bin-prettier.js" } }, "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q=="], | |
| 2346 | + "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="], | |
| 2723 | 2347 | |
| 2724 | − "@changesets/write/prettier": ["prettier@2.8.8", "", { "bin": { "prettier": "bin-prettier.js" } }, "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q=="], | |
| 2348 | + "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg=="], | |
| 2725 | 2349 | |
| 2726 | − "@dotenvx/dotenvx/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], | |
| 2350 | + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.2", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" }, "bundled": true }, "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw=="], | |
| 2727 | 2351 | |
| 2728 | − "@dotenvx/dotenvx/execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], | |
| 2352 | + "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], | |
| 2729 | 2353 | |
| 2730 | − "@dotenvx/dotenvx/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], | |
| 2354 | + "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], | |
| 2731 | 2355 | |
| 2732 | − "@dotenvx/dotenvx/which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="], | |
| 2356 | + "bun-types/@types/node": ["@types/node@25.5.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw=="], | |
| 2733 | 2357 | |
| 2734 | − "@manypkg/find-root/@types/node": ["@types/node@12.20.55", "", {}, "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="], | |
| 2358 | + "cytoscape-fcose/cose-base": ["cose-base@2.2.0", "", { "dependencies": { "layout-base": "^2.0.0" } }, "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g=="], | |
| 2735 | 2359 | |
| 2736 | − "@manypkg/find-root/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], | |
| 2360 | + "d3-dsv/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], | |
| 2737 | 2361 | |
| 2738 | − "@manypkg/get-packages/@changesets/types": ["@changesets/types@4.1.0", "", {}, "sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw=="], | |
| 2362 | + "d3-dsv/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], | |
| 2739 | 2363 | |
| 2740 | − "@manypkg/get-packages/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], | |
| 2364 | + "d3-sankey/d3-array": ["d3-array@2.12.1", "", { "dependencies": { "internmap": "^1.0.0" } }, "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ=="], | |
| 2365 | + | |
| 2366 | + "d3-sankey/d3-shape": ["d3-shape@1.3.7", "", { "dependencies": { "d3-path": "1" } }, "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw=="], | |
| 2741 | 2367 | |
| 2742 | − "@radix-ui/react-dialog/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], | |
| 2368 | + "mermaid/marked": ["marked@16.4.2", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA=="], | |
| 2743 | 2369 | |
| 2744 | − "@radix-ui/react-dismissable-layer/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], | |
| 2370 | + "micromatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], | |
| 2745 | 2371 | |
| 2746 | − "@radix-ui/react-focus-scope/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], | |
| 2372 | + "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], | |
| 2747 | 2373 | |
| 2748 | − "@radix-ui/react-portal/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], | |
| 2374 | + "rc/ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], | |
| 2749 | 2375 | |
| 2750 | − "@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA=="], | |
| 2376 | + "read-yaml-file/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], | |
| 2751 | 2377 | |
| 2752 | − "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], | |
| 2378 | + "vite-node/vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.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", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], | |
| 2753 | 2379 | |
| 2754 | − "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], | |
| 2380 | + "vitest/vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.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", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], | |
| 2755 | 2381 | |
| 2756 | − "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], | |
| 2382 | + "bun-types/@types/node/undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], | |
| 2757 | 2383 | |
| 2758 | − "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="], | |
| 2384 | + "cytoscape-fcose/cose-base/layout-base": ["layout-base@2.0.1", "", {}, "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg=="], | |
| 2759 | 2385 | |
| 2760 | − "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], | |
| 2386 | + "d3-sankey/d3-array/internmap": ["internmap@1.0.1", "", {}, "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="], | |
| 2761 | 2387 | |
| 2762 | − "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], | |
| 2388 | + "d3-sankey/d3-shape/d3-path": ["d3-path@1.0.9", "", {}, "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="], | |
| 2763 | 2389 | |
| 2764 | − "@ts-morph/common/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], | |
| 2390 | + "read-yaml-file/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], | |
| 2765 | 2391 | |
| 2766 | − "cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], | |
| 2392 | + "vite-node/vite/esbuild": ["esbuild@0.27.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.4", "@esbuild/android-arm": "0.27.4", "@esbuild/android-arm64": "0.27.4", "@esbuild/android-x64": "0.27.4", "@esbuild/darwin-arm64": "0.27.4", "@esbuild/darwin-x64": "0.27.4", "@esbuild/freebsd-arm64": "0.27.4", "@esbuild/freebsd-x64": "0.27.4", "@esbuild/linux-arm": "0.27.4", "@esbuild/linux-arm64": "0.27.4", "@esbuild/linux-ia32": "0.27.4", "@esbuild/linux-loong64": "0.27.4", "@esbuild/linux-mips64el": "0.27.4", "@esbuild/linux-ppc64": "0.27.4", "@esbuild/linux-riscv64": "0.27.4", "@esbuild/linux-s390x": "0.27.4", "@esbuild/linux-x64": "0.27.4", "@esbuild/netbsd-arm64": "0.27.4", "@esbuild/netbsd-x64": "0.27.4", "@esbuild/openbsd-arm64": "0.27.4", "@esbuild/openbsd-x64": "0.27.4", "@esbuild/openharmony-arm64": "0.27.4", "@esbuild/sunos-x64": "0.27.4", "@esbuild/win32-arm64": "0.27.4", "@esbuild/win32-ia32": "0.27.4", "@esbuild/win32-x64": "0.27.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ=="], | |
| 2767 | 2393 | |
| 2768 | − "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], | |
| 2394 | + "vitest/vite/esbuild": ["esbuild@0.27.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.4", "@esbuild/android-arm": "0.27.4", "@esbuild/android-arm64": "0.27.4", "@esbuild/android-x64": "0.27.4", "@esbuild/darwin-arm64": "0.27.4", "@esbuild/darwin-x64": "0.27.4", "@esbuild/freebsd-arm64": "0.27.4", "@esbuild/freebsd-x64": "0.27.4", "@esbuild/linux-arm": "0.27.4", "@esbuild/linux-arm64": "0.27.4", "@esbuild/linux-ia32": "0.27.4", "@esbuild/linux-loong64": "0.27.4", "@esbuild/linux-mips64el": "0.27.4", "@esbuild/linux-ppc64": "0.27.4", "@esbuild/linux-riscv64": "0.27.4", "@esbuild/linux-s390x": "0.27.4", "@esbuild/linux-x64": "0.27.4", "@esbuild/netbsd-arm64": "0.27.4", "@esbuild/netbsd-x64": "0.27.4", "@esbuild/openbsd-arm64": "0.27.4", "@esbuild/openbsd-x64": "0.27.4", "@esbuild/openharmony-arm64": "0.27.4", "@esbuild/sunos-x64": "0.27.4", "@esbuild/win32-arm64": "0.27.4", "@esbuild/win32-ia32": "0.27.4", "@esbuild/win32-x64": "0.27.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ=="], | |
| 2769 | 2395 | |
| 2770 | − "globby/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], | |
| 2396 | + "vite-node/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q=="], | |
| 2771 | 2397 | |
| 2772 | − "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], | |
| 2398 | + "vite-node/vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.4", "", { "os": "android", "cpu": "arm" }, "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ=="], | |
| 2773 | 2399 | |
| 2774 | − "log-symbols/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="], | |
| 2400 | + "vite-node/vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.4", "", { "os": "android", "cpu": "arm64" }, "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw=="], | |
| 2775 | 2401 | |
| 2776 | − "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], | |
| 2402 | + "vite-node/vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.4", "", { "os": "android", "cpu": "x64" }, "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw=="], | |
| 2777 | 2403 | |
| 2778 | − "msw/cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], | |
| 2404 | + "vite-node/vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ=="], | |
| 2779 | 2405 | |
| 2780 | − "msw/tough-cookie": ["tough-cookie@6.0.1", "", { "dependencies": { "tldts": "^7.0.5" } }, "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw=="], | |
| 2406 | + "vite-node/vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw=="], | |
| 2781 | 2407 | |
| 2782 | − "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], | |
| 2408 | + "vite-node/vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw=="], | |
| 2783 | 2409 | |
| 2784 | − "ora/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], | |
| 2410 | + "vite-node/vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ=="], | |
| 2785 | 2411 | |
| 2786 | − "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], | |
| 2412 | + "vite-node/vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.4", "", { "os": "linux", "cpu": "arm" }, "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg=="], | |
| 2787 | 2413 | |
| 2788 | − "prompts/kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], | |
| 2414 | + "vite-node/vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA=="], | |
| 2789 | 2415 | |
| 2790 | − "read-yaml-file/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], | |
| 2416 | + "vite-node/vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.4", "", { "os": "linux", "cpu": "ia32" }, "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA=="], | |
| 2791 | 2417 | |
| 2792 | − "restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], | |
| 2418 | + "vite-node/vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.4", "", { "os": "linux", "cpu": "none" }, "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA=="], | |
| 2793 | 2419 | |
| 2794 | − "router/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], | |
| 2420 | + "vite-node/vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.4", "", { "os": "linux", "cpu": "none" }, "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw=="], | |
| 2795 | 2421 | |
| 2796 | − "shadcn/fs-extra": ["fs-extra@11.3.4", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA=="], | |
| 2422 | + "vite-node/vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA=="], | |
| 2797 | 2423 | |
| 2798 | − "shadcn/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], | |
| 2424 | + "vite-node/vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.4", "", { "os": "linux", "cpu": "none" }, "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw=="], | |
| 2799 | 2425 | |
| 2800 | − "string-width/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], | |
| 2426 | + "vite-node/vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA=="], | |
| 2801 | 2427 | |
| 2802 | − "tough-cookie/tldts": ["tldts@6.1.86", "", { "dependencies": { "tldts-core": "^6.1.86" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ=="], | |
| 2428 | + "vite-node/vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.4", "", { "os": "linux", "cpu": "x64" }, "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA=="], | |
| 2803 | 2429 | |
| 2804 | − "whatwg-encoding/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], | |
| 2430 | + "vite-node/vite/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.4", "", { "os": "none", "cpu": "arm64" }, "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q=="], | |
| 2805 | 2431 | |
| 2806 | − "wrap-ansi/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], | |
| 2432 | + "vite-node/vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.4", "", { "os": "none", "cpu": "x64" }, "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg=="], | |
| 2807 | 2433 | |
| 2808 | − "yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], | |
| 2434 | + "vite-node/vite/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.4", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow=="], | |
| 2809 | 2435 | |
| 2810 | − "@dotenvx/dotenvx/execa/get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], | |
| 2436 | + "vite-node/vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ=="], | |
| 2811 | 2437 | |
| 2812 | − "@dotenvx/dotenvx/execa/human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], | |
| 2438 | + "vite-node/vite/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.4", "", { "os": "none", "cpu": "arm64" }, "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg=="], | |
| 2813 | 2439 | |
| 2814 | − "@dotenvx/dotenvx/execa/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], | |
| 2440 | + "vite-node/vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.4", "", { "os": "sunos", "cpu": "x64" }, "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g=="], | |
| 2815 | 2441 | |
| 2816 | − "@dotenvx/dotenvx/execa/npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="], | |
| 2442 | + "vite-node/vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg=="], | |
| 2817 | 2443 | |
| 2818 | − "@dotenvx/dotenvx/execa/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], | |
| 2444 | + "vite-node/vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw=="], | |
| 2819 | 2445 | |
| 2820 | − "@dotenvx/dotenvx/execa/strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="], | |
| 2446 | + "vite-node/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.4", "", { "os": "win32", "cpu": "x64" }, "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg=="], | |
| 2821 | 2447 | |
| 2822 | − "@dotenvx/dotenvx/which/isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="], | |
| 2448 | + "vitest/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q=="], | |
| 2823 | 2449 | |
| 2824 | − "@ts-morph/common/minimatch/brace-expansion": ["brace-expansion@5.0.5", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ=="], | |
| 2450 | + "vitest/vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.4", "", { "os": "android", "cpu": "arm" }, "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ=="], | |
| 2825 | 2451 | |
| 2826 | − "cliui/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], | |
| 2452 | + "vitest/vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.4", "", { "os": "android", "cpu": "arm64" }, "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw=="], | |
| 2827 | 2453 | |
| 2828 | − "msw/tough-cookie/tldts": ["tldts@7.0.25", "", { "dependencies": { "tldts-core": "^7.0.25" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-keinCnPbwXEUG3ilrWQZU+CqcTTzHq9m2HhoUP2l7Xmi8l1LuijAXLpAJ5zRW+ifKTNscs4NdCkfkDCBYm352w=="], | |
| 2454 | + "vitest/vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.4", "", { "os": "android", "cpu": "x64" }, "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw=="], | |
| 2829 | 2455 | |
| 2830 | − "ora/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], | |
| 2456 | + "vitest/vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ=="], | |
| 2831 | 2457 | |
| 2832 | − "read-yaml-file/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], | |
| 2458 | + "vitest/vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw=="], | |
| 2459 | + | |
| 2460 | + "vitest/vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw=="], | |
| 2461 | + | |
| 2462 | + "vitest/vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ=="], | |
| 2463 | + | |
| 2464 | + "vitest/vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.4", "", { "os": "linux", "cpu": "arm" }, "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg=="], | |
| 2465 | + | |
| 2466 | + "vitest/vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA=="], | |
| 2467 | + | |
| 2468 | + "vitest/vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.4", "", { "os": "linux", "cpu": "ia32" }, "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA=="], | |
| 2469 | + | |
| 2470 | + "vitest/vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.4", "", { "os": "linux", "cpu": "none" }, "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA=="], | |
| 2471 | + | |
| 2472 | + "vitest/vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.4", "", { "os": "linux", "cpu": "none" }, "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw=="], | |
| 2473 | + | |
| 2474 | + "vitest/vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA=="], | |
| 2475 | + | |
| 2476 | + "vitest/vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.4", "", { "os": "linux", "cpu": "none" }, "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw=="], | |
| 2477 | + | |
| 2478 | + "vitest/vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA=="], | |
| 2479 | + | |
| 2480 | + "vitest/vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.4", "", { "os": "linux", "cpu": "x64" }, "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA=="], | |
| 2481 | + | |
| 2482 | + "vitest/vite/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.4", "", { "os": "none", "cpu": "arm64" }, "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q=="], | |
| 2833 | 2483 | |
| 2834 | − "shadcn/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], | |
| 2484 | + "vitest/vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.4", "", { "os": "none", "cpu": "x64" }, "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg=="], | |
| 2835 | 2485 | |
| 2836 | − "shadcn/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], | |
| 2486 | + "vitest/vite/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.4", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow=="], | |
| 2837 | 2487 | |
| 2838 | − "string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], | |
| 2488 | + "vitest/vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ=="], | |
| 2839 | 2489 | |
| 2840 | − "tough-cookie/tldts/tldts-core": ["tldts-core@6.1.86", "", {}, "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA=="], | |
| 2490 | + "vitest/vite/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.4", "", { "os": "none", "cpu": "arm64" }, "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg=="], | |
| 2841 | 2491 | |
| 2842 | − "wrap-ansi/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], | |
| 2492 | + "vitest/vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.4", "", { "os": "sunos", "cpu": "x64" }, "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g=="], | |
| 2843 | 2493 | |
| 2844 | − "yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], | |
| 2494 | + "vitest/vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg=="], | |
| 2845 | 2495 | |
| 2846 | − "@ts-morph/common/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], | |
| 2496 | + "vitest/vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw=="], | |
| 2847 | 2497 | |
| 2848 | − "msw/tough-cookie/tldts/tldts-core": ["tldts-core@7.0.25", "", {}, "sha512-ZjCZK0rppSBu7rjHYDYsEaMOIbbT+nWF57hKkv4IUmZWBNrBWBOjIElc0mKRgLM8bm7x/BBlof6t2gi/Oq/Asw=="], | |
| 2498 | + "vitest/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.4", "", { "os": "win32", "cpu": "x64" }, "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg=="], | |
| 2849 | 2499 | } |
| 2850 | 2500 | } |
| @@ -1,9 +0,0 @@ | ||
| 1 | −services: | |
| 2 | − jaeger: | |
| 3 | − image: jaegertracing/all-in-one:1.65.0 | |
| 4 | − ports: | |
| 5 | − - "16686:16686" | |
| 6 | − - "4317:4317" | |
| 7 | − - "4318:4318" | |
| 8 | − environment: | |
| 9 | − COLLECTOR_OTLP_ENABLED: "true" | |
| @@ -1,3 +0,0 @@ | ||
| 1 | −# @executor/mcp-elicitation-demo | |
| 2 | − | |
| 3 | −## null | |
| @@ -1,21 +0,0 @@ | ||
| 1 | −{ | |
| 2 | − "name": "@executor/mcp-elicitation-demo", | |
| 3 | − "private": true, | |
| 4 | − "type": "module", | |
| 5 | − "exports": { | |
| 6 | − ".": "./src/index.ts" | |
| 7 | − }, | |
| 8 | − "scripts": { | |
| 9 | − "typecheck": "bunx tsc --noEmit -p tsconfig.json", | |
| 10 | − "start": "bun src/main.ts" | |
| 11 | − }, | |
| 12 | − "dependencies": { | |
| 13 | − "@modelcontextprotocol/sdk": "^1.26.0", | |
| 14 | − "zod": "catalog:" | |
| 15 | − }, | |
| 16 | − "devDependencies": { | |
| 17 | − "@types/node": "catalog:", | |
| 18 | − "bun-types": "catalog:" | |
| 19 | − }, | |
| 20 | − "version": "0.0.0" | |
| 21 | −} | |
| @@ -1,4 +0,0 @@ | ||
| 1 | −export { | |
| 2 | − startMcpElicitationDemoServer, | |
| 3 | − type McpElicitationDemoServer, | |
| 4 | −} from "./server"; | |
| @@ -1,20 +0,0 @@ | ||
| 1 | −import { startMcpElicitationDemoServer } from "./server"; | |
| 2 | − | |
| 3 | −const host = process.env.HOST ?? "127.0.0.1"; | |
| 4 | −const port = process.env.PORT ? Number(process.env.PORT) : 58506; | |
| 5 | − | |
| 6 | −const server = await startMcpElicitationDemoServer({ host, port }); | |
| 7 | −console.error(`mcp-elicitation-demo listening on ${server.endpoint}`); | |
| 8 | − | |
| 9 | −const shutdown = async () => { | |
| 10 | − await server.close(); | |
| 11 | − process.exit(0); | |
| 12 | −}; | |
| 13 | − | |
| 14 | −process.once("SIGINT", () => { | |
| 15 | − void shutdown(); | |
| 16 | −}); | |
| 17 | − | |
| 18 | −process.once("SIGTERM", () => { | |
| 19 | − void shutdown(); | |
| 20 | −}); | |
| @@ -1,222 +0,0 @@ | ||
| 1 | −import { randomUUID } from "node:crypto"; | |
| 2 | − | |
| 3 | −import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js"; | |
| 4 | −import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | |
| 5 | −import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; | |
| 6 | −import { z } from "zod/v4"; | |
| 7 | − | |
| 8 | −export type McpElicitationDemoServer = { | |
| 9 | − readonly endpoint: string; | |
| 10 | − readonly close: () => Promise<void>; | |
| 11 | −}; | |
| 12 | − | |
| 13 | −const registerDemoTools = (server: McpServer) => { | |
| 14 | − server.registerTool( | |
| 15 | − "gated_echo", | |
| 16 | − { | |
| 17 | − description: "Ask for approval before echoing the provided value.", | |
| 18 | − inputSchema: { | |
| 19 | − value: z.string(), | |
| 20 | − }, | |
| 21 | − }, | |
| 22 | − async ({ value }: { value: string }) => { | |
| 23 | − const response = await server.server.elicitInput({ | |
| 24 | − mode: "form", | |
| 25 | − message: `Approve gated echo for ${value}?`, | |
| 26 | − requestedSchema: { | |
| 27 | − type: "object", | |
| 28 | − properties: { | |
| 29 | − approve: { | |
| 30 | − type: "boolean", | |
| 31 | − title: "Approve", | |
| 32 | − }, | |
| 33 | − }, | |
| 34 | − required: ["approve"], | |
| 35 | − }, | |
| 36 | − }); | |
| 37 | − | |
| 38 | − if ( | |
| 39 | − response.action !== "accept" | |
| 40 | − || !response.content | |
| 41 | − || response.content.approve !== true | |
| 42 | − ) { | |
| 43 | − return { | |
| 44 | − content: [{ type: "text", text: "denied" }], | |
| 45 | − }; | |
| 46 | − } | |
| 47 | − | |
| 48 | − return { | |
| 49 | − content: [{ type: "text", text: `approved:${value}` }], | |
| 50 | − }; | |
| 51 | − }, | |
| 52 | − ); | |
| 53 | −}; | |
| 54 | − | |
| 55 | −export const startMcpElicitationDemoServer = async (input: { | |
| 56 | − readonly host?: string; | |
| 57 | − readonly port?: number; | |
| 58 | −} = {}): Promise<McpElicitationDemoServer> => { | |
| 59 | − const host = input.host ?? "127.0.0.1"; | |
| 60 | − const app = createMcpExpressApp({ host }); | |
| 61 | − const transports: Record<string, StreamableHTTPServerTransport> = {}; | |
| 62 | − const servers: Record<string, McpServer> = {}; | |
| 63 | − | |
| 64 | − const createServer = () => { | |
| 65 | − const server = new McpServer( | |
| 66 | − { | |
| 67 | − name: "executor-mcp-elicitation-demo", | |
| 68 | − version: "1.0.0", | |
| 69 | − }, | |
| 70 | − { | |
| 71 | − capabilities: { | |
| 72 | − tools: {}, | |
| 73 | − }, | |
| 74 | − }, | |
| 75 | − ); | |
| 76 | − | |
| 77 | − registerDemoTools(server); | |
| 78 | − return server; | |
| 79 | − }; | |
| 80 | − | |
| 81 | − app.post("/mcp", async (req: any, res: any) => { | |
| 82 | − const sessionIdHeader = req.headers["mcp-session-id"]; | |
| 83 | − const sessionId = | |
| 84 | − typeof sessionIdHeader === "string" | |
| 85 | − ? sessionIdHeader | |
| 86 | − : Array.isArray(sessionIdHeader) | |
| 87 | − ? sessionIdHeader[0] | |
| 88 | − : undefined; | |
| 89 | − | |
| 90 | − try { | |
| 91 | − let transport: StreamableHTTPServerTransport; | |
| 92 | − | |
| 93 | − if (sessionId && transports[sessionId]) { | |
| 94 | − transport = transports[sessionId]; | |
| 95 | − } else { | |
| 96 | − transport = new StreamableHTTPServerTransport({ | |
| 97 | − sessionIdGenerator: () => randomUUID(), | |
| 98 | − onsessioninitialized: (newSessionId) => { | |
| 99 | − transports[newSessionId] = transport; | |
| 100 | − }, | |
| 101 | − }); | |
| 102 | − | |
| 103 | − transport.onclose = () => { | |
| 104 | − const closedSessionId = transport.sessionId; | |
| 105 | − if (closedSessionId && transports[closedSessionId]) { | |
| 106 | − delete transports[closedSessionId]; | |
| 107 | − } | |
| 108 | − if (closedSessionId && servers[closedSessionId]) { | |
| 109 | − void servers[closedSessionId].close().catch(() => undefined); | |
| 110 | − delete servers[closedSessionId]; | |
| 111 | − } | |
| 112 | − }; | |
| 113 | − | |
| 114 | − const server = createServer(); | |
| 115 | − await server.connect(transport); | |
| 116 | − const newSessionId = transport.sessionId; | |
| 117 | − if (newSessionId) { | |
| 118 | − servers[newSessionId] = server; | |
| 119 | − } | |
| 120 | − } | |
| 121 | − | |
| 122 | − await transport.handleRequest(req, res, req.body); | |
| 123 | − } catch (error) { | |
| 124 | − if (!res.headersSent) { | |
| 125 | − res.status(500).json({ | |
| 126 | − jsonrpc: "2.0", | |
| 127 | − error: { | |
| 128 | − code: -32603, | |
| 129 | − message: error instanceof Error ? error.message : "Internal server error", | |
| 130 | − }, | |
| 131 | − id: null, | |
| 132 | − }); | |
| 133 | − } | |
| 134 | − } | |
| 135 | − }); | |
| 136 | − | |
| 137 | − app.get("/mcp", async (req: any, res: any) => { | |
| 138 | − const sessionIdHeader = req.headers["mcp-session-id"]; | |
| 139 | − const sessionId = | |
| 140 | − typeof sessionIdHeader === "string" | |
| 141 | − ? sessionIdHeader | |
| 142 | − : Array.isArray(sessionIdHeader) | |
| 143 | − ? sessionIdHeader[0] | |
| 144 | − : undefined; | |
| 145 | − | |
| 146 | − if (!sessionId || !transports[sessionId]) { | |
| 147 | − res.status(400).send("Invalid or missing session ID"); | |
| 148 | − return; | |
| 149 | − } | |
| 150 | − | |
| 151 | − await transports[sessionId].handleRequest(req, res); | |
| 152 | − }); | |
| 153 | − | |
| 154 | − app.delete("/mcp", async (req: any, res: any) => { | |
| 155 | − const sessionIdHeader = req.headers["mcp-session-id"]; | |
| 156 | − const sessionId = | |
| 157 | − typeof sessionIdHeader === "string" | |
| 158 | − ? sessionIdHeader | |
| 159 | − : Array.isArray(sessionIdHeader) | |
| 160 | − ? sessionIdHeader[0] | |
| 161 | − : undefined; | |
| 162 | − | |
| 163 | − if (!sessionId || !transports[sessionId]) { | |
| 164 | − res.status(400).send("Invalid or missing session ID"); | |
| 165 | − return; | |
| 166 | − } | |
| 167 | − | |
| 168 | − const transport = transports[sessionId]; | |
| 169 | − await transport.handleRequest(req, res, req.body); | |
| 170 | − await transport.close(); | |
| 171 | − delete transports[sessionId]; | |
| 172 | − | |
| 173 | − if (servers[sessionId]) { | |
| 174 | − await servers[sessionId].close().catch(() => undefined); | |
| 175 | − delete servers[sessionId]; | |
| 176 | − } | |
| 177 | − }); | |
| 178 | − | |
| 179 | − const listener = await new Promise<import("node:http").Server>((resolve, reject) => { | |
| 180 | − const server = app.listen(input.port ?? 0, host); | |
| 181 | − | |
| 182 | − const onListening = () => { | |
| 183 | − server.off("error", onError); | |
| 184 | − resolve(server); | |
| 185 | − }; | |
| 186 | − | |
| 187 | − const onError = (error: Error) => { | |
| 188 | − server.off("listening", onListening); | |
| 189 | − reject(error); | |
| 190 | − }; | |
| 191 | − | |
| 192 | − server.once("listening", onListening); | |
| 193 | − server.once("error", onError); | |
| 194 | − }); | |
| 195 | − | |
| 196 | − const address = listener.address(); | |
| 197 | − if (!address || typeof address === "string") { | |
| 198 | − if (listener.listening) { | |
| 199 | − await new Promise<void>((resolve, reject) => { | |
| 200 | − listener.close((error) => (error ? reject(error) : resolve())); | |
| 201 | − }); | |
| 202 | − } | |
| 203 | − throw new Error("Failed to resolve MCP elicitation demo server address"); | |
| 204 | − } | |
| 205 | − | |
| 206 | − return { | |
| 207 | − endpoint: `http://${host}:${address.port}/mcp`, | |
| 208 | − close: async () => { | |
| 209 | − for (const transport of Object.values(transports)) { | |
| 210 | − await transport.close().catch(() => undefined); | |
| 211 | − } | |
| 212 | − | |
| 213 | − for (const server of Object.values(servers)) { | |
| 214 | − await server.close().catch(() => undefined); | |
| 215 | − } | |
| 216 | − | |
| 217 | − await new Promise<void>((resolve, reject) => { | |
| 218 | − listener.close((error) => (error ? reject(error) : resolve())); | |
| 219 | − }); | |
| 220 | − }, | |
| 221 | − }; | |
| 222 | −}; | |
| @@ -1,15 +0,0 @@ | ||
| 1 | −{ | |
| 2 | − "compilerOptions": { | |
| 3 | − "target": "ES2022", | |
| 4 | − "module": "ESNext", | |
| 5 | − "moduleResolution": "Bundler", | |
| 6 | − "strict": true, | |
| 7 | − "skipLibCheck": true, | |
| 8 | − "noEmit": true, | |
| 9 | − "lib": ["ES2022"], | |
| 10 | − "types": ["bun-types", "node"] | |
| 11 | − }, | |
| 12 | − "include": [ | |
| 13 | − "src/**/*.ts" | |
| 14 | − ] | |
| 15 | −} | |
| @@ -1,3 +0,0 @@ | ||
| 1 | −# @executor/serve-skills-via-mcp-demo | |
| 2 | − | |
| 3 | −## null | |
| @@ -1,38 +0,0 @@ | ||
| 1 | −# Serve Skills Via MCP | |
| 2 | − | |
| 3 | −This demo shows one practical way to distribute [Agent Skills](https://agentskills.io) | |
| 4 | −over MCP resources. | |
| 5 | − | |
| 6 | −It exposes: | |
| 7 | − | |
| 8 | −- a catalog resource that lists available skill bundles | |
| 9 | −- one manifest resource per skill bundle | |
| 10 | −- one direct `SKILL.md` resource per bundle | |
| 11 | −- a `skill://demo/{skill}/{version}/{+path}` resource template for bundled files | |
| 12 | − | |
| 13 | −The important boundary is that MCP resources only transport the bundle. The host still | |
| 14 | −owns activation logic: | |
| 15 | − | |
| 16 | −1. list resources | |
| 17 | −2. read the catalog or a manifest | |
| 18 | −3. choose a skill | |
| 19 | −4. read that skill's `SKILL.md` | |
| 20 | −5. fetch additional files from the manifest on demand | |
| 21 | − | |
| 22 | −## Run | |
| 23 | − | |
| 24 | −```bash | |
| 25 | −bun run --filter @executor/serve-skills-via-mcp-demo start | |
| 26 | −``` | |
| 27 | − | |
| 28 | −The server listens on `http://127.0.0.1:<port>/mcp` and logs the final endpoint to | |
| 29 | −stderr. | |
| 30 | − | |
| 31 | −## Smoke Test | |
| 32 | − | |
| 33 | −```bash | |
| 34 | −bun run --filter @executor/serve-skills-via-mcp-demo smoke | |
| 35 | −``` | |
| 36 | − | |
| 37 | −The smoke script starts the server, connects with an MCP client, lists resources, | |
| 38 | −reads a skill manifest, then reads `SKILL.md` and one support file. | |
| @@ -1,21 +0,0 @@ | ||
| 1 | −{ | |
| 2 | − "name": "@executor/serve-skills-via-mcp-demo", | |
| 3 | − "private": true, | |
| 4 | − "type": "module", | |
| 5 | − "exports": { | |
| 6 | − ".": "./src/index.ts" | |
| 7 | − }, | |
| 8 | − "scripts": { | |
| 9 | − "typecheck": "bunx tsc --noEmit -p tsconfig.json", | |
| 10 | − "start": "bun src/main.ts", | |
| 11 | − "smoke": "bun src/smoke.ts" | |
| 12 | − }, | |
| 13 | − "dependencies": { | |
| 14 | − "@modelcontextprotocol/sdk": "^1.26.0" | |
| 15 | − }, | |
| 16 | − "devDependencies": { | |
| 17 | − "@types/node": "catalog:", | |
| 18 | − "bun-types": "catalog:" | |
| 19 | − }, | |
| 20 | − "version": "0.0.0" | |
| 21 | −} | |
| @@ -1,28 +0,0 @@ | ||
| 1 | −--- | |
| 2 | −name: postgres-incident-triage | |
| 3 | −description: Triage production PostgreSQL incidents involving lock contention, slow queries, or saturation. Use when the user asks for database incident diagnosis or immediate next steps. | |
| 4 | −compatibility: Assumes SQL access to pg_stat_activity and pg_locks. | |
| 5 | −allowed-tools: Bash(psql:*) Read | |
| 6 | −--- | |
| 7 | − | |
| 8 | −# Postgres Incident Triage | |
| 9 | − | |
| 10 | −## When to use this skill | |
| 11 | − | |
| 12 | −Use this skill for live operational diagnosis of PostgreSQL incidents, especially when | |
| 13 | −latency spikes or blocked sessions appear. | |
| 14 | − | |
| 15 | −## Workflow | |
| 16 | − | |
| 17 | −1. Read `references/error-codes.md` for common failure patterns. | |
| 18 | −2. Use `scripts/blocked-session-query.sql` to inspect blockers and waiters. | |
| 19 | −3. Separate symptoms from root cause: CPU saturation, I/O pressure, lock chains, or | |
| 20 | − connection pileups. | |
| 21 | −4. Recommend the least-destructive mitigation first. | |
| 22 | −5. If proposing session termination, identify the blocker and expected blast radius. | |
| 23 | − | |
| 24 | −## Output rules | |
| 25 | − | |
| 26 | −- Summarize the current condition in one paragraph. | |
| 27 | −- List the most likely root causes in order. | |
| 28 | −- Provide immediate next commands before longer-term remediation. | |
| @@ -1,6 +0,0 @@ | ||
| 1 | −# Common PostgreSQL Incident Signals | |
| 2 | − | |
| 3 | −- `55P03` often points to lock contention or explicit lock timeouts. | |
| 4 | −- `53300` indicates too many connections. | |
| 5 | −- Long idle-in-transaction sessions are frequently the hidden blocker behind lock trees. | |
| 6 | −- A high count of active queries is not enough to prove saturation; check wait events. | |
| @@ -1,26 +0,0 @@ | ||
| 1 | −select | |
| 2 | − blocked.pid as blocked_pid, | |
| 3 | − blocked.query as blocked_query, | |
| 4 | − blocking.pid as blocking_pid, | |
| 5 | − blocking.query as blocking_query, | |
| 6 | − blocked.wait_event_type, | |
| 7 | − blocked.wait_event | |
| 8 | −from pg_stat_activity blocked | |
| 9 | −join pg_locks blocked_locks | |
| 10 | − on blocked.pid = blocked_locks.pid | |
| 11 | −join pg_locks blocking_locks | |
| 12 | − on blocked_locks.locktype = blocking_locks.locktype | |
| 13 | − and blocked_locks.database is not distinct from blocking_locks.database | |
| 14 | − and blocked_locks.relation is not distinct from blocking_locks.relation | |
| 15 | − and blocked_locks.page is not distinct from blocking_locks.page | |
| 16 | − and blocked_locks.tuple is not distinct from blocking_locks.tuple | |
| 17 | − and blocked_locks.virtualxid is not distinct from blocking_locks.virtualxid | |
| 18 | − and blocked_locks.transactionid is not distinct from blocking_locks.transactionid | |
| 19 | − and blocked_locks.classid is not distinct from blocking_locks.classid | |
| 20 | − and blocked_locks.objid is not distinct from blocking_locks.objid | |
| 21 | − and blocked_locks.objsubid is not distinct from blocking_locks.objsubid | |
| 22 | −join pg_stat_activity blocking | |
| 23 | − on blocking.pid = blocking_locks.pid | |
| 24 | −where not blocked_locks.granted | |
| 25 | − and blocking_locks.granted | |
| 26 | − and blocked.pid <> blocking.pid; | |
| @@ -1,28 +0,0 @@ | ||
| 1 | −--- | |
| 2 | −name: release-notes-writer | |
| 3 | −description: Draft product release notes from commits, changelogs, and issue summaries. Use when the user asks for release notes, launch notes, or upgrade summaries. | |
| 4 | −compatibility: Requires markdown output and access to bundled templates. | |
| 5 | −allowed-tools: Read Write | |
| 6 | −--- | |
| 7 | − | |
| 8 | −# Release Notes Writer | |
| 9 | − | |
| 10 | −## When to use this skill | |
| 11 | − | |
| 12 | −Use this skill when the user wants polished release notes, changelog summaries, or | |
| 13 | −customer-facing upgrade notes. | |
| 14 | − | |
| 15 | −## Workflow | |
| 16 | − | |
| 17 | −1. Read the release template in `assets/release-template.md`. | |
| 18 | −2. Read the voice and structure rules in `references/style-guide.md`. | |
| 19 | −3. Group changes into user-facing themes instead of commit-by-commit narration. | |
| 20 | −4. Prefer concrete impact statements over internal implementation details. | |
| 21 | −5. Call out breaking changes, migrations, and feature flags explicitly. | |
| 22 | − | |
| 23 | −## Output rules | |
| 24 | − | |
| 25 | −- Start with a short overview paragraph. | |
| 26 | −- Include sections only for categories that actually changed. | |
| 27 | −- End with a short rollout or migration note when relevant. | |
| 28 | −- Keep internal ticket IDs out of the final draft unless the user asked for them. | |
| @@ -1,16 +0,0 @@ | ||
| 1 | −# [Release Name] | |
| 2 | − | |
| 3 | −## Overview | |
| 4 | −[Two to four sentences describing the release in user language.] | |
| 5 | − | |
| 6 | −## New | |
| 7 | −- [New capability] | |
| 8 | − | |
| 9 | −## Improved | |
| 10 | −- [Improvement] | |
| 11 | − | |
| 12 | −## Fixed | |
| 13 | −- [Bug fix] | |
| 14 | − | |
| 15 | −## Upgrade Notes | |
| 16 | −- [Migration or rollout note if needed] | |
| @@ -1,7 +0,0 @@ | ||
| 1 | −# Release Notes Style Guide | |
| 2 | − | |
| 3 | −- Write for product users first, operators second, engineers last. | |
| 4 | −- Lead with outcomes: faster setup, clearer workflows, lower failure rates. | |
| 5 | −- Replace vague claims like "enhanced performance" with specific behavior changes. | |
| 6 | −- Mention removals and breaking changes directly instead of hiding them in "Improved". | |
| 7 | −- Keep bullets parallel and concrete. | |
| @@ -1,10 +0,0 @@ | ||
| 1 | −const requiredHeadings = [ | |
| 2 | − "## Overview", | |
| 3 | − "## New", | |
| 4 | − "## Improved", | |
| 5 | − "## Fixed", | |
| 6 | −]; | |
| 7 | − | |
| 8 | −for (const heading of requiredHeadings) { | |
| 9 | − console.log(`Expect heading: ${heading}`); | |
| 10 | −} | |
| @@ -1,243 +0,0 @@ | ||
| 1 | −import { readdir, readFile, stat } from "node:fs/promises"; | |
| 2 | −import { extname, join, posix, relative } from "node:path"; | |
| 3 | −import { fileURLToPath } from "node:url"; | |
| 4 | − | |
| 5 | −export type SkillFrontmatter = { | |
| 6 | − readonly name: string; | |
| 7 | − readonly description: string; | |
| 8 | − readonly compatibility?: string; | |
| 9 | − readonly license?: string; | |
| 10 | − readonly allowedTools?: string; | |
| 11 | −}; | |
| 12 | − | |
| 13 | −export type DistributedSkillFile = { | |
| 14 | − readonly path: string; | |
| 15 | − readonly uri: string; | |
| 16 | − readonly mimeType: string; | |
| 17 | − readonly size: number; | |
| 18 | − readonly role: "instructions" | "script" | "reference" | "asset" | "other"; | |
| 19 | −}; | |
| 20 | − | |
| 21 | −export type SkillManifest = { | |
| 22 | − readonly kind: "agent-skill-distribution"; | |
| 23 | − readonly publisher: string; | |
| 24 | − readonly version: string; | |
| 25 | − readonly skill: SkillFrontmatter; | |
| 26 | − readonly instructionsUri: string; | |
| 27 | − readonly manifestUri: string; | |
| 28 | − readonly fileTemplate: string; | |
| 29 | − readonly files: readonly DistributedSkillFile[]; | |
| 30 | −}; | |
| 31 | − | |
| 32 | −export type DistributedSkillBundle = { | |
| 33 | − readonly publisher: string; | |
| 34 | − readonly version: string; | |
| 35 | − readonly rootDir: string; | |
| 36 | − readonly skill: SkillFrontmatter; | |
| 37 | − readonly manifestUri: string; | |
| 38 | − readonly instructionsUri: string; | |
| 39 | − readonly fileTemplate: string; | |
| 40 | − readonly files: readonly DistributedSkillFile[]; | |
| 41 | − readonly manifest: SkillManifest; | |
| 42 | −}; | |
| 43 | − | |
| 44 | −const demoPublisher = "demo"; | |
| 45 | −const catalogUri = "skill://catalog/index.json"; | |
| 46 | −const fileTemplate = "skill://demo/{skill}/{version}/{+path}"; | |
| 47 | − | |
| 48 | −const bundleVersions = { | |
| 49 | − "postgres-incident-triage": "1.1.0", | |
| 50 | − "release-notes-writer": "1.0.0", | |
| 51 | −} as const; | |
| 52 | − | |
| 53 | −const skillsDir = fileURLToPath(new URL("../skills", import.meta.url)); | |
| 54 | − | |
| 55 | −const mimeTypeFor = (filePath: string): string => { | |
| 56 | − switch (extname(filePath)) { | |
| 57 | − case ".json": | |
| 58 | − return "application/json"; | |
| 59 | − case ".md": | |
| 60 | − return "text/markdown"; | |
| 61 | − case ".sql": | |
| 62 | − return "application/sql"; | |
| 63 | − case ".ts": | |
| 64 | − return "text/typescript"; | |
| 65 | − default: | |
| 66 | − return "text/plain"; | |
| 67 | − } | |
| 68 | −}; | |
| 69 | − | |
| 70 | −const roleFor = (filePath: string): DistributedSkillFile["role"] => { | |
| 71 | − if (filePath === "SKILL.md") { | |
| 72 | − return "instructions"; | |
| 73 | − } | |
| 74 | − if (filePath.startsWith("scripts/")) { | |
| 75 | − return "script"; | |
| 76 | − } | |
| 77 | − if (filePath.startsWith("references/")) { | |
| 78 | − return "reference"; | |
| 79 | − } | |
| 80 | − if (filePath.startsWith("assets/")) { | |
| 81 | − return "asset"; | |
| 82 | − } | |
| 83 | − return "other"; | |
| 84 | −}; | |
| 85 | − | |
| 86 | −const parseFrontmatter = (content: string): SkillFrontmatter => { | |
| 87 | − const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/u.exec(content); | |
| 88 | − if (!match) { | |
| 89 | − throw new Error("Expected SKILL.md to start with YAML frontmatter"); | |
| 90 | − } | |
| 91 | − | |
| 92 | − const fields: Record<string, string> = {}; | |
| 93 | − for (const line of match[1].split(/\r?\n/u)) { | |
| 94 | − const trimmed = line.trim(); | |
| 95 | − if (trimmed.length === 0 || trimmed.startsWith("#")) { | |
| 96 | − continue; | |
| 97 | − } | |
| 98 | − | |
| 99 | − const entry = /^([A-Za-z0-9-]+):\s*(.+)$/u.exec(trimmed); | |
| 100 | − if (!entry) { | |
| 101 | − continue; | |
| 102 | − } | |
| 103 | − | |
| 104 | − fields[entry[1]] = entry[2]; | |
| 105 | − } | |
| 106 | − | |
| 107 | − if (!fields.name || !fields.description) { | |
| 108 | − throw new Error("Expected SKILL.md frontmatter to include name and description"); | |
| 109 | − } | |
| 110 | − | |
| 111 | − return { | |
| 112 | − name: fields.name, | |
| 113 | − description: fields.description, | |
| 114 | − compatibility: fields.compatibility, | |
| 115 | − license: fields.license, | |
| 116 | − allowedTools: fields["allowed-tools"], | |
| 117 | − }; | |
| 118 | −}; | |
| 119 | − | |
| 120 | −const collectFiles = async (rootDir: string): Promise<string[]> => { | |
| 121 | − const output: string[] = []; | |
| 122 | − | |
| 123 | − const visit = async (directory: string) => { | |
| 124 | − const entries = await readdir(directory, { withFileTypes: true }); | |
| 125 | − entries.sort((left, right) => left.name.localeCompare(right.name)); | |
| 126 | − | |
| 127 | − for (const entry of entries) { | |
| 128 | − const absolutePath = join(directory, entry.name); | |
| 129 | − if (entry.isDirectory()) { | |
| 130 | − await visit(absolutePath); | |
| 131 | − continue; | |
| 132 | − } | |
| 133 | − output.push(posix.join(...relative(rootDir, absolutePath).split("\\").filter(Boolean))); | |
| 134 | − } | |
| 135 | − }; | |
| 136 | − | |
| 137 | − await visit(rootDir); | |
| 138 | − return output; | |
| 139 | −}; | |
| 140 | − | |
| 141 | −export const getCatalogUri = (): string => catalogUri; | |
| 142 | − | |
| 143 | −export const getFileTemplate = (): string => fileTemplate; | |
| 144 | − | |
| 145 | −export const loadDistributedSkillBundles = async (): Promise<readonly DistributedSkillBundle[]> => { | |
| 146 | − const bundles = await Promise.all( | |
| 147 | − Object.entries(bundleVersions).map(async ([directoryName, version]) => { | |
| 148 | − const rootDir = join(skillsDir, directoryName); | |
| 149 | − const skillContent = await readFile(join(rootDir, "SKILL.md"), "utf8"); | |
| 150 | − const skill = parseFrontmatter(skillContent); | |
| 151 | − const files = await collectFiles(rootDir); | |
| 152 | − | |
| 153 | − const distributedFiles = await Promise.all( | |
| 154 | − files.map(async (filePath) => { | |
| 155 | − const absolutePath = join(rootDir, filePath); | |
| 156 | − const fileStats = await stat(absolutePath); | |
| 157 | − return { | |
| 158 | − path: filePath, | |
| 159 | − uri: `skill://${demoPublisher}/${skill.name}/${version}/${filePath}`, | |
| 160 | − mimeType: mimeTypeFor(filePath), | |
| 161 | − size: fileStats.size, | |
| 162 | − role: roleFor(filePath), | |
| 163 | − } satisfies DistributedSkillFile; | |
| 164 | − }), | |
| 165 | − ); | |
| 166 | − | |
| 167 | − const manifestUri = `skill://${demoPublisher}/${skill.name}/${version}/manifest.json`; | |
| 168 | − const instructionsUri = `skill://${demoPublisher}/${skill.name}/${version}/SKILL.md`; | |
| 169 | − | |
| 170 | − const manifest: SkillManifest = { | |
| 171 | − kind: "agent-skill-distribution", | |
| 172 | − publisher: demoPublisher, | |
| 173 | − version, | |
| 174 | − skill, | |
| 175 | − instructionsUri, | |
| 176 | − manifestUri, | |
| 177 | − fileTemplate, | |
| 178 | − files: distributedFiles, | |
| 179 | − }; | |
| 180 | − | |
| 181 | − return { | |
| 182 | − publisher: demoPublisher, | |
| 183 | − version, | |
| 184 | − rootDir, | |
| 185 | − skill, | |
| 186 | − manifestUri, | |
| 187 | − instructionsUri, | |
| 188 | − fileTemplate, | |
| 189 | − files: distributedFiles, | |
| 190 | − manifest, | |
| 191 | − } satisfies DistributedSkillBundle; | |
| 192 | − }), | |
| 193 | − ); | |
| 194 | − | |
| 195 | − return bundles.sort((left, right) => left.skill.name.localeCompare(right.skill.name)); | |
| 196 | −}; | |
| 197 | − | |
| 198 | −export const renderCatalog = (bundles: readonly DistributedSkillBundle[]): string => | |
| 199 | − JSON.stringify( | |
| 200 | − { | |
| 201 | − kind: "agent-skill-catalog", | |
| 202 | − distributionMethod: "mcp-resources", | |
| 203 | − catalogUri, | |
| 204 | − fileTemplate, | |
| 205 | − activationGuidance: [ | |
| 206 | − "Use this catalog for discovery only.", | |
| 207 | − "Read a skill manifest next to find the concrete SKILL.md URI.", | |
| 208 | − "Load SKILL.md into the model only when the task matches the skill description.", | |
| 209 | − "Fetch support files from the manifest on demand.", | |
| 210 | − ], | |
| 211 | − skills: bundles.map((bundle) => ({ | |
| 212 | − name: bundle.skill.name, | |
| 213 | − description: bundle.skill.description, | |
| 214 | − version: bundle.version, | |
| 215 | − manifestUri: bundle.manifestUri, | |
| 216 | − instructionsUri: bundle.instructionsUri, | |
| 217 | − })), | |
| 218 | − }, | |
| 219 | − null, | |
| 220 | − 2, | |
| 221 | − ); | |
| 222 | − | |
| 223 | −export const findBundleByName = ( | |
| 224 | − bundles: readonly DistributedSkillBundle[], | |
| 225 | − skillName: string, | |
| 226 | −): DistributedSkillBundle | undefined => | |
| 227 | − bundles.find((bundle) => bundle.skill.name === skillName); | |
| 228 | − | |
| 229 | −export const findBundleFile = ( | |
| 230 | − bundles: readonly DistributedSkillBundle[], | |
| 231 | − skillName: string, | |
| 232 | − version: string, | |
| 233 | − filePath: string, | |
| 234 | −): DistributedSkillFile | undefined => | |
| 235 | − bundles | |
| 236 | − .find((bundle) => bundle.skill.name === skillName && bundle.version === version) | |
| 237 | − ?.files.find((file) => file.path === filePath); | |
| 238 | − | |
| 239 | −export const readBundleFileText = async ( | |
| 240 | − bundle: DistributedSkillBundle, | |
| 241 | − filePath: string, | |
| 242 | −): Promise<string> => | |
| 243 | − readFile(join(bundle.rootDir, filePath), "utf8"); | |
| @@ -1,4 +0,0 @@ | ||
| 1 | −export { | |
| 2 | − startServeSkillsViaMcpDemoServer, | |
| 3 | − type ServeSkillsViaMcpDemoServer, | |
| 4 | −} from "./server"; | |
| @@ -1,20 +0,0 @@ | ||
| 1 | −import { startServeSkillsViaMcpDemoServer } from "./server"; | |
| 2 | − | |
| 3 | −const host = process.env.HOST ?? "127.0.0.1"; | |
| 4 | −const port = process.env.PORT ? Number(process.env.PORT) : 58507; | |
| 5 | − | |
| 6 | −const server = await startServeSkillsViaMcpDemoServer({ host, port }); | |
| 7 | −console.error(`serve-skills-via-mcp listening on ${server.endpoint}`); | |
| 8 | − | |
| 9 | −const shutdown = async () => { | |
| 10 | − await server.close(); | |
| 11 | − process.exit(0); | |
| 12 | −}; | |
| 13 | − | |
| 14 | −process.once("SIGINT", () => { | |
| 15 | − void shutdown(); | |
| 16 | −}); | |
| 17 | − | |
| 18 | −process.once("SIGTERM", () => { | |
| 19 | − void shutdown(); | |
| 20 | −}); | |
| @@ -1,346 +0,0 @@ | ||
| 1 | −import { randomUUID } from "node:crypto"; | |
| 2 | −import type { Server as HttpServer } from "node:http"; | |
| 3 | − | |
| 4 | −import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js"; | |
| 5 | −import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; | |
| 6 | −import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; | |
| 7 | − | |
| 8 | −import { | |
| 9 | − type DistributedSkillBundle, | |
| 10 | − findBundleByName, | |
| 11 | − findBundleFile, | |
| 12 | − getCatalogUri, | |
| 13 | − getFileTemplate, | |
| 14 | − loadDistributedSkillBundles, | |
| 15 | − readBundleFileText, | |
| 16 | − renderCatalog, | |
| 17 | −} from "./catalog"; | |
| 18 | − | |
| 19 | −export type ServeSkillsViaMcpDemoServer = { | |
| 20 | − readonly endpoint: string; | |
| 21 | − readonly close: () => Promise<void>; | |
| 22 | −}; | |
| 23 | − | |
| 24 | −const registerSkillResources = ( | |
| 25 | − server: McpServer, | |
| 26 | − bundles: readonly DistributedSkillBundle[], | |
| 27 | −) => { | |
| 28 | − server.registerResource( | |
| 29 | − "skill-catalog", | |
| 30 | − getCatalogUri(), | |
| 31 | − { | |
| 32 | − title: "Distributed Agent Skills Catalog", | |
| 33 | − description: "Catalog of skill bundles exposed over MCP resources.", | |
| 34 | − mimeType: "application/json", | |
| 35 | − annotations: { | |
| 36 | − audience: ["assistant", "user"], | |
| 37 | − priority: 0.7, | |
| 38 | − }, | |
| 39 | − }, | |
| 40 | − async () => ({ | |
| 41 | − contents: [ | |
| 42 | − { | |
| 43 | − uri: getCatalogUri(), | |
| 44 | − mimeType: "application/json", | |
| 45 | − text: renderCatalog(bundles), | |
| 46 | − }, | |
| 47 | − ], | |
| 48 | − }), | |
| 49 | − ); | |
| 50 | − | |
| 51 | − for (const bundle of bundles) { | |
| 52 | − server.registerResource( | |
| 53 | − `${bundle.skill.name}-manifest`, | |
| 54 | − bundle.manifestUri, | |
| 55 | − { | |
| 56 | − title: `${bundle.skill.name} manifest`, | |
| 57 | − description: `Distribution manifest for ${bundle.skill.name}.`, | |
| 58 | − mimeType: "application/json", | |
| 59 | − annotations: { | |
| 60 | − audience: ["assistant"], | |
| 61 | − priority: 0.85, | |
| 62 | − }, | |
| 63 | − }, | |
| 64 | − async () => ({ | |
| 65 | − contents: [ | |
| 66 | − { | |
| 67 | − uri: bundle.manifestUri, | |
| 68 | − mimeType: "application/json", | |
| 69 | − text: JSON.stringify(bundle.manifest, null, 2), | |
| 70 | − }, | |
| 71 | − ], | |
| 72 | − }), | |
| 73 | − ); | |
| 74 | − | |
| 75 | − server.registerResource( | |
| 76 | − `${bundle.skill.name}-instructions`, | |
| 77 | − bundle.instructionsUri, | |
| 78 | − { | |
| 79 | − title: `${bundle.skill.name} SKILL.md`, | |
| 80 | − description: bundle.skill.description, | |
| 81 | − mimeType: "text/markdown", | |
| 82 | − annotations: { | |
| 83 | − audience: ["assistant"], | |
| 84 | − priority: 1, | |
| 85 | − }, | |
| 86 | − }, | |
| 87 | − async () => ({ | |
| 88 | − contents: [ | |
| 89 | − { | |
| 90 | − uri: bundle.instructionsUri, | |
| 91 | − mimeType: "text/markdown", | |
| 92 | − text: await readBundleFileText(bundle, "SKILL.md"), | |
| 93 | − }, | |
| 94 | − ], | |
| 95 | − }), | |
| 96 | − ); | |
| 97 | − } | |
| 98 | − | |
| 99 | − server.registerResource( | |
| 100 | − "skill-bundle-file", | |
| 101 | − new ResourceTemplate(getFileTemplate(), { | |
| 102 | − list: undefined, | |
| 103 | − complete: { | |
| 104 | − skill: (value) => | |
| 105 | − bundles | |
| 106 | − .map((bundle) => bundle.skill.name) | |
| 107 | − .filter((skillName) => skillName.startsWith(value)), | |
| 108 | − version: (value, context) => { | |
| 109 | − const skillName = context?.arguments?.skill; | |
| 110 | − if (!skillName) { | |
| 111 | − return bundles | |
| 112 | − .map((bundle) => bundle.version) | |
| 113 | − .filter((version) => version.startsWith(value)); | |
| 114 | − } | |
| 115 | − | |
| 116 | − const bundle = findBundleByName(bundles, skillName); | |
| 117 | − if (!bundle) { | |
| 118 | − return []; | |
| 119 | − } | |
| 120 | − | |
| 121 | − return bundle.version.startsWith(value) ? [bundle.version] : []; | |
| 122 | − }, | |
| 123 | − path: (value, context) => { | |
| 124 | − const skillName = context?.arguments?.skill; | |
| 125 | − const version = context?.arguments?.version; | |
| 126 | − if (!skillName || !version) { | |
| 127 | − return []; | |
| 128 | − } | |
| 129 | − | |
| 130 | − const bundle = bundles.find((entry) => | |
| 131 | − entry.skill.name === skillName && entry.version === version | |
| 132 | − ); | |
| 133 | − if (!bundle) { | |
| 134 | − return []; | |
| 135 | − } | |
| 136 | − | |
| 137 | − return bundle.files | |
| 138 | − .map((file) => file.path) | |
| 139 | − .filter((filePath) => filePath.startsWith(value)); | |
| 140 | − }, | |
| 141 | − }, | |
| 142 | − }), | |
| 143 | − { | |
| 144 | − title: "Skill bundle files", | |
| 145 | − description: "Read any file inside a distributed skill bundle.", | |
| 146 | − mimeType: "text/plain", | |
| 147 | − annotations: { | |
| 148 | − audience: ["assistant"], | |
| 149 | − priority: 0.5, | |
| 150 | − }, | |
| 151 | − }, | |
| 152 | − async (_uri, variables) => { | |
| 153 | − const skillName = typeof variables.skill === "string" ? variables.skill : undefined; | |
| 154 | − const version = typeof variables.version === "string" ? variables.version : undefined; | |
| 155 | − const filePath = typeof variables.path === "string" ? variables.path : undefined; | |
| 156 | − | |
| 157 | − if (!skillName || !version || !filePath) { | |
| 158 | − throw new Error("Expected skill, version, and path variables"); | |
| 159 | − } | |
| 160 | − | |
| 161 | − const bundle = bundles.find((entry) => | |
| 162 | − entry.skill.name === skillName && entry.version === version | |
| 163 | − ); | |
| 164 | − const file = findBundleFile(bundles, skillName, version, filePath); | |
| 165 | − if (!bundle || !file) { | |
| 166 | − throw new Error(`Unknown distributed skill file: ${skillName}@${version}/${filePath}`); | |
| 167 | − } | |
| 168 | − | |
| 169 | − return { | |
| 170 | − contents: [ | |
| 171 | − { | |
| 172 | − uri: file.uri, | |
| 173 | − mimeType: file.mimeType, | |
| 174 | − text: await readBundleFileText(bundle, filePath), | |
| 175 | − }, | |
| 176 | − ], | |
| 177 | − }; | |
| 178 | − }, | |
| 179 | − ); | |
| 180 | −}; | |
| 181 | − | |
| 182 | −const createSessionServer = (bundles: readonly DistributedSkillBundle[]): McpServer => { | |
| 183 | − const server = new McpServer( | |
| 184 | − { | |
| 185 | − name: "executor-serve-skills-via-mcp-demo", | |
| 186 | − version: "1.0.0", | |
| 187 | − }, | |
| 188 | − { | |
| 189 | − capabilities: { | |
| 190 | − resources: { | |
| 191 | − listChanged: true, | |
| 192 | − }, | |
| 193 | − }, | |
| 194 | − instructions: [ | |
| 195 | − "This server demonstrates one way to distribute Agent Skills over MCP resources.", | |
| 196 | − "Read the catalog and a skill manifest first, then load SKILL.md only when you decide to activate that skill.", | |
| 197 | − ].join(" "), | |
| 198 | − }, | |
| 199 | − ); | |
| 200 | − | |
| 201 | − registerSkillResources(server, bundles); | |
| 202 | − return server; | |
| 203 | −}; | |
| 204 | − | |
| 205 | −const resolveSessionId = (headers: Record<string, string | string[] | undefined>): string | undefined => { | |
| 206 | − const value = headers["mcp-session-id"]; | |
| 207 | − if (typeof value === "string") { | |
| 208 | − return value; | |
| 209 | − } | |
| 210 | − if (Array.isArray(value)) { | |
| 211 | − return value[0]; | |
| 212 | − } | |
| 213 | − return undefined; | |
| 214 | −}; | |
| 215 | − | |
| 216 | −const listen = async (app: ReturnType<typeof createMcpExpressApp>, port: number, host: string) => | |
| 217 | − new Promise<HttpServer>((resolve, reject) => { | |
| 218 | − const listener = app.listen(port, host); | |
| 219 | − | |
| 220 | − const onListening = () => { | |
| 221 | − listener.off("error", onError); | |
| 222 | − resolve(listener); | |
| 223 | − }; | |
| 224 | − | |
| 225 | − const onError = (error: Error) => { | |
| 226 | − listener.off("listening", onListening); | |
| 227 | − reject(error); | |
| 228 | − }; | |
| 229 | − | |
| 230 | − listener.once("listening", onListening); | |
| 231 | − listener.once("error", onError); | |
| 232 | − }); | |
| 233 | − | |
| 234 | −export const startServeSkillsViaMcpDemoServer = async (input: { | |
| 235 | − readonly host?: string; | |
| 236 | − readonly port?: number; | |
| 237 | −} = {}): Promise<ServeSkillsViaMcpDemoServer> => { | |
| 238 | − const host = input.host ?? "127.0.0.1"; | |
| 239 | − const bundles = await loadDistributedSkillBundles(); | |
| 240 | − const app = createMcpExpressApp({ host }); | |
| 241 | − const transports: Record<string, StreamableHTTPServerTransport> = {}; | |
| 242 | − const servers: Record<string, McpServer> = {}; | |
| 243 | − | |
| 244 | − app.post("/mcp", async (req: any, res: any) => { | |
| 245 | − const sessionId = resolveSessionId(req.headers); | |
| 246 | − | |
| 247 | − try { | |
| 248 | − let transport: StreamableHTTPServerTransport; | |
| 249 | − | |
| 250 | − if (sessionId && transports[sessionId]) { | |
| 251 | − transport = transports[sessionId]; | |
| 252 | − } else { | |
| 253 | − transport = new StreamableHTTPServerTransport({ | |
| 254 | − sessionIdGenerator: () => randomUUID(), | |
| 255 | − onsessioninitialized: (newSessionId) => { | |
| 256 | − transports[newSessionId] = transport; | |
| 257 | − }, | |
| 258 | − }); | |
| 259 | − | |
| 260 | − transport.onclose = () => { | |
| 261 | − const closedSessionId = transport.sessionId; | |
| 262 | − if (closedSessionId && transports[closedSessionId]) { | |
| 263 | − delete transports[closedSessionId]; | |
| 264 | − } | |
| 265 | − if (closedSessionId && servers[closedSessionId]) { | |
| 266 | − void servers[closedSessionId].close().catch(() => undefined); | |
| 267 | − delete servers[closedSessionId]; | |
| 268 | − } | |
| 269 | − }; | |
| 270 | − | |
| 271 | − const server = createSessionServer(bundles); | |
| 272 | − await server.connect(transport); | |
| 273 | − if (transport.sessionId) { | |
| 274 | − servers[transport.sessionId] = server; | |
| 275 | − } | |
| 276 | − } | |
| 277 | − | |
| 278 | − await transport.handleRequest(req, res, req.body); | |
| 279 | − } catch (error) { | |
| 280 | − if (!res.headersSent) { | |
| 281 | − res.status(500).json({ | |
| 282 | − jsonrpc: "2.0", | |
| 283 | − error: { | |
| 284 | − code: -32603, | |
| 285 | − message: error instanceof Error ? error.message : "Internal server error", | |
| 286 | − }, | |
| 287 | − id: null, | |
| 288 | − }); | |
| 289 | − } | |
| 290 | − } | |
| 291 | − }); | |
| 292 | − | |
| 293 | − app.get("/mcp", async (req: any, res: any) => { | |
| 294 | − const sessionId = resolveSessionId(req.headers); | |
| 295 | − if (!sessionId || !transports[sessionId]) { | |
| 296 | − res.status(400).send("Invalid or missing session ID"); | |
| 297 | − return; | |
| 298 | − } | |
| 299 | − | |
| 300 | − await transports[sessionId].handleRequest(req, res); | |
| 301 | − }); | |
| 302 | − | |
| 303 | − app.delete("/mcp", async (req: any, res: any) => { | |
| 304 | − const sessionId = resolveSessionId(req.headers); | |
| 305 | − if (!sessionId || !transports[sessionId]) { | |
| 306 | − res.status(400).send("Invalid or missing session ID"); | |
| 307 | − return; | |
| 308 | − } | |
| 309 | − | |
| 310 | − const transport = transports[sessionId]; | |
| 311 | − await transport.handleRequest(req, res, req.body); | |
| 312 | − await transport.close(); | |
| 313 | − delete transports[sessionId]; | |
| 314 | − | |
| 315 | − if (servers[sessionId]) { | |
| 316 | − await servers[sessionId].close().catch(() => undefined); | |
| 317 | − delete servers[sessionId]; | |
| 318 | − } | |
| 319 | − }); | |
| 320 | − | |
| 321 | − const listener = await listen(app, input.port ?? 0, host); | |
| 322 | − const address = listener.address(); | |
| 323 | − if (!address || typeof address === "string") { | |
| 324 | − await new Promise<void>((resolve, reject) => { | |
| 325 | − listener.close((error) => (error ? reject(error) : resolve())); | |
| 326 | − }); | |
| 327 | − throw new Error("Failed to resolve serve-skills-via-mcp demo address"); | |
| 328 | − } | |
| 329 | − | |
| 330 | − return { | |
| 331 | − endpoint: `http://${host}:${address.port}/mcp`, | |
| 332 | − close: async () => { | |
| 333 | − for (const transport of Object.values(transports)) { | |
| 334 | − await transport.close().catch(() => undefined); | |
| 335 | − } | |
| 336 | − | |
| 337 | − for (const server of Object.values(servers)) { | |
| 338 | − await server.close().catch(() => undefined); | |
| 339 | − } | |
| 340 | − | |
| 341 | − await new Promise<void>((resolve, reject) => { | |
| 342 | − listener.close((error) => (error ? reject(error) : resolve())); | |
| 343 | − }); | |
| 344 | − }, | |
| 345 | − }; | |
| 346 | −}; | |
| @@ -1,67 +0,0 @@ | ||
| 1 | −import { Client } from "@modelcontextprotocol/sdk/client/index.js"; | |
| 2 | −import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; | |
| 3 | − | |
| 4 | −import { startServeSkillsViaMcpDemoServer } from "./server"; | |
| 5 | − | |
| 6 | −const server = await startServeSkillsViaMcpDemoServer(); | |
| 7 | −const client = new Client({ | |
| 8 | − name: "serve-skills-via-mcp-smoke", | |
| 9 | − version: "1.0.0", | |
| 10 | −}); | |
| 11 | −const transport = new StreamableHTTPClientTransport(new URL(server.endpoint)); | |
| 12 | − | |
| 13 | −try { | |
| 14 | − await client.connect(transport); | |
| 15 | − | |
| 16 | − const resources = await client.listResources(); | |
| 17 | − console.log(`resources: ${resources.resources.length}`); | |
| 18 | − for (const resource of resources.resources) { | |
| 19 | − console.log(`- ${resource.uri}`); | |
| 20 | − } | |
| 21 | − | |
| 22 | − const templates = await client.listResourceTemplates(); | |
| 23 | − console.log(`resourceTemplates: ${templates.resourceTemplates.length}`); | |
| 24 | − for (const template of templates.resourceTemplates) { | |
| 25 | − console.log(`- ${template.uriTemplate}`); | |
| 26 | − } | |
| 27 | − | |
| 28 | − const catalog = await client.readResource({ uri: "skill://catalog/index.json" }); | |
| 29 | − const catalogText = "text" in catalog.contents[0]! ? catalog.contents[0]!.text : ""; | |
| 30 | − const parsedCatalog = JSON.parse(catalogText) as { | |
| 31 | − readonly skills: ReadonlyArray<{ | |
| 32 | − readonly name: string; | |
| 33 | − readonly manifestUri: string; | |
| 34 | − readonly instructionsUri: string; | |
| 35 | − }>; | |
| 36 | − }; | |
| 37 | − | |
| 38 | − const selectedSkill = parsedCatalog.skills[0]!; | |
| 39 | − console.log(`selectedSkill: ${selectedSkill.name}`); | |
| 40 | − | |
| 41 | − const manifest = await client.readResource({ uri: selectedSkill.manifestUri }); | |
| 42 | − const manifestText = "text" in manifest.contents[0]! ? manifest.contents[0]!.text : ""; | |
| 43 | − const parsedManifest = JSON.parse(manifestText) as { | |
| 44 | − readonly instructionsUri: string; | |
| 45 | − readonly files: ReadonlyArray<{ | |
| 46 | − readonly path: string; | |
| 47 | − readonly uri: string; | |
| 48 | − readonly role: string; | |
| 49 | − }>; | |
| 50 | − }; | |
| 51 | − | |
| 52 | − const instructions = await client.readResource({ uri: parsedManifest.instructionsUri }); | |
| 53 | − const instructionsText = "text" in instructions.contents[0]! ? instructions.contents[0]!.text : ""; | |
| 54 | − console.log(`instructionsPreview: ${instructionsText.split("\n").slice(0, 6).join("\n")}`); | |
| 55 | − | |
| 56 | − const supportFile = parsedManifest.files.find((file) => file.role !== "instructions"); | |
| 57 | − if (supportFile) { | |
| 58 | − const support = await client.readResource({ uri: supportFile.uri }); | |
| 59 | − const supportText = "text" in support.contents[0]! ? support.contents[0]!.text : ""; | |
| 60 | − console.log(`supportFile: ${supportFile.path}`); | |
| 61 | − console.log(`supportPreview: ${supportText.split("\n").slice(0, 4).join("\n")}`); | |
| 62 | − } | |
| 63 | −} finally { | |
| 64 | − await client.close().catch(() => undefined); | |
| 65 | − await transport.close().catch(() => undefined); | |
| 66 | − await server.close().catch(() => undefined); | |
| 67 | −} | |
| @@ -1,15 +0,0 @@ | ||
| 1 | −{ | |
| 2 | − "compilerOptions": { | |
| 3 | − "target": "ES2022", | |
| 4 | − "module": "ESNext", | |
| 5 | − "moduleResolution": "Bundler", | |
| 6 | − "strict": true, | |
| 7 | − "skipLibCheck": true, | |
| 8 | − "noEmit": true, | |
| 9 | − "lib": ["ES2022"], | |
| 10 | − "types": ["bun-types", "node"] | |
| 11 | − }, | |
| 12 | − "include": [ | |
| 13 | − "src/**/*.ts" | |
| 14 | − ] | |
| 15 | −} | |
| @@ -1 +0,0 @@ | ||
| 1 | −.data/ | |
| @@ -1,41 +0,0 @@ | ||
| 1 | −# SQLite SDK Consumer Example | |
| 2 | − | |
| 3 | −This example shows how an embedder can implement a custom SQLite-backed adapter | |
| 4 | −using the public Promise-facing `@executor/platform-sdk`. | |
| 5 | − | |
| 6 | −The adapter is intentionally simple: | |
| 7 | − | |
| 8 | −- installation state is stored in SQLite | |
| 9 | −- scope config and scope state are stored in SQLite | |
| 10 | −- source artifacts are stored in SQLite | |
| 11 | −- executor state is stored in SQLite | |
| 12 | −- secret material is stored in SQLite | |
| 13 | − | |
| 14 | −There is no direct `effect` usage in the example. | |
| 15 | − | |
| 16 | −## Run | |
| 17 | − | |
| 18 | −```sh | |
| 19 | −bun run --cwd examples/sqlite-sdk-consumer start | |
| 20 | −``` | |
| 21 | − | |
| 22 | −To keep the demo ephemeral: | |
| 23 | − | |
| 24 | −```sh | |
| 25 | −DATABASE_PATH=:memory: bun run --cwd examples/sqlite-sdk-consumer start | |
| 26 | −``` | |
| 27 | − | |
| 28 | −## Shape | |
| 29 | − | |
| 30 | −The important bit is the consumer-facing construction: | |
| 31 | − | |
| 32 | −```ts | |
| 33 | −import { createExecutor } from "@executor/platform-sdk"; | |
| 34 | −import { createSqliteExecutorBackend } from "@executor/sqlite-sdk-consumer-example"; | |
| 35 | − | |
| 36 | −const executor = await createExecutor({ | |
| 37 | − backend: createSqliteExecutorBackend({ | |
| 38 | − databasePath: "./executor.sqlite", | |
| 39 | − }), | |
| 40 | −}); | |
| 41 | −``` | |
| @@ -1,22 +0,0 @@ | ||
| 1 | −{ | |
| 2 | − "name": "@executor/sqlite-sdk-consumer-example", | |
| 3 | − "private": true, | |
| 4 | − "type": "module", | |
| 5 | − "exports": { | |
| 6 | − ".": "./src/index.ts" | |
| 7 | − }, | |
| 8 | − "scripts": { | |
| 9 | − "typecheck": "bunx tsc --noEmit -p tsconfig.json", | |
| 10 | − "start": "bun src/main.ts" | |
| 11 | − }, | |
| 12 | − "dependencies": { | |
| 13 | − "@executor/platform-sdk": "workspace:*", | |
| 14 | − "@executor/source-core": "workspace:*", | |
| 15 | − "drizzle-orm": "^0.44.5" | |
| 16 | − }, | |
| 17 | − "devDependencies": { | |
| 18 | − "@types/node": "catalog:", | |
| 19 | − "bun-types": "catalog:" | |
| 20 | − }, | |
| 21 | − "version": "0.0.0" | |
| 22 | −} | |
| @@ -1,4 +0,0 @@ | ||
| 1 | −export { | |
| 2 | − createSqliteExecutorBackend, | |
| 3 | − type CreateSqliteExecutorBackendOptions, | |
| 4 | −} from "./sqlite-backend"; | |
| @@ -1,54 +0,0 @@ | ||
| 1 | −import { createExecutor } from "@executor/platform-sdk"; | |
| 2 | − | |
| 3 | −import { createSqliteExecutorBackend } from "./sqlite-backend"; | |
| 4 | − | |
| 5 | −const databasePath = process.env.DATABASE_PATH | |
| 6 | − ?? new URL("../.data/executor.sqlite", import.meta.url).pathname; | |
| 7 | − | |
| 8 | −const executor = await createExecutor({ | |
| 9 | − backend: createSqliteExecutorBackend({ | |
| 10 | − databasePath, | |
| 11 | − }), | |
| 12 | −}); | |
| 13 | − | |
| 14 | −try { | |
| 15 | − const installation = await executor.local.installation(); | |
| 16 | − | |
| 17 | − const policy = await executor.policies.create({ | |
| 18 | − resourcePattern: "math.add", | |
| 19 | − effect: "allow", | |
| 20 | − approvalMode: "auto", | |
| 21 | − }); | |
| 22 | − | |
| 23 | − const secret = await executor.secrets.create({ | |
| 24 | − name: "demo-api-key", | |
| 25 | − value: "secret-value", | |
| 26 | − }); | |
| 27 | − | |
| 28 | − const execution = await executor.executions.create({ | |
| 29 | − code: "return 20 + 22;", | |
| 30 | − }); | |
| 31 | − | |
| 32 | − const sources = await executor.sources.list(); | |
| 33 | − const secrets = await executor.secrets.list(); | |
| 34 | − const policies = await executor.policies.list(); | |
| 35 | − | |
| 36 | − console.log(JSON.stringify({ | |
| 37 | − databasePath, | |
| 38 | − installation, | |
| 39 | − createdPolicyId: policy.id, | |
| 40 | − createdSecretId: secret.id, | |
| 41 | − execution: { | |
| 42 | − id: execution.execution.id, | |
| 43 | − status: execution.execution.status, | |
| 44 | − resultJson: execution.execution.resultJson, | |
| 45 | − }, | |
| 46 | − counts: { | |
| 47 | − sources: sources.length, | |
| 48 | − secrets: secrets.length, | |
| 49 | − policies: policies.length, | |
| 50 | − }, | |
| 51 | − }, null, 2)); | |
| 52 | −} finally { | |
| 53 | − await executor.close(); | |
| 54 | −} | |
| @@ -1,733 +0,0 @@ | ||
| 1 | −import { createHash, randomUUID } from "node:crypto"; | |
| 2 | −import { mkdirSync } from "node:fs"; | |
| 3 | −import { dirname, resolve as resolvePath } from "node:path"; | |
| 4 | − | |
| 5 | −import { Database } from "bun:sqlite"; | |
| 6 | −import { and, eq } from "drizzle-orm"; | |
| 7 | −import { drizzle } from "drizzle-orm/bun-sqlite"; | |
| 8 | −import { | |
| 9 | − integer, | |
| 10 | − sqliteTable, | |
| 11 | − text, | |
| 12 | −} from "drizzle-orm/sqlite-core"; | |
| 13 | − | |
| 14 | −import { | |
| 15 | − createExecutorBackend, | |
| 16 | − type ExecutorBackend, | |
| 17 | − type ExecutorBackendRepositories, | |
| 18 | − type ExecutorWorkspaceConfigRepository, | |
| 19 | − type ExecutorWorkspaceStateRepository, | |
| 20 | − type ExecutorWorkspaceSourceArtifactRepository, | |
| 21 | −} from "@executor/platform-sdk"; | |
| 22 | −import type { | |
| 23 | − Execution, | |
| 24 | − ExecutionInteraction, | |
| 25 | − ExecutionStep, | |
| 26 | − ExecutorScopeConfig, | |
| 27 | − LocalInstallation, | |
| 28 | − SecretMaterial, | |
| 29 | − SecretRef, | |
| 30 | − SecretStore, | |
| 31 | −} from "@executor/platform-sdk/schema"; | |
| 32 | −import { | |
| 33 | − ScopeIdSchema, | |
| 34 | − SecretMaterialIdSchema, | |
| 35 | − SourceCatalogIdSchema, | |
| 36 | − SourceCatalogRevisionIdSchema, | |
| 37 | −} from "@executor/platform-sdk/schema"; | |
| 38 | −import type { | |
| 39 | − SecretMaterialStoredDataRecord, | |
| 40 | −} from "@executor/platform-sdk/runtime"; | |
| 41 | −import { | |
| 42 | − contentHash, | |
| 43 | − snapshotFromSourceCatalogSyncResult, | |
| 44 | −} from "@executor/source-core"; | |
| 45 | − | |
| 46 | −export type CreateSqliteExecutorBackendOptions = { | |
| 47 | − databasePath?: string; | |
| 48 | − scopeId?: string; | |
| 49 | − actorScopeId?: string; | |
| 50 | −}; | |
| 51 | − | |
| 52 | −type ScopeConfig = Awaited<ReturnType<ExecutorWorkspaceConfigRepository["load"]>>; | |
| 53 | −type ScopeState = Awaited<ReturnType<ExecutorWorkspaceStateRepository["load"]>>; | |
| 54 | −type SourceArtifact = | |
| 55 | − ReturnType<ExecutorWorkspaceSourceArtifactRepository["build"]>; | |
| 56 | −type SourceArtifactBuildInput = Parameters< | |
| 57 | − ExecutorWorkspaceSourceArtifactRepository["build"] | |
| 58 | −>[0]; | |
| 59 | − | |
| 60 | −type SecretMaterialSummary = { | |
| 61 | − id: string; | |
| 62 | − storeId: string; | |
| 63 | − name: string | null; | |
| 64 | − purpose: string; | |
| 65 | − createdAt: number; | |
| 66 | − updatedAt: number; | |
| 67 | −}; | |
| 68 | − | |
| 69 | −type SqliteSecretStoredData = { | |
| 70 | − value: string; | |
| 71 | −}; | |
| 72 | − | |
| 73 | −const SQLITE_SECRET_STORE_KIND = "sqlite"; | |
| 74 | −const SQLITE_SECRET_STORE_ID = "sts_sqlite"; | |
| 75 | − | |
| 76 | −const installations = sqliteTable("installations", { | |
| 77 | − key: text("key").primaryKey(), | |
| 78 | − scopeId: text("scope_id").notNull(), | |
| 79 | − actorScopeId: text("actor_scope_id").notNull(), | |
| 80 | −}); | |
| 81 | − | |
| 82 | −const scopeConfigs = sqliteTable("scope_configs", { | |
| 83 | − key: text("key").primaryKey(), | |
| 84 | − projectConfigJson: text("project_config_json").notNull(), | |
| 85 | −}); | |
| 86 | − | |
| 87 | −const scopeStates = sqliteTable("scope_states", { | |
| 88 | − key: text("key").primaryKey(), | |
| 89 | − stateJson: text("state_json").notNull(), | |
| 90 | −}); | |
| 91 | − | |
| 92 | −const sourceArtifacts = sqliteTable("source_artifacts", { | |
| 93 | − sourceId: text("source_id").primaryKey(), | |
| 94 | − artifactJson: text("artifact_json").notNull(), | |
| 95 | −}); | |
| 96 | − | |
| 97 | −const secretMaterials = sqliteTable("secret_materials", { | |
| 98 | − id: text("id").primaryKey(), | |
| 99 | − storeId: text("store_id").notNull(), | |
| 100 | − name: text("name"), | |
| 101 | − purpose: text("purpose").notNull(), | |
| 102 | − createdAt: integer("created_at").notNull(), | |
| 103 | − updatedAt: integer("updated_at").notNull(), | |
| 104 | − json: text("json").notNull(), | |
| 105 | −}); | |
| 106 | − | |
| 107 | −const secretMaterialStoredData = sqliteTable("secret_material_stored_data", { | |
| 108 | − secretId: text("secret_id").primaryKey(), | |
| 109 | − json: text("json").notNull(), | |
| 110 | −}); | |
| 111 | − | |
| 112 | −const executions = sqliteTable("executions", { | |
| 113 | − id: text("id").primaryKey(), | |
| 114 | − scopeId: text("scope_id").notNull(), | |
| 115 | − json: text("json").notNull(), | |
| 116 | −}); | |
| 117 | − | |
| 118 | −const executionInteractions = sqliteTable("execution_interactions", { | |
| 119 | − id: text("id").primaryKey(), | |
| 120 | − executionId: text("execution_id").notNull(), | |
| 121 | − status: text("status").notNull(), | |
| 122 | − json: text("json").notNull(), | |
| 123 | −}); | |
| 124 | − | |
| 125 | −const executionSteps = sqliteTable("execution_steps", { | |
| 126 | − id: text("id").primaryKey(), | |
| 127 | − executionId: text("execution_id").notNull(), | |
| 128 | − sequence: integer("sequence").notNull(), | |
| 129 | − json: text("json").notNull(), | |
| 130 | −}); | |
| 131 | − | |
| 132 | −const makeHash = (value: string): string => | |
| 133 | − createHash("sha256").update(value).digest("hex").slice(0, 24); | |
| 134 | − | |
| 135 | −const parseJson = <T>(value: string): T => JSON.parse(value) as T; | |
| 136 | − | |
| 137 | −const createSourceArtifact = (input: SourceArtifactBuildInput): SourceArtifact => { | |
| 138 | − const snapshot = snapshotFromSourceCatalogSyncResult(input.syncResult); | |
| 139 | − const sourceConfigJson = JSON.stringify({ | |
| 140 | − kind: input.source.kind, | |
| 141 | − namespace: input.source.namespace, | |
| 142 | − name: input.source.name, | |
| 143 | − enabled: input.source.enabled, | |
| 144 | − }); | |
| 145 | − const importMetadataJson = JSON.stringify(snapshot.import); | |
| 146 | − const catalogId = SourceCatalogIdSchema.make(`src_catalog_${makeHash(sourceConfigJson)}`); | |
| 147 | − const revisionId = SourceCatalogRevisionIdSchema.make( | |
| 148 | − `src_catalog_rev_${makeHash(sourceConfigJson)}`, | |
| 149 | − ); | |
| 150 | − | |
| 151 | − return { | |
| 152 | − version: 4, | |
| 153 | − sourceId: input.source.id, | |
| 154 | − catalogId, | |
| 155 | − generatedAt: Date.now(), | |
| 156 | − revision: { | |
| 157 | − id: revisionId, | |
| 158 | − catalogId, | |
| 159 | − revisionNumber: 1, | |
| 160 | − sourceConfigJson, | |
| 161 | − importMetadataJson, | |
| 162 | − importMetadataHash: contentHash(importMetadataJson), | |
| 163 | − snapshotHash: contentHash(JSON.stringify(snapshot)), | |
| 164 | − createdAt: input.source.createdAt, | |
| 165 | − updatedAt: input.source.updatedAt, | |
| 166 | − }, | |
| 167 | − snapshot, | |
| 168 | − }; | |
| 169 | −}; | |
| 170 | − | |
| 171 | −const defaultScopeState = (): ScopeState => ({ | |
| 172 | − version: 1, | |
| 173 | − sources: {}, | |
| 174 | − policies: {}, | |
| 175 | −}); | |
| 176 | − | |
| 177 | −const createInstallation = ( | |
| 178 | − options: CreateSqliteExecutorBackendOptions, | |
| 179 | −): LocalInstallation => { | |
| 180 | − const scopeId = ScopeIdSchema.make(options.scopeId ?? "scope_sqlite_example"); | |
| 181 | − const actorScopeId = ScopeIdSchema.make( | |
| 182 | − options.actorScopeId ?? "account_sqlite_example", | |
| 183 | − ); | |
| 184 | − | |
| 185 | − return { | |
| 186 | − scopeId, | |
| 187 | − actorScopeId, | |
| 188 | − }; | |
| 189 | −}; | |
| 190 | − | |
| 191 | −const openSqliteStore = (databasePath: string) => { | |
| 192 | − if (databasePath !== ":memory:") { | |
| 193 | − mkdirSync(dirname(databasePath), { recursive: true }); | |
| 194 | − } | |
| 195 | − | |
| 196 | − const sqlite = new Database(databasePath, { create: true, strict: true }); | |
| 197 | − const db = drizzle(sqlite); | |
| 198 | − | |
| 199 | − sqlite.exec(` | |
| 200 | − CREATE TABLE IF NOT EXISTS installations ( | |
| 201 | − key TEXT PRIMARY KEY NOT NULL, | |
| 202 | − scope_id TEXT NOT NULL, | |
| 203 | − actor_scope_id TEXT NOT NULL | |
| 204 | − ); | |
| 205 | − | |
| 206 | − CREATE TABLE IF NOT EXISTS scope_configs ( | |
| 207 | − key TEXT PRIMARY KEY NOT NULL, | |
| 208 | − project_config_json TEXT NOT NULL | |
| 209 | − ); | |
| 210 | − | |
| 211 | − CREATE TABLE IF NOT EXISTS scope_states ( | |
| 212 | − key TEXT PRIMARY KEY NOT NULL, | |
| 213 | − state_json TEXT NOT NULL | |
| 214 | − ); | |
| 215 | − | |
| 216 | − CREATE TABLE IF NOT EXISTS source_artifacts ( | |
| 217 | − source_id TEXT PRIMARY KEY NOT NULL, | |
| 218 | − artifact_json TEXT NOT NULL | |
| 219 | − ); | |
| 220 | − | |
| 221 | − CREATE TABLE IF NOT EXISTS secret_materials ( | |
| 222 | − id TEXT PRIMARY KEY NOT NULL, | |
| 223 | − store_id TEXT NOT NULL, | |
| 224 | − name TEXT, | |
| 225 | − purpose TEXT NOT NULL, | |
| 226 | − created_at INTEGER NOT NULL, | |
| 227 | − updated_at INTEGER NOT NULL, | |
| 228 | − json TEXT NOT NULL | |
| 229 | − ); | |
| 230 | − | |
| 231 | − CREATE TABLE IF NOT EXISTS secret_material_stored_data ( | |
| 232 | − secret_id TEXT PRIMARY KEY NOT NULL, | |
| 233 | − json TEXT NOT NULL | |
| 234 | − ); | |
| 235 | − | |
| 236 | − CREATE TABLE IF NOT EXISTS executions ( | |
| 237 | − id TEXT PRIMARY KEY NOT NULL, | |
| 238 | − scope_id TEXT NOT NULL, | |
| 239 | − json TEXT NOT NULL | |
| 240 | − ); | |
| 241 | − | |
| 242 | − CREATE TABLE IF NOT EXISTS execution_interactions ( | |
| 243 | − id TEXT PRIMARY KEY NOT NULL, | |
| 244 | − execution_id TEXT NOT NULL, | |
| 245 | − status TEXT NOT NULL, | |
| 246 | − json TEXT NOT NULL | |
| 247 | − ); | |
| 248 | − | |
| 249 | − CREATE TABLE IF NOT EXISTS execution_steps ( | |
| 250 | − id TEXT PRIMARY KEY NOT NULL, | |
| 251 | − execution_id TEXT NOT NULL, | |
| 252 | − sequence INTEGER NOT NULL, | |
| 253 | − json TEXT NOT NULL | |
| 254 | − ); | |
| 255 | − `); | |
| 256 | − | |
| 257 | − return { | |
| 258 | − sqlite, | |
| 259 | − db, | |
| 260 | − close: () => { | |
| 261 | − sqlite.close(); | |
| 262 | − }, | |
| 263 | − }; | |
| 264 | −}; | |
| 265 | − | |
| 266 | −type SqliteStore = ReturnType<typeof openSqliteStore>; | |
| 267 | − | |
| 268 | −const createStorageDomains = ( | |
| 269 | − store: SqliteStore, | |
| 270 | − installation: LocalInstallation, | |
| 271 | −) => ({ | |
| 272 | − secrets: { | |
| 273 | − secretStores: { | |
| 274 | − getById: (id: SecretStore["id"]) => | |
| 275 | − id === SQLITE_SECRET_STORE_ID | |
| 276 | − ? { | |
| 277 | − id: SQLITE_SECRET_STORE_ID as SecretStore["id"], | |
| 278 | − scopeId: installation.scopeId, | |
| 279 | − kind: SQLITE_SECRET_STORE_KIND, | |
| 280 | − name: "SQLite Store", | |
| 281 | − status: "connected" as const, | |
| 282 | − enabled: true, | |
| 283 | − createdAt: 0, | |
| 284 | − updatedAt: 0, | |
| 285 | − } | |
| 286 | − : null, | |
| 287 | − listAll: () => [{ | |
| 288 | − id: SQLITE_SECRET_STORE_ID, | |
| 289 | − scopeId: installation.scopeId, | |
| 290 | − kind: SQLITE_SECRET_STORE_KIND, | |
| 291 | − name: "SQLite Store", | |
| 292 | − status: "connected", | |
| 293 | − enabled: true, | |
| 294 | − createdAt: 0, | |
| 295 | − updatedAt: 0, | |
| 296 | − }], | |
| 297 | − upsert: (_secretStore: SecretStore) => {}, | |
| 298 | − updateById: (_id: SecretStore["id"], _update: Partial<Pick<SecretStore, "name" | "status" | "enabled">>) => null, | |
| 299 | − removeById: (_id: SecretStore["id"]) => false, | |
| 300 | − }, | |
| 301 | − getById: (id: SecretMaterial["id"]) => { | |
| 302 | − const row = store.db.select().from(secretMaterials).where(eq(secretMaterials.id, id)).get(); | |
| 303 | − return row ? parseJson<SecretMaterial>(row.json) : null; | |
| 304 | − }, | |
| 305 | − listAll: (): readonly SecretMaterialSummary[] => | |
| 306 | − store.db.select().from(secretMaterials).all().map((row) => ({ | |
| 307 | − id: row.id, | |
| 308 | − storeId: row.storeId, | |
| 309 | − name: row.name, | |
| 310 | − purpose: row.purpose, | |
| 311 | − createdAt: row.createdAt, | |
| 312 | − updatedAt: row.updatedAt, | |
| 313 | − })), | |
| 314 | − upsert: (material: SecretMaterial) => | |
| 315 | − store.db.insert(secretMaterials).values({ | |
| 316 | − id: material.id, | |
| 317 | − storeId: material.storeId, | |
| 318 | − name: material.name, | |
| 319 | − purpose: material.purpose, | |
| 320 | − createdAt: material.createdAt, | |
| 321 | − updatedAt: material.updatedAt, | |
| 322 | − json: JSON.stringify(material), | |
| 323 | − }).onConflictDoUpdate({ | |
| 324 | − target: secretMaterials.id, | |
| 325 | − set: { | |
| 326 | − storeId: material.storeId, | |
| 327 | − name: material.name, | |
| 328 | − purpose: material.purpose, | |
| 329 | − createdAt: material.createdAt, | |
| 330 | − updatedAt: material.updatedAt, | |
| 331 | − json: JSON.stringify(material), | |
| 332 | − }, | |
| 333 | − }).run(), | |
| 334 | − updateById: ( | |
| 335 | − id: SecretMaterial["id"], | |
| 336 | − update: { name?: string | null }, | |
| 337 | − ) => { | |
| 338 | − const row = store.db.select().from(secretMaterials).where(eq(secretMaterials.id, id)).get(); | |
| 339 | − if (!row) return null; | |
| 340 | − const current = parseJson<SecretMaterial>(row.json); | |
| 341 | − const next = { | |
| 342 | − ...current, | |
| 343 | − name: update.name === undefined ? current.name : update.name, | |
| 344 | − updatedAt: Date.now(), | |
| 345 | − }; | |
| 346 | − store.db.update(secretMaterials).set({ | |
| 347 | − storeId: next.storeId, | |
| 348 | − name: next.name, | |
| 349 | − purpose: next.purpose, | |
| 350 | − createdAt: next.createdAt, | |
| 351 | − updatedAt: next.updatedAt, | |
| 352 | − json: JSON.stringify(next), | |
| 353 | − }).where(eq(secretMaterials.id, id)).run(); | |
| 354 | − return { | |
| 355 | − id: next.id, | |
| 356 | − storeId: next.storeId, | |
| 357 | − name: next.name, | |
| 358 | − purpose: next.purpose, | |
| 359 | − createdAt: next.createdAt, | |
| 360 | − updatedAt: next.updatedAt, | |
| 361 | − } satisfies SecretMaterialSummary; | |
| 362 | − }, | |
| 363 | − removeById: (id: SecretMaterial["id"]) => { | |
| 364 | − const row = store.db.select({ id: secretMaterials.id }).from(secretMaterials).where( | |
| 365 | − eq(secretMaterials.id, id), | |
| 366 | − ).get(); | |
| 367 | − if (!row) return false; | |
| 368 | − store.db.delete(secretMaterials).where(eq(secretMaterials.id, id)).run(); | |
| 369 | − return true; | |
| 370 | − }, | |
| 371 | − secretMaterialStoredData: { | |
| 372 | − getBySecretId: (secretId: SecretMaterial["id"]) => { | |
| 373 | − const row = store.db.select().from(secretMaterialStoredData).where( | |
| 374 | − eq(secretMaterialStoredData.secretId, secretId), | |
| 375 | − ).get(); | |
| 376 | − return row | |
| 377 | − ? { | |
| 378 | − secretId, | |
| 379 | − data: parseJson<SqliteSecretStoredData>(row.json), | |
| 380 | − } | |
| 381 | − : null; | |
| 382 | − }, | |
| 383 | − upsert: (record: SecretMaterialStoredDataRecord) => { | |
| 384 | − store.db.insert(secretMaterialStoredData).values({ | |
| 385 | − secretId: record.secretId, | |
| 386 | − json: JSON.stringify(record.data), | |
| 387 | − }).onConflictDoUpdate({ | |
| 388 | − target: secretMaterialStoredData.secretId, | |
| 389 | − set: { | |
| 390 | − json: JSON.stringify(record.data), | |
| 391 | − }, | |
| 392 | − }).run(); | |
| 393 | − }, | |
| 394 | − removeBySecretId: (secretId: SecretMaterial["id"]) => { | |
| 395 | − const row = store.db.select({ secretId: secretMaterialStoredData.secretId }).from( | |
| 396 | − secretMaterialStoredData, | |
| 397 | − ).where(eq(secretMaterialStoredData.secretId, secretId)).get(); | |
| 398 | − if (!row) return false; | |
| 399 | − store.db.delete(secretMaterialStoredData).where( | |
| 400 | − eq(secretMaterialStoredData.secretId, secretId), | |
| 401 | − ).run(); | |
| 402 | − return true; | |
| 403 | − }, | |
| 404 | − }, | |
| 405 | − }, | |
| 406 | − executions: { | |
| 407 | − runs: { | |
| 408 | − listByScope: (scopeId: Execution["scopeId"]) => | |
| 409 | − store.db.select().from(executions).where( | |
| 410 | − eq(executions.scopeId, scopeId), | |
| 411 | − ).all() | |
| 412 | − .map((row) => parseJson<Execution>(row.json)) | |
| 413 | − .sort((left, right) => right.createdAt - left.createdAt), | |
| 414 | − getById: (executionId: Execution["id"]) => { | |
| 415 | − const row = store.db.select().from(executions).where(eq(executions.id, executionId)).get(); | |
| 416 | − return row ? parseJson<Execution>(row.json) : null; | |
| 417 | − }, | |
| 418 | − getByScopeAndId: ( | |
| 419 | − scopeId: Execution["scopeId"], | |
| 420 | − executionId: Execution["id"], | |
| 421 | − ) => { | |
| 422 | − const row = store.db.select().from(executions).where( | |
| 423 | − and(eq(executions.scopeId, scopeId), eq(executions.id, executionId)), | |
| 424 | − ).get(); | |
| 425 | − return row ? parseJson<Execution>(row.json) : null; | |
| 426 | − }, | |
| 427 | − insert: (execution: Execution) => | |
| 428 | − store.db.insert(executions).values({ | |
| 429 | − id: execution.id, | |
| 430 | − scopeId: execution.scopeId, | |
| 431 | − json: JSON.stringify(execution), | |
| 432 | − }).run(), | |
| 433 | − update: ( | |
| 434 | − executionId: Execution["id"], | |
| 435 | − patch: Partial<Omit<Execution, "id" | "scopeId" | "createdByScopeId" | "createdAt">>, | |
| 436 | − ) => { | |
| 437 | − const row = store.db.select().from(executions).where(eq(executions.id, executionId)).get(); | |
| 438 | − if (!row) return null; | |
| 439 | − const next = { ...parseJson<Execution>(row.json), ...patch }; | |
| 440 | − store.db.update(executions).set({ | |
| 441 | − scopeId: next.scopeId, | |
| 442 | − json: JSON.stringify(next), | |
| 443 | − }).where(eq(executions.id, executionId)).run(); | |
| 444 | − return next; | |
| 445 | − }, | |
| 446 | − }, | |
| 447 | − interactions: { | |
| 448 | − getById: (interactionId: ExecutionInteraction["id"]) => { | |
| 449 | − const row = store.db.select().from(executionInteractions).where( | |
| 450 | − eq(executionInteractions.id, interactionId), | |
| 451 | − ).get(); | |
| 452 | − return row ? parseJson<ExecutionInteraction>(row.json) : null; | |
| 453 | − }, | |
| 454 | − listByExecutionId: (executionId: ExecutionInteraction["executionId"]) => | |
| 455 | − store.db.select().from(executionInteractions).where( | |
| 456 | − eq(executionInteractions.executionId, executionId), | |
| 457 | − ).all().map((row) => parseJson<ExecutionInteraction>(row.json)), | |
| 458 | − getPendingByExecutionId: (executionId: ExecutionInteraction["executionId"]) => { | |
| 459 | − const row = store.db.select().from(executionInteractions).where( | |
| 460 | − and( | |
| 461 | − eq(executionInteractions.executionId, executionId), | |
| 462 | − eq(executionInteractions.status, "pending"), | |
| 463 | − ), | |
| 464 | − ).get(); | |
| 465 | − return row ? parseJson<ExecutionInteraction>(row.json) : null; | |
| 466 | − }, | |
| 467 | − insert: (interaction: ExecutionInteraction) => | |
| 468 | − store.db.insert(executionInteractions).values({ | |
| 469 | − id: interaction.id, | |
| 470 | − executionId: interaction.executionId, | |
| 471 | − status: interaction.status, | |
| 472 | − json: JSON.stringify(interaction), | |
| 473 | − }).run(), | |
| 474 | − update: ( | |
| 475 | − interactionId: ExecutionInteraction["id"], | |
| 476 | − patch: Partial<Omit<ExecutionInteraction, "id" | "executionId" | "createdAt">>, | |
| 477 | − ) => { | |
| 478 | − const row = store.db.select().from(executionInteractions).where( | |
| 479 | − eq(executionInteractions.id, interactionId), | |
| 480 | − ).get(); | |
| 481 | − if (!row) return null; | |
| 482 | − const next = { ...parseJson<ExecutionInteraction>(row.json), ...patch }; | |
| 483 | − store.db.update(executionInteractions).set({ | |
| 484 | − executionId: next.executionId, | |
| 485 | − status: next.status, | |
| 486 | − json: JSON.stringify(next), | |
| 487 | − }).where(eq(executionInteractions.id, interactionId)).run(); | |
| 488 | − return next; | |
| 489 | − }, | |
| 490 | − }, | |
| 491 | − steps: { | |
| 492 | − getByExecutionAndSequence: ( | |
| 493 | − executionId: ExecutionStep["executionId"], | |
| 494 | − sequence: ExecutionStep["sequence"], | |
| 495 | − ) => { | |
| 496 | − const row = store.db.select().from(executionSteps).where( | |
| 497 | − and( | |
| 498 | − eq(executionSteps.executionId, executionId), | |
| 499 | − eq(executionSteps.sequence, sequence), | |
| 500 | − ), | |
| 501 | − ).get(); | |
| 502 | − return row ? parseJson<ExecutionStep>(row.json) : null; | |
| 503 | − }, | |
| 504 | − listByExecutionId: (executionId: ExecutionStep["executionId"]) => | |
| 505 | − store.db.select().from(executionSteps).where( | |
| 506 | − eq(executionSteps.executionId, executionId), | |
| 507 | − ).orderBy(executionSteps.sequence).all().map((row) => parseJson<ExecutionStep>(row.json)), | |
| 508 | − insert: (step: ExecutionStep) => | |
| 509 | − store.db.insert(executionSteps).values({ | |
| 510 | − id: step.id, | |
| 511 | − executionId: step.executionId, | |
| 512 | − sequence: step.sequence, | |
| 513 | − json: JSON.stringify(step), | |
| 514 | − }).run(), | |
| 515 | − deleteByExecutionId: (executionId: ExecutionStep["executionId"]) => { | |
| 516 | − store.db.delete(executionSteps).where(eq(executionSteps.executionId, executionId)).run(); | |
| 517 | − }, | |
| 518 | − updateByExecutionAndSequence: ( | |
| 519 | − executionId: ExecutionStep["executionId"], | |
| 520 | − sequence: ExecutionStep["sequence"], | |
| 521 | − patch: Partial<Omit<ExecutionStep, "id" | "executionId" | "sequence" | "createdAt">>, | |
| 522 | − ) => { | |
| 523 | − const row = store.db.select().from(executionSteps).where( | |
| 524 | − and( | |
| 525 | − eq(executionSteps.executionId, executionId), | |
| 526 | − eq(executionSteps.sequence, sequence), | |
| 527 | − ), | |
| 528 | − ).get(); | |
| 529 | − if (!row) return null; | |
| 530 | − const next = { ...parseJson<ExecutionStep>(row.json), ...patch }; | |
| 531 | − store.db.update(executionSteps).set({ | |
| 532 | − id: next.id, | |
| 533 | − executionId: next.executionId, | |
| 534 | − sequence: next.sequence, | |
| 535 | − json: JSON.stringify(next), | |
| 536 | − }).where(eq(executionSteps.id, row.id)).run(); | |
| 537 | − return next; | |
| 538 | − }, | |
| 539 | − }, | |
| 540 | − }, | |
| 541 | −}); | |
| 542 | − | |
| 543 | −export const createSqliteExecutorBackend = ( | |
| 544 | − options: CreateSqliteExecutorBackendOptions = {}, | |
| 545 | −): ExecutorBackend => { | |
| 546 | − const databasePath = options.databasePath && options.databasePath !== ":memory:" | |
| 547 | − ? resolvePath(options.databasePath) | |
| 548 | − : (options.databasePath ?? ":memory:"); | |
| 549 | − | |
| 550 | − return createExecutorBackend({ | |
| 551 | − loadRepositories: () => { | |
| 552 | − const store = openSqliteStore(databasePath); | |
| 553 | − const installation = (() => { | |
| 554 | − const row = store.db.select().from(installations).where(eq(installations.key, "active")).get(); | |
| 555 | − return row | |
| 556 | − ? { | |
| 557 | − scopeId: row.scopeId as LocalInstallation["scopeId"], | |
| 558 | − actorScopeId: row.actorScopeId as LocalInstallation["actorScopeId"], | |
| 559 | − } | |
| 560 | − : createInstallation(options); | |
| 561 | − })(); | |
| 562 | − const { secrets, executions } = createStorageDomains(store, installation); | |
| 563 | − | |
| 564 | − return { | |
| 565 | − scope: { | |
| 566 | − metadata: { | |
| 567 | − kind: "sqlite", | |
| 568 | − databasePath, | |
| 569 | − }, | |
| 570 | − }, | |
| 571 | − installation: { | |
| 572 | − load: () => { | |
| 573 | − return installation; | |
| 574 | − }, | |
| 575 | − getOrProvision: () => { | |
| 576 | − store.db.insert(installations).values({ | |
| 577 | − key: "active", | |
| 578 | − scopeId: installation.scopeId, | |
| 579 | − actorScopeId: installation.actorScopeId, | |
| 580 | − }).onConflictDoUpdate({ | |
| 581 | − target: installations.key, | |
| 582 | − set: { | |
| 583 | − scopeId: installation.scopeId, | |
| 584 | − actorScopeId: installation.actorScopeId, | |
| 585 | − }, | |
| 586 | − }).run(); | |
| 587 | − return installation; | |
| 588 | − }, | |
| 589 | − }, | |
| 590 | − workspace: { | |
| 591 | − config: { | |
| 592 | − load: () => { | |
| 593 | − const row = store.db.select().from(scopeConfigs).where(eq(scopeConfigs.key, "project")).get(); | |
| 594 | − const projectConfig = row | |
| 595 | − ? parseJson<ExecutorScopeConfig>(row.projectConfigJson) | |
| 596 | − : {}; | |
| 597 | − return { | |
| 598 | − config: projectConfig, | |
| 599 | − homeConfig: null, | |
| 600 | − projectConfig, | |
| 601 | − } satisfies ScopeConfig; | |
| 602 | − }, | |
| 603 | − writeProject: (config) => { | |
| 604 | − store.db.insert(scopeConfigs).values({ | |
| 605 | − key: "project", | |
| 606 | − projectConfigJson: JSON.stringify(config), | |
| 607 | − }).onConflictDoUpdate({ | |
| 608 | − target: scopeConfigs.key, | |
| 609 | − set: { projectConfigJson: JSON.stringify(config) }, | |
| 610 | − }).run(); | |
| 611 | − }, | |
| 612 | − }, | |
| 613 | − state: { | |
| 614 | − load: () => { | |
119 more lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 445 lines aren’t shown here.
This diff is large: its 211 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 136 lines aren’t shown here.
This diff is large: its 154 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 429 lines aren’t shown here.
This diff is large: its 147 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 199 lines aren’t shown here.
This diff is large: its 919 lines aren’t shown here.
This diff is large: its 138 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 165 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 212 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 106 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 109 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 137 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 191 lines aren’t shown here.
This diff is large: its 305 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 128 lines aren’t shown here.
This diff is large: its 173 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
File renamed without changes.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 257 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 230 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 134 lines aren’t shown here.
This diff is large: its 202 lines aren’t shown here.
This diff is large: its 683 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 336 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 184 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 187 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 215 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
File renamed without changes.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 262 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 177 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 215 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 104 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 135 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 667 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 212 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 487 lines aren’t shown here.
This diff is large: its 165 lines aren’t shown here.
This diff is large: its 685 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 133 lines aren’t shown here.
This diff is large: its 99 lines aren’t shown here.
This diff is large: its 250 lines aren’t shown here.
This diff is large: its 248 lines aren’t shown here.
This diff is large: its 550 lines aren’t shown here.
This diff is large: its 319 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 896 lines aren’t shown here.
This diff is large: its 1430 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 920 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 86 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 206 lines aren’t shown here.
This diff is large: its 598 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 442 lines aren’t shown here.
This diff is large: its 86 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 240 lines aren’t shown here.
This diff is large: its 183 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 128 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 375 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 190 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 540 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 391 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 106 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 232 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 357 lines aren’t shown here.
This diff is large: its 703 lines aren’t shown here.
This diff is large: its 427 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 101 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 99 lines aren’t shown here.
This diff is large: its 503 lines aren’t shown here.
This diff is large: its 171 lines aren’t shown here.
This diff is large: its 428 lines aren’t shown here.
This diff is large: its 644 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 273 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 503 lines aren’t shown here.
This diff is large: its 176 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 445 lines aren’t shown here.
This diff is large: its 242 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 1629 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 430 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 3295 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 1265 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 115 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 1324 lines aren’t shown here.
This diff is large: its 296 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 177 lines aren’t shown here.
This diff is large: its 86 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 279 lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 176 lines aren’t shown here.
This diff is large: its 191 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 325 lines aren’t shown here.
This diff is large: its 395 lines aren’t shown here.
This diff is large: its 298 lines aren’t shown here.
This diff is large: its 1025 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 163 lines aren’t shown here.
This diff is large: its 8315 lines aren’t shown here.
This diff is large: its 129478 lines aren’t shown here.
This diff is large: its 14359 lines aren’t shown here.
This diff is larger than a page shows: the files after these aren’t listed. Clone the repository to see all of it.