opencode-kiro 0.5.0-beta.3 → 0.5.0-beta.4
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 +94 -47
- package/dist/server.js +102 -36
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
# opencode-kiro
|
|
2
2
|
|
|
3
|
-
> ⚠️ **Experimental prerelease** — `0.5.0-beta.
|
|
3
|
+
> ⚠️ **Experimental prerelease** — `0.5.0-beta.4` targets the **unreleased OpenCode v2**
|
|
4
4
|
> plugin contract at a pinned snapshot. It does **not** work with OpenCode v1.
|
|
5
5
|
> v1 users: stay on **`opencode-kiro@0.4.0`** (the `main` branch / npm `latest` line,
|
|
6
|
-
> which remains the supported stable release). See
|
|
7
|
-
> [
|
|
8
|
-
>
|
|
9
|
-
> No OpenCode v2 release date is known or claimed here.
|
|
6
|
+
> which remains the supported stable release). See [CHANGELOG.md](./CHANGELOG.md) and
|
|
7
|
+
> [docs/COMPATIBILITY.md](./docs/COMPATIBILITY.md) for exact pins and the tested
|
|
8
|
+
> OpenCode SHA. No OpenCode v2 release date is known or claimed here.
|
|
10
9
|
|
|
11
10
|
The ACP-compliant [Kiro](https://kiro.dev) plugin for [opencode](https://opencode.ai).
|
|
12
11
|
|
|
@@ -36,11 +35,11 @@ This prerelease is built and tested against **one pinned OpenCode v2 snapshot**:
|
|
|
36
35
|
|
|
37
36
|
| Item | Value |
|
|
38
37
|
|---|---|
|
|
39
|
-
| Tested OpenCode commit (`upstream/v2`) | `8ba434b5973856b2f32b8cd3543e154b25c413e6` |
|
|
38
|
+
| Tested OpenCode commit (`upstream/v2` head, 2026-08-29) | `8ba434b5973856b2f32b8cd3543e154b25c413e6` |
|
|
40
39
|
| `@opencode-ai/plugin` | `0.0.0-dev-18686` (exact) |
|
|
41
|
-
| Package version | `0.5.0-beta.
|
|
40
|
+
| Package version | `0.5.0-beta.4` |
|
|
42
41
|
|
|
43
|
-
Full pin table and verification
|
|
42
|
+
Full pin table and verification steps: [docs/COMPATIBILITY.md](./docs/COMPATIBILITY.md).
|
|
44
43
|
There is no `engines.opencode` constraint — the v2 host has no stable semver yet; the
|
|
45
44
|
tested SHA above is the compatibility target. Other v2 snapshots may or may not work.
|
|
46
45
|
|
|
@@ -55,26 +54,29 @@ tested SHA above is the compatibility target. Other v2 snapshots may or may not
|
|
|
55
54
|
## Install and configure
|
|
56
55
|
|
|
57
56
|
**One config entry — that's the whole setup.** Add the package to the **`plugins`**
|
|
58
|
-
array (plural) of your OpenCode config
|
|
57
|
+
array (plural) of your OpenCode config. That is any `opencode.json` or `opencode.jsonc`
|
|
58
|
+
(or `.opencode/opencode.json`) found walking up from the project directory, or the
|
|
59
|
+
global `~/.config/opencode/opencode.json`:
|
|
59
60
|
|
|
60
61
|
```json
|
|
61
62
|
{
|
|
62
|
-
"plugins": ["opencode-kiro@0.5.0-beta.
|
|
63
|
+
"plugins": ["opencode-kiro@0.5.0-beta.4"]
|
|
63
64
|
}
|
|
64
65
|
```
|
|
65
66
|
|
|
66
|
-
> ⚠️ **Always pin the exact version, as above.** The host
|
|
67
|
-
>
|
|
67
|
+
> ⚠️ **Always pin the exact version, as above.** The host background-auto-refreshes
|
|
68
|
+
> unpinned npm plugin packages to whatever the registry serves, so a bare `"opencode-kiro"`
|
|
68
69
|
> spec can silently move you off the tested build. Use the exact
|
|
69
|
-
> `opencode-kiro@0.5.0-beta.
|
|
70
|
+
> `opencode-kiro@0.5.0-beta.4` spec.
|
|
70
71
|
|
|
71
|
-
The object form pins the same version and
|
|
72
|
+
The object form pins the same version and takes the plugin options described in
|
|
73
|
+
[Plugin options](#plugin-options):
|
|
72
74
|
|
|
73
75
|
```json
|
|
74
76
|
{
|
|
75
77
|
"plugins": [
|
|
76
78
|
{
|
|
77
|
-
"package": "opencode-kiro@0.5.0-beta.
|
|
79
|
+
"package": "opencode-kiro@0.5.0-beta.4",
|
|
78
80
|
"options": {}
|
|
79
81
|
}
|
|
80
82
|
]
|
|
@@ -85,8 +87,47 @@ This loads the server entry (`./server` export): auth, model discovery, and prov
|
|
|
85
87
|
ownership. The server plugin declares **`tui: true`**, so the host TUI **auto-loads the
|
|
86
88
|
package's `./tui` entrypoint by itself** — the sidebar credits box and the prompt footer
|
|
87
89
|
credits chip appear with no further configuration. **No `cli.json` TUI entry is
|
|
88
|
-
needed.**
|
|
89
|
-
|
|
90
|
+
needed.**
|
|
91
|
+
|
|
92
|
+
### Plugin options
|
|
93
|
+
|
|
94
|
+
All options are optional; omit the `options` object entirely to get the defaults.
|
|
95
|
+
|
|
96
|
+
| Option | Type | Default | Meaning |
|
|
97
|
+
|---|---|---|---|
|
|
98
|
+
| `agent` | string | `"opencode"` | kiro-cli agent name the provider runs under |
|
|
99
|
+
| `mcpTimeout` | number | `45` | MCP tool-call timeout, in **minutes** |
|
|
100
|
+
| `discover` | boolean | `true` | Set `false` to skip the setup-time model discovery kick-off when Kiro is already connected. Discovery triggered by login/credential events still runs. |
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"plugins": [
|
|
105
|
+
{
|
|
106
|
+
"package": "opencode-kiro@0.5.0-beta.4",
|
|
107
|
+
"options": {
|
|
108
|
+
"agent": "opencode",
|
|
109
|
+
"mcpTimeout": 45,
|
|
110
|
+
"discover": true
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
A value of the wrong type falls back to its default; unknown keys are ignored. The
|
|
118
|
+
contract per option: `mcpTimeout` must be a positive number of minutes; zero, negative,
|
|
119
|
+
or non-numeric values fall back to the default (`45`); an empty `agent` string falls
|
|
120
|
+
back to `"opencode"`.
|
|
121
|
+
|
|
122
|
+
> ⚠️ **Options work on the npm channel only.** The host passes `options` to plugins it
|
|
123
|
+
> installed from npm (the `"package": "opencode-kiro@<version>"` form above). Local
|
|
124
|
+
> `name@file:` tarball installs count as the npm channel, so options work there too.
|
|
125
|
+
> Bundled or built-in plugin loads receive an empty options object, so **the defaults
|
|
126
|
+
> always apply there** regardless of what you write in `options`.
|
|
127
|
+
|
|
128
|
+
There is **no `cwd` option**. The working directory handed to kiro-cli is derived
|
|
129
|
+
automatically from the OpenCode location the plugin is set up for, once per location;
|
|
130
|
+
a user-supplied path could only be less accurate.
|
|
90
131
|
|
|
91
132
|
### Disabling
|
|
92
133
|
|
|
@@ -96,7 +137,7 @@ activates either:
|
|
|
96
137
|
|
|
97
138
|
```json
|
|
98
139
|
{
|
|
99
|
-
"plugins": ["opencode-kiro@0.5.0-beta.
|
|
140
|
+
"plugins": ["opencode-kiro@0.5.0-beta.4", "-kiro"]
|
|
100
141
|
}
|
|
101
142
|
```
|
|
102
143
|
|
|
@@ -118,14 +159,14 @@ npm install && npm run build && npm pack
|
|
|
118
159
|
```
|
|
119
160
|
|
|
120
161
|
```json
|
|
121
|
-
{ "plugins": ["opencode-kiro@file:/absolute/path/to/opencode-kiro-0.5.0-beta.
|
|
162
|
+
{ "plugins": ["opencode-kiro@file:/absolute/path/to/opencode-kiro-0.5.0-beta.4.tgz"] }
|
|
122
163
|
```
|
|
123
164
|
|
|
124
165
|
A bare path or bare `file:` spec is rejected at the tested SHA — the `name@file:` form
|
|
125
166
|
is required. **Caveat (local `file:` installs only)**: the colon in the resulting
|
|
126
167
|
install dirname defeats the host's OpenTUI loader shim, so the TUI surfaces render a
|
|
127
168
|
contained per-slot error notice instead of the credits views (the rest of the TUI keeps
|
|
128
|
-
working). Registry installs (`opencode-kiro@0.5.0-beta.
|
|
169
|
+
working). Registry installs (`opencode-kiro@0.5.0-beta.4`) use colon-free paths and are
|
|
129
170
|
fully green — this affects local tarball validation only.
|
|
130
171
|
|
|
131
172
|
The host resolves entrypoints from the package `exports` (`./server` for the server
|
|
@@ -148,10 +189,8 @@ Select the **Kiro** integration, then the **Kiro CLI Login** method:
|
|
|
148
189
|
Complete the login there; the plugin polls for up to 120 seconds and stores a minimal
|
|
149
190
|
credential record when kiro-cli reports success.
|
|
150
191
|
|
|
151
|
-
There is no configuration prompt during login
|
|
152
|
-
|
|
153
|
-
prompts API in favor of forms — and the sidebar no longer needs consent-driven config,
|
|
154
|
-
since `tui: true` auto-loads it).
|
|
192
|
+
There is no configuration prompt during login; the sidebar and footer credits surfaces
|
|
193
|
+
auto-load from the single `plugins` entry.
|
|
155
194
|
|
|
156
195
|
If the flow times out, authenticate directly with kiro-cli (`kiro-cli login`) and run
|
|
157
196
|
`opencode auth login` again; the fast path then completes immediately.
|
|
@@ -176,16 +215,11 @@ opencode models
|
|
|
176
215
|
opencode run -m kiro/<exact-model-id> "hello"
|
|
177
216
|
```
|
|
178
217
|
|
|
179
|
-
Effort-capable models expose their variants through OpenCode's model-variant selection
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
(not `reasoningEffort`) — and why the SDK factory setting, not per-call provider
|
|
185
|
-
options, is the working carrier: OpenCode builds per-call `providerOptions` only for
|
|
186
|
-
the first-party `@ai-sdk/*` provider families, so `providerOptions.kiro.*` is never
|
|
187
|
-
populated for an `aisdk:` package provider like this one. Kiro cannot disable thinking,
|
|
188
|
-
so even the lowest level still produces a reasoning trail.
|
|
218
|
+
Effort-capable models expose their variants through OpenCode's model-variant selection:
|
|
219
|
+
pick the variant to choose a reasoning-effort level. The selected level is applied per
|
|
220
|
+
request, and one provider instance (one kiro-cli process) serves every effort level, so
|
|
221
|
+
switching effort does not start additional kiro-cli processes. Kiro cannot disable
|
|
222
|
+
thinking, so even the lowest level still produces a reasoning trail.
|
|
189
223
|
|
|
190
224
|
## Credits in the TUI
|
|
191
225
|
|
|
@@ -196,7 +230,7 @@ plugin renders two surfaces:
|
|
|
196
230
|
- a Kiro credits box in the sidebar (`sidebar.content` claim), showing the session's
|
|
197
231
|
live credits total and unit
|
|
198
232
|
- a compact credits chip in the prompt footer row beside the host cost/context
|
|
199
|
-
display (`prompt.footer.status` claim
|
|
233
|
+
display (`prompt.footer.status` claim) with the same total
|
|
200
234
|
|
|
201
235
|
Both are additive `append` claims — they compose with the host's built-in content and
|
|
202
236
|
never replace it — and both pick up the active theme's text tokens (feature-detected;
|
|
@@ -208,11 +242,11 @@ The only configuration needed is the single `plugins` entry from
|
|
|
208
242
|
[Install](#install-and-configure) — the TUI half auto-loads via `tui: true`.
|
|
209
243
|
|
|
210
244
|
Durable credits are read straight from host message state (the host persists provider
|
|
211
|
-
state on text end
|
|
245
|
+
state on text end). While a turn is still streaming,
|
|
212
246
|
credits for just-ended text are picked up live through a transient overlay that works
|
|
213
247
|
around a host reducer bug at the pinned snapshot (the live event path still drops
|
|
214
248
|
provider state); once durable state arrives it is authoritative and nothing is
|
|
215
|
-
double-counted. See
|
|
249
|
+
double-counted. See [CHANGELOG.md](./CHANGELOG.md) for details.
|
|
216
250
|
|
|
217
251
|
## Known limitations (prerelease)
|
|
218
252
|
|
|
@@ -220,7 +254,7 @@ double-counted. See the release notes for details.
|
|
|
220
254
|
upstream, but the live `session.text.ended` reducer still drops provider state at
|
|
221
255
|
the tested SHA, so in-turn updates come from the plugin's transient overlay
|
|
222
256
|
(durable state always wins on reconcile). See
|
|
223
|
-
[Credits in the TUI](#credits-in-the-tui) and
|
|
257
|
+
[Credits in the TUI](#credits-in-the-tui) and [CHANGELOG.md](./CHANGELOG.md).
|
|
224
258
|
- **Credits render in the TUI only.** Every other cost surface (ACP clients, web,
|
|
225
259
|
desktop, share pages, CLI cost output) shows $0.00 for Kiro sessions because the
|
|
226
260
|
catalog declares Kiro's per-token `cost` as 0 (subscription-metered, no per-token
|
|
@@ -239,17 +273,30 @@ double-counted. See the release notes for details.
|
|
|
239
273
|
## How it works
|
|
240
274
|
|
|
241
275
|
- **Auth (Integration + Credential)**: the plugin upserts the `kiro` integration with a
|
|
242
|
-
"Kiro CLI Login" OAuth method. `
|
|
243
|
-
authority (it delegates to kiro-cli
|
|
244
|
-
`Credential.OAuth` presence record.
|
|
276
|
+
"Kiro CLI Login" OAuth method. `verifyAuthAsync` from `kiro-acp-ai-provider` is the
|
|
277
|
+
auth authority (it delegates to kiro-cli without blocking the host's event loop);
|
|
278
|
+
success is stored as a minimal `Credential.OAuth` presence record. Starting a new
|
|
279
|
+
login while one is pending cancels the earlier attempt.
|
|
245
280
|
- **Model discovery (catalog transform)**: after login (and on later login events) the
|
|
246
281
|
plugin runs `listModels()` outside the transform, then applies the validated capture
|
|
247
282
|
via a catalog transform and reload — exact ID matching, catalog metadata preserved,
|
|
248
283
|
effort variants projected, fail-open on any discovery error.
|
|
249
|
-
- **Provider ownership (AISDK
|
|
250
|
-
|
|
251
|
-
the event's SDK, so the Kiro provider is
|
|
252
|
-
|
|
284
|
+
- **Provider ownership (AISDK hooks)**: the plugin's `sdk` hook constructs the provider
|
|
285
|
+
from `kiro-acp-ai-provider` with the plugin-supplied settings (identifying itself to
|
|
286
|
+
kiro-cli as `opencode-kiro`) and sets it as the event's SDK, so the Kiro provider is
|
|
287
|
+
always plugin-owned; one instance is cached per distinct settings and shared across
|
|
288
|
+
effort variants. The `language` hook applies the selected effort per request. The
|
|
289
|
+
settings relay each model's context window into the SDK's `contextWindows` map keyed
|
|
290
|
+
by model ID.
|
|
291
|
+
- **Effort carrier (why SDK settings, not `providerOptions`)**: OpenCode overlays the
|
|
292
|
+
selected variant's `settings` onto the model's `settings` and hands them to the
|
|
293
|
+
plugin's `aisdk` hooks as `event.options`; the `language` hook reads
|
|
294
|
+
`event.options.effort` and passes it to the shared provider as a per-model override
|
|
295
|
+
(`languageModel(id, { effort })`). The plugin emits the SDK's own `effort` key (not
|
|
296
|
+
`reasoningEffort`), and the settings path is the working carrier because OpenCode
|
|
297
|
+
builds per-call `providerOptions` only for the first-party `@ai-sdk/*` provider
|
|
298
|
+
families - `providerOptions.kiro.*` is never populated for an `aisdk:` package
|
|
299
|
+
provider like this one.
|
|
253
300
|
- **Session affinity & reset (in-SDK)**: the SDK keys kiro-cli sessions off OpenCode's
|
|
254
301
|
session affinity, isolates tool-less utility calls on an ephemeral session, detects
|
|
255
302
|
prompt-history divergence, and starts a fresh kiro session when needed.
|
|
@@ -269,7 +316,7 @@ double-counted. See the release notes for details.
|
|
|
269
316
|
| `kiro` provider not showing in `opencode models` | Run `opencode auth login` first: models are discovered after auth. If the loaded catalog lacks a `kiro` entry, the plugin self-registers a minimal fallback during discovery. |
|
|
270
317
|
| Path install rejected (`must export id`) | Use the `name@file:<absolute tarball path>` form after `npm run build && npm pack` in your checkout (both entry modules export ids). |
|
|
271
318
|
| Provider visible but runs fail | The provider can be selectable before any credential exists. Run `opencode auth login` first. |
|
|
272
|
-
| Worked yesterday, broken today | This prerelease targets one pinned OpenCode snapshot (see [Compatibility](#compatibility)). If your OpenCode build moved past the tested SHA, the v2 plugin surface may have changed underneath it. |
|
|
319
|
+
| Worked yesterday, broken today | This prerelease targets one pinned OpenCode snapshot (see [Compatibility](#compatibility)). If your OpenCode build moved past the tested SHA, the v2 plugin surface may have changed underneath it. The other cause is an **unpinned** `plugins` entry (a bare `"opencode-kiro"`): the host background-auto-refreshes unpinned npm plugin packages, so the plugin itself can move off the tested build without you changing anything — pin the exact `opencode-kiro@0.5.0-beta.4` spec. |
|
|
273
320
|
|
|
274
321
|
## Legacy: v1 / OpenCode v1 users (`0.4.0`)
|
|
275
322
|
|
|
@@ -278,7 +325,7 @@ v1 (`opencode >= 1.16.0`). It uses the v1 contract throughout: singular `plugin`
|
|
|
278
325
|
arrays in `opencode.json` and `tui.json`, the `opencode plugin opencode-kiro`
|
|
279
326
|
installer, and `part.metadata.kiro` credits. Its full documentation is the README at
|
|
280
327
|
the [`v0.4.0` tag](https://github.com/NachoFLizaur/opencode-kiro/tree/v0.4.0)
|
|
281
|
-
(equivalently, `main`). Do not install `0.5.0-beta.
|
|
328
|
+
(equivalently, `main`). Do not install `0.5.0-beta.4` into an OpenCode v1 setup.
|
|
282
329
|
|
|
283
330
|
## Development
|
|
284
331
|
|
package/dist/server.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// package.json
|
|
2
|
+
var version = "0.5.0-beta.4";
|
|
3
|
+
|
|
1
4
|
// src/server/auth.ts
|
|
2
5
|
var KIRO_INTEGRATION_ID = "kiro";
|
|
3
6
|
var KIRO_INTEGRATION_NAME = "Kiro";
|
|
@@ -8,6 +11,8 @@ var POLL_INTERVAL_MS = 2e3;
|
|
|
8
11
|
var MAX_WAIT_MS = 12e4;
|
|
9
12
|
var NOT_INSTALLED_MESSAGE = "kiro-cli is not installed. Install it from https://kiro.dev/docs/cli/";
|
|
10
13
|
var TIMEOUT_MESSAGE = "Kiro authentication timed out. Run `kiro-cli login` manually, then re-run `opencode auth login`.";
|
|
14
|
+
var CANCELLED_MESSAGE = "Kiro authentication was cancelled.";
|
|
15
|
+
var SUPERSEDED_MESSAGE = "Kiro CLI login superseded by a new login attempt.";
|
|
11
16
|
var LOGIN_INSTRUCTIONS = "Complete Kiro authentication in the browser window that just opened (if no browser opened, run `kiro-cli login` in another terminal). Waiting for login...";
|
|
12
17
|
var ALREADY_AUTHENTICATED_INSTRUCTIONS = "Already authenticated with Kiro CLI.";
|
|
13
18
|
function createAuthResources() {
|
|
@@ -18,7 +23,7 @@ function createAuthResources() {
|
|
|
18
23
|
disposeRegistration: void 0
|
|
19
24
|
};
|
|
20
25
|
}
|
|
21
|
-
function releaseLoginResources(resources) {
|
|
26
|
+
function releaseLoginResources(resources, reason) {
|
|
22
27
|
if (resources.pollTimer !== void 0) {
|
|
23
28
|
clearTimeout(resources.pollTimer);
|
|
24
29
|
resources.pollTimer = void 0;
|
|
@@ -30,7 +35,7 @@ function releaseLoginResources(resources) {
|
|
|
30
35
|
if (resources.cancelPoll !== void 0) {
|
|
31
36
|
const cancel = resources.cancelPoll;
|
|
32
37
|
resources.cancelPoll = void 0;
|
|
33
|
-
cancel();
|
|
38
|
+
cancel(reason);
|
|
34
39
|
}
|
|
35
40
|
}
|
|
36
41
|
function kiroCredential() {
|
|
@@ -45,12 +50,15 @@ function kiroCredential() {
|
|
|
45
50
|
function pollForLogin(verifyAuth, resources) {
|
|
46
51
|
return new Promise((resolve, reject) => {
|
|
47
52
|
const start = Date.now();
|
|
48
|
-
|
|
49
|
-
reject(new Error(
|
|
53
|
+
const cancel = (reason) => {
|
|
54
|
+
reject(reason ?? new Error(CANCELLED_MESSAGE));
|
|
50
55
|
};
|
|
51
|
-
|
|
56
|
+
resources.cancelPoll = cancel;
|
|
57
|
+
const tick = async () => {
|
|
52
58
|
resources.pollTimer = void 0;
|
|
53
|
-
|
|
59
|
+
const status = await verifyAuth();
|
|
60
|
+
if (resources.cancelPoll !== cancel) return;
|
|
61
|
+
if (status.authenticated) {
|
|
54
62
|
resources.cancelPoll = void 0;
|
|
55
63
|
releaseLoginResources(resources);
|
|
56
64
|
resolve(kiroCredential());
|
|
@@ -62,14 +70,19 @@ function pollForLogin(verifyAuth, resources) {
|
|
|
62
70
|
reject(new Error(TIMEOUT_MESSAGE));
|
|
63
71
|
return;
|
|
64
72
|
}
|
|
65
|
-
resources.pollTimer = setTimeout(
|
|
73
|
+
resources.pollTimer = setTimeout(() => {
|
|
74
|
+
void tick();
|
|
75
|
+
}, POLL_INTERVAL_MS);
|
|
66
76
|
};
|
|
67
|
-
resources.pollTimer = setTimeout(
|
|
77
|
+
resources.pollTimer = setTimeout(() => {
|
|
78
|
+
void tick();
|
|
79
|
+
}, POLL_INTERVAL_MS);
|
|
68
80
|
});
|
|
69
81
|
}
|
|
70
82
|
async function authorize(resources) {
|
|
71
|
-
const {
|
|
72
|
-
const
|
|
83
|
+
const { verifyAuthAsync } = await import("kiro-acp-ai-provider");
|
|
84
|
+
const { execFile } = await import("child_process");
|
|
85
|
+
const status = await verifyAuthAsync();
|
|
73
86
|
if (!status.installed) throw new Error(NOT_INSTALLED_MESSAGE);
|
|
74
87
|
if (status.authenticated) {
|
|
75
88
|
return {
|
|
@@ -79,16 +92,16 @@ async function authorize(resources) {
|
|
|
79
92
|
callback: Promise.resolve(kiroCredential())
|
|
80
93
|
};
|
|
81
94
|
}
|
|
82
|
-
|
|
95
|
+
if (resources.cancelPoll !== void 0) {
|
|
96
|
+
releaseLoginResources(resources, new Error(SUPERSEDED_MESSAGE));
|
|
97
|
+
}
|
|
83
98
|
resources.child = execFile("kiro-cli", ["login"], {
|
|
84
99
|
shell: process.platform === "win32"
|
|
85
100
|
});
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
callback: pollForLogin(verifyAuth, resources)
|
|
91
|
-
};
|
|
101
|
+
const callback = pollForLogin(verifyAuthAsync, resources);
|
|
102
|
+
callback.catch(() => {
|
|
103
|
+
});
|
|
104
|
+
return { url: KIRO_DOCS_URL, instructions: LOGIN_INSTRUCTIONS, mode: "auto", callback };
|
|
92
105
|
}
|
|
93
106
|
async function registerAuth(context, resources) {
|
|
94
107
|
const registration = await context.integration.transform((draft) => {
|
|
@@ -184,9 +197,10 @@ function applyCatalogSnapshot(draft, state) {
|
|
|
184
197
|
provider.settings = {
|
|
185
198
|
...provider.settings,
|
|
186
199
|
cwd: state.cwd,
|
|
187
|
-
agent:
|
|
200
|
+
agent: state.options.agent,
|
|
188
201
|
trustAllTools: true,
|
|
189
|
-
|
|
202
|
+
// intentionally not exposed as a plugin option
|
|
203
|
+
mcpTimeout: state.options.mcpTimeout,
|
|
190
204
|
contextWindows
|
|
191
205
|
};
|
|
192
206
|
});
|
|
@@ -248,10 +262,11 @@ async function consumeEvents(iterator, discover) {
|
|
|
248
262
|
} catch {
|
|
249
263
|
}
|
|
250
264
|
}
|
|
251
|
-
async function registerDiscovery(context, resources) {
|
|
265
|
+
async function registerDiscovery(context, resources, options) {
|
|
252
266
|
const { location } = await context.integration.list();
|
|
253
267
|
const state = {
|
|
254
268
|
cwd: location.directory,
|
|
269
|
+
options,
|
|
255
270
|
snapshot: void 0,
|
|
256
271
|
generation: 0,
|
|
257
272
|
inflight: void 0
|
|
@@ -265,7 +280,7 @@ async function registerDiscovery(context, resources) {
|
|
|
265
280
|
const iterator = context.event.subscribe()[Symbol.asyncIterator]();
|
|
266
281
|
resources.eventIterator = iterator;
|
|
267
282
|
resources.eventTask = consumeEvents(iterator, discover);
|
|
268
|
-
if (await context.integration.connection.active(KIRO_INTEGRATION_ID)) {
|
|
283
|
+
if (options.discover && await context.integration.connection.active(KIRO_INTEGRATION_ID)) {
|
|
269
284
|
void discover("setup").catch(() => {
|
|
270
285
|
});
|
|
271
286
|
}
|
|
@@ -299,16 +314,38 @@ async function registerDiscovery(context, resources) {
|
|
|
299
314
|
|
|
300
315
|
// src/server/aisdk.ts
|
|
301
316
|
var KIRO_SDK_PACKAGE = "kiro-acp-ai-provider";
|
|
317
|
+
var CLIENT_INFO = { name: "opencode-kiro", version };
|
|
302
318
|
function createAisdkResources() {
|
|
303
319
|
return {
|
|
304
320
|
ownedSdks: /* @__PURE__ */ new Set(),
|
|
305
321
|
cache: /* @__PURE__ */ new Map(),
|
|
306
|
-
|
|
322
|
+
disposeHooks: []
|
|
307
323
|
};
|
|
308
324
|
}
|
|
309
325
|
function isKiroPackage(pkg) {
|
|
310
326
|
return pkg === KIRO_SDK_PACKAGE || pkg === `aisdk:${KIRO_SDK_PACKAGE}`;
|
|
311
327
|
}
|
|
328
|
+
var SETTINGS_ALLOWLIST = [
|
|
329
|
+
"cwd",
|
|
330
|
+
"model",
|
|
331
|
+
"agent",
|
|
332
|
+
"trustAllTools",
|
|
333
|
+
"agentPrompt",
|
|
334
|
+
"env",
|
|
335
|
+
"clientInfo",
|
|
336
|
+
"sessionId",
|
|
337
|
+
"contextWindow",
|
|
338
|
+
"contextWindows",
|
|
339
|
+
"mcpTimeout"
|
|
340
|
+
];
|
|
341
|
+
function sanitizeSettings(options) {
|
|
342
|
+
const settings = {};
|
|
343
|
+
for (const key of SETTINGS_ALLOWLIST) {
|
|
344
|
+
const value = options[key];
|
|
345
|
+
if (value !== void 0) settings[key] = value;
|
|
346
|
+
}
|
|
347
|
+
return settings;
|
|
348
|
+
}
|
|
312
349
|
function isJsonSafe(value) {
|
|
313
350
|
if (value === null) return true;
|
|
314
351
|
const kind = typeof value;
|
|
@@ -329,19 +366,20 @@ function stableStringify(value) {
|
|
|
329
366
|
}
|
|
330
367
|
return JSON.stringify(value);
|
|
331
368
|
}
|
|
332
|
-
function
|
|
333
|
-
return isJsonSafe(
|
|
369
|
+
function stableSettingsKey(settings) {
|
|
370
|
+
return isJsonSafe(settings) ? stableStringify(settings) : void 0;
|
|
334
371
|
}
|
|
335
372
|
async function registerAisdkHook(context, resources) {
|
|
336
|
-
const
|
|
373
|
+
const sdkRegistration = await context.aisdk.hook(
|
|
337
374
|
"sdk",
|
|
338
375
|
async (event) => {
|
|
339
376
|
if (!isKiroPackage(event.package)) return;
|
|
340
|
-
const
|
|
341
|
-
const key =
|
|
377
|
+
const settings = { ...sanitizeSettings(event.options), clientInfo: CLIENT_INFO };
|
|
378
|
+
const key = stableSettingsKey(settings);
|
|
342
379
|
let sdk = key === void 0 ? void 0 : resources.cache.get(key);
|
|
343
380
|
if (sdk === void 0) {
|
|
344
|
-
|
|
381
|
+
const { createKiroAcp } = await import("kiro-acp-ai-provider");
|
|
382
|
+
sdk = createKiroAcp(settings);
|
|
345
383
|
resources.ownedSdks.add(sdk);
|
|
346
384
|
if (key !== void 0) resources.cache.set(key, sdk);
|
|
347
385
|
}
|
|
@@ -349,14 +387,34 @@ async function registerAisdkHook(context, resources) {
|
|
|
349
387
|
},
|
|
350
388
|
{ providerID: KIRO_PROVIDER_ID }
|
|
351
389
|
);
|
|
352
|
-
resources.
|
|
390
|
+
resources.disposeHooks.push(sdkRegistration.dispose);
|
|
391
|
+
let languageRegistration;
|
|
392
|
+
try {
|
|
393
|
+
languageRegistration = await context.aisdk.hook(
|
|
394
|
+
"language",
|
|
395
|
+
async (event) => {
|
|
396
|
+
const effort = typeof event.options.effort === "string" ? event.options.effort : void 0;
|
|
397
|
+
const overrides = effort === void 0 ? void 0 : { effort };
|
|
398
|
+
event.language = event.sdk.languageModel(String(event.model.modelID), overrides);
|
|
399
|
+
},
|
|
400
|
+
{ providerID: KIRO_PROVIDER_ID }
|
|
401
|
+
);
|
|
402
|
+
} catch (error) {
|
|
403
|
+
await sdkRegistration.dispose().catch(() => {
|
|
404
|
+
});
|
|
405
|
+
resources.disposeHooks.length = 0;
|
|
406
|
+
throw error;
|
|
407
|
+
}
|
|
408
|
+
resources.disposeHooks.push(languageRegistration.dispose);
|
|
353
409
|
return async () => {
|
|
354
410
|
const errors = [];
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
411
|
+
const disposeHooks = resources.disposeHooks.splice(0);
|
|
412
|
+
for (const dispose of disposeHooks) {
|
|
413
|
+
try {
|
|
414
|
+
await dispose();
|
|
415
|
+
} catch (error) {
|
|
416
|
+
errors.push(error);
|
|
417
|
+
}
|
|
360
418
|
}
|
|
361
419
|
const owned = Array.from(resources.ownedSdks);
|
|
362
420
|
resources.ownedSdks.clear();
|
|
@@ -405,17 +463,25 @@ function buildCleanup(state) {
|
|
|
405
463
|
}
|
|
406
464
|
|
|
407
465
|
// src/server.ts
|
|
466
|
+
function resolveOptions(raw) {
|
|
467
|
+
return {
|
|
468
|
+
agent: typeof raw.agent === "string" && raw.agent !== "" ? raw.agent : "opencode",
|
|
469
|
+
mcpTimeout: typeof raw.mcpTimeout === "number" && Number.isFinite(raw.mcpTimeout) && raw.mcpTimeout > 0 ? raw.mcpTimeout : 45,
|
|
470
|
+
discover: typeof raw.discover === "boolean" ? raw.discover : true
|
|
471
|
+
};
|
|
472
|
+
}
|
|
408
473
|
var plugin = {
|
|
409
474
|
id: "kiro",
|
|
410
|
-
// tui: true (dist/promise/plugin.d.ts
|
|
475
|
+
// tui: true (dist/promise/plugin.d.ts) — the host auto-loads this
|
|
411
476
|
// package's `./tui` entrypoint for npm-channel installs (single config entry)
|
|
412
477
|
tui: true,
|
|
413
478
|
async setup(context) {
|
|
479
|
+
const options = resolveOptions(context.options ?? {});
|
|
414
480
|
const state = createServerState();
|
|
415
481
|
const cleanup = buildCleanup(state);
|
|
416
482
|
try {
|
|
417
483
|
state.disposers.push(await registerAuth(context, state.auth));
|
|
418
|
-
state.disposers.push(await registerDiscovery(context, state.discovery));
|
|
484
|
+
state.disposers.push(await registerDiscovery(context, state.discovery, options));
|
|
419
485
|
state.disposers.push(await registerAisdkHook(context, state.aisdk));
|
|
420
486
|
} catch (error) {
|
|
421
487
|
await Promise.resolve(cleanup()).catch(() => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-kiro",
|
|
3
|
-
"version": "0.5.0-beta.
|
|
3
|
+
"version": "0.5.0-beta.4",
|
|
4
4
|
"description": "The ACP-compliant Kiro plugin for opencode: auth via the official kiro-cli login, the live Kiro model lineup through the Agent Client Protocol, and TUI credits display",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Nacho F. Lizaur (https://github.com/NachoFLizaur)",
|
|
@@ -38,12 +38,15 @@
|
|
|
38
38
|
"engines": {
|
|
39
39
|
"node": ">=20"
|
|
40
40
|
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"tag": "beta"
|
|
43
|
+
},
|
|
41
44
|
"peerDependencies": {
|
|
42
45
|
"@opencode-ai/plugin": "0.0.0-dev-18686"
|
|
43
46
|
},
|
|
44
47
|
"dependencies": {
|
|
45
48
|
"@opentui/solid": "0.5.9",
|
|
46
|
-
"kiro-acp-ai-provider": "3.
|
|
49
|
+
"kiro-acp-ai-provider": "3.1.0",
|
|
47
50
|
"solid-js": "1.9.12"
|
|
48
51
|
},
|
|
49
52
|
"devDependencies": {
|