@bogyie/opencode-kiro-plugin 0.3.22 → 0.3.24
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 -3
- package/dist/plugin.d.ts +1 -0
- package/dist/plugin.js +46 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -59,7 +59,7 @@ For personal Kiro login with GitHub:
|
|
|
59
59
|
}
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
For AWS IAM Identity Center login, configure the default device-flow Start URL separately from the API region:
|
|
62
|
+
For AWS IAM Identity Center login, configure the default device-flow Start URL separately from the Kiro LLM API region:
|
|
63
63
|
|
|
64
64
|
```jsonc
|
|
65
65
|
{
|
|
@@ -67,7 +67,7 @@ For AWS IAM Identity Center login, configure the default device-flow Start URL s
|
|
|
67
67
|
[
|
|
68
68
|
"@bogyie/opencode-kiro-plugin",
|
|
69
69
|
{
|
|
70
|
-
"region": "
|
|
70
|
+
"region": "us-east-1",
|
|
71
71
|
"login": {
|
|
72
72
|
"method": "organization",
|
|
73
73
|
"identityProvider": "https://example.awsapps.com/start",
|
|
@@ -79,7 +79,7 @@ For AWS IAM Identity Center login, configure the default device-flow Start URL s
|
|
|
79
79
|
}
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
For IAM Identity Center, configure `login.method: "organization"`, `login.identityProvider`, and `login.region` in plugin options. The connector opens the Identity Center device URL for that Start URL and region, then waits until the device authorization completes.
|
|
82
|
+
For IAM Identity Center, configure `login.method: "organization"`, `login.identityProvider`, and `login.region` in plugin options. The top-level `region` controls the Kiro LLM/API endpoint and should usually remain `us-east-1`; `login.region` controls the IAM Identity Center OIDC/device authorization endpoint, for example `ap-northeast-2`. The connector opens the Identity Center device URL for that Start URL and login region, then waits until the device authorization completes.
|
|
83
83
|
|
|
84
84
|
Use the `kiro_status` plugin tool to inspect provider id, backend, region, auth method, and discovered model count. Use `kiro_refresh_models` when you explicitly want to run the configured model discovery command and update the in-memory and stored model cache. Secrets are redacted in diagnostics.
|
|
85
85
|
|
|
@@ -183,6 +183,8 @@ The plugin injects `provider.kiro` with the `auto` placeholder needed for OpenCo
|
|
|
183
183
|
- `KIRO_ACP_TIMEOUT`: ACP did not send a `TurnEnd` notification before the prompt timeout.
|
|
184
184
|
- `KIRO_ACP_PROCESS_ERROR` or `KIRO_ACP_PROCESS_EXITED`: `kiro-cli acp` could not start or exited while a request was pending.
|
|
185
185
|
|
|
186
|
+
If IAM Identity Center login succeeds but chat requests cannot connect or fail against the LLM endpoint, check that top-level `region` is the Kiro LLM/API region, not necessarily the IAM Identity Center region. A common organization setup is `"region": "us-east-1"` with `"login.region": "ap-northeast-2"`.
|
|
187
|
+
|
|
186
188
|
Direct fetch mode calls Kiro's `generateAssistantResponse` endpoint and can fall back from the `q` endpoint to the CodeWhisperer endpoint on quota or upstream failures. Tune `maxAttempts` and `requestTimeoutMs` if you need stricter failure boundaries in automation. Fetch mode also accepts `endpoint`, `profileArn`, `userAgent`, and `agentMode` for controlled environments. `cli-chat` uses `requestTimeoutMs` for the `kiro-cli chat --no-interactive` child process, and ACP uses it while waiting for `session/prompt` completion and `TurnEnd`.
|
|
187
189
|
|
|
188
190
|
OpenAI-compatible `temperature`, `max_tokens`, and `max_completion_tokens` are preserved for direct fetch mode through Kiro's `inferenceConfig` fields on a best-effort basis.
|
package/dist/plugin.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { KiroPluginOptions } from "./config.js";
|
|
|
4
4
|
import type { KiroRestTransportOptions } from "./kiro-rest-transport.js";
|
|
5
5
|
type EffectiveBackend = "fetch" | "cli-chat" | "acp" | "none";
|
|
6
6
|
export declare function effectiveBackend(options: Pick<KiroPluginOptions, "backend">, accessToken?: string): EffectiveBackend;
|
|
7
|
+
export declare function __resetKiroPluginSharedStateForTest(): void;
|
|
7
8
|
export declare function acpTransportOptions(options: Pick<KiroPluginOptions, "requestTimeoutMs" | "trustAllTools">): KiroAcpTransportOptions;
|
|
8
9
|
export declare function fetchTransportOptions(options: Pick<KiroPluginOptions, "region" | "endpoint" | "profileArn" | "userAgent" | "agentMode" | "maxAttempts" | "requestTimeoutMs">, accessToken?: string): KiroRestTransportOptions;
|
|
9
10
|
export declare function createKiroPlugin(): Plugin;
|
package/dist/plugin.js
CHANGED
|
@@ -16,6 +16,7 @@ const PLACEHOLDER_MODEL = { name: "Auto" };
|
|
|
16
16
|
const OPENCODE_AGENT_HEADER = "x-opencode-kiro-agent";
|
|
17
17
|
const LOGIN_SUPPRESSED_AGENTS = new Set(["title"]);
|
|
18
18
|
const LOGIN_METHODS = new Set(["builder-id", "google", "github", "organization"]);
|
|
19
|
+
let sharedDeviceAuthKey;
|
|
19
20
|
function discoveredProviderModels(cache) {
|
|
20
21
|
return Object.fromEntries(cache.all().map((model) => [
|
|
21
22
|
model.id,
|
|
@@ -64,6 +65,20 @@ function bearerToken(init) {
|
|
|
64
65
|
const match = header?.match(/^Bearer\s+(.+)$/i);
|
|
65
66
|
return match?.[1] || undefined;
|
|
66
67
|
}
|
|
68
|
+
function isLikelyKiroApiKey(value) {
|
|
69
|
+
return Boolean(value?.startsWith("ksk_"));
|
|
70
|
+
}
|
|
71
|
+
function localAccessToken(incoming, fallback) {
|
|
72
|
+
if (!incoming || incoming === KIRO_LOCAL_TRANSPORT_KEY)
|
|
73
|
+
return fallback ?? incoming;
|
|
74
|
+
if (isKiroDeviceAuthKey(incoming))
|
|
75
|
+
return incoming;
|
|
76
|
+
if (process.env.KIRO_API_KEY && incoming === process.env.KIRO_API_KEY)
|
|
77
|
+
return incoming;
|
|
78
|
+
if (isLikelyKiroApiKey(incoming))
|
|
79
|
+
return incoming;
|
|
80
|
+
return fallback;
|
|
81
|
+
}
|
|
67
82
|
export function effectiveBackend(options, accessToken) {
|
|
68
83
|
const apiKey = accessToken || process.env.KIRO_API_KEY;
|
|
69
84
|
if (options.backend === "acp")
|
|
@@ -113,6 +128,13 @@ function openExternalUrl(url) {
|
|
|
113
128
|
child.on("error", () => undefined);
|
|
114
129
|
child.unref();
|
|
115
130
|
}
|
|
131
|
+
function rememberDeviceAuthKey(key) {
|
|
132
|
+
sharedDeviceAuthKey = key;
|
|
133
|
+
return key;
|
|
134
|
+
}
|
|
135
|
+
export function __resetKiroPluginSharedStateForTest() {
|
|
136
|
+
sharedDeviceAuthKey = undefined;
|
|
137
|
+
}
|
|
116
138
|
function loginPrompts(options) {
|
|
117
139
|
const prompts = [];
|
|
118
140
|
const login = options.login;
|
|
@@ -223,7 +245,7 @@ export function createKiroPlugin() {
|
|
|
223
245
|
}
|
|
224
246
|
let discovery;
|
|
225
247
|
let lastModelDiscoveryAt = 0;
|
|
226
|
-
let startupDeviceAuthKey;
|
|
248
|
+
let startupDeviceAuthKey = sharedDeviceAuthKey;
|
|
227
249
|
let startupLogin;
|
|
228
250
|
let startupLoginAttempted = false;
|
|
229
251
|
const refreshModels = async (force = false) => {
|
|
@@ -256,6 +278,7 @@ export function createKiroPlugin() {
|
|
|
256
278
|
return discovery;
|
|
257
279
|
};
|
|
258
280
|
const ensureStartupAuthenticated = async () => {
|
|
281
|
+
startupDeviceAuthKey ??= sharedDeviceAuthKey;
|
|
259
282
|
if (startupDeviceAuthKey)
|
|
260
283
|
return true;
|
|
261
284
|
const current = await detectAuth().catch(() => undefined);
|
|
@@ -276,7 +299,7 @@ export function createKiroPlugin() {
|
|
|
276
299
|
region: options.region,
|
|
277
300
|
...(options.profileArn ? { profileArn: options.profileArn } : {}),
|
|
278
301
|
});
|
|
279
|
-
startupDeviceAuthKey = encodeKiroDeviceAuthKey(credential);
|
|
302
|
+
startupDeviceAuthKey = rememberDeviceAuthKey(encodeKiroDeviceAuthKey(credential));
|
|
280
303
|
return true;
|
|
281
304
|
}
|
|
282
305
|
catch {
|
|
@@ -300,22 +323,24 @@ export function createKiroPlugin() {
|
|
|
300
323
|
disabledModels: options.disabledModels,
|
|
301
324
|
disablePassThrough: options.disableModelPassThrough,
|
|
302
325
|
});
|
|
326
|
+
const localFetch = async (input, init) => {
|
|
327
|
+
startupDeviceAuthKey ??= sharedDeviceAuthKey;
|
|
328
|
+
const accessToken = localAccessToken(bearerToken(init), startupDeviceAuthKey || sharedDeviceAuthKey);
|
|
329
|
+
const transport = localTransport(options, accessToken, {
|
|
330
|
+
loginOnAuthFailure: shouldLoginOnAuthFailure(init),
|
|
331
|
+
});
|
|
332
|
+
return createKiroFetch({
|
|
333
|
+
resolver,
|
|
334
|
+
models: async () => {
|
|
335
|
+
await refreshModels(true).catch(() => []);
|
|
336
|
+
return Object.keys(visibleProviderModels(modelCache, configuredModels, options.hiddenModels, disabledModels));
|
|
337
|
+
},
|
|
338
|
+
...(transport ? { transport } : {}),
|
|
339
|
+
})(input, init);
|
|
340
|
+
};
|
|
303
341
|
const ensureLocalServer = async () => {
|
|
304
342
|
if (localServer)
|
|
305
343
|
return localServer;
|
|
306
|
-
const localFetch = async (input, init) => {
|
|
307
|
-
const transport = localTransport(options, bearerToken(init) || startupDeviceAuthKey, {
|
|
308
|
-
loginOnAuthFailure: shouldLoginOnAuthFailure(init),
|
|
309
|
-
});
|
|
310
|
-
return createKiroFetch({
|
|
311
|
-
resolver,
|
|
312
|
-
models: async () => {
|
|
313
|
-
await refreshModels(true).catch(() => []);
|
|
314
|
-
return Object.keys(visibleProviderModels(modelCache, configuredModels, options.hiddenModels, disabledModels));
|
|
315
|
-
},
|
|
316
|
-
...(transport ? { transport } : {}),
|
|
317
|
-
})(input, init);
|
|
318
|
-
};
|
|
319
344
|
localServer = await startLocalKiroServer(localFetch);
|
|
320
345
|
return localServer;
|
|
321
346
|
};
|
|
@@ -334,7 +359,7 @@ export function createKiroPlugin() {
|
|
|
334
359
|
region: options.region,
|
|
335
360
|
...(options.profileArn ? { profileArn: options.profileArn } : {}),
|
|
336
361
|
});
|
|
337
|
-
const key = encodeKiroDeviceAuthKey(credential);
|
|
362
|
+
const key = rememberDeviceAuthKey(encodeKiroDeviceAuthKey(credential));
|
|
338
363
|
startupDeviceAuthKey = key;
|
|
339
364
|
await refreshModels(true).catch(() => []);
|
|
340
365
|
return {
|
|
@@ -394,6 +419,8 @@ export function createKiroPlugin() {
|
|
|
394
419
|
provider.npm = "@ai-sdk/openai-compatible";
|
|
395
420
|
provider.api = server.baseURL;
|
|
396
421
|
provider.options ??= {};
|
|
422
|
+
provider.options.baseURL = server.baseURL;
|
|
423
|
+
provider.options.apiKey ??= KIRO_LOCAL_TRANSPORT_KEY;
|
|
397
424
|
provider.models = visibleProviderModels(modelCache, configuredModels, options.hiddenModels, disabledModels);
|
|
398
425
|
},
|
|
399
426
|
auth: {
|
|
@@ -426,10 +453,12 @@ export function createKiroPlugin() {
|
|
|
426
453
|
],
|
|
427
454
|
loader: async (auth) => {
|
|
428
455
|
const apiKey = await resolveApiKey(auth);
|
|
456
|
+
startupDeviceAuthKey ??= sharedDeviceAuthKey;
|
|
429
457
|
const server = await ensureLocalServer();
|
|
430
458
|
return {
|
|
431
|
-
apiKey: apiKey || startupDeviceAuthKey || KIRO_LOCAL_TRANSPORT_KEY,
|
|
459
|
+
apiKey: apiKey || startupDeviceAuthKey || sharedDeviceAuthKey || KIRO_LOCAL_TRANSPORT_KEY,
|
|
432
460
|
baseURL: server.baseURL,
|
|
461
|
+
fetch: localFetch,
|
|
433
462
|
};
|
|
434
463
|
},
|
|
435
464
|
},
|