@bogyie/opencode-kiro-plugin 0.3.19 → 0.3.21
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 +16 -1
- package/dist/auth.d.ts +4 -0
- package/dist/auth.js +64 -7
- package/dist/model-discovery.js +23 -8
- package/dist/plugin.js +103 -19
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -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 so they are passed to `kiro-cli login --license pro --
|
|
82
|
+
For IAM Identity Center, configure `login.method: "organization"`, `login.identityProvider`, and `login.region` in plugin options so they are passed to `kiro-cli login --use-device-flow --license pro --identity-provider <start-url> --region <region>`.
|
|
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
|
|
|
@@ -204,6 +204,21 @@ For a real Kiro smoke test that uses your local `kiro-cli` login, runs runtime m
|
|
|
204
204
|
npm run smoke:kiro
|
|
205
205
|
```
|
|
206
206
|
|
|
207
|
+
For the same real checks under the test runner, including actual `kiro-cli chat --list-models --format json` and real local plugin API calls:
|
|
208
|
+
|
|
209
|
+
```sh
|
|
210
|
+
npm run test:real
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
To also run the real IAM Identity Center device login flow and wait for completion, set the explicit opt-in variables:
|
|
214
|
+
|
|
215
|
+
```sh
|
|
216
|
+
OPENCODE_KIRO_REAL_LOGIN=1 \
|
|
217
|
+
KIRO_REAL_IDENTITY_PROVIDER=https://example.awsapps.com/start \
|
|
218
|
+
KIRO_REAL_IDENTITY_REGION=ap-northeast-2 \
|
|
219
|
+
npm run test:real
|
|
220
|
+
```
|
|
221
|
+
|
|
207
222
|
For real Kiro/OpenCode validation, use [docs/e2e-validation.md](docs/e2e-validation.md).
|
|
208
223
|
|
|
209
224
|
## Release
|
package/dist/auth.d.ts
CHANGED
|
@@ -35,6 +35,9 @@ export interface KiroLoginSession {
|
|
|
35
35
|
readonly url: string;
|
|
36
36
|
readonly code: string | undefined;
|
|
37
37
|
readonly instructions: string;
|
|
38
|
+
readonly output: string;
|
|
39
|
+
readonly exitCode: number | null;
|
|
40
|
+
readonly args: ReadonlyArray<string>;
|
|
38
41
|
waitForPrompt(timeoutMs?: number): Promise<boolean>;
|
|
39
42
|
waitForAuth(runner?: CommandRunner): Promise<boolean>;
|
|
40
43
|
}
|
|
@@ -77,6 +80,7 @@ export interface KiroLoginFlowOptions {
|
|
|
77
80
|
readonly login?: KiroCliLoginOptions;
|
|
78
81
|
}
|
|
79
82
|
export declare const KIRO_LOGIN_URL = "https://view.awsapps.com/start";
|
|
83
|
+
export declare const KIRO_LOCAL_TRANSPORT_KEY = "kiro-plugin-local-transport";
|
|
80
84
|
export declare const DEFAULT_KIRO_CLI_DB_PATH: string;
|
|
81
85
|
export declare const DEFAULT_KIRO_CLI_TOKEN_KEYS: readonly ["kirocli:odic:token", "codewhisperer:odic:token"];
|
|
82
86
|
export declare function runCommand(command: string, args: ReadonlyArray<string>, options?: CommandRunOptions): Promise<CommandResult>;
|
package/dist/auth.js
CHANGED
|
@@ -6,6 +6,7 @@ import { join } from "node:path";
|
|
|
6
6
|
import { promisify } from "node:util";
|
|
7
7
|
const execFileAsync = promisify(execFile);
|
|
8
8
|
export const KIRO_LOGIN_URL = "https://view.awsapps.com/start";
|
|
9
|
+
export const KIRO_LOCAL_TRANSPORT_KEY = "kiro-plugin-local-transport";
|
|
9
10
|
export const DEFAULT_KIRO_CLI_DB_PATH = join(homedir(), "Library", "Application Support", "kiro-cli", "data.sqlite3");
|
|
10
11
|
export const DEFAULT_KIRO_CLI_TOKEN_KEYS = ["kirocli:odic:token", "codewhisperer:odic:token"];
|
|
11
12
|
const KIRO_DEVICE_AUTH_KEY_PREFIX = "kiro-device:";
|
|
@@ -424,15 +425,20 @@ function loginOptionsAndSpawner(optionsOrSpawner, spawner) {
|
|
|
424
425
|
}
|
|
425
426
|
export function kiroCliLoginArgs(options = {}) {
|
|
426
427
|
const args = ["login"];
|
|
427
|
-
const license = options.license ??
|
|
428
|
+
const license = options.license ??
|
|
429
|
+
(options.method === "organization" || options.identityProvider || options.region
|
|
430
|
+
? "pro"
|
|
431
|
+
: options.method
|
|
432
|
+
? "free"
|
|
433
|
+
: undefined);
|
|
434
|
+
if (options.useDeviceFlow)
|
|
435
|
+
args.push("--use-device-flow");
|
|
428
436
|
if (license)
|
|
429
437
|
args.push("--license", license);
|
|
430
438
|
if (options.identityProvider)
|
|
431
439
|
args.push("--identity-provider", options.identityProvider);
|
|
432
440
|
if (options.region)
|
|
433
441
|
args.push("--region", options.region);
|
|
434
|
-
if (options.useDeviceFlow)
|
|
435
|
-
args.push("--use-device-flow");
|
|
436
442
|
args.push(...(options.extraArgs ?? []));
|
|
437
443
|
return args;
|
|
438
444
|
}
|
|
@@ -458,13 +464,28 @@ function loginMethodPromptSeen(output) {
|
|
|
458
464
|
function loginPromptReady(output) {
|
|
459
465
|
return Boolean(extractKiroLoginCode(output) || firstLoginUrl(output));
|
|
460
466
|
}
|
|
467
|
+
function identityPromptSeen(output) {
|
|
468
|
+
return /enter start url/i.test(output);
|
|
469
|
+
}
|
|
470
|
+
function regionPromptSeen(output) {
|
|
471
|
+
return /enter region/i.test(output);
|
|
472
|
+
}
|
|
473
|
+
function loginUrl(output, options) {
|
|
474
|
+
const code = extractKiroLoginCode(output);
|
|
475
|
+
if (code && options.identityProvider)
|
|
476
|
+
return kiroDeviceVerificationUrl(options.identityProvider, code);
|
|
477
|
+
return extractKiroLoginUrl(output);
|
|
478
|
+
}
|
|
461
479
|
export function startKiroCliLogin(optionsOrSpawner, spawner) {
|
|
462
480
|
const resolved = loginOptionsAndSpawner(optionsOrSpawner, spawner);
|
|
463
|
-
const
|
|
481
|
+
const args = kiroCliLoginArgs(resolved.options);
|
|
482
|
+
const child = resolved.spawner("kiro-cli", args);
|
|
464
483
|
let output = "";
|
|
465
484
|
let exited = false;
|
|
466
485
|
let exitCode = null;
|
|
467
486
|
let selectedLoginMethod = false;
|
|
487
|
+
let wroteIdentityProvider = false;
|
|
488
|
+
let wroteRegion = false;
|
|
468
489
|
const maybeSelectLoginMethod = () => {
|
|
469
490
|
if (!resolved.options.method ||
|
|
470
491
|
resolved.options.method === "organization" ||
|
|
@@ -475,13 +496,25 @@ export function startKiroCliLogin(optionsOrSpawner, spawner) {
|
|
|
475
496
|
child.stdin?.write(loginMethodSelection(resolved.options.method));
|
|
476
497
|
selectedLoginMethod = true;
|
|
477
498
|
};
|
|
499
|
+
const maybeAnswerIdentityPrompts = () => {
|
|
500
|
+
if (resolved.options.identityProvider && !wroteIdentityProvider && identityPromptSeen(output)) {
|
|
501
|
+
child.stdin?.write(`${resolved.options.identityProvider}\n`);
|
|
502
|
+
wroteIdentityProvider = true;
|
|
503
|
+
}
|
|
504
|
+
if (resolved.options.region && !wroteRegion && regionPromptSeen(output)) {
|
|
505
|
+
child.stdin?.write(`${resolved.options.region}\n`);
|
|
506
|
+
wroteRegion = true;
|
|
507
|
+
}
|
|
508
|
+
};
|
|
478
509
|
child.stdout?.on("data", (chunk) => {
|
|
479
510
|
output += chunk.toString("utf8");
|
|
480
511
|
maybeSelectLoginMethod();
|
|
512
|
+
maybeAnswerIdentityPrompts();
|
|
481
513
|
});
|
|
482
514
|
child.stderr?.on("data", (chunk) => {
|
|
483
515
|
output += chunk.toString("utf8");
|
|
484
516
|
maybeSelectLoginMethod();
|
|
517
|
+
maybeAnswerIdentityPrompts();
|
|
485
518
|
});
|
|
486
519
|
child.on("exit", (code) => {
|
|
487
520
|
exited = true;
|
|
@@ -489,15 +522,27 @@ export function startKiroCliLogin(optionsOrSpawner, spawner) {
|
|
|
489
522
|
});
|
|
490
523
|
return {
|
|
491
524
|
get url() {
|
|
492
|
-
return
|
|
525
|
+
return loginUrl(output, resolved.options);
|
|
493
526
|
},
|
|
494
527
|
get code() {
|
|
495
528
|
return extractKiroLoginCode(output);
|
|
496
529
|
},
|
|
497
530
|
get instructions() {
|
|
498
531
|
const code = extractKiroLoginCode(output);
|
|
532
|
+
if (code && resolved.options.identityProvider) {
|
|
533
|
+
return `Open ${kiroDeviceVerificationUrl(resolved.options.identityProvider, code)} and confirm code: ${code}`;
|
|
534
|
+
}
|
|
499
535
|
return code ? `Enter code: ${code}` : "Complete Kiro CLI login in your browser. This window will close automatically.";
|
|
500
536
|
},
|
|
537
|
+
get output() {
|
|
538
|
+
return output;
|
|
539
|
+
},
|
|
540
|
+
get exitCode() {
|
|
541
|
+
return exitCode;
|
|
542
|
+
},
|
|
543
|
+
get args() {
|
|
544
|
+
return args;
|
|
545
|
+
},
|
|
501
546
|
async waitForPrompt(timeoutMs = 15_000) {
|
|
502
547
|
const deadline = Date.now() + timeoutMs;
|
|
503
548
|
while (Date.now() < deadline) {
|
|
@@ -513,7 +558,7 @@ export function startKiroCliLogin(optionsOrSpawner, spawner) {
|
|
|
513
558
|
const deadline = Date.now() + 10 * 60 * 1000;
|
|
514
559
|
while (Date.now() < deadline) {
|
|
515
560
|
const auth = await detectAuth(process.env, runner);
|
|
516
|
-
if (auth.authenticated)
|
|
561
|
+
if (auth.authenticated && (!loginPromptReady(output) || exited))
|
|
517
562
|
return true;
|
|
518
563
|
if (exited && exitCode !== 0 && !loginPromptReady(output))
|
|
519
564
|
return false;
|
|
@@ -541,6 +586,15 @@ export function startKiroCliLoginOnce(optionsOrSpawner, spawner) {
|
|
|
541
586
|
get instructions() {
|
|
542
587
|
return session.instructions;
|
|
543
588
|
},
|
|
589
|
+
get output() {
|
|
590
|
+
return session.output;
|
|
591
|
+
},
|
|
592
|
+
get exitCode() {
|
|
593
|
+
return session.exitCode;
|
|
594
|
+
},
|
|
595
|
+
get args() {
|
|
596
|
+
return session.args;
|
|
597
|
+
},
|
|
544
598
|
waitForPrompt(timeoutMs) {
|
|
545
599
|
return session.waitForPrompt(timeoutMs);
|
|
546
600
|
},
|
|
@@ -630,7 +684,10 @@ export async function resolveApiKey(auth, env = process.env) {
|
|
|
630
684
|
return env.KIRO_API_KEY;
|
|
631
685
|
try {
|
|
632
686
|
const credential = await auth();
|
|
633
|
-
|
|
687
|
+
if (credential.type === "api")
|
|
688
|
+
return credential.key || credential.access || "";
|
|
689
|
+
const key = credential.key || credential.access || "";
|
|
690
|
+
return key === KIRO_LOCAL_TRANSPORT_KEY || isKiroDeviceAuthKey(key) ? key : "";
|
|
634
691
|
}
|
|
635
692
|
catch {
|
|
636
693
|
return "";
|
package/dist/model-discovery.js
CHANGED
|
@@ -61,18 +61,33 @@ function fromLines(raw) {
|
|
|
61
61
|
.map(fromItem)
|
|
62
62
|
.filter((item) => item !== undefined);
|
|
63
63
|
}
|
|
64
|
+
function jsonCandidates(raw) {
|
|
65
|
+
const trimmed = raw.trim();
|
|
66
|
+
const candidates = [trimmed];
|
|
67
|
+
const objectStart = trimmed.indexOf("{");
|
|
68
|
+
const objectEnd = trimmed.lastIndexOf("}");
|
|
69
|
+
if (objectStart >= 0 && objectEnd > objectStart)
|
|
70
|
+
candidates.push(trimmed.slice(objectStart, objectEnd + 1));
|
|
71
|
+
const arrayStart = trimmed.indexOf("[");
|
|
72
|
+
const arrayEnd = trimmed.lastIndexOf("]");
|
|
73
|
+
if (arrayStart >= 0 && arrayEnd > arrayStart)
|
|
74
|
+
candidates.push(trimmed.slice(arrayStart, arrayEnd + 1));
|
|
75
|
+
return [...new Set(candidates)];
|
|
76
|
+
}
|
|
64
77
|
export function parseDiscoveredModels(raw) {
|
|
65
78
|
const trimmed = raw.trim();
|
|
66
79
|
if (!trimmed)
|
|
67
80
|
return [];
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
81
|
+
for (const candidate of jsonCandidates(trimmed)) {
|
|
82
|
+
try {
|
|
83
|
+
const parsed = JSON.parse(candidate);
|
|
84
|
+
const models = fromJson(parsed);
|
|
85
|
+
if (models.length > 0)
|
|
86
|
+
return dedupe(models);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// Try the next JSON candidate, then fall back to line parsing below.
|
|
90
|
+
}
|
|
76
91
|
}
|
|
77
92
|
return dedupe(fromLines(trimmed));
|
|
78
93
|
}
|
package/dist/plugin.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { tool } from "@opencode-ai/plugin";
|
|
2
2
|
import { KiroAcpTransport } from "./acp-transport.js";
|
|
3
|
-
import { credentialFromKiroDeviceAuthKey, detectAuth, isKiroDeviceAuthKey, readKiroCliSessionCredential, resolveApiKey, startKiroCliLoginOnce, runKiroLoginFlowOnce, } from "./auth.js";
|
|
3
|
+
import { authorizeKiroDevice, credentialFromKiroDeviceAuthKey, detectAuth, encodeKiroDeviceAuthKey, isKiroDeviceAuthKey, kiroDeviceVerificationUrl, KIRO_LOCAL_TRANSPORT_KEY, pollKiroDeviceToken, readKiroCliSessionCredential, resolveApiKey, startKiroCliLoginOnce, runKiroLoginFlowOnce, } from "./auth.js";
|
|
4
4
|
import { KiroCliChatTransport } from "./cli-transport.js";
|
|
5
5
|
import { loadOptions } from "./config.js";
|
|
6
6
|
import { createKiroFetch } from "./fetch-adapter.js";
|
|
@@ -14,6 +14,7 @@ const PLACEHOLDER_MODEL_ID = "auto";
|
|
|
14
14
|
const PLACEHOLDER_MODEL = { name: "Auto" };
|
|
15
15
|
const OPENCODE_AGENT_HEADER = "x-opencode-kiro-agent";
|
|
16
16
|
const LOGIN_SUPPRESSED_AGENTS = new Set(["title"]);
|
|
17
|
+
const LOGIN_METHODS = new Set(["builder-id", "google", "github", "organization"]);
|
|
17
18
|
function discoveredProviderModels(cache) {
|
|
18
19
|
return Object.fromEntries(cache.all().map((model) => [
|
|
19
20
|
model.id,
|
|
@@ -70,7 +71,7 @@ export function effectiveBackend(options, accessToken) {
|
|
|
70
71
|
return "cli-chat";
|
|
71
72
|
if (options.backend === "fetch")
|
|
72
73
|
return "fetch";
|
|
73
|
-
if (apiKey && apiKey !==
|
|
74
|
+
if (apiKey && apiKey !== KIRO_LOCAL_TRANSPORT_KEY)
|
|
74
75
|
return "fetch";
|
|
75
76
|
return "fetch";
|
|
76
77
|
}
|
|
@@ -78,16 +79,74 @@ function shouldLoginOnAuthFailure(init) {
|
|
|
78
79
|
const agent = new Headers(init?.headers).get(OPENCODE_AGENT_HEADER);
|
|
79
80
|
return !agent || !LOGIN_SUPPRESSED_AGENTS.has(agent);
|
|
80
81
|
}
|
|
82
|
+
function inputString(inputs, key) {
|
|
83
|
+
const value = inputs?.[key]?.trim();
|
|
84
|
+
return value || undefined;
|
|
85
|
+
}
|
|
86
|
+
function loginOptions(base, inputs) {
|
|
87
|
+
const inputMethod = inputString(inputs, "method");
|
|
88
|
+
const method = inputMethod && LOGIN_METHODS.has(inputMethod) ? inputMethod : undefined;
|
|
89
|
+
const identityProvider = inputString(inputs, "identityProvider");
|
|
90
|
+
const region = inputString(inputs, "region");
|
|
91
|
+
return {
|
|
92
|
+
...base,
|
|
93
|
+
...(method ? { method } : {}),
|
|
94
|
+
...(identityProvider ? { identityProvider } : {}),
|
|
95
|
+
...(region ? { region } : {}),
|
|
96
|
+
useDeviceFlow: true,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function isOrganizationLogin(login) {
|
|
100
|
+
return login.method === "organization" || login.license === "pro" || Boolean(login.identityProvider || login.region);
|
|
101
|
+
}
|
|
102
|
+
function loginPrompts(options) {
|
|
103
|
+
const prompts = [];
|
|
104
|
+
const login = options.login;
|
|
105
|
+
const hasLoginRoute = Boolean(login.method || login.license || login.identityProvider || login.region);
|
|
106
|
+
if (!hasLoginRoute) {
|
|
107
|
+
prompts.push({
|
|
108
|
+
type: "select",
|
|
109
|
+
key: "method",
|
|
110
|
+
message: "Select Kiro login method",
|
|
111
|
+
options: [
|
|
112
|
+
{ label: "Use with Builder ID", value: "builder-id" },
|
|
113
|
+
{ label: "Use with Google", value: "google" },
|
|
114
|
+
{ label: "Use with GitHub", value: "github" },
|
|
115
|
+
{ label: "Use with Your Organization", value: "organization" },
|
|
116
|
+
],
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
const organizationIsConfigured = login.method === "organization" || login.license === "pro" || Boolean(login.identityProvider || login.region);
|
|
120
|
+
const organizationWhen = hasLoginRoute ? undefined : { key: "method", op: "eq", value: "organization" };
|
|
121
|
+
if (organizationIsConfigured || !hasLoginRoute) {
|
|
122
|
+
if (!login.identityProvider) {
|
|
123
|
+
prompts.push({
|
|
124
|
+
type: "text",
|
|
125
|
+
key: "identityProvider",
|
|
126
|
+
message: "IAM Identity Center Start URL",
|
|
127
|
+
placeholder: "https://example.awsapps.com/start",
|
|
128
|
+
...(organizationWhen ? { when: organizationWhen } : {}),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
if (!login.region) {
|
|
132
|
+
prompts.push({
|
|
133
|
+
type: "text",
|
|
134
|
+
key: "region",
|
|
135
|
+
message: "IAM Identity Center region",
|
|
136
|
+
placeholder: "ap-northeast-2",
|
|
137
|
+
...(organizationWhen ? { when: organizationWhen } : {}),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return prompts.length > 0 ? prompts : undefined;
|
|
142
|
+
}
|
|
81
143
|
function localTransport(options, accessToken, behavior = {}) {
|
|
82
144
|
const backend = effectiveBackend(options, accessToken);
|
|
83
145
|
const login = () => {
|
|
84
146
|
if (behavior.loginOnAuthFailure === false)
|
|
85
147
|
return Promise.resolve(false);
|
|
86
148
|
return runKiroLoginFlowOnce({
|
|
87
|
-
login:
|
|
88
|
-
...options.login,
|
|
89
|
-
useDeviceFlow: true,
|
|
90
|
-
},
|
|
149
|
+
login: loginOptions(options.login),
|
|
91
150
|
});
|
|
92
151
|
};
|
|
93
152
|
if (backend === "acp")
|
|
@@ -107,7 +166,7 @@ function localTransport(options, accessToken, behavior = {}) {
|
|
|
107
166
|
login,
|
|
108
167
|
});
|
|
109
168
|
}
|
|
110
|
-
return new KiroRestTransport(fetchTransportOptions(options, apiKey ===
|
|
169
|
+
return new KiroRestTransport(fetchTransportOptions(options, apiKey === KIRO_LOCAL_TRANSPORT_KEY ? undefined : apiKey), {
|
|
111
170
|
login,
|
|
112
171
|
});
|
|
113
172
|
}
|
|
@@ -182,10 +241,7 @@ export function createKiroPlugin() {
|
|
|
182
241
|
return false;
|
|
183
242
|
startupLoginAttempted = true;
|
|
184
243
|
startupLogin = (async () => {
|
|
185
|
-
const session = startKiroCliLoginOnce(
|
|
186
|
-
...options.login,
|
|
187
|
-
useDeviceFlow: true,
|
|
188
|
-
});
|
|
244
|
+
const session = startKiroCliLoginOnce(loginOptions(options.login));
|
|
189
245
|
const prompted = await session.waitForPrompt(options.requestTimeoutMs);
|
|
190
246
|
if (!prompted)
|
|
191
247
|
return false;
|
|
@@ -221,11 +277,37 @@ export function createKiroPlugin() {
|
|
|
221
277
|
localServer = await startLocalKiroServer(localFetch);
|
|
222
278
|
return localServer;
|
|
223
279
|
};
|
|
224
|
-
const authorizeCliDeviceLogin = async () => {
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
280
|
+
const authorizeCliDeviceLogin = async (inputs) => {
|
|
281
|
+
const login = loginOptions(options.login, inputs);
|
|
282
|
+
if (isOrganizationLogin(login) && login.identityProvider) {
|
|
283
|
+
const authorization = await authorizeKiroDevice(login);
|
|
284
|
+
const url = kiroDeviceVerificationUrl(login.identityProvider, authorization.userCode);
|
|
285
|
+
return {
|
|
286
|
+
url,
|
|
287
|
+
instructions: `Open ${url} and confirm code: ${authorization.userCode}`,
|
|
288
|
+
method: "auto",
|
|
289
|
+
callback: async () => {
|
|
290
|
+
try {
|
|
291
|
+
const credential = await pollKiroDeviceToken(authorization, {
|
|
292
|
+
region: options.region,
|
|
293
|
+
...(options.profileArn ? { profileArn: options.profileArn } : {}),
|
|
294
|
+
});
|
|
295
|
+
await refreshModels(true).catch(() => []);
|
|
296
|
+
return {
|
|
297
|
+
type: "success",
|
|
298
|
+
key: encodeKiroDeviceAuthKey(credential),
|
|
299
|
+
metadata: {
|
|
300
|
+
source: "kiro-device-auth",
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
catch {
|
|
305
|
+
return { type: "failed" };
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
const session = startKiroCliLoginOnce(login);
|
|
229
311
|
await session.waitForPrompt(options.requestTimeoutMs);
|
|
230
312
|
return {
|
|
231
313
|
url: session.url,
|
|
@@ -238,7 +320,7 @@ export function createKiroPlugin() {
|
|
|
238
320
|
await refreshModels(true).catch(() => []);
|
|
239
321
|
return {
|
|
240
322
|
type: "success",
|
|
241
|
-
key:
|
|
323
|
+
key: KIRO_LOCAL_TRANSPORT_KEY,
|
|
242
324
|
metadata: {
|
|
243
325
|
source: "kiro-cli-device-flow",
|
|
244
326
|
},
|
|
@@ -246,6 +328,7 @@ export function createKiroPlugin() {
|
|
|
246
328
|
},
|
|
247
329
|
};
|
|
248
330
|
};
|
|
331
|
+
const authPrompts = loginPrompts(options);
|
|
249
332
|
return {
|
|
250
333
|
dispose: async () => {
|
|
251
334
|
await localServer?.close();
|
|
@@ -275,7 +358,8 @@ export function createKiroPlugin() {
|
|
|
275
358
|
{
|
|
276
359
|
type: "oauth",
|
|
277
360
|
label: "Kiro device login",
|
|
278
|
-
|
|
361
|
+
...(authPrompts ? { prompts: authPrompts } : {}),
|
|
362
|
+
authorize: async (inputs) => authorizeCliDeviceLogin(inputs),
|
|
279
363
|
},
|
|
280
364
|
{
|
|
281
365
|
type: "api",
|
|
@@ -300,7 +384,7 @@ export function createKiroPlugin() {
|
|
|
300
384
|
const apiKey = await resolveApiKey(auth);
|
|
301
385
|
const server = await ensureLocalServer();
|
|
302
386
|
return {
|
|
303
|
-
apiKey: apiKey ||
|
|
387
|
+
apiKey: apiKey || KIRO_LOCAL_TRANSPORT_KEY,
|
|
304
388
|
baseURL: server.baseURL,
|
|
305
389
|
};
|
|
306
390
|
},
|
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.21",
|
|
4
4
|
"description": "OpenCode plugin for using Kiro as a provider adapter",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"smoke:package": "npm run build && node scripts/smoke-package.mjs",
|
|
27
27
|
"smoke:kiro": "npm run build && node scripts/real-kiro-smoke.mjs",
|
|
28
28
|
"test": "bun test test/*.test.ts",
|
|
29
|
+
"test:real": "OPENCODE_KIRO_REAL=1 bun test test/real-kiro-cli.test.ts",
|
|
29
30
|
"typecheck": "tsc --noEmit"
|
|
30
31
|
},
|
|
31
32
|
"keywords": [
|