@andoai/opencode 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/index.js +33 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,12 +5,16 @@ Official Ando Wallet integration for [OpenCode](https://opencode.ai/).
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
|
-
opencode plugin --global --force @andoai/opencode@0.2.
|
|
8
|
+
opencode plugin --global --force @andoai/opencode@0.2.2
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
Then run `/connect` in OpenCode, choose **Ando**, and select **Connect Ando Wallet**. Your browser opens
|
|
12
12
|
`wallet.andoai.xyz`, where you choose an existing open, funded OpenCode session or open a new one.
|
|
13
13
|
|
|
14
|
+
The plugin owns the Ando provider implementation, endpoint, and authentication fields. It ignores legacy
|
|
15
|
+
`provider.ando` API-key or authorization-header overrides so the credential saved by `/connect` is always
|
|
16
|
+
used, while preserving unrelated provider options.
|
|
17
|
+
|
|
14
18
|
The browser returns only a short-lived, single-use authorization code over the IPv4 loopback callback.
|
|
15
19
|
The plugin redeems that code over HTTPS using an S256 PKCE verifier that never leaves the OpenCode process.
|
|
16
20
|
The MPP session credential is therefore never placed in the callback URL or submitted from HTTPS to an HTTP
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { exchangeAuthorizationCode } from "./token-exchange.js";
|
|
|
3
3
|
const WALLET_ORIGIN = "https://wallet.andoai.xyz";
|
|
4
4
|
const INFERENCE_BASE_URL = "https://inference.andoai.xyz/v1/mpp";
|
|
5
5
|
const MODELS = {
|
|
6
|
-
"Ando/
|
|
6
|
+
"Ando/Model-Optimisation": { name: "Model Optimisation" },
|
|
7
7
|
"Ando/gpt-oss-120b": { name: "GPT OSS 120B" },
|
|
8
8
|
"ando/nemotron-3-ultra-550b-a55b": { name: "Nemotron 3 Ultra 550B" }
|
|
9
9
|
};
|
|
@@ -12,6 +12,7 @@ export function createAndoOpenCodePlugin(runtime = {}) {
|
|
|
12
12
|
const exchangeCode = runtime.exchangeCode ?? exchangeAuthorizationCode;
|
|
13
13
|
return async () => {
|
|
14
14
|
const pending = new Set();
|
|
15
|
+
let connectedCredential;
|
|
15
16
|
return {
|
|
16
17
|
config: async (config) => configureAndoProvider(config),
|
|
17
18
|
auth: {
|
|
@@ -33,13 +34,15 @@ export function createAndoOpenCodePlugin(runtime = {}) {
|
|
|
33
34
|
instructions: "Choose an open, funded OpenCode session in Ando Wallet.",
|
|
34
35
|
callback: async () => {
|
|
35
36
|
try {
|
|
37
|
+
const credential = await exchangeCode({
|
|
38
|
+
code: await callback.waitForCode(),
|
|
39
|
+
codeVerifier: callback.codeVerifier
|
|
40
|
+
});
|
|
41
|
+
connectedCredential = credential;
|
|
36
42
|
return {
|
|
37
43
|
type: "success",
|
|
38
44
|
provider: "ando",
|
|
39
|
-
key:
|
|
40
|
-
code: await callback.waitForCode(),
|
|
41
|
-
codeVerifier: callback.codeVerifier
|
|
42
|
-
})
|
|
45
|
+
key: credential
|
|
43
46
|
};
|
|
44
47
|
}
|
|
45
48
|
catch {
|
|
@@ -55,7 +58,13 @@ export function createAndoOpenCodePlugin(runtime = {}) {
|
|
|
55
58
|
}
|
|
56
59
|
]
|
|
57
60
|
},
|
|
61
|
+
"chat.headers": async (input, output) => {
|
|
62
|
+
if (input.model.providerID !== "ando" || !connectedCredential)
|
|
63
|
+
return;
|
|
64
|
+
output.headers.Authorization = `Bearer ${connectedCredential}`;
|
|
65
|
+
},
|
|
58
66
|
dispose: async () => {
|
|
67
|
+
connectedCredential = undefined;
|
|
59
68
|
const callbacks = Array.from(pending);
|
|
60
69
|
pending.clear();
|
|
61
70
|
await Promise.all(callbacks.map((callback) => callback.close()));
|
|
@@ -68,18 +77,33 @@ function configureAndoProvider(config) {
|
|
|
68
77
|
const current = providers.ando;
|
|
69
78
|
providers.ando = {
|
|
70
79
|
...current,
|
|
71
|
-
name:
|
|
72
|
-
npm:
|
|
80
|
+
name: "Ando",
|
|
81
|
+
npm: "@ai-sdk/openai-compatible",
|
|
73
82
|
models: {
|
|
74
83
|
...MODELS,
|
|
75
84
|
...current?.models
|
|
76
85
|
},
|
|
77
86
|
options: {
|
|
78
|
-
|
|
79
|
-
|
|
87
|
+
...managedProviderOptions(current?.options),
|
|
88
|
+
baseURL: INFERENCE_BASE_URL
|
|
80
89
|
}
|
|
81
90
|
};
|
|
82
91
|
config.provider = providers;
|
|
83
92
|
}
|
|
93
|
+
function managedProviderOptions(options) {
|
|
94
|
+
// OpenCode injects the credential from /connect only when config does not provide one.
|
|
95
|
+
return Object.fromEntries(Object.entries(options ?? {}).flatMap(([name, value]) => {
|
|
96
|
+
if (name === "apiKey" || name === "baseURL")
|
|
97
|
+
return [];
|
|
98
|
+
if (name === "headers")
|
|
99
|
+
return [[name, withoutAuthorizationHeader(value)]];
|
|
100
|
+
return [[name, value]];
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
function withoutAuthorizationHeader(value) {
|
|
104
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
105
|
+
return value;
|
|
106
|
+
return Object.fromEntries(Object.entries(value).filter(([name]) => name.toLowerCase() !== "authorization"));
|
|
107
|
+
}
|
|
84
108
|
const AndoOpenCodePlugin = createAndoOpenCodePlugin();
|
|
85
109
|
export default AndoOpenCodePlugin;
|