opencode-kiro 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nacho F. Lizaur
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,239 @@
1
+ # opencode-kiro
2
+
3
+ The ACP-compliant [Kiro](https://kiro.dev) auth plugin for [opencode](https://opencode.ai).
4
+
5
+ opencode learns the `kiro` provider and its 12 models from the
6
+ [models.dev](https://models.dev) catalog, exactly like the first-party Copilot and
7
+ GitLab integrations. This plugin supplies the piece the catalog can't: the **auth**.
8
+
9
+ - **Auth** via the official `kiro-cli` login flow (`opencode auth login`, then "Kiro CLI Login")
10
+ - **Provider options loader**: the `cwd`, `agent`, `trustAllTools`, `mcpTimeout` values
11
+ opencode forwards into the SDK factory
12
+ - **TUI credits display**: an opt-in sidebar context box showing tokens, context usage,
13
+ and Kiro credits
14
+
15
+ The `kiro` provider resolves to [`kiro-acp-ai-provider`](https://www.npmjs.com/package/kiro-acp-ai-provider),
16
+ an AI-SDK provider that talks to your locally installed `kiro-cli` over Kiro's
17
+ [Agent Client Protocol](https://agentclientprotocol.com) (ACP); opencode picks it up from
18
+ the catalog's `npm` field. This is the supported integration path: requests go through
19
+ kiro-cli exactly like Kiro's own IDE clients, with no credential scraping and no reuse of
20
+ Kiro credentials against other providers.
21
+
22
+ Not affiliated with any other kiro-named npm packages.
23
+
24
+ ## Prerequisites
25
+
26
+ | Requirement | Notes |
27
+ |---|---|
28
+ | [kiro-cli](https://kiro.dev/docs/cli/) | Must be installed and on `PATH`; a Kiro subscription / AWS Builder ID account |
29
+ | opencode `>= 1.16.0` | Enforced via `engines.opencode` on released builds. The shipped catalog must include the `kiro` provider (see [Troubleshooting](#troubleshooting)). |
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ opencode plugin opencode-kiro
35
+ ```
36
+
37
+ (alias: `opencode plug opencode-kiro`; add `--global`/`-g` to install into your global config instead of the project)
38
+
39
+ The installer reads this package's `exports` and detects both plugin entrypoints
40
+ (`./server` and `./tui`), then patches **both** config files automatically:
41
+
42
+ - `.opencode/opencode.json`: the server plugin (auth)
43
+ - `.opencode/tui.json`: the TUI plugin (credits sidebar box)
44
+
45
+ (with `--global`: `~/.config/opencode/opencode.json` and `~/.config/opencode/tui.json`)
46
+
47
+ You do **not** add a `provider.kiro` block; opencode loads the `kiro` provider and its
48
+ models straight from the models.dev catalog. Then disable the builtin context box, see
49
+ [Credits in the sidebar](#credits-in-the-sidebar).
50
+
51
+ ### Manual alternative
52
+
53
+ Add the package name to the `plugin` array of **both** files yourself (in the
54
+ project's `.opencode/` directory, at the project root, or in the global
55
+ `~/.config/opencode/`, all are valid config locations):
56
+
57
+ `opencode.json`:
58
+
59
+ ```json
60
+ {
61
+ "plugin": ["opencode-kiro"]
62
+ }
63
+ ```
64
+
65
+ `tui.json`:
66
+
67
+ ```json
68
+ {
69
+ "plugin": ["opencode-kiro"],
70
+ "plugin_enabled": { "internal:sidebar-context": false }
71
+ }
72
+ ```
73
+
74
+ (`plugin_enabled` is the [credits sidebar](#credits-in-the-sidebar) step, recommended now, explained below.)
75
+
76
+ ### Local development (path source)
77
+
78
+ Run a local checkout without npm: build first, then reference the repo directory by
79
+ absolute path in both `plugin` arrays:
80
+
81
+ ```bash
82
+ git clone https://github.com/NachoFLizaur/opencode-kiro && cd opencode-kiro
83
+ npm install && npm run build
84
+ ```
85
+
86
+ ```json
87
+ { "plugin": ["/absolute/path/to/opencode-kiro"] }
88
+ ```
89
+
90
+ opencode resolves the right entrypoint per file from the package `exports`. Note that
91
+ path-sourced TUI plugins **must export an `id`** (opencode rejects them otherwise);
92
+ this package ships `{ id: "opencode-kiro", tui }`, so the id (and your
93
+ `plugin_enabled` keys) are identical across path and npm installs.
94
+
95
+ Because the provider now comes from the catalog rather than the plugin, a local checkout
96
+ also needs a catalog that includes `kiro`. opencode reads its catalog from
97
+ `OPENCODE_MODELS_PATH` when set; point it at an `api.json` that contains the `kiro`
98
+ provider (for example one generated from a [models.dev](https://models.dev) checkout):
99
+
100
+ ```bash
101
+ OPENCODE_MODELS_PATH=/path/to/api.json opencode models | grep '^kiro/'
102
+ ```
103
+
104
+ Until the catalog opencode loads contains `kiro`, the provider will not appear regardless
105
+ of this plugin being installed (the plugin only adds auth, not the provider definition).
106
+
107
+ ## Auth
108
+
109
+ ```bash
110
+ opencode auth login
111
+ ```
112
+
113
+ Select the **Kiro (plugin)** provider, then the **Kiro CLI Login** method:
114
+
115
+ - **Already logged in to kiro-cli**: immediate success; the existing kiro-cli session is reused.
116
+ - **Not logged in**: the plugin launches `kiro-cli login`, which opens a browser window.
117
+ Complete the login there; the plugin polls for up to 120 seconds and stores the
118
+ credential when kiro-cli reports success.
119
+
120
+ If the flow times out, authenticate directly with kiro-cli (`kiro-cli login`) and run
121
+ `opencode auth login` again; the fast path then completes immediately.
122
+
123
+ > **Note:** opencode will also surface `kiro` if the `KIRO_API_KEY` environment variable
124
+ > is set, because the catalog entry declares `env: ["KIRO_API_KEY"]`. The intended auth
125
+ > path for this plugin is still **Kiro CLI Login** above (it reuses your local kiro-cli
126
+ > session); the env var is a secondary route opencode offers for any catalog provider.
127
+
128
+ ## Models
129
+
130
+ 12 models, defined in the [models.dev](https://models.dev) `kiro` catalog entry. opencode
131
+ loads them from there; the table below is a convenience snapshot, not the source of
132
+ truth. All models support tool calling and have a 64K-token output limit.
133
+
134
+ | Model | ID | Context window | Image input |
135
+ |---|---|---|---|
136
+ | Auto | `auto` | 1,000,000 | yes |
137
+ | Claude Haiku 4.5 | `claude-haiku-4.5` | 200,000 | yes |
138
+ | Claude Opus 4.5 | `claude-opus-4.5` | 200,000 | yes |
139
+ | Claude Opus 4.6 | `claude-opus-4.6` | 1,000,000 | yes |
140
+ | Claude Opus 4.7 | `claude-opus-4.7` | 1,000,000 | yes |
141
+ | Claude Sonnet 4 | `claude-sonnet-4` | 200,000 | yes |
142
+ | Claude Sonnet 4.5 | `claude-sonnet-4.5` | 200,000 | yes |
143
+ | Claude Sonnet 4.6 | `claude-sonnet-4.6` | 1,000,000 | yes |
144
+ | Deepseek v3.2 | `deepseek-3.2` | 164,000 | yes |
145
+ | MiniMax M2.1 | `minimax-m2.1` | 196,000 | yes |
146
+ | MiniMax M2.5 | `minimax-m2.5` | 196,000 | no |
147
+ | Qwen3 Coder Next | `qwen3-coder-next` | 256,000 | yes |
148
+
149
+ ```bash
150
+ opencode models # lists kiro/auto, kiro/claude-sonnet-4.6, ...
151
+ opencode run -m kiro/auto "hello"
152
+ ```
153
+
154
+ Image input is capability-driven: paste an image path into the TUI prompt and
155
+ image-capable models receive it as an attachment.
156
+
157
+ ## Credits in the sidebar
158
+
159
+ Kiro is subscription-metered: requests consume **credits**, and the dollar cost
160
+ opencode normally displays is always $0.00. The plugin therefore registers a
161
+ **full replacement** for the built-in sidebar context box, showing tokens, context
162
+ percentage, and session credits.
163
+
164
+ Disable the builtin box in `tui.json` so only the replacement renders:
165
+
166
+ ```json
167
+ {
168
+ "plugin_enabled": { "internal:sidebar-context": false }
169
+ }
170
+ ```
171
+
172
+ Without this you will see **two** context boxes (cosmetic duplication: the builtin
173
+ one plus the plugin's). The credits value and its unit come from provider metadata
174
+ emitted by the SDK (kiro-cli reports the unit); nothing is hardcoded client-side.
175
+
176
+ Trade-off: the replacement box applies to **every** session and disabling the builtin
177
+ is global: mixed-provider users lose the builtin `$X.XX spent` line for non-Kiro
178
+ sessions too; if you need dollar cost there, leave the builtin enabled at the cost of
179
+ the duplicate box.
180
+
181
+ ## Known limitation (read this)
182
+
183
+ **Credits display is TUI-sidebar-only.** Every other cost surface (the prompt footer,
184
+ ACP clients, the web app, desktop, web share pages, and CLI cost output) shows $0.00
185
+ for Kiro sessions. The models.dev catalog declares Kiro's per-token `cost` as 0 (it is a
186
+ subscription-metered provider with no per-token pricing), so opencode core computes $0.00
187
+ everywhere it renders dollar cost. That is expected, not a defect. A cross-surface credits
188
+ display would require opencode core changes and is intentionally out of scope for this
189
+ plugin.
190
+
191
+ ## How it works
192
+
193
+ - **Provider & models (models.dev)**: opencode loads the `kiro` provider and its full
194
+ model list from the models.dev catalog. This plugin does **not** define any provider or
195
+ model config of its own; there is no `config` hook.
196
+ - **SDK resolution (resolveSDK)**: opencode reads the catalog's `npm` field
197
+ (`kiro-acp-ai-provider`), installs that package into its package cache on first model
198
+ use, and imports it. This plugin's `auth` loader supplies the provider options
199
+ (`cwd`, `agent`, `trustAllTools`, `mcpTimeout`, `contextWindows`) that opencode forwards
200
+ into `createKiroAcp(...)`. The loader relays each model's `limit.context` (from
201
+ models.dev, via opencode's resolved catalog) into the SDK's `contextWindows` map keyed
202
+ by `api.id`, so the SDK keeps no hardcoded per-model data and falls back to 1,000,000
203
+ for any model absent from the relay.
204
+ - **Auth (this plugin)**: registers the "Kiro CLI Login" OAuth method (kiro-cli login
205
+ flow) plus the options loader above. The same plugin also imports `verifyAuth` from
206
+ `kiro-acp-ai-provider` to check kiro-cli installation/login state.
207
+ - **Session affinity & reset (in-SDK)**: the SDK keys kiro-cli sessions off opencode's
208
+ `x-session-affinity` header, isolates tool-less utility calls (title generation) on
209
+ an ephemeral session, detects prompt-history divergence (fork/`/undo`), and starts a
210
+ fresh kiro session when needed. No host-side session plumbing.
211
+ - **Credits metadata**: the SDK attaches `{ kiro: { credits, creditsUnit } }` provider
212
+ metadata to the final part of each turn; opencode persists it, and the TUI plugin
213
+ sums it per assistant message (deduped across text/reasoning parts) for the sidebar.
214
+
215
+ ## Troubleshooting
216
+
217
+ | Symptom | Cause / fix |
218
+ |---|---|
219
+ | `kiro-cli is not installed` during auth | Install kiro-cli from <https://kiro.dev/docs/cli/> and ensure it is on `PATH` for the opencode process. |
220
+ | Auth times out after ~120s | Complete the browser login faster, or run `kiro-cli login` yourself, then re-run `opencode auth login` (fast path). |
221
+ | Two "Context" boxes in the sidebar | Add `"plugin_enabled": { "internal:sidebar-context": false }` to `tui.json` (see [Credits in the sidebar](#credits-in-the-sidebar)). |
222
+ | No credits line / credits stay 0 | Credits appear after the first **completed** kiro turn; cancelled turns and turns without usage metadata contribute nothing. Check the TUI plugin is `active` in the Plugins dialog (and listed in `tui.json`). |
223
+ | `kiro` provider not showing in `opencode models` | The provider comes from the models.dev catalog, not this plugin. Ensure your opencode version ships a catalog that includes `kiro` (run `opencode models --refresh` to update the cache). For local development, point opencode at a kiro-inclusive catalog via `OPENCODE_MODELS_PATH=/path/to/api.json` (see [Local development](#local-development-path-source)). |
224
+ | `sdk.languageModel is not a function` | A stale `kiro-acp-ai-provider` < 2.0.0 resolved from opencode's package cache. Remove the cached copy (`$XDG_CACHE_HOME/opencode/packages/kiro-acp-ai-provider`, default `~/.cache/opencode/packages/...`) and retry; 2.0.0 fixed the factory auto-discovery clash. |
225
+ | Path install rejected (`must export id`) | Run `npm run build` in your checkout first and reference the repo root (both entry modules export ids). |
226
+ | Provider visible but runs fail | The provider is selectable (from the catalog) before any credential exists. Run `opencode auth login` first. |
227
+
228
+ ## Development
229
+
230
+ ```bash
231
+ npm install
232
+ npm run typecheck # tsc --noEmit
233
+ npm run build # tsup builds dist/server.js + dist/tui.js (+ d.ts)
234
+ npm test # vitest
235
+ ```
236
+
237
+ ## License
238
+
239
+ [MIT](./LICENSE)
@@ -0,0 +1,56 @@
1
+ // src/tui/credits.ts
2
+ function isRecord(value) {
3
+ return typeof value === "object" && value !== null;
4
+ }
5
+ function readPartCredits(part) {
6
+ if (!isRecord(part)) return void 0;
7
+ const metadata = part.metadata;
8
+ if (!isRecord(metadata)) return void 0;
9
+ const kiro = metadata.kiro;
10
+ if (!isRecord(kiro)) return void 0;
11
+ if (typeof kiro.credits !== "number" || !Number.isFinite(kiro.credits)) return void 0;
12
+ return {
13
+ credits: kiro.credits,
14
+ unit: typeof kiro.creditsUnit === "string" && kiro.creditsUnit.length > 0 ? kiro.creditsUnit : void 0
15
+ };
16
+ }
17
+ function messageCredits(parts) {
18
+ const carriers = parts.map(readPartCredits).filter((value) => value !== void 0);
19
+ const last = carriers.at(-1);
20
+ if (!last) return void 0;
21
+ return {
22
+ credits: last.credits,
23
+ unit: last.unit ?? carriers.findLast((carrier) => carrier.unit !== void 0)?.unit
24
+ };
25
+ }
26
+ function creditsForMessage(parts) {
27
+ return messageCredits(parts)?.credits;
28
+ }
29
+ function sumSessionCredits(messages, partsByMessage) {
30
+ return messages.filter((message) => message.role === "assistant").reduce(
31
+ (acc, message) => {
32
+ const hit = messageCredits(partsByMessage(message.id));
33
+ if (!hit) return acc;
34
+ return {
35
+ total: acc.total + hit.credits,
36
+ unit: hit.unit ?? acc.unit
37
+ };
38
+ },
39
+ { total: 0, unit: void 0 }
40
+ );
41
+ }
42
+ var creditsAmount = new Intl.NumberFormat("en-US", { maximumFractionDigits: 2 });
43
+ function formatCredits(value, unit) {
44
+ const amount = creditsAmount.format(Number.isFinite(value) ? value : 0);
45
+ if (!unit) return amount;
46
+ const label = value === 1 || unit.endsWith("s") ? unit : `${unit}s`;
47
+ return `${amount} ${label}`;
48
+ }
49
+
50
+ export {
51
+ readPartCredits,
52
+ messageCredits,
53
+ creditsForMessage,
54
+ sumSessionCredits,
55
+ formatCredits
56
+ };
@@ -0,0 +1,62 @@
1
+ import {
2
+ formatCredits,
3
+ sumSessionCredits
4
+ } from "./chunk-JO7U4OSF.js";
5
+
6
+ // src/tui/context-view.ts
7
+ import { createElement, effect, insert, insertNode, setProp } from "@opentui/solid";
8
+ import { createMemo } from "solid-js";
9
+ function createContextView(api, sessionID) {
10
+ const theme = () => api.theme.current;
11
+ const messages = createMemo(() => api.state.session.messages(sessionID));
12
+ const usage = createMemo(() => {
13
+ const last = messages().findLast(
14
+ (item) => item.role === "assistant" && item.tokens.output > 0
15
+ );
16
+ if (!last) {
17
+ return {
18
+ tokens: 0,
19
+ percent: null
20
+ };
21
+ }
22
+ const tokens = last.tokens.input + last.tokens.output + last.tokens.reasoning + last.tokens.cache.read + last.tokens.cache.write;
23
+ const model = api.state.provider.find((item) => item.id === last.providerID)?.models[last.modelID];
24
+ return {
25
+ tokens,
26
+ percent: model?.limit.context ? Math.round(tokens / model.limit.context * 100) : null
27
+ };
28
+ });
29
+ const credits = createMemo(() => sumSessionCredits(messages(), (messageID) => api.state.part(messageID)));
30
+ const root = createElement("box");
31
+ insertNode(root, headerLine(theme));
32
+ insertNode(
33
+ root,
34
+ mutedLine(theme, () => `${usage().tokens.toLocaleString()} tokens`)
35
+ );
36
+ insertNode(
37
+ root,
38
+ mutedLine(theme, () => `${usage().percent ?? 0}% used`)
39
+ );
40
+ insertNode(
41
+ root,
42
+ mutedLine(theme, () => formatCredits(credits().total, credits().unit))
43
+ );
44
+ return root;
45
+ }
46
+ function headerLine(theme) {
47
+ const line = createElement("text");
48
+ effect(() => setProp(line, "fg", theme().text));
49
+ const bold = createElement("b");
50
+ insert(bold, "Context");
51
+ insertNode(line, bold);
52
+ return line;
53
+ }
54
+ function mutedLine(theme, content) {
55
+ const line = createElement("text");
56
+ effect(() => setProp(line, "fg", theme().textMuted));
57
+ insert(line, content);
58
+ return line;
59
+ }
60
+ export {
61
+ createContextView
62
+ };
@@ -0,0 +1,8 @@
1
+ import { PluginInput, Hooks } from '@opencode-ai/plugin';
2
+
3
+ declare const _default: {
4
+ id: string;
5
+ server: (input: PluginInput) => Promise<Hooks>;
6
+ };
7
+
8
+ export { _default as default };
package/dist/server.js ADDED
@@ -0,0 +1,91 @@
1
+ // src/server.ts
2
+ var server = async (input) => ({
3
+ auth: {
4
+ provider: "kiro",
5
+ // Returned options are forwarded into createKiroAcp({...}). Relays each
6
+ // catalog model's limit.context into contextWindows keyed by api.id;
7
+ // zero/missing limits are skipped (SDK falls back to 1M).
8
+ loader: async (_getAuth, provider) => ({
9
+ cwd: input.directory ?? input.worktree,
10
+ agent: "opencode",
11
+ trustAllTools: true,
12
+ mcpTimeout: 45,
13
+ contextWindows: Object.fromEntries(
14
+ Object.values(provider.models).filter((m) => (m.limit?.context ?? 0) > 0).map((m) => [m.api.id, m.limit.context])
15
+ )
16
+ }),
17
+ methods: [
18
+ {
19
+ type: "oauth",
20
+ label: "Kiro CLI Login",
21
+ async authorize() {
22
+ const { verifyAuth } = await import("kiro-acp-ai-provider");
23
+ const status = verifyAuth();
24
+ if (!status.installed)
25
+ throw new Error(
26
+ "kiro-cli is not installed. Install it from https://kiro.dev/docs/cli/"
27
+ );
28
+ if (status.authenticated) {
29
+ return {
30
+ url: "",
31
+ instructions: "",
32
+ method: "auto",
33
+ async callback() {
34
+ return readToken(status.tokenPath);
35
+ }
36
+ };
37
+ }
38
+ const { execFile } = await import("child_process");
39
+ const child = execFile("kiro-cli", ["login"]);
40
+ return {
41
+ url: "",
42
+ instructions: "Complete Kiro authentication in the browser window that just opened. Waiting for login...",
43
+ method: "auto",
44
+ async callback() {
45
+ const maxWait = 12e4;
46
+ const start = Date.now();
47
+ while (Date.now() - start < maxWait) {
48
+ await new Promise((r) => setTimeout(r, 2e3));
49
+ const check = verifyAuth();
50
+ if (check.authenticated) {
51
+ child.kill();
52
+ return readToken(check.tokenPath);
53
+ }
54
+ }
55
+ child.kill();
56
+ throw new Error(
57
+ "Kiro authentication timed out. Run `kiro-cli auth login` manually."
58
+ );
59
+ }
60
+ };
61
+ }
62
+ }
63
+ ]
64
+ }
65
+ });
66
+ async function readToken(tokenPath) {
67
+ if (tokenPath) {
68
+ try {
69
+ const { readFileSync } = await import("fs");
70
+ const raw = JSON.parse(readFileSync(tokenPath, "utf8"));
71
+ return {
72
+ type: "success",
73
+ refresh: "",
74
+ access: raw.accessToken || "authenticated",
75
+ expires: raw.expiresAt ? new Date(raw.expiresAt).getTime() : Date.now() + 36e5
76
+ };
77
+ } catch {
78
+ return { type: "failed" };
79
+ }
80
+ }
81
+ return {
82
+ type: "success",
83
+ refresh: "",
84
+ access: "authenticated",
85
+ expires: Date.now() + 36e5
86
+ };
87
+ }
88
+ var server_default = { id: "kiro", server };
89
+ export {
90
+ server_default as default
91
+ };
package/dist/tui.d.ts ADDED
@@ -0,0 +1,36 @@
1
+ import { TuiPlugin } from '@opencode-ai/plugin/tui';
2
+
3
+ /** Any part-like object. `object` (not `{ metadata?: unknown }`) so metadata-less SDK Part variants stay assignable. */
4
+ type CreditPart = object;
5
+ /** Minimal message shape; SDK `Message` is assignable. */
6
+ interface CreditMessage {
7
+ readonly id: string;
8
+ readonly role: string;
9
+ }
10
+ /** One part's credit metadata: the turn total plus the SDK-reported unit. */
11
+ interface PartCredits {
12
+ credits: number;
13
+ unit?: string;
14
+ }
15
+ /** Session-wide rollup. `unit` stays undefined until metadata reports one. */
16
+ interface SessionCredits {
17
+ total: number;
18
+ unit?: string;
19
+ }
20
+ /** Read `{ kiro: { credits, creditsUnit } }` from a part; only finite numeric credits count. */
21
+ declare function readPartCredits(part: CreditPart): PartCredits | undefined;
22
+ /** One message's credits, deduped by the last-carrier-wins rule (parts never summed); unit from the most recent carrier. */
23
+ declare function messageCredits(parts: ReadonlyArray<CreditPart>): PartCredits | undefined;
24
+ /** Per-message credit total, or undefined when no part carries credits. */
25
+ declare function creditsForMessage(parts: ReadonlyArray<CreditPart>): number | undefined;
26
+ /** Sum per-message totals across a session's assistant messages (one value each); unit from the most recent carrier. */
27
+ declare function sumSessionCredits(messages: ReadonlyArray<CreditMessage>, partsByMessage: (messageID: string) => ReadonlyArray<CreditPart>): SessionCredits;
28
+ /** Render credits with the unit, e.g. "12.5 credits", "1 credit". Unit is naively pluralized unless it ends in "s"; with no unit, only the number renders. */
29
+ declare function formatCredits(value: number, unit?: string): string;
30
+
31
+ declare const _default: {
32
+ id: string;
33
+ tui: TuiPlugin;
34
+ };
35
+
36
+ export { type CreditMessage, type CreditPart, type PartCredits, type SessionCredits, creditsForMessage, _default as default, formatCredits, messageCredits, readPartCredits, sumSessionCredits };
package/dist/tui.js ADDED
@@ -0,0 +1,29 @@
1
+ import {
2
+ creditsForMessage,
3
+ formatCredits,
4
+ messageCredits,
5
+ readPartCredits,
6
+ sumSessionCredits
7
+ } from "./chunk-JO7U4OSF.js";
8
+
9
+ // src/tui.ts
10
+ var tui = async (api) => {
11
+ const { createContextView } = await import("./context-view-CGBZAYM5.js");
12
+ api.slots.register({
13
+ order: 100,
14
+ slots: {
15
+ sidebar_content(_ctx, props) {
16
+ return createContextView(api, props.session_id);
17
+ }
18
+ }
19
+ });
20
+ };
21
+ var tui_default = { id: "opencode-kiro", tui };
22
+ export {
23
+ creditsForMessage,
24
+ tui_default as default,
25
+ formatCredits,
26
+ messageCredits,
27
+ readPartCredits,
28
+ sumSessionCredits
29
+ };
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "opencode-kiro",
3
+ "version": "0.1.0",
4
+ "description": "The ACP-compliant Kiro plugin for opencode: auth via the official kiro-cli login, 12 Kiro models through the Agent Client Protocol, and TUI credits display",
5
+ "license": "MIT",
6
+ "author": "Nacho F. Lizaur (https://github.com/NachoFLizaur)",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/NachoFLizaur/opencode-kiro.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/NachoFLizaur/opencode-kiro/issues"
13
+ },
14
+ "homepage": "https://github.com/NachoFLizaur/opencode-kiro#readme",
15
+ "type": "module",
16
+ "exports": {
17
+ "./server": {
18
+ "types": "./dist/server.d.ts",
19
+ "default": "./dist/server.js"
20
+ },
21
+ "./tui": {
22
+ "types": "./dist/tui.d.ts",
23
+ "default": "./dist/tui.js"
24
+ },
25
+ "./package.json": "./package.json"
26
+ },
27
+ "files": [
28
+ "dist"
29
+ ],
30
+ "scripts": {
31
+ "build": "tsup",
32
+ "test": "vitest run",
33
+ "test:watch": "vitest",
34
+ "typecheck": "tsc --noEmit",
35
+ "prepublishOnly": "npm run build"
36
+ },
37
+ "engines": {
38
+ "node": ">=20",
39
+ "opencode": ">=1.16.0"
40
+ },
41
+ "peerDependencies": {
42
+ "@opencode-ai/plugin": "*"
43
+ },
44
+ "dependencies": {
45
+ "kiro-acp-ai-provider": "^2.0.0"
46
+ },
47
+ "devDependencies": {
48
+ "@opencode-ai/plugin": "1.16.2",
49
+ "@opentui/solid": "^0.3.4",
50
+ "@types/node": "^20.19.42",
51
+ "solid-js": "^1.9.12",
52
+ "tsup": "^8.0.0",
53
+ "typescript": "^5.7.0",
54
+ "vitest": "^4.1.8"
55
+ },
56
+ "keywords": [
57
+ "opencode",
58
+ "opencode-plugin",
59
+ "kiro",
60
+ "kiro-cli",
61
+ "acp",
62
+ "agent-client-protocol",
63
+ "amazon-q",
64
+ "aws"
65
+ ]
66
+ }