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.
Files changed (3) hide show
  1. package/README.md +94 -47
  2. package/dist/server.js +102 -36
  3. 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` targets the **unreleased OpenCode v2**
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
- > [RELEASE_NOTES_0.5.0-beta.3.md](./RELEASE_NOTES_0.5.0-beta.3.md) and
8
- > [PINNED_VERSIONS.md](./PINNED_VERSIONS.md) for exact pins and the tested OpenCode SHA.
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.3` |
40
+ | Package version | `0.5.0-beta.4` |
42
41
 
43
- Full pin table and verification evidence: [PINNED_VERSIONS.md](./PINNED_VERSIONS.md).
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 (`opencode.json`, project or global):
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.3"]
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 now background-auto-refreshes
67
- > UNPINNED npm plugin packages to whatever the registry serves — a bare `"opencode-kiro"`
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.3` spec.
70
+ > `opencode-kiro@0.5.0-beta.4` spec.
70
71
 
71
- The object form pins the same version and leaves room for future options:
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.3",
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.** (The beta.1 two-file setup is obsolete: if you added `"opencode-kiro"` to
89
- your global `cli.json` `plugins` array for beta.1, remove it.)
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.3", "-kiro"]
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.3.tgz"] }
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.3`) use colon-free paths and are
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 anymore: the beta.1
152
- "Enable the Kiro credits sidebar?" consent select was removed (upstream deleted the
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
- The chosen level reaches the SDK through the provider-settings path: OpenCode overlays
181
- the selected variant's `settings` onto the model's `settings`, hands them to the
182
- plugin's `aisdk` hook as `event.options`, and the plugin passes them verbatim to
183
- `createKiroAcp({ effort })`. That is why the plugin emits the SDK's own `effort` key
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, v1 placement restored) with the same total
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 — fixed upstream since beta.1). While a turn is still streaming,
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 the release notes for details.
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 the release notes.
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. `verifyAuth` from `kiro-acp-ai-provider` is the auth
243
- authority (it delegates to kiro-cli); success is stored as a minimal
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 hook)**: the plugin's SDK hook always constructs the
250
- provider from `kiro-acp-ai-provider` with the plugin-supplied options and sets it as
251
- the event's SDK, so the Kiro provider is always plugin-owned. The options relay each
252
- model's context window into the SDK's `contextWindows` map keyed by model ID.
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.3` into an OpenCode v1 setup.
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
- resources.cancelPoll = () => {
49
- reject(new Error("Kiro authentication was cancelled."));
53
+ const cancel = (reason) => {
54
+ reject(reason ?? new Error(CANCELLED_MESSAGE));
50
55
  };
51
- const tick = () => {
56
+ resources.cancelPoll = cancel;
57
+ const tick = async () => {
52
58
  resources.pollTimer = void 0;
53
- if (verifyAuth().authenticated) {
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(tick, POLL_INTERVAL_MS);
73
+ resources.pollTimer = setTimeout(() => {
74
+ void tick();
75
+ }, POLL_INTERVAL_MS);
66
76
  };
67
- resources.pollTimer = setTimeout(tick, POLL_INTERVAL_MS);
77
+ resources.pollTimer = setTimeout(() => {
78
+ void tick();
79
+ }, POLL_INTERVAL_MS);
68
80
  });
69
81
  }
70
82
  async function authorize(resources) {
71
- const { verifyAuth } = await import("kiro-acp-ai-provider");
72
- const status = verifyAuth();
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
- const { execFile } = await import("child_process");
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
- return {
87
- url: KIRO_DOCS_URL,
88
- instructions: LOGIN_INSTRUCTIONS,
89
- mode: "auto",
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: "opencode",
200
+ agent: state.options.agent,
188
201
  trustAllTools: true,
189
- mcpTimeout: 45,
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
- disposeHook: void 0
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 stableOptionsKey(options) {
333
- return isJsonSafe(options) ? stableStringify(options) : void 0;
369
+ function stableSettingsKey(settings) {
370
+ return isJsonSafe(settings) ? stableStringify(settings) : void 0;
334
371
  }
335
372
  async function registerAisdkHook(context, resources) {
336
- const registration = await context.aisdk.hook(
373
+ const sdkRegistration = await context.aisdk.hook(
337
374
  "sdk",
338
375
  async (event) => {
339
376
  if (!isKiroPackage(event.package)) return;
340
- const { createKiroAcp } = await import("kiro-acp-ai-provider");
341
- const key = stableOptionsKey(event.options);
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
- sdk = createKiroAcp(event.options);
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.disposeHook = registration.dispose;
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
- resources.disposeHook = void 0;
356
- try {
357
- await registration.dispose();
358
- } catch (error) {
359
- errors.push(error);
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:40) — the host auto-loads this
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",
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.0.0",
49
+ "kiro-acp-ai-provider": "3.1.0",
47
50
  "solid-js": "1.9.12"
48
51
  },
49
52
  "devDependencies": {