@bogyie/opencode-kiro-plugin 0.1.0 → 0.2.1

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/CHANGELOG.md CHANGED
@@ -15,6 +15,7 @@ Initial OpenCode Kiro provider plugin implementation.
15
15
  - OpenAI-compatible request adapter for system prompts, chat history, multimodal data URL images/documents, tool specs, and tool results.
16
16
  - OpenAI-compatible generation options for temperature, token limit, and reasoning/thinking effort are preserved as best-effort model request fields in direct fetch mode.
17
17
  - CodeWhisperer metadata token usage is mapped to OpenAI-compatible non-streaming usage fields on a best-effort basis.
18
+ - CodeWhisperer reasoning content is preserved separately from assistant text as OpenAI-compatible `reasoning_content`.
18
19
  - CodeWhisperer/Kiro transport with streaming text, tool-call deltas, configurable retry attempts, and request timeout.
19
20
  - CLI fallback using `kiro-cli chat --no-interactive`.
20
21
  - CLI fallback responses are wrapped as OpenAI-compatible SSE for streaming OpenCode calls and sanitized to remove terminal prompt/credits output.
package/README.md CHANGED
@@ -155,6 +155,9 @@ Direct fetch mode uses AWS SDK standard retry behavior. Tune `maxAttempts` and `
155
155
 
156
156
  OpenAI-compatible `temperature`, `max_tokens`, `max_completion_tokens`, `reasoning_effort`, `reasoning.effort`, and `thinking.effort` are preserved for direct fetch mode through Kiro's `additionalModelRequestFields` path on a best-effort basis.
157
157
 
158
+ When Kiro emits token metadata in direct fetch mode, non-streaming responses map it to OpenAI-compatible `usage` fields.
159
+ When Kiro emits reasoning text, it is preserved separately from assistant text as `reasoning_content`.
160
+
158
161
  For local checks:
159
162
 
160
163
  ```sh
