@bogyie/opencode-kiro-plugin 0.3.15 → 0.3.17
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 +1 -1
- package/dist/plugin.js +51 -8
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -155,7 +155,7 @@ This keeps new Kiro model ids usable before the package is updated without adver
|
|
|
155
155
|
|
|
156
156
|
The plugin injects `provider.kiro` with the `auto` placeholder needed for OpenCode's provider connector. Define `provider.kiro.models` yourself only when you need explicit model-picker metadata such as a display name or context limit. Use plugin `modelAliases` for aliases that should resolve one requested model id to another.
|
|
157
157
|
|
|
158
|
-
`modelDiscoveryCommand` defaults to `["kiro-cli", "chat", "--list-models", "--format", "json"]`. Set `modelDiscovery` to `"off"` to disable startup discovery and `kiro_refresh_models`; in that mode the plugin uses any stored cache and then the `auto` fallback.
|
|
158
|
+
`modelDiscoveryCommand` defaults to `["kiro-cli", "chat", "--list-models", "--format", "json"]`. Set `modelDiscovery` to `"off"` to disable startup discovery and `kiro_refresh_models`; in that mode the plugin uses any stored cache and then the `auto` fallback. During OpenCode startup, the plugin checks Kiro auth in the blocking `config` hook. If no `KIRO_API_KEY` or active `kiro-cli` session exists, it starts `kiro-cli login --use-device-flow` once and waits for login to finish before model discovery and provider registration continue. `/v1/models` still uses only the discovery/cache path: it never invokes the chat transport or login fallback, and returns the cached list or `auto` if discovery fails. OpenCode title-generation requests also suppress login fallback so startup helper traffic cannot open a second Kiro login window. A successful connector login also triggers a forced model refresh. Discovery stdout can be a JSON array, `{ "models": [...] }`, `{ "data": [...] }`, Kiro CLI list-models JSON, Kiro CLI plain list output, or one model id per line.
|
|
159
159
|
|
|
160
160
|
## Troubleshooting
|
|
161
161
|
|
package/dist/plugin.js
CHANGED
|
@@ -12,6 +12,8 @@ import { ModelResolver, normalizeModelName } from "./model-resolver.js";
|
|
|
12
12
|
import { KiroRestTransport } from "./kiro-rest-transport.js";
|
|
13
13
|
const PLACEHOLDER_MODEL_ID = "auto";
|
|
14
14
|
const PLACEHOLDER_MODEL = { name: "Auto" };
|
|
15
|
+
const OPENCODE_AGENT_HEADER = "x-opencode-kiro-agent";
|
|
16
|
+
const LOGIN_SUPPRESSED_AGENTS = new Set(["title"]);
|
|
15
17
|
function discoveredProviderModels(cache) {
|
|
16
18
|
return Object.fromEntries(cache.all().map((model) => [
|
|
17
19
|
model.id,
|
|
@@ -72,14 +74,22 @@ export function effectiveBackend(options, accessToken) {
|
|
|
72
74
|
return "fetch";
|
|
73
75
|
return "fetch";
|
|
74
76
|
}
|
|
75
|
-
function
|
|
77
|
+
function shouldLoginOnAuthFailure(init) {
|
|
78
|
+
const agent = new Headers(init?.headers).get(OPENCODE_AGENT_HEADER);
|
|
79
|
+
return !agent || !LOGIN_SUPPRESSED_AGENTS.has(agent);
|
|
80
|
+
}
|
|
81
|
+
function localTransport(options, accessToken, behavior = {}) {
|
|
76
82
|
const backend = effectiveBackend(options, accessToken);
|
|
77
|
-
const login = () =>
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
const login = () => {
|
|
84
|
+
if (behavior.loginOnAuthFailure === false)
|
|
85
|
+
return Promise.resolve(false);
|
|
86
|
+
return runKiroLoginFlowOnce({
|
|
87
|
+
login: {
|
|
88
|
+
...options.login,
|
|
89
|
+
useDeviceFlow: true,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
};
|
|
83
93
|
if (backend === "acp")
|
|
84
94
|
return new KiroAcpTransport(acpTransportOptions(options));
|
|
85
95
|
if (backend === "cli-chat") {
|
|
@@ -138,6 +148,8 @@ export function createKiroPlugin() {
|
|
|
138
148
|
}
|
|
139
149
|
let discovery;
|
|
140
150
|
let lastModelDiscoveryAt = 0;
|
|
151
|
+
let startupLogin;
|
|
152
|
+
let startupLoginAttempted = false;
|
|
141
153
|
const refreshModels = async (force = false) => {
|
|
142
154
|
const discoveryIsStale = lastModelDiscoveryAt === 0 || Date.now() - lastModelDiscoveryAt > options.modelCacheTtlSeconds * 1000;
|
|
143
155
|
if (options.modelDiscovery === "off" || options.modelDiscoveryCommand.length === 0 || (!force && !discoveryIsStale)) {
|
|
@@ -160,6 +172,29 @@ export function createKiroPlugin() {
|
|
|
160
172
|
}
|
|
161
173
|
return discovery;
|
|
162
174
|
};
|
|
175
|
+
const ensureStartupAuthenticated = async () => {
|
|
176
|
+
const current = await detectAuth().catch(() => undefined);
|
|
177
|
+
if (current?.authenticated)
|
|
178
|
+
return true;
|
|
179
|
+
if (startupLogin)
|
|
180
|
+
return startupLogin;
|
|
181
|
+
if (startupLoginAttempted)
|
|
182
|
+
return false;
|
|
183
|
+
startupLoginAttempted = true;
|
|
184
|
+
startupLogin = (async () => {
|
|
185
|
+
const session = startKiroCliLoginOnce({
|
|
186
|
+
...options.login,
|
|
187
|
+
useDeviceFlow: true,
|
|
188
|
+
});
|
|
189
|
+
const prompted = await session.waitForPrompt(options.requestTimeoutMs);
|
|
190
|
+
if (!prompted)
|
|
191
|
+
return false;
|
|
192
|
+
return session.waitForAuth();
|
|
193
|
+
})().finally(() => {
|
|
194
|
+
startupLogin = undefined;
|
|
195
|
+
});
|
|
196
|
+
return startupLogin;
|
|
197
|
+
};
|
|
163
198
|
const resolver = new ModelResolver({
|
|
164
199
|
cache: modelCache,
|
|
165
200
|
aliases: options.modelAliases,
|
|
@@ -171,7 +206,9 @@ export function createKiroPlugin() {
|
|
|
171
206
|
if (localServer)
|
|
172
207
|
return localServer;
|
|
173
208
|
const localFetch = async (input, init) => {
|
|
174
|
-
const transport = localTransport(options, bearerToken(init)
|
|
209
|
+
const transport = localTransport(options, bearerToken(init), {
|
|
210
|
+
loginOnAuthFailure: shouldLoginOnAuthFailure(init),
|
|
211
|
+
});
|
|
175
212
|
return createKiroFetch({
|
|
176
213
|
resolver,
|
|
177
214
|
models: async () => {
|
|
@@ -215,6 +252,7 @@ export function createKiroPlugin() {
|
|
|
215
252
|
localServer = undefined;
|
|
216
253
|
},
|
|
217
254
|
config: async (config) => {
|
|
255
|
+
await ensureStartupAuthenticated();
|
|
218
256
|
await refreshModels();
|
|
219
257
|
config.provider ??= {};
|
|
220
258
|
config.provider[options.providerID] ??= {};
|
|
@@ -343,6 +381,11 @@ export function createKiroPlugin() {
|
|
|
343
381
|
}));
|
|
344
382
|
},
|
|
345
383
|
},
|
|
384
|
+
"chat.headers": async (input, output) => {
|
|
385
|
+
if (input.model.providerID !== options.providerID)
|
|
386
|
+
return;
|
|
387
|
+
output.headers[OPENCODE_AGENT_HEADER] = input.agent;
|
|
388
|
+
},
|
|
346
389
|
};
|
|
347
390
|
};
|
|
348
391
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bogyie/opencode-kiro-plugin",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.17",
|
|
4
4
|
"description": "OpenCode plugin for using Kiro as a provider adapter",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"type": "plugin",
|
|
61
61
|
"hooks": [
|
|
62
62
|
"auth",
|
|
63
|
+
"chat.headers",
|
|
63
64
|
"config",
|
|
64
65
|
"provider",
|
|
65
66
|
"tool"
|