pi-meta-oauth 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 BlockedPath
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.
package/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # pi-meta-oauth
2
+
3
+ Meta Model API OAuth provider for [pi](https://pi.dev) — use **Muse Spark** (`muse-spark-1.2`, `muse-spark-1.2-contributor`, `muse-spark-1.1`) via `openai-responses` inside pi.
4
+
5
+ - Device authorization (same client as Muse Code) against `https://auth.meta.com`
6
+ - Mints a Model API key via `POST https://api.meta.ai/muse-code/key`
7
+ - Stores OAuth `refresh = identity token` + `access = Model API key` in `~/.pi/agent/auth.json` under provider `meta`
8
+ - Refresh re-mints the Model API key daily
9
+ - Model catalog from `GET https://api.meta.ai/v1/models` with thinking levels `minimal/low/medium/high/xhigh`
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ # local path (no publish needed)
15
+ pi install ./pi-meta-provider
16
+ # or npm (after publish)
17
+ pi install npm:pi-meta-oauth
18
+
19
+ pi --list-models meta
20
+ ```
21
+
22
+ ## Login
23
+
24
+ ```bash
25
+ pi
26
+ /login meta
27
+ # shows device code -> approve in browser -> mints Model API key automatically
28
+ ```
29
+
30
+ Stored credential shape:
31
+
32
+ ```json
33
+ { "meta": { "type": "oauth", "refresh": "<identity>", "access": "<MODEL_API_KEY>", "expires": 123 } }
34
+ ```
35
+
36
+ ## Models
37
+
38
+ All three share 1,048,576 context, 256K output, `supportsReasoningEffort: true`, and `input: ["text","image"]`:
39
+
40
+ | id | pricing (input/output/cached) $/M |
41
+ |---|---|
42
+ | `muse-spark-1.2` | 1.25 / 4.25 / 0.15 |
43
+ | `muse-spark-1.2-contributor` | 0.10 / 0.20 / 0.002 |
44
+ | `muse-spark-1.1` | 1.25 / 4.25 / 0.15 |
45
+
46
+ Add to `enabledModels` in `~/.pi/agent/settings.json`:
47
+
48
+ ```json
49
+ { "enabledModels": ["meta/*"] }
50
+ ```
51
+
52
+ ## Verify
53
+
54
+ ```bash
55
+ pi --list-models meta
56
+ pi -p --provider meta --model muse-spark-1.2 "Reply exactly: META_OK"
57
+ bun test extensions/meta.test.ts
58
+ ```
59
+
60
+ ## Publish to pi.dev
61
+
62
+ `pi-package` keyword makes it appear at https://pi.dev/packages
63
+
64
+ ```bash
65
+ npm publish --access public
66
+ # users then run: pi install npm:pi-meta-oauth
67
+ ```
68
+
69
+ See `extensions/meta.ts` for the `registerProvider` / `refreshModels` / `oauth` implementation reused from Muse Code's launcher flow.
package/bun.lock ADDED
@@ -0,0 +1,296 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "configVersion": 1,
4
+ "workspaces": {
5
+ "": {
6
+ "name": "pi-meta-oauth",
7
+ "devDependencies": {
8
+ "@earendil-works/pi-ai": "0.83.0",
9
+ "@earendil-works/pi-coding-agent": "0.83.0",
10
+ "bun-types": "latest",
11
+ "typescript": "^5.9.0",
12
+ },
13
+ "peerDependencies": {
14
+ "@earendil-works/pi-ai": ">=0.83.0 <0.84.0",
15
+ "@earendil-works/pi-coding-agent": ">=0.83.0 <0.84.0",
16
+ },
17
+ },
18
+ },
19
+ "packages": {
20
+ "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.91.1", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw=="],
21
+
22
+ "@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="],
23
+
24
+ "@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA=="],
25
+
26
+ "@aws-crypto/supports-web-crypto": ["@aws-crypto/supports-web-crypto@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg=="],
27
+
28
+ "@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="],
29
+
30
+ "@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.1048.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.11", "@aws-sdk/credential-provider-node": "^3.972.42", "@aws-sdk/eventstream-handler-node": "^3.972.16", "@aws-sdk/middleware-eventstream": "^3.972.12", "@aws-sdk/middleware-websocket": "^3.972.19", "@aws-sdk/token-providers": "3.1048.0", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/fetch-http-handler": "^5.4.2", "@smithy/node-http-handler": "^4.7.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ=="],
31
+
32
+ "@aws-sdk/core": ["@aws-sdk/core@3.977.6", "", { "dependencies": { "@aws-sdk/types": "^3.974.2", "@aws-sdk/xml-builder": "^3.972.37", "@aws/lambda-invoke-store": "^0.3.0", "@smithy/core": "^3.31.1", "@smithy/signature-v4": "^5.6.12", "@smithy/types": "^4.16.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-QiaJV4/zDrB4ZY2mfeSXSzSTc36W16sZXcGz+SPFk0CJ26gziO0cS+4LjJUMAbdeeBOvS0k0Aq1cZpfGdUXxSw=="],
33
+
34
+ "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.67", "", { "dependencies": { "@aws-sdk/core": "^3.977.6", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-rcIpk5kxUqDaaNa6Xk23pQ6ViY7jlqzmfFWCahQcBT97ddXaXYYwzCen9Tz1Jvo6aJft6wDl5bN44/Jw5B4oLA=="],
35
+
36
+ "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.69", "", { "dependencies": { "@aws-sdk/core": "^3.977.6", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.31.1", "@smithy/fetch-http-handler": "^5.6.13", "@smithy/node-http-handler": "^4.9.13", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-nggwJtZ4eeNsUw5IeWBMXsi1ryct5idi0K+/SCRF3kybLubOMaNTb3XCihXpWMiVpyzyPeIrl0zTkzhBH9porA=="],
37
+
38
+ "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.973.12", "", { "dependencies": { "@aws-sdk/core": "^3.977.6", "@aws-sdk/credential-provider-env": "^3.972.67", "@aws-sdk/credential-provider-http": "^3.972.69", "@aws-sdk/credential-provider-login": "^3.972.74", "@aws-sdk/credential-provider-process": "^3.972.67", "@aws-sdk/credential-provider-sso": "^3.973.11", "@aws-sdk/credential-provider-web-identity": "^3.972.73", "@aws-sdk/nested-clients": "^3.997.41", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.31.1", "@smithy/credential-provider-imds": "^4.4.16", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-pNEf/OeyN5X3VmLKlgSO6TqaWmW10CvI3TfwL1XhsuhYjSLT2VDaxFnCPHnOeQXSaFisMX4jNhpETriqN8DOmg=="],
39
+
40
+ "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.74", "", { "dependencies": { "@aws-sdk/core": "^3.977.6", "@aws-sdk/nested-clients": "^3.997.41", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-0AQfDcf99TNmqVKv0owHrw/TQs6i4ZE5t9qmz6NvO53bE/sA/tpXhXL9AAcEP1qHc6Zzjd1UMb69+/9zdhvY3g=="],
41
+
42
+ "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.78", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.67", "@aws-sdk/credential-provider-http": "^3.972.69", "@aws-sdk/credential-provider-ini": "^3.973.12", "@aws-sdk/credential-provider-process": "^3.972.67", "@aws-sdk/credential-provider-sso": "^3.973.11", "@aws-sdk/credential-provider-web-identity": "^3.972.73", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.31.1", "@smithy/credential-provider-imds": "^4.4.16", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-OgPAnfvbGAMWac6yvxJ1ihslrvDpPVwR68D2csospdNCCyPvHk9JLzYKwz48SNiS1T2znDwHauywRKRFfpyYng=="],
43
+
44
+ "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.67", "", { "dependencies": { "@aws-sdk/core": "^3.977.6", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-IlUEejorGTWKb4/Dm7K5Yw4QxUmXLThLhrvBmzVBqZFTbW72cv9LTcITmo1dsnYriALE4h68mOq4LB99x6sQ7Q=="],
45
+
46
+ "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.973.11", "", { "dependencies": { "@aws-sdk/core": "^3.977.6", "@aws-sdk/nested-clients": "^3.997.41", "@aws-sdk/token-providers": "3.1103.0", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-gAQBkBZxUB84d71+pPcI9L+jh2ujhuAVxc/4FgGiWFDjkPBlMKxzd5XDtkSXTFX8Ro7ansnT88+XadasxMeCRw=="],
47
+
48
+ "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.73", "", { "dependencies": { "@aws-sdk/core": "^3.977.6", "@aws-sdk/nested-clients": "^3.997.41", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-SnlEmQa6SjOgs6iOPLUQl1Eyq4AKiAdPQlkOhFhqNfDtDCwibMGvL6QlkSmf3o6vAUSImzdPCxowT5dfQUZP1A=="],
49
+
50
+ "@aws-sdk/eventstream-handler-node": ["@aws-sdk/eventstream-handler-node@3.972.31", "", { "dependencies": { "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-/BRzvkp46mF6eXBL/l9WKPQQfifLlUPaWli6n9/T/WDLUg8he7TCyuNFnk6RvHP5j5W/kMj5Gxw7W778LJaXDA=="],
51
+
52
+ "@aws-sdk/middleware-eventstream": ["@aws-sdk/middleware-eventstream@3.972.26", "", { "dependencies": { "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-2eIvouTZoxPu5ClHY6ij13De1yhY8Rmllt0dlGeBNXX3wmR7fU1pvMCGb50fKm1GxcuntWK0t1T0cMjTyDoUQA=="],
53
+
54
+ "@aws-sdk/middleware-websocket": ["@aws-sdk/middleware-websocket@3.972.49", "", { "dependencies": { "@aws-sdk/core": "^3.977.6", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.31.1", "@smithy/fetch-http-handler": "^5.6.13", "@smithy/signature-v4": "^5.6.12", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-wGYJvu1/stdWuzGcNyh44u8aY7ArU8XFrMesBlzIYn70HWVCRBNEngQexDuPIMu0NEgsKGKmTc0uvnS/bF7KWw=="],
55
+
56
+ "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.41", "", { "dependencies": { "@aws-sdk/core": "^3.977.6", "@aws-sdk/signature-v4-multi-region": "^3.996.43", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.31.1", "@smithy/fetch-http-handler": "^5.6.13", "@smithy/node-http-handler": "^4.9.13", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-RDHqPGQWlF6tatA/Tp3rg6oIwtgN9IVderxE+9av2Y93Dfyu+mO1hZ5Bu2jpfZg2rwdNbsssnwM+sLafIczMlQ=="],
57
+
58
+ "@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.43", "", { "dependencies": { "@aws-sdk/types": "^3.974.2", "@smithy/signature-v4": "^5.6.12", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-lKekx8bLBXSv4O+cslk9Zfnw2XKSkWBs3uWL5QGhH2ZAQfNS7FE0vcSSN2vD/AhxX54ZTywWxR4STThoeOXlBA=="],
59
+
60
+ "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1048.0", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/nested-clients": "^3.997.9", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA=="],
61
+
62
+ "@aws-sdk/types": ["@aws-sdk/types@3.974.2", "", { "dependencies": { "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-3W6IUtSxFbH6X7Wb7DzGCV5QiFQsd0g8bOfntpmDxQlzBoKWUMBu/JPQR0DwkE+Hpnxd6db1tXbOwdeHddG6cA=="],
63
+
64
+ "@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.965.8", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-uUbMs1cBZPafD0ohUj6EwNf0fPZ534NvBxHox4hjX+0Rxq5paSYUem7+hi833pYrzrcnBATKIYpR02MDXT5M9g=="],
65
+
66
+ "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.37", "", { "dependencies": { "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-zKq4HQum8JwDyEuyfuI4bbiAcU0KxP6qy+9PR/IsR92IyE/DaBAikzAS50tjxip4bqIIANpCcG+Yyj6CVhXupg=="],
67
+
68
+ "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.3.0", "", {}, "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ=="],
69
+
70
+ "@babel/runtime": ["@babel/runtime@7.29.7", "", {}, "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="],
71
+
72
+ "@earendil-works/pi-agent-core": ["@earendil-works/pi-agent-core@0.83.0", "", { "dependencies": { "@earendil-works/pi-ai": "^0.83.0", "diff": "8.0.4", "ignore": "7.0.5", "typebox": "1.3.7", "yaml": "2.9.0" } }, "sha512-RorGp9OH5l3ElpuC5a5ZQ2eWcchZGXflXRzVGkV99y3y6tT+LLNyxoYIdVKvTKWEObwhExeQbTH0fI2tE4iX4g=="],
73
+
74
+ "@earendil-works/pi-ai": ["@earendil-works/pi-ai@0.83.0", "", { "dependencies": { "@anthropic-ai/sdk": "0.91.1", "@aws-sdk/client-bedrock-runtime": "3.1048.0", "@google/genai": "1.52.0", "@mistralai/mistralai": "2.2.6", "@opentelemetry/api": "1.9.0", "@smithy/node-http-handler": "4.7.3", "http-proxy-agent": "7.0.2", "https-proxy-agent": "7.0.6", "openai": "6.26.0", "partial-json": "0.1.7", "typebox": "1.3.7" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-m3IZD4g3er0V8TC9+Vpgw/sjTKqcJlkcIBy/JvsgRubuuik3tAVzyugUg4rVrShIkkOT69mEd34NEqKUIsl6JQ=="],
75
+
76
+ "@earendil-works/pi-coding-agent": ["@earendil-works/pi-coding-agent@0.83.0", "", { "dependencies": { "@earendil-works/pi-agent-core": "^0.83.0", "@earendil-works/pi-ai": "^0.83.0", "@earendil-works/pi-tui": "^0.83.0", "@silvia-odwyer/photon-node": "0.3.4", "chalk": "5.6.2", "cross-spawn": "7.0.6", "diff": "8.0.4", "glob": "13.0.6", "highlight.js": "10.7.3", "hosted-git-info": "9.0.3", "ignore": "7.0.5", "jiti": "2.7.0", "minimatch": "10.2.5", "proper-lockfile": "4.1.2", "semver": "7.8.0", "typebox": "1.3.7", "undici": "8.5.0", "yaml": "2.9.0" }, "optionalDependencies": { "@mariozechner/clipboard": "0.3.9" }, "bin": { "pi": "dist/cli.js" } }, "sha512-uYhF+FsZxogoSX/AxBcUdiY+ZklubwaXyAoEGA2eQwsHcyEAhUYIKh/WLXe/a8+k8eTCmxb+ZN2Zo9mzQtzbWw=="],
77
+
78
+ "@earendil-works/pi-tui": ["@earendil-works/pi-tui@0.83.0", "", { "dependencies": { "get-east-asian-width": "1.6.0", "marked": "18.0.5" } }, "sha512-IoYrb0rORjELmEpNtoCA/U8je3KopMkRAVJRdSzvXRvgb+Huo1gNh8Q5CSZvNOiYtDxJdj2tYZZHZ4B3+IN3hA=="],
79
+
80
+ "@google/genai": ["@google/genai@1.52.0", "", { "dependencies": { "google-auth-library": "^10.3.0", "p-retry": "^4.6.2", "protobufjs": "^7.5.4", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.2" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q=="],
81
+
82
+ "@mariozechner/clipboard": ["@mariozechner/clipboard@0.3.9", "", { "optionalDependencies": { "@mariozechner/clipboard-darwin-arm64": "0.3.9", "@mariozechner/clipboard-darwin-universal": "0.3.9", "@mariozechner/clipboard-darwin-x64": "0.3.9", "@mariozechner/clipboard-linux-arm64-gnu": "0.3.9", "@mariozechner/clipboard-linux-arm64-musl": "0.3.9", "@mariozechner/clipboard-linux-riscv64-gnu": "0.3.9", "@mariozechner/clipboard-linux-x64-gnu": "0.3.9", "@mariozechner/clipboard-linux-x64-musl": "0.3.9", "@mariozechner/clipboard-win32-arm64-msvc": "0.3.9", "@mariozechner/clipboard-win32-x64-msvc": "0.3.9" } }, "sha512-ABnA53mdfkGZwOFUdZNv2S0CWGO/EIuPj8Vv9xmBFmSYg/qFc7ihO6q5FcQjvoE67kZpWkEc4AhD6B/os04yuA=="],
83
+
84
+ "@mariozechner/clipboard-darwin-arm64": ["@mariozechner/clipboard-darwin-arm64@0.3.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-BfgV7vCEWZwJwZJw03r6bP5+tf0iI/ANuQYCxi9RNn7FrWB3yzGuMKCrNLRl6V761vXRdL8+OqZ0wd4TqlsNOQ=="],
85
+
86
+ "@mariozechner/clipboard-darwin-universal": ["@mariozechner/clipboard-darwin-universal@0.3.9", "", { "os": "darwin" }, "sha512-BGGR4iA9Z2shAjI65eI5xtyb3LYNlDW9X3gxKxDbqtbnREohsrqznov6zpKoIrsRWpzlYVEdKphS7ksJ0/ndSQ=="],
87
+
88
+ "@mariozechner/clipboard-darwin-x64": ["@mariozechner/clipboard-darwin-x64@0.3.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-4kURmCbS6nt8uYhtmWpUcJWyPHfmAr5dTpXD1nO3pIfa+TSQ9DbrGOYCKH+aEFW47XhQ4Vp8ZTszie+wfFvDKg=="],
89
+
90
+ "@mariozechner/clipboard-linux-arm64-gnu": ["@mariozechner/clipboard-linux-arm64-gnu@0.3.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-g59OkUGP2DDfCOIKypHeYgv2M55u/cKvXa5dSxFbEJ34XvIQMdcVmpKCkGUro3ZgefXiGVdwguvTMQGpHWzIXw=="],
91
+
92
+ "@mariozechner/clipboard-linux-arm64-musl": ["@mariozechner/clipboard-linux-arm64-musl@0.3.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-AGuJdgKsmJdm4Pych7kv3sqe591ERRaAHW3xjLooiFzn8J+PxUyof++7YZrB5Y5tpnTO+K18Og3taj2NpluCRQ=="],
93
+
94
+ "@mariozechner/clipboard-linux-riscv64-gnu": ["@mariozechner/clipboard-linux-riscv64-gnu@0.3.9", "", { "os": "linux", "cpu": "none" }, "sha512-DXBEAiuMpk7dhS1a9NzNxVAFi1vaKoPu7rQNgY8LIDLGrK3lnIp3nT10DUum+PKVJoJppIP+NAA8IZe4DMNDPw=="],
95
+
96
+ "@mariozechner/clipboard-linux-x64-gnu": ["@mariozechner/clipboard-linux-x64-gnu@0.3.9", "", { "os": "linux", "cpu": "x64" }, "sha512-WORrMLd6EpElEME7JRKfSaY34nW1P5LbdgK5YNCS1ncG2LqmITsSMEJ8nh2mpvxb3TxqbOOKgY7k9eMJYlW9Mw=="],
97
+
98
+ "@mariozechner/clipboard-linux-x64-musl": ["@mariozechner/clipboard-linux-x64-musl@0.3.9", "", { "os": "linux", "cpu": "x64" }, "sha512-/DHn+1DrfL6oRaPPWXaOKvonFFrni666fxd+zFqiQEfvBH0tsHVWjq9iqBk0oDp0qaPA72lIMy5BptxISBEhZQ=="],
99
+
100
+ "@mariozechner/clipboard-win32-arm64-msvc": ["@mariozechner/clipboard-win32-arm64-msvc@0.3.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-O5FHD3ErkMwMhNzAfu3ggy0ug4z7btZuoQgwwxlzPrwV2bxlD6WDpqBY4NCgICAgZdDKdp+loUEKVAVt8aYnhQ=="],
101
+
102
+ "@mariozechner/clipboard-win32-x64-msvc": ["@mariozechner/clipboard-win32-x64-msvc@0.3.9", "", { "os": "win32", "cpu": "x64" }, "sha512-ihQC3EufqEY81vhXBgVBtK4prL+wc62zJsSvxrgz7K1hsdt6OObz6v9p3Rn1OG3GJksTTKMJF0u/guMISHPhSA=="],
103
+
104
+ "@mistralai/mistralai": ["@mistralai/mistralai@2.2.6", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.40.0", "ws": "^8.18.0", "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "^3.25.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0" }, "optionalPeers": ["@opentelemetry/api"] }, "sha512-W8pX7zHxjJvMIpw8JMxeJEleapXX0Q9NPszdNzqkM3MIEoIGPObdodujj+WHteXEvGfaP/AMwlNyRfEzSY6dQQ=="],
105
+
106
+ "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
107
+
108
+ "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.43.0", "", {}, "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="],
109
+
110
+ "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="],
111
+
112
+ "@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="],
113
+
114
+ "@protobufjs/codegen": ["@protobufjs/codegen@2.0.5", "", {}, "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g=="],
115
+
116
+ "@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.1", "", {}, "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg=="],
117
+
118
+ "@protobufjs/fetch": ["@protobufjs/fetch@1.1.1", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1" } }, "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw=="],
119
+
120
+ "@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="],
121
+
122
+ "@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="],
123
+
124
+ "@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="],
125
+
126
+ "@protobufjs/utf8": ["@protobufjs/utf8@1.1.2", "", {}, "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug=="],
127
+
128
+ "@silvia-odwyer/photon-node": ["@silvia-odwyer/photon-node@0.3.4", "", {}, "sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA=="],
129
+
130
+ "@smithy/core": ["@smithy/core@3.31.1", "", { "dependencies": { "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-CyogUINxvi7C7LDsh8Syo6hVJOT9ckz4rG8dRZfTJ8r91HkMY59PnNooaj7WcHyxEkxPfBAmbgztZU+xTo76lg=="],
131
+
132
+ "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.4.16", "", { "dependencies": { "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-QfuLWAkLzptffFW980AFeHZFdqds2B64rpEd3uJ6lgs3xVn9QegGMUgUcj+4d7dRrAsya3r58ZKpku97WcFb4w=="],
133
+
134
+ "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.6.13", "", { "dependencies": { "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-4fW86pEUOMbrD5nkbyl/tTvPHHWJFbuB2odl6ps9lWfHoXf9HWh3Q/Smh59qH1g7+c/BSZghX6bbUk4gsiMs8A=="],
135
+
136
+ "@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
137
+
138
+ "@smithy/node-http-handler": ["@smithy/node-http-handler@4.7.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA=="],
139
+
140
+ "@smithy/signature-v4": ["@smithy/signature-v4@5.6.12", "", { "dependencies": { "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-I6KLtq3H0qqSuV9vLglfi8puHqzygzWHOnI4z/Rdoo+q50vvo18vBRdPAvvEtcaKROz7Zn6qnPa14kRfPH6PcQ=="],
141
+
142
+ "@smithy/types": ["@smithy/types@4.16.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-0JFs3V2y2M9tKW5na/qxe69Zv+uxLMO7QBbhxF/FHu/Gp2NFZAAL9tWl9PU02xxo07pb3G9FTyjNc6D5uZrJIg=="],
143
+
144
+ "@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
145
+
146
+ "@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
147
+
148
+ "@types/node": ["@types/node@26.1.2", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg=="],
149
+
150
+ "@types/retry": ["@types/retry@0.12.0", "", {}, "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="],
151
+
152
+ "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
153
+
154
+ "balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
155
+
156
+ "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
157
+
158
+ "bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="],
159
+
160
+ "bowser": ["bowser@2.14.1", "", {}, "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg=="],
161
+
162
+ "brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="],
163
+
164
+ "buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
165
+
166
+ "bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
167
+
168
+ "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
169
+
170
+ "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
171
+
172
+ "data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="],
173
+
174
+ "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
175
+
176
+ "diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="],
177
+
178
+ "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],
179
+
180
+ "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
181
+
182
+ "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
183
+
184
+ "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="],
185
+
186
+ "gaxios": ["gaxios@7.3.0", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2" } }, "sha512-RB5vLV+vvQeoFPCX4QMK6/hjVkbIamPp1QSUD0CiZcnj12qbpiL+pLbYtgD+oZkWl0tl9z+o2Utp+MpM3QRhBA=="],
187
+
188
+ "gcp-metadata": ["gcp-metadata@8.1.2", "", { "dependencies": { "gaxios": "^7.0.0", "google-logging-utils": "^1.0.0", "json-bigint": "^1.0.0" } }, "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg=="],
189
+
190
+ "get-east-asian-width": ["get-east-asian-width@1.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="],
191
+
192
+ "glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="],
193
+
194
+ "google-auth-library": ["google-auth-library@10.9.1", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.1.4", "gcp-metadata": "8.1.2", "google-logging-utils": "1.1.3", "jws": "^4.0.0" } }, "sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw=="],
195
+
196
+ "google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="],
197
+
198
+ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
199
+
200
+ "highlight.js": ["highlight.js@10.7.3", "", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="],
201
+
202
+ "hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="],
203
+
204
+ "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="],
205
+
206
+ "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
207
+
208
+ "ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
209
+
210
+ "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
211
+
212
+ "jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="],
213
+
214
+ "json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="],
215
+
216
+ "json-schema-to-ts": ["json-schema-to-ts@3.1.1", "", { "dependencies": { "@babel/runtime": "^7.18.3", "ts-algebra": "^2.0.0" } }, "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g=="],
217
+
218
+ "jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="],
219
+
220
+ "jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="],
221
+
222
+ "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
223
+
224
+ "lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="],
225
+
226
+ "marked": ["marked@18.0.5", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-S6GcvALHg6K4ohtu4E7x0a1AqhAjp6cV8KhLSyN9qVapnzJkusVBxZRcIU9AeYsbe6P1hKDusSbEOzGyyuce6w=="],
227
+
228
+ "minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
229
+
230
+ "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="],
231
+
232
+ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
233
+
234
+ "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
235
+
236
+ "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=="],
237
+
238
+ "openai": ["openai@6.26.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA=="],
239
+
240
+ "p-retry": ["p-retry@4.6.2", "", { "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" } }, "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ=="],
241
+
242
+ "partial-json": ["partial-json@0.1.7", "", {}, "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA=="],
243
+
244
+ "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
245
+
246
+ "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="],
247
+
248
+ "proper-lockfile": ["proper-lockfile@4.1.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", "signal-exit": "^3.0.2" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="],
249
+
250
+ "protobufjs": ["protobufjs@7.6.5", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.5", "@protobufjs/eventemitter": "^1.1.1", "@protobufjs/fetch": "^1.1.1", "@protobufjs/float": "^1.0.2", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", "long": "^5.3.2" } }, "sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw=="],
251
+
252
+ "retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="],
253
+
254
+ "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
255
+
256
+ "semver": ["semver@7.8.0", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA=="],
257
+
258
+ "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
259
+
260
+ "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
261
+
262
+ "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
263
+
264
+ "ts-algebra": ["ts-algebra@2.0.0", "", {}, "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw=="],
265
+
266
+ "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
267
+
268
+ "typebox": ["typebox@1.3.7", "", {}, "sha512-meKuifc33Pccx0O6PdIzYMq3Og8zvP4TIi/a+Bw3AEMZMxOD0+RHGQvpglEe6Zdy3wZ8nqn/j95h8LUZLk/6Hg=="],
269
+
270
+ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
271
+
272
+ "undici": ["undici@8.5.0", "", {}, "sha512-xamtWoB1EshgjpmlXd7GGm2VfdDtw1+rD8uhry8pSNW3If6S8E0m2T2+orSKeZXEn/aPJMviCpDBA65WJt8zhg=="],
273
+
274
+ "undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="],
275
+
276
+ "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
277
+
278
+ "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
279
+
280
+ "ws": ["ws@8.21.2", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-54dMVAo4WIe6SKy3vBgN+9bJZqqQ8IMRevAkOLQALhi49qkkQDQfWdAZ8KQlXiEabw88ARXXdUrlvtbKQX+aKw=="],
281
+
282
+ "yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="],
283
+
284
+ "zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="],
285
+
286
+ "zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="],
287
+
288
+ "@aws-sdk/credential-provider-http/@smithy/node-http-handler": ["@smithy/node-http-handler@4.9.13", "", { "dependencies": { "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-Nmd/Nl35zfYrd+a6OO2cDJb3GPh9bgTjIUhcM+JFfjpp8/osCgboDV5nCT1I01Pv6R13eSKDKLSoVa5ZB6Zsfw=="],
289
+
290
+ "@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1103.0", "", { "dependencies": { "@aws-sdk/core": "^3.977.6", "@aws-sdk/nested-clients": "^3.997.41", "@aws-sdk/types": "^3.974.2", "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-N4wy26MNn31ItGVHYHPrEuCIFY4MBBjC+C5v1lJKqIUSA7OZBdhleCY53zCCrXn27hsk7YNOaTuhQu807S4AfQ=="],
291
+
292
+ "@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.9.13", "", { "dependencies": { "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-Nmd/Nl35zfYrd+a6OO2cDJb3GPh9bgTjIUhcM+JFfjpp8/osCgboDV5nCT1I01Pv6R13eSKDKLSoVa5ZB6Zsfw=="],
293
+
294
+ "p-retry/retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="],
295
+ }
296
+ }
@@ -0,0 +1,373 @@
1
+ import type {
2
+ OAuthCredentials,
3
+ OAuthLoginCallbacks,
4
+ RefreshModelsContext,
5
+ } from "@earendil-works/pi-ai";
6
+ import type { ExtensionAPI, ProviderConfig } from "@earendil-works/pi-coding-agent";
7
+
8
+ export const META_PROVIDER_ID = "meta";
9
+ export const META_API_BASE_URL = "https://api.meta.ai/v1";
10
+ export const META_MODEL_CATALOG_URL = "https://api.meta.ai/v1/models";
11
+ export const META_AUTH_BASE_URL = "https://auth.meta.com";
12
+ export const META_CLIENT_ID = "1031625952748946";
13
+
14
+ const DEVICE_AUTHORIZATION_URL = `${META_AUTH_BASE_URL}/oidc/device/authorization/`;
15
+ const DEVICE_TOKEN_URL = `${META_AUTH_BASE_URL}/oidc/device/token/`;
16
+ const API_KEY_MINT_URL = "https://api.meta.ai/muse-code/key";
17
+ const DEVICE_CODE_GRANT = "urn:ietf:params:oauth:grant-type:device_code";
18
+ const API_KEY_REFRESH_INTERVAL_MS = 24 * 60 * 60 * 1000;
19
+
20
+ export type MetaProviderModel = NonNullable<ProviderConfig["models"]>[number];
21
+ type Fetch = typeof fetch;
22
+ type Sleep = (milliseconds: number) => Promise<void>;
23
+
24
+ interface DeviceAuthorization {
25
+ device_code: string;
26
+ user_code: string;
27
+ verification_uri: string;
28
+ verification_uri_complete?: string;
29
+ expires_in?: number;
30
+ interval?: number;
31
+ }
32
+
33
+ interface DeviceTokenGrant {
34
+ access_token: string;
35
+ }
36
+
37
+ interface OAuthError {
38
+ error?: string;
39
+ error_description?: string;
40
+ }
41
+
42
+ interface MintResponse {
43
+ api_key?: string;
44
+ base_url?: string;
45
+ require_payment?: boolean;
46
+ action_url?: string;
47
+ }
48
+
49
+ interface CatalogResponse {
50
+ data?: MetaCatalogModel[];
51
+ }
52
+
53
+ interface MetaCatalogModel {
54
+ id?: string;
55
+ metadata?: {
56
+ "muse-code"?: {
57
+ name?: string;
58
+ is_hidden?: boolean;
59
+ reasoning?: boolean;
60
+ modalities?: { input?: string[] };
61
+ limit?: { context?: number; output?: number };
62
+ variants?: Record<string, { reasoningEffort?: string }>;
63
+ cost?: { input?: string | number; output?: string | number; cached?: string | number };
64
+ };
65
+ };
66
+ }
67
+
68
+ const FALLBACK_MODELS: MetaProviderModel[] = [
69
+ {
70
+ id: "muse-spark-1.2",
71
+ name: "Muse Spark 1.2",
72
+ reasoning: true,
73
+ thinkingLevelMap: {
74
+ off: null,
75
+ minimal: "minimal",
76
+ low: "low",
77
+ medium: "medium",
78
+ high: "high",
79
+ xhigh: "xhigh",
80
+ max: null,
81
+ },
82
+ input: ["text", "image"],
83
+ cost: { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 },
84
+ contextWindow: 1_048_576,
85
+ maxTokens: 256_000,
86
+ compat: { supportsReasoningEffort: true },
87
+ },
88
+ {
89
+ id: "muse-spark-1.2-contributor",
90
+ name: "Muse Spark 1.2 Contributor",
91
+ reasoning: true,
92
+ thinkingLevelMap: {
93
+ off: null,
94
+ minimal: "minimal",
95
+ low: "low",
96
+ medium: "medium",
97
+ high: "high",
98
+ xhigh: "xhigh",
99
+ max: null,
100
+ },
101
+ input: ["text", "image"],
102
+ cost: { input: 0.1, output: 0.2, cacheRead: 0.002, cacheWrite: 0 },
103
+ contextWindow: 1_048_576,
104
+ maxTokens: 256_000,
105
+ compat: { supportsReasoningEffort: true },
106
+ },
107
+ {
108
+ id: "muse-spark-1.1",
109
+ name: "Muse Spark 1.1",
110
+ reasoning: true,
111
+ thinkingLevelMap: {
112
+ off: null,
113
+ minimal: "minimal",
114
+ low: "low",
115
+ medium: "medium",
116
+ high: "high",
117
+ xhigh: "xhigh",
118
+ max: null,
119
+ },
120
+ input: ["text", "image"],
121
+ cost: { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 },
122
+ contextWindow: 1_048_576,
123
+ maxTokens: 256_000,
124
+ compat: { supportsReasoningEffort: true },
125
+ },
126
+ ];
127
+
128
+ function delay(milliseconds: number): Promise<void> {
129
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
130
+ }
131
+
132
+ async function responseBody(response: Response): Promise<Record<string, unknown>> {
133
+ const text = await response.text();
134
+ if (!text) return {};
135
+ try {
136
+ const value = JSON.parse(text) as unknown;
137
+ return value && typeof value === "object" && !Array.isArray(value)
138
+ ? (value as Record<string, unknown>)
139
+ : {};
140
+ } catch {
141
+ return {};
142
+ }
143
+ }
144
+
145
+ function errorDetail(body: Record<string, unknown>): string | undefined {
146
+ for (const key of ["error_description", "detail", "message", "error"]) {
147
+ const value = body[key];
148
+ if (typeof value === "string" && value.trim()) return value.trim();
149
+ }
150
+ return undefined;
151
+ }
152
+
153
+ async function postForm<T>(
154
+ url: string,
155
+ fields: Record<string, string>,
156
+ fetchImpl: Fetch,
157
+ ): Promise<{ response: Response; body: T & Record<string, unknown> }> {
158
+ const response = await fetchImpl(url, {
159
+ method: "POST",
160
+ headers: { Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded" },
161
+ body: new URLSearchParams(fields),
162
+ redirect: "manual",
163
+ });
164
+ return { response, body: (await responseBody(response)) as T & Record<string, unknown> };
165
+ }
166
+
167
+ export async function mintMetaApiKey(identityToken: string, fetchImpl: Fetch = fetch): Promise<string> {
168
+ const response = await fetchImpl(API_KEY_MINT_URL, {
169
+ method: "POST",
170
+ headers: {
171
+ Accept: "application/json",
172
+ Authorization: `Bearer ${identityToken}`,
173
+ "Content-Type": "application/json",
174
+ "x-api-version": "1.0.0",
175
+ },
176
+ body: "{}",
177
+ });
178
+ const body = (await responseBody(response)) as MintResponse & Record<string, unknown>;
179
+ if (!response.ok) {
180
+ throw new Error(`Meta API-key mint failed (HTTP ${response.status})${errorDetail(body) ? `: ${errorDetail(body)}` : ""}`);
181
+ }
182
+ if (typeof body.api_key !== "string" || !body.api_key) {
183
+ const setup = typeof body.action_url === "string" && body.action_url ? ` Complete setup at ${body.action_url}.` : "";
184
+ throw new Error(`Meta did not issue an API key.${setup}`);
185
+ }
186
+ return body.api_key;
187
+ }
188
+
189
+ export async function loginMeta(
190
+ callbacks: OAuthLoginCallbacks,
191
+ fetchImpl: Fetch = fetch,
192
+ sleep: Sleep = delay,
193
+ ): Promise<OAuthCredentials> {
194
+ callbacks.onProgress?.("Starting Meta device authorization…");
195
+ const authorization = await postForm<DeviceAuthorization>(
196
+ DEVICE_AUTHORIZATION_URL,
197
+ { client_id: META_CLIENT_ID },
198
+ fetchImpl,
199
+ );
200
+ if (!authorization.response.ok) {
201
+ throw new Error(
202
+ `Meta login could not be started (HTTP ${authorization.response.status})${errorDetail(authorization.body) ? `: ${errorDetail(authorization.body)}` : ""}`,
203
+ );
204
+ }
205
+ const device = authorization.body;
206
+ if (!device.device_code || !device.user_code || !device.verification_uri) {
207
+ throw new Error("Meta device authorization returned an incomplete response");
208
+ }
209
+
210
+ let intervalSeconds = Number.isFinite(device.interval) && Number(device.interval) > 0 ? Number(device.interval) : 5;
211
+ const expiresInSeconds = Number.isFinite(device.expires_in) && Number(device.expires_in) > 0
212
+ ? Number(device.expires_in)
213
+ : 900;
214
+ const deadline = Date.now() + expiresInSeconds * 1000;
215
+ callbacks.onDeviceCode({
216
+ userCode: device.user_code,
217
+ verificationUri: device.verification_uri_complete || device.verification_uri,
218
+ intervalSeconds,
219
+ expiresInSeconds,
220
+ });
221
+ callbacks.onProgress?.("Waiting for Meta login approval…");
222
+
223
+ let identityToken: string | undefined;
224
+ while (Date.now() < deadline) {
225
+ await sleep(intervalSeconds * 1000);
226
+ const grant = await postForm<DeviceTokenGrant & OAuthError>(
227
+ DEVICE_TOKEN_URL,
228
+ {
229
+ grant_type: DEVICE_CODE_GRANT,
230
+ device_code: device.device_code,
231
+ client_id: META_CLIENT_ID,
232
+ },
233
+ fetchImpl,
234
+ );
235
+ if (grant.response.ok && grant.body.access_token) {
236
+ identityToken = grant.body.access_token;
237
+ break;
238
+ }
239
+ switch (grant.body.error) {
240
+ case "authorization_pending":
241
+ continue;
242
+ case "slow_down":
243
+ intervalSeconds += 5;
244
+ continue;
245
+ case "access_denied":
246
+ throw new Error("Meta login was denied");
247
+ case "expired_token":
248
+ throw new Error("Meta login request expired");
249
+ default:
250
+ throw new Error(
251
+ `Meta login failed (HTTP ${grant.response.status})${errorDetail(grant.body) ? `: ${errorDetail(grant.body)}` : ""}`,
252
+ );
253
+ }
254
+ }
255
+ if (!identityToken) throw new Error("Meta login request expired");
256
+
257
+ callbacks.onProgress?.("Enabling Meta Model API access…");
258
+ const apiKey = await mintMetaApiKey(identityToken, fetchImpl);
259
+ return {
260
+ refresh: identityToken,
261
+ access: apiKey,
262
+ expires: Date.now() + API_KEY_REFRESH_INTERVAL_MS,
263
+ };
264
+ }
265
+
266
+ export async function refreshMetaToken(
267
+ credentials: OAuthCredentials,
268
+ fetchImpl: Fetch = fetch,
269
+ ): Promise<OAuthCredentials> {
270
+ if (!credentials.refresh) throw new Error("Meta login is missing its identity token; run /login meta again");
271
+ return {
272
+ ...credentials,
273
+ access: await mintMetaApiKey(credentials.refresh, fetchImpl),
274
+ expires: Date.now() + API_KEY_REFRESH_INTERVAL_MS,
275
+ };
276
+ }
277
+
278
+ function finitePositive(value: unknown, fallback: number): number {
279
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
280
+ }
281
+
282
+ function numericCost(value: unknown, fallback: number): number {
283
+ const number = typeof value === "number" ? value : typeof value === "string" ? Number(value) : Number.NaN;
284
+ return Number.isFinite(number) && number >= 0 ? number : fallback;
285
+ }
286
+
287
+ function displayName(id: string): string {
288
+ return id
289
+ .split("-")
290
+ .map((part) => part ? part[0].toUpperCase() + part.slice(1) : part)
291
+ .join(" ");
292
+ }
293
+
294
+ export function toProviderModels(catalog: CatalogResponse): MetaProviderModel[] {
295
+ return (catalog.data ?? []).flatMap((entry) => {
296
+ if (typeof entry.id !== "string" || !entry.id) return [];
297
+ const metadata = entry.metadata?.["muse-code"];
298
+ if (metadata?.is_hidden) return [];
299
+ const fallback = FALLBACK_MODELS.find((model) => model.id === entry.id);
300
+ const catalogName = metadata?.name === entry.id ? undefined : metadata?.name;
301
+ const variants = metadata?.variants ?? {};
302
+ const thinkingLevelMap: NonNullable<MetaProviderModel["thinkingLevelMap"]> = {
303
+ off: null,
304
+ minimal: variants.minimal?.reasoningEffort ?? "minimal",
305
+ low: variants.low?.reasoningEffort ?? "low",
306
+ medium: variants.medium?.reasoningEffort ?? "medium",
307
+ high: variants.high?.reasoningEffort ?? "high",
308
+ xhigh: variants.xhigh?.reasoningEffort ?? "xhigh",
309
+ max: null,
310
+ };
311
+ return [{
312
+ id: entry.id,
313
+ name: catalogName || fallback?.name || displayName(entry.id),
314
+ reasoning: metadata?.reasoning ?? fallback?.reasoning ?? true,
315
+ thinkingLevelMap,
316
+ input: metadata
317
+ ? (metadata.modalities?.input?.includes("image") ? ["text", "image"] : ["text"])
318
+ : (fallback?.input ?? ["text"]),
319
+ cost: {
320
+ input: numericCost(metadata?.cost?.input, fallback?.cost.input ?? 0),
321
+ output: numericCost(metadata?.cost?.output, fallback?.cost.output ?? 0),
322
+ cacheRead: numericCost(metadata?.cost?.cached, fallback?.cost.cacheRead ?? 0),
323
+ cacheWrite: 0,
324
+ },
325
+ contextWindow: finitePositive(metadata?.limit?.context, fallback?.contextWindow ?? 1_048_576),
326
+ maxTokens: finitePositive(metadata?.limit?.output, fallback?.maxTokens ?? 256_000),
327
+ compat: { supportsReasoningEffort: true },
328
+ } satisfies MetaProviderModel];
329
+ });
330
+ }
331
+
332
+ export async function refreshMetaModels(
333
+ context: RefreshModelsContext,
334
+ fetchImpl: Fetch = fetch,
335
+ ): Promise<MetaProviderModel[]> {
336
+ if (!context.allowNetwork || context.signal?.aborted) return [...FALLBACK_MODELS];
337
+ const apiKey = context.credential?.type === "oauth"
338
+ ? context.credential.access
339
+ : context.credential?.type === "api_key"
340
+ ? context.credential.key
341
+ : undefined;
342
+ if (!apiKey) return [...FALLBACK_MODELS];
343
+
344
+ const response = await fetchImpl(META_MODEL_CATALOG_URL, {
345
+ headers: { Accept: "application/json", Authorization: `Bearer ${apiKey}`, "x-api-version": "1.0.0" },
346
+ signal: context.signal,
347
+ });
348
+ const body = (await responseBody(response)) as CatalogResponse & Record<string, unknown>;
349
+ if (!response.ok) {
350
+ throw new Error(`Meta model catalog failed (HTTP ${response.status})${errorDetail(body) ? `: ${errorDetail(body)}` : ""}`);
351
+ }
352
+ return toProviderModels(body);
353
+ }
354
+
355
+ export function createMetaProviderConfig(): ProviderConfig {
356
+ return {
357
+ name: "Meta Model API",
358
+ baseUrl: META_API_BASE_URL,
359
+ api: "openai-responses",
360
+ models: [...FALLBACK_MODELS],
361
+ refreshModels: refreshMetaModels,
362
+ oauth: {
363
+ name: "Meta Model API (browser login)",
364
+ login: loginMeta,
365
+ refreshToken: refreshMetaToken,
366
+ getApiKey: (credentials: { access: string }) => credentials.access,
367
+ },
368
+ };
369
+ }
370
+
371
+ export default function metaOAuthProvider(pi: ExtensionAPI): void {
372
+ pi.registerProvider(META_PROVIDER_ID, createMetaProviderConfig());
373
+ }
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "pi-meta-oauth",
3
+ "version": "0.1.0",
4
+ "description": "Meta Model API OAuth provider for pi — device login, API-key minting, and Muse Spark model catalog for pi.dev",
5
+ "keywords": ["pi-package", "meta", "muse-spark", "oauth", "provider"],
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/BlockedPath/pi-meta-oauth"
11
+ },
12
+ "homepage": "https://github.com/BlockedPath/pi-meta-oauth#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/BlockedPath/pi-meta-oauth/issues"
15
+ },
16
+ "pi": {
17
+ "extensions": ["./extensions/meta.ts"],
18
+ "image": "https://raw.githubusercontent.com/BlockedPath/pi-meta-oauth/main/preview.png"
19
+ },
20
+ "peerDependencies": {
21
+ "@earendil-works/pi-ai": ">=0.83.0 <0.84.0",
22
+ "@earendil-works/pi-coding-agent": ">=0.83.0 <0.84.0"
23
+ },
24
+ "devDependencies": {
25
+ "@earendil-works/pi-ai": "0.83.0",
26
+ "@earendil-works/pi-coding-agent": "0.83.0",
27
+ "bun-types": "latest",
28
+ "typescript": "^5.9.0"
29
+ },
30
+ "scripts": {
31
+ "typecheck": "tsc --noEmit",
32
+ "test": "bun test tests/meta.test.ts"
33
+ }
34
+ }
package/preview.png ADDED
Binary file
@@ -0,0 +1,102 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import {
3
+ loginMeta,
4
+ mintMetaApiKey,
5
+ toProviderModels,
6
+ } from "../extensions/meta.ts";
7
+
8
+ function jsonResponse(body: unknown, status = 200): Response {
9
+ return new Response(JSON.stringify(body), {
10
+ status,
11
+ headers: { "Content-Type": "application/json" },
12
+ });
13
+ }
14
+
15
+ describe("Meta OAuth provider", () => {
16
+ test("maps the Muse catalog into Pi model metadata", () => {
17
+ const models = toProviderModels({
18
+ data: [
19
+ {
20
+ id: "muse-spark-test",
21
+ metadata: {
22
+ "muse-code": {
23
+ name: "Muse Spark Test",
24
+ reasoning: true,
25
+ modalities: { input: ["text", "image"] },
26
+ limit: { context: 123_000, output: 45_000 },
27
+ variants: { high: { reasoningEffort: "deep" } },
28
+ cost: { input: "1.25", output: "4.25", cached: "0.15" },
29
+ },
30
+ },
31
+ },
32
+ { id: "hidden", metadata: { "muse-code": { is_hidden: true } } },
33
+ ],
34
+ });
35
+
36
+ expect(models).toHaveLength(1);
37
+ expect(models[0]).toMatchObject({
38
+ id: "muse-spark-test",
39
+ name: "Muse Spark Test",
40
+ input: ["text", "image"],
41
+ contextWindow: 123_000,
42
+ maxTokens: 45_000,
43
+ cost: { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 },
44
+ thinkingLevelMap: { off: null, high: "deep", max: null },
45
+ });
46
+ });
47
+
48
+ test("runs device login, polls, and mints a Model API key", async () => {
49
+ const requests: Array<{ url: string; authorization?: string }> = [];
50
+ const responses = [
51
+ jsonResponse({
52
+ device_code: "device-token",
53
+ user_code: "ABCD-1234",
54
+ verification_uri: "https://auth.meta.com/device",
55
+ verification_uri_complete: "https://auth.meta.com/device?code=ABCD-1234",
56
+ expires_in: 900,
57
+ interval: 1,
58
+ }),
59
+ jsonResponse({ error: "authorization_pending" }, 400),
60
+ jsonResponse({ access_token: "identity-token" }),
61
+ jsonResponse({ api_key: "model-api-key", base_url: "https://api.meta.ai/v1" }),
62
+ ];
63
+ const fetchMock = (async (input: string | URL | Request, init?: RequestInit) => {
64
+ const headers = new Headers(init?.headers);
65
+ requests.push({ url: String(input), authorization: headers.get("Authorization") ?? undefined });
66
+ const response = responses.shift();
67
+ if (!response) throw new Error("Unexpected request");
68
+ return response;
69
+ }) as unknown as typeof fetch;
70
+ const deviceCodes: unknown[] = [];
71
+ const credentials = await loginMeta(
72
+ {
73
+ onAuth() {},
74
+ onDeviceCode(value: unknown) { deviceCodes.push(value); },
75
+ onPrompt: async () => "",
76
+ onSelect: async () => undefined,
77
+ },
78
+ fetchMock,
79
+ async () => {},
80
+ );
81
+
82
+ expect(deviceCodes).toEqual([{
83
+ userCode: "ABCD-1234",
84
+ verificationUri: "https://auth.meta.com/device?code=ABCD-1234",
85
+ intervalSeconds: 1,
86
+ expiresInSeconds: 900,
87
+ }]);
88
+ expect(credentials.refresh).toBe("identity-token");
89
+ expect(credentials.access).toBe("model-api-key");
90
+ expect(requests.at(-1)?.authorization).toBe("Bearer identity-token");
91
+ });
92
+
93
+ test("reports account setup when minting yields no API key", async () => {
94
+ const fetchMock = (async () => jsonResponse({
95
+ require_payment: true,
96
+ action_url: "https://dev.meta.ai/billing",
97
+ })) as unknown as typeof fetch;
98
+ await expect(mintMetaApiKey("identity-token", fetchMock)).rejects.toThrow(
99
+ "Complete setup at https://dev.meta.ai/billing",
100
+ );
101
+ });
102
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "allowImportingTsExtensions": true,
8
+ "skipLibCheck": true,
9
+ "types": ["bun-types"]
10
+ },
11
+ "include": ["extensions"]
12
+ }