@@ -167,13 +170,18 @@ For real Kiro/OpenCode validation, use [docs/e2e-validation.md](docs/e2e-validat
167
170
 
168
171
  ## Release
169
172
 
170
- GitHub Release publishing drives npm publishing. To publish a new npm package:
173
+ The npm package is published through npm Trusted Publishing with the GitHub Actions environment named `npm`. No `NPM_TOKEN` repository secret is required.
174
+
175
+ Configure the npm package trusted publisher to use:
176
+
177
+ - repository owner: `bogyie`
178
+ - repository name: `opencode-kiro-plugin`
179
+ - workflow filename: `npm-publish.yml`
180
+ - environment name: `npm`
171
181
 
172
- 1. Set the repository secret `NPM_TOKEN` to an npm automation token with publish access to `@bogyie/opencode-kiro-plugin`.
173
- 2. Update `package.json` and `package-lock.json` to the release version.
174
- 3. Create and publish a GitHub Release whose tag matches the package version, for example `v0.1.0`.
182
+ To publish a new version, update `package.json` and `package-lock.json` to the release version and merge the change to `main`. `package.json.version` is the source of truth: when it changes on `main`, the `Publish npm package` workflow publishes that package version to npm and creates the matching GitHub Release tag, for example `v0.1.0`.
175
183
 
176
- The `Publish npm package` workflow runs tests, typecheck, package smoke validation, `npm pack --dry-run`, and then `npm publish --provenance --access public`.
184
+ The workflow runs tests, typecheck, package smoke validation, `npm pack --dry-run`, and then `npm publish --access public`.
177
185
 
178
186
  ## License And References
179
187
 
@@ -8,6 +8,8 @@ const unsupportedTransport = {
8
8
  };
9
9
  async function* streamGeneratedResponse(transport, request) {
10
10
  const response = await transport.generate(request);
11
+ if (response.reasoning)
12
+ yield { type: "reasoning", text: response.reasoning, modelId: response.modelId ?? request.modelId };
11
13
  if (response.text)
12
14
  yield { type: "text", text: response.text, modelId: response.modelId ?? request.modelId };
13
15
  for (const toolCall of response.toolCalls ?? [])
package/dist/index.d.ts CHANGED
@@ -16,7 +16,7 @@ export { FALLBACK_MODELS } from "./models.js";
16
16
  export { toKiroGenerateRequest } from "./request-adapter.js";
17
17
  export type { KiroGenerateRequest, KiroModelOptions } from "./request-adapter.js";
18
18
  export { toOpenAIChatResponse, toOpenAIChatStreamResponse } from "./response-adapter.js";
19
- export type { KiroStreamEvent, KiroToolCallChunk } from "./response-adapter.js";
19
+ export type { KiroReasoningChunk, KiroStreamEvent, KiroToolCallChunk } from "./response-adapter.js";
20
20
  declare const _default: {
21
21
  id: string;
22
22
  server: import("@opencode-ai/plugin").Plugin;
@@ -135,6 +135,7 @@ export async function collectAssistantText(stream) {
135
135
  if (!stream)
136
136
  return { text: "" };
137
137
  let text = "";
138
+ let reasoning = "";
138
139
  let modelId;
139
140
  let usage;
140
141
  for await (const event of stream) {
@@ -142,6 +143,9 @@ export async function collectAssistantText(stream) {
142
143
  text += event.assistantResponseEvent.content ?? "";
143
144
  modelId = event.assistantResponseEvent.modelId ?? modelId;
144
145
  }
146
+ if (event.reasoningContentEvent?.text) {
147
+ reasoning += event.reasoningContentEvent.text;
148
+ }
145
149
  usage = usageFromMetadataEvent(event) ?? usage;
146
150
  if (event.error) {
147
151
  throw new Error(event.error.message ?? "Kiro stream returned an error event");
@@ -149,6 +153,7 @@ export async function collectAssistantText(stream) {
149
153
  }
150
154
  return {
151
155
  text,
156
+ ...(reasoning ? { reasoning } : {}),
152
157
  ...(modelId ? { modelId } : {}),
153
158
  ...(usage ? { usage } : {}),
154
159
  };
@@ -165,6 +170,12 @@ export async function* streamAssistantText(stream) {
165
170
  ...(event.assistantResponseEvent.modelId ? { modelId: event.assistantResponseEvent.modelId } : {}),
166
171
  };
167
172
  }
173
+ if (event.reasoningContentEvent?.text) {
174
+ yield {
175
+ type: "reasoning",
176
+ text: event.reasoningContentEvent.text,
177
+ };
178
+ }
168
179
  if (event.toolUseEvent?.toolUseId && event.toolUseEvent.name) {
169
180
  const id = event.toolUseEvent.toolUseId;
170
181
  const current = toolInputs.get(id) ?? { name: event.toolUseEvent.name, input: "" };
@@ -196,6 +207,7 @@ export async function* streamAssistantText(stream) {
196
207
  }
197
208
  async function collectChunks(chunks, fallbackModelId) {
198
209
  let text = "";
210
+ let reasoning = "";
199
211
  let modelId;
200
212
  let usage;
201
213
  const toolCalls = [];
@@ -205,6 +217,11 @@ async function collectChunks(chunks, fallbackModelId) {
205
217
  modelId = chunk.modelId ?? modelId;
206
218
  continue;
207
219
  }
220
+ if (chunk.type === "reasoning") {
221
+ reasoning += chunk.text;
222
+ modelId = chunk.modelId ?? modelId;
223
+ continue;
224
+ }
208
225
  text += chunk.text;
209
226
  modelId = chunk.modelId ?? modelId;
210
227
  if (chunk.usage)
@@ -212,6 +229,7 @@ async function collectChunks(chunks, fallbackModelId) {
212
229
  }
213
230
  return {
214
231
  text,
232
+ ...(reasoning ? { reasoning } : {}),
215
233
  modelId: modelId ?? fallbackModelId,
216
234
  ...(toolCalls.length > 0 ? { toolCalls } : {}),
217
235
  ...(usage ? { usage } : {}),
@@ -1,5 +1,6 @@
1
1
  export interface KiroGenerateResponse {
2
2
  readonly text: string;
3
+ readonly reasoning?: string;
3
4
  readonly modelId?: string;
4
5
  readonly toolCalls?: ReadonlyArray<KiroToolCallChunk>;
5
6
  readonly usage?: {
@@ -20,6 +21,11 @@ export interface KiroToolCallChunk {
20
21
  readonly arguments: string;
21
22
  readonly modelId?: string;
22
23
  }
23
- export type KiroStreamEvent = KiroStreamChunk | KiroToolCallChunk;
24
+ export interface KiroReasoningChunk {
25
+ readonly type: "reasoning";
26
+ readonly text: string;
27
+ readonly modelId?: string;
28
+ }
29
+ export type KiroStreamEvent = KiroStreamChunk | KiroToolCallChunk | KiroReasoningChunk;
24
30
  export declare function toOpenAIChatResponse(response: KiroGenerateResponse, model: string): Response;
25
31
  export declare function toOpenAIChatStreamResponse(chunks: AsyncIterable<KiroStreamEvent>, model: string): Response;
@@ -11,6 +11,7 @@ export function toOpenAIChatResponse(response, model) {
11
11
  message: {
12
12
  role: "assistant",
13
13
  content: toolCalls.length > 0 ? response.text || null : response.text,
14
+ ...(response.reasoning ? { reasoning_content: response.reasoning } : {}),
14
15
  ...(toolCalls.length > 0
15
16
  ? {
16
17
  tool_calls: toolCalls.map((toolCall, index) => ({
@@ -70,6 +71,11 @@ export function toOpenAIChatStreamResponse(chunks, model) {
70
71
  ],
71
72
  };
72
73
  }
74
+ else if (chunk.type === "reasoning") {
75
+ if (!chunk.text)
76
+ continue;
77
+ delta = { reasoning_content: chunk.text };
78
+ }
73
79
  else {
74
80
  if (!chunk.text)
75
81
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bogyie/opencode-kiro-plugin",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "OpenCode plugin for using Kiro as a provider adapter",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",