opencode-kiro 0.4.0 → 0.5.0-beta.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/README.md +179 -158
- package/dist/chunk-M7OUVABX.js +40 -0
- package/dist/credits-box-view-FIHO6TR6.js +35 -0
- package/dist/server.d.ts +5 -18
- package/dist/server.js +402 -228
- package/dist/tui.d.ts +3 -50
- package/dist/tui.js +129 -27
- package/package.json +7 -8
- package/dist/chunk-MQVMKLNA.js +0 -70
- package/dist/credits-box-view-BYKGQHSS.js +0 -40
- package/dist/credits-chip-view-RL5JAEZ5.js +0 -20
package/dist/server.js
CHANGED
|
@@ -1,258 +1,432 @@
|
|
|
1
|
-
// src/server.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { dirname, join } from "path";
|
|
5
|
-
var KIRO_PLUGIN_NAME = "opencode-kiro";
|
|
6
|
-
var server = async (input) => {
|
|
7
|
-
const prompts = [
|
|
8
|
-
{
|
|
9
|
-
type: "select",
|
|
10
|
-
key: "sidebar",
|
|
11
|
-
message: "Enable the Kiro credits sidebar?",
|
|
12
|
-
options: [
|
|
13
|
-
{ label: "Yes", value: "yes", hint: "writes tui.json; restart to apply" },
|
|
14
|
-
{ label: "No", value: "no" }
|
|
15
|
-
]
|
|
16
|
-
}
|
|
17
|
-
];
|
|
1
|
+
// src/server/aisdk.ts
|
|
2
|
+
var KIRO_SDK_PACKAGE = "kiro-acp-ai-provider";
|
|
3
|
+
function createAisdkResources() {
|
|
18
4
|
return {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
]
|
|
85
|
-
},
|
|
86
|
-
// crash guard: core derefs an undefined kiro provider during auth init when a cred exists but the catalog lacks kiro.
|
|
87
|
-
// only inject when authed; ??= is idempotent and won't clobber a real catalog entry.
|
|
88
|
-
config: async (input2) => {
|
|
89
|
-
if (!hasStoredKiroCredential()) return;
|
|
90
|
-
input2.provider ??= {};
|
|
91
|
-
input2.provider.kiro ??= {};
|
|
92
|
-
},
|
|
93
|
-
provider: {
|
|
94
|
-
id: "kiro",
|
|
95
|
-
// expose the exact runtime/models.dev intersection with catalog metadata intact
|
|
96
|
-
async models(provider, ctx) {
|
|
97
|
-
if (!ctx.auth) return provider.models;
|
|
98
|
-
try {
|
|
99
|
-
const { listModels } = await import("kiro-acp-ai-provider");
|
|
100
|
-
const discoveredModels = await listModels({
|
|
101
|
-
cwd: input.directory ?? input.worktree
|
|
102
|
-
});
|
|
103
|
-
const runtimeModels = new Map(discoveredModels.map((model) => [model.modelId, model]));
|
|
104
|
-
if (runtimeModels.size !== discoveredModels.length) return provider.models;
|
|
105
|
-
const models = {};
|
|
106
|
-
for (const [catalogKey, catalogModel] of Object.entries(provider.models)) {
|
|
107
|
-
const apiId = catalogModel.api?.id;
|
|
108
|
-
if (typeof apiId !== "string") continue;
|
|
109
|
-
const runtimeModel = runtimeModels.get(apiId);
|
|
110
|
-
if (!runtimeModel) continue;
|
|
111
|
-
if (runtimeModel.runtimeEfforts.length === 0) {
|
|
112
|
-
models[catalogKey] = catalogModel;
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
models[catalogKey] = {
|
|
116
|
-
...catalogModel,
|
|
117
|
-
...runtimeModel.baselineEffort === void 0 ? {} : {
|
|
118
|
-
options: {
|
|
119
|
-
...catalogModel.options,
|
|
120
|
-
reasoningEffort: runtimeModel.baselineEffort
|
|
121
|
-
}
|
|
122
|
-
},
|
|
123
|
-
variants: {
|
|
124
|
-
...catalogModel.variants,
|
|
125
|
-
...Object.fromEntries(
|
|
126
|
-
runtimeModel.runtimeEfforts.map((effort) => [
|
|
127
|
-
effort,
|
|
128
|
-
{
|
|
129
|
-
...catalogModel.variants?.[effort],
|
|
130
|
-
reasoningEffort: effort
|
|
131
|
-
}
|
|
132
|
-
])
|
|
133
|
-
)
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
return models;
|
|
138
|
-
} catch {
|
|
139
|
-
return provider.models;
|
|
140
|
-
}
|
|
5
|
+
ownedSdks: /* @__PURE__ */ new Set(),
|
|
6
|
+
cache: /* @__PURE__ */ new Map(),
|
|
7
|
+
disposeHook: void 0
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function isKiroPackage(pkg) {
|
|
11
|
+
return pkg === KIRO_SDK_PACKAGE || pkg === `aisdk:${KIRO_SDK_PACKAGE}`;
|
|
12
|
+
}
|
|
13
|
+
function isJsonSafe(value) {
|
|
14
|
+
if (value === null) return true;
|
|
15
|
+
const kind = typeof value;
|
|
16
|
+
if (kind === "string" || kind === "number" || kind === "boolean") return true;
|
|
17
|
+
if (Array.isArray(value)) return value.every(isJsonSafe);
|
|
18
|
+
if (kind === "object") {
|
|
19
|
+
const proto = Object.getPrototypeOf(value);
|
|
20
|
+
if (proto !== Object.prototype && proto !== null) return false;
|
|
21
|
+
return Object.values(value).every(isJsonSafe);
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
function stableStringify(value) {
|
|
26
|
+
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
27
|
+
if (typeof value === "object" && value !== null) {
|
|
28
|
+
const entries = Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, entry]) => `${JSON.stringify(key)}:${stableStringify(entry)}`);
|
|
29
|
+
return `{${entries.join(",")}}`;
|
|
30
|
+
}
|
|
31
|
+
return JSON.stringify(value);
|
|
32
|
+
}
|
|
33
|
+
function stableOptionsKey(options) {
|
|
34
|
+
return isJsonSafe(options) ? stableStringify(options) : void 0;
|
|
35
|
+
}
|
|
36
|
+
async function registerAisdkHook(context, resources) {
|
|
37
|
+
const registration = await context.aisdk.hook("sdk", async (event) => {
|
|
38
|
+
if (!isKiroPackage(event.package)) return;
|
|
39
|
+
const { createKiroAcp } = await import("kiro-acp-ai-provider");
|
|
40
|
+
const key = stableOptionsKey(event.options);
|
|
41
|
+
let sdk = key === void 0 ? void 0 : resources.cache.get(key);
|
|
42
|
+
if (sdk === void 0) {
|
|
43
|
+
sdk = createKiroAcp(event.options);
|
|
44
|
+
resources.ownedSdks.add(sdk);
|
|
45
|
+
if (key !== void 0) resources.cache.set(key, sdk);
|
|
46
|
+
}
|
|
47
|
+
event.sdk = sdk;
|
|
48
|
+
});
|
|
49
|
+
resources.disposeHook = registration.dispose;
|
|
50
|
+
return async () => {
|
|
51
|
+
const errors = [];
|
|
52
|
+
resources.disposeHook = void 0;
|
|
53
|
+
try {
|
|
54
|
+
await registration.dispose();
|
|
55
|
+
} catch (error) {
|
|
56
|
+
errors.push(error);
|
|
57
|
+
}
|
|
58
|
+
const owned = Array.from(resources.ownedSdks);
|
|
59
|
+
resources.ownedSdks.clear();
|
|
60
|
+
resources.cache.clear();
|
|
61
|
+
for (const sdk of owned) {
|
|
62
|
+
try {
|
|
63
|
+
await sdk.shutdown();
|
|
64
|
+
} catch (error) {
|
|
65
|
+
errors.push(error);
|
|
141
66
|
}
|
|
142
67
|
}
|
|
68
|
+
if (errors.length > 0) throw new AggregateError(errors, "kiro aisdk cleanup failures");
|
|
143
69
|
};
|
|
144
|
-
};
|
|
145
|
-
function kiroTokenPath() {
|
|
146
|
-
return join(homedir(), ".aws", "sso", "cache", "kiro-auth-token.json");
|
|
147
70
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
71
|
+
|
|
72
|
+
// src/server/auth.ts
|
|
73
|
+
var KIRO_INTEGRATION_ID = "kiro";
|
|
74
|
+
var KIRO_INTEGRATION_NAME = "Kiro";
|
|
75
|
+
var KIRO_OAUTH_METHOD_ID = "kiro-cli-login";
|
|
76
|
+
var KIRO_OAUTH_METHOD_LABEL = "Kiro CLI Login";
|
|
77
|
+
var KIRO_DOCS_URL = "https://kiro.dev/docs/cli/";
|
|
78
|
+
var POLL_INTERVAL_MS = 2e3;
|
|
79
|
+
var MAX_WAIT_MS = 12e4;
|
|
80
|
+
var NOT_INSTALLED_MESSAGE = "kiro-cli is not installed. Install it from https://kiro.dev/docs/cli/";
|
|
81
|
+
var TIMEOUT_MESSAGE = "Kiro authentication timed out. Run `kiro-cli login` manually, then re-run `opencode auth login`.";
|
|
82
|
+
var LOGIN_INSTRUCTIONS = "Complete Kiro authentication in the browser window that just opened. Waiting for login...";
|
|
83
|
+
var ALREADY_AUTHENTICATED_INSTRUCTIONS = "Already authenticated with Kiro CLI.";
|
|
84
|
+
var SIDEBAR_INSTRUCTIONS = 'To enable the Kiro credits sidebar, add "opencode-kiro" to the "plugins" array in your global cli.json and restart opencode.';
|
|
85
|
+
function createAuthResources() {
|
|
86
|
+
return {
|
|
87
|
+
child: void 0,
|
|
88
|
+
pollTimer: void 0,
|
|
89
|
+
cancelPoll: void 0,
|
|
90
|
+
disposeRegistration: void 0
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function releaseLoginResources(resources) {
|
|
94
|
+
if (resources.pollTimer !== void 0) {
|
|
95
|
+
clearTimeout(resources.pollTimer);
|
|
96
|
+
resources.pollTimer = void 0;
|
|
97
|
+
}
|
|
98
|
+
if (resources.child !== void 0) {
|
|
99
|
+
resources.child.kill();
|
|
100
|
+
resources.child = void 0;
|
|
101
|
+
}
|
|
102
|
+
if (resources.cancelPoll !== void 0) {
|
|
103
|
+
const cancel = resources.cancelPoll;
|
|
104
|
+
resources.cancelPoll = void 0;
|
|
105
|
+
cancel();
|
|
155
106
|
}
|
|
156
107
|
}
|
|
157
|
-
|
|
158
|
-
const { verifyAuth } = await import("kiro-acp-ai-provider");
|
|
159
|
-
if (!verifyAuth().authenticated) return { type: "failed" };
|
|
160
|
-
const token = tokenPath ? await readKiroTokenFile(tokenPath) : void 0;
|
|
161
|
-
const access = typeof token?.accessToken === "string" ? token.accessToken : "";
|
|
162
|
-
const refresh = typeof token?.refreshToken === "string" ? token.refreshToken : "";
|
|
108
|
+
function kiroCredential() {
|
|
163
109
|
return {
|
|
164
|
-
type: "
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
access:
|
|
168
|
-
|
|
169
|
-
// future expiry, refreshed each startup (server() re-runs per session) so core doesn't flag a logged-in user as expired. not the file value.
|
|
170
|
-
expires: Date.now() + 8 * 60 * 60 * 1e3
|
|
110
|
+
type: "oauth",
|
|
111
|
+
methodID: KIRO_OAUTH_METHOD_ID,
|
|
112
|
+
refresh: "",
|
|
113
|
+
access: "kiro-cli",
|
|
114
|
+
expires: 0
|
|
171
115
|
};
|
|
172
116
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
117
|
+
function withSidebarGuidance(instructions, inputs) {
|
|
118
|
+
return inputs["sidebar"] === "yes" ? `${instructions}
|
|
119
|
+
|
|
120
|
+
${SIDEBAR_INSTRUCTIONS}` : instructions;
|
|
121
|
+
}
|
|
122
|
+
function pollForLogin(verifyAuth, resources) {
|
|
123
|
+
return new Promise((resolve, reject) => {
|
|
124
|
+
const start = Date.now();
|
|
125
|
+
resources.cancelPoll = () => {
|
|
126
|
+
reject(new Error("Kiro authentication was cancelled."));
|
|
127
|
+
};
|
|
128
|
+
const tick = () => {
|
|
129
|
+
resources.pollTimer = void 0;
|
|
130
|
+
if (verifyAuth().authenticated) {
|
|
131
|
+
resources.cancelPoll = void 0;
|
|
132
|
+
releaseLoginResources(resources);
|
|
133
|
+
resolve(kiroCredential());
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (Date.now() - start >= MAX_WAIT_MS) {
|
|
137
|
+
resources.cancelPoll = void 0;
|
|
138
|
+
releaseLoginResources(resources);
|
|
139
|
+
reject(new Error(TIMEOUT_MESSAGE));
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
resources.pollTimer = setTimeout(tick, POLL_INTERVAL_MS);
|
|
143
|
+
};
|
|
144
|
+
resources.pollTimer = setTimeout(tick, POLL_INTERVAL_MS);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
async function authorize(inputs, resources) {
|
|
148
|
+
const { verifyAuth } = await import("kiro-acp-ai-provider");
|
|
149
|
+
const status = verifyAuth();
|
|
150
|
+
if (!status.installed) throw new Error(NOT_INSTALLED_MESSAGE);
|
|
151
|
+
if (status.authenticated) {
|
|
152
|
+
return {
|
|
153
|
+
url: KIRO_DOCS_URL,
|
|
154
|
+
instructions: withSidebarGuidance(ALREADY_AUTHENTICATED_INSTRUCTIONS, inputs),
|
|
155
|
+
mode: "auto",
|
|
156
|
+
callback: Promise.resolve(kiroCredential())
|
|
157
|
+
};
|
|
182
158
|
}
|
|
159
|
+
const { execFile } = await import("child_process");
|
|
160
|
+
resources.child = execFile("kiro-cli", ["login"], {
|
|
161
|
+
shell: process.platform === "win32"
|
|
162
|
+
});
|
|
163
|
+
return {
|
|
164
|
+
url: KIRO_DOCS_URL,
|
|
165
|
+
instructions: withSidebarGuidance(LOGIN_INSTRUCTIONS, inputs),
|
|
166
|
+
mode: "auto",
|
|
167
|
+
callback: pollForLogin(verifyAuth, resources)
|
|
168
|
+
};
|
|
183
169
|
}
|
|
184
|
-
function
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
170
|
+
async function registerAuth(context, resources) {
|
|
171
|
+
const registration = await context.integration.transform((draft) => {
|
|
172
|
+
draft.update(KIRO_INTEGRATION_ID, (integration) => {
|
|
173
|
+
integration.name = KIRO_INTEGRATION_NAME;
|
|
174
|
+
});
|
|
175
|
+
draft.method.update({
|
|
176
|
+
integrationID: KIRO_INTEGRATION_ID,
|
|
177
|
+
method: {
|
|
178
|
+
id: KIRO_OAUTH_METHOD_ID,
|
|
179
|
+
type: "oauth",
|
|
180
|
+
label: KIRO_OAUTH_METHOD_LABEL,
|
|
181
|
+
prompts: [
|
|
182
|
+
{
|
|
183
|
+
type: "select",
|
|
184
|
+
key: "sidebar",
|
|
185
|
+
message: "Enable the Kiro credits sidebar?",
|
|
186
|
+
options: [
|
|
187
|
+
{ label: "Yes", value: "yes", hint: "shows manual cli.json setup steps" },
|
|
188
|
+
{ label: "No", value: "no" }
|
|
189
|
+
]
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
},
|
|
193
|
+
authorize: (inputs) => authorize(inputs, resources)
|
|
194
|
+
// no refresh callback: kiro-cli owns credential storage and refresh
|
|
195
|
+
});
|
|
192
196
|
});
|
|
197
|
+
resources.disposeRegistration = registration.dispose;
|
|
198
|
+
return async () => {
|
|
199
|
+
releaseLoginResources(resources);
|
|
200
|
+
resources.disposeRegistration = void 0;
|
|
201
|
+
await registration.dispose();
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// src/server/discovery.ts
|
|
206
|
+
var KIRO_PROVIDER_ID = "kiro";
|
|
207
|
+
var KIRO_PROVIDER_PACKAGE = "aisdk:kiro-acp-ai-provider";
|
|
208
|
+
function asString(value) {
|
|
209
|
+
return value;
|
|
193
210
|
}
|
|
194
|
-
function
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
211
|
+
function createDiscoveryResources() {
|
|
212
|
+
return {
|
|
213
|
+
state: void 0,
|
|
214
|
+
disposeTransform: void 0,
|
|
215
|
+
eventIterator: void 0,
|
|
216
|
+
eventTask: void 0
|
|
217
|
+
};
|
|
199
218
|
}
|
|
200
|
-
function
|
|
201
|
-
|
|
202
|
-
return join(base, "opencode", "tui.json");
|
|
219
|
+
function effortSettings(effort) {
|
|
220
|
+
return { effort };
|
|
203
221
|
}
|
|
204
|
-
function
|
|
205
|
-
if (
|
|
206
|
-
|
|
207
|
-
|
|
222
|
+
function applyEfforts(model, runtimeModel) {
|
|
223
|
+
if (runtimeModel.runtimeEfforts.length === 0) return;
|
|
224
|
+
if (runtimeModel.baselineEffort !== void 0) {
|
|
225
|
+
model.settings = { ...model.settings, ...effortSettings(runtimeModel.baselineEffort) };
|
|
226
|
+
}
|
|
227
|
+
for (const effort of runtimeModel.runtimeEfforts) {
|
|
228
|
+
const existing = model.variants.find((variant) => asString(variant.id) === effort);
|
|
229
|
+
if (existing !== void 0) {
|
|
230
|
+
existing.settings = { ...existing.settings, ...effortSettings(effort) };
|
|
231
|
+
} else {
|
|
232
|
+
model.variants.push({
|
|
233
|
+
id: effort,
|
|
234
|
+
settings: effortSettings(effort)
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
208
238
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
239
|
+
function applyCatalogSnapshot(draft, state) {
|
|
240
|
+
const snapshot = state.snapshot;
|
|
241
|
+
if (snapshot === void 0 || snapshot.length === 0) return;
|
|
242
|
+
const runtime = new Map(snapshot.map((model) => [model.modelId, model]));
|
|
243
|
+
const record = draft.provider.get(KIRO_PROVIDER_ID);
|
|
244
|
+
const rich = record !== void 0 && record.models.size > 0;
|
|
245
|
+
const contextWindows = {};
|
|
246
|
+
if (rich) {
|
|
247
|
+
for (const [catalogKey, catalogModel] of Array.from(record.models.entries())) {
|
|
248
|
+
const runtimeModel = runtime.get(asString(catalogModel.modelID));
|
|
249
|
+
if (runtimeModel === void 0) {
|
|
250
|
+
draft.model.remove(KIRO_PROVIDER_ID, catalogKey);
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
draft.model.update(KIRO_PROVIDER_ID, catalogKey, (model) => {
|
|
254
|
+
applyEfforts(model, runtimeModel);
|
|
255
|
+
if (model.limit.context > 0) contextWindows[asString(model.modelID)] = model.limit.context;
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
for (const runtimeModel of snapshot) {
|
|
260
|
+
draft.model.update(KIRO_PROVIDER_ID, runtimeModel.modelId, (model) => {
|
|
261
|
+
model.name = runtimeModel.name || runtimeModel.modelId;
|
|
262
|
+
model.modelID = runtimeModel.modelId;
|
|
263
|
+
applyEfforts(model, runtimeModel);
|
|
264
|
+
if (model.limit.context > 0) contextWindows[asString(model.modelID)] = model.limit.context;
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
draft.provider.update(KIRO_PROVIDER_ID, (provider) => {
|
|
269
|
+
provider.name = KIRO_INTEGRATION_NAME;
|
|
270
|
+
provider.integrationID = KIRO_INTEGRATION_ID;
|
|
271
|
+
provider.package = KIRO_PROVIDER_PACKAGE;
|
|
272
|
+
provider.settings = {
|
|
273
|
+
...provider.settings,
|
|
274
|
+
cwd: state.cwd,
|
|
275
|
+
agent: "opencode",
|
|
276
|
+
trustAllTools: true,
|
|
277
|
+
mcpTimeout: 45,
|
|
278
|
+
contextWindows
|
|
279
|
+
};
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
function createDiscover(context, state) {
|
|
283
|
+
async function runDiscovery(gen) {
|
|
213
284
|
try {
|
|
214
|
-
|
|
285
|
+
const { listModels } = await import("kiro-acp-ai-provider");
|
|
286
|
+
const discovered = await listModels({ cwd: state.cwd });
|
|
287
|
+
if (gen !== state.generation) return;
|
|
288
|
+
const uniqueIds = new Set(discovered.map((model) => model.modelId));
|
|
289
|
+
if (uniqueIds.size !== discovered.length) return;
|
|
290
|
+
state.snapshot = discovered;
|
|
291
|
+
await context.catalog.reload();
|
|
215
292
|
} catch {
|
|
216
|
-
raw = void 0;
|
|
217
293
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
294
|
+
}
|
|
295
|
+
return async function discover(_reason) {
|
|
296
|
+
const active = await context.integration.connection.active(KIRO_INTEGRATION_ID);
|
|
297
|
+
if (!active) {
|
|
298
|
+
state.generation += 1;
|
|
299
|
+
state.snapshot = void 0;
|
|
300
|
+
await context.catalog.reload();
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
if (state.inflight !== void 0) return state.inflight;
|
|
304
|
+
const gen = ++state.generation;
|
|
305
|
+
const run = runDiscovery(gen).finally(() => {
|
|
306
|
+
if (state.inflight === run) state.inflight = void 0;
|
|
307
|
+
});
|
|
308
|
+
state.inflight = run;
|
|
309
|
+
return run;
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
async function consumeEvents(iterator, discover) {
|
|
313
|
+
try {
|
|
314
|
+
while (true) {
|
|
315
|
+
const result = await iterator.next();
|
|
316
|
+
if (result.done) return;
|
|
317
|
+
const event = result.value;
|
|
318
|
+
if (event.type === "integration.connection.updated" && event.data.integrationID === KIRO_INTEGRATION_ID) {
|
|
319
|
+
try {
|
|
320
|
+
await discover("connection-updated");
|
|
321
|
+
} catch {
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
} catch {
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
async function registerDiscovery(context, resources) {
|
|
329
|
+
const { location } = await context.integration.list();
|
|
330
|
+
const state = {
|
|
331
|
+
cwd: location.directory,
|
|
332
|
+
snapshot: void 0,
|
|
333
|
+
generation: 0,
|
|
334
|
+
inflight: void 0
|
|
335
|
+
};
|
|
336
|
+
resources.state = state;
|
|
337
|
+
const discover = createDiscover(context, state);
|
|
338
|
+
const registration = await context.catalog.transform(
|
|
339
|
+
(draft) => applyCatalogSnapshot(draft, state)
|
|
340
|
+
);
|
|
341
|
+
resources.disposeTransform = registration.dispose;
|
|
342
|
+
const iterator = context.event.subscribe()[Symbol.asyncIterator]();
|
|
343
|
+
resources.eventIterator = iterator;
|
|
344
|
+
resources.eventTask = consumeEvents(iterator, discover);
|
|
345
|
+
if (await context.integration.connection.active(KIRO_INTEGRATION_ID)) {
|
|
346
|
+
void discover("setup").catch(() => {
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
return async () => {
|
|
350
|
+
state.generation += 1;
|
|
351
|
+
const errors = [];
|
|
352
|
+
const eventIterator = resources.eventIterator;
|
|
353
|
+
resources.eventIterator = void 0;
|
|
354
|
+
if (eventIterator?.return !== void 0) {
|
|
222
355
|
try {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
|
|
356
|
+
await eventIterator.return();
|
|
357
|
+
} catch (error) {
|
|
358
|
+
errors.push(error);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
const eventTask = resources.eventTask;
|
|
362
|
+
resources.eventTask = void 0;
|
|
363
|
+
if (eventTask !== void 0) await eventTask;
|
|
364
|
+
const disposeTransform = resources.disposeTransform;
|
|
365
|
+
resources.disposeTransform = void 0;
|
|
366
|
+
if (disposeTransform !== void 0) {
|
|
367
|
+
try {
|
|
368
|
+
await disposeTransform();
|
|
369
|
+
} catch (error) {
|
|
370
|
+
errors.push(error);
|
|
228
371
|
}
|
|
229
372
|
}
|
|
230
|
-
if (
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
373
|
+
if (errors.length > 0) throw new AggregateError(errors, "kiro discovery cleanup failures");
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// src/server/lifecycle.ts
|
|
378
|
+
function createServerState() {
|
|
379
|
+
return {
|
|
380
|
+
auth: createAuthResources(),
|
|
381
|
+
discovery: createDiscoveryResources(),
|
|
382
|
+
aisdk: createAisdkResources(),
|
|
383
|
+
disposers: [],
|
|
384
|
+
disposed: false,
|
|
385
|
+
cleanup: void 0
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
async function disposeAll(disposers) {
|
|
389
|
+
const errors = [];
|
|
390
|
+
for (const dispose of [...disposers].reverse()) {
|
|
236
391
|
try {
|
|
237
|
-
await
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
});
|
|
243
|
-
} catch {
|
|
392
|
+
await dispose();
|
|
393
|
+
} catch (error) {
|
|
394
|
+
if (error instanceof AggregateError) errors.push(...error.errors);
|
|
395
|
+
else errors.push(error);
|
|
244
396
|
}
|
|
245
|
-
} catch (err) {
|
|
246
|
-
console.error("opencode-kiro: failed to enable the Kiro credits sidebar in tui.json:", err);
|
|
247
397
|
}
|
|
398
|
+
if (errors.length > 0) throw new AggregateError(errors, "kiro server cleanup failures");
|
|
399
|
+
}
|
|
400
|
+
function buildCleanup(state) {
|
|
401
|
+
return () => {
|
|
402
|
+
if (state.cleanup !== void 0) return state.cleanup;
|
|
403
|
+
state.disposed = true;
|
|
404
|
+
state.cleanup = disposeAll(state.disposers);
|
|
405
|
+
return state.cleanup;
|
|
406
|
+
};
|
|
248
407
|
}
|
|
249
|
-
|
|
250
|
-
|
|
408
|
+
|
|
409
|
+
// src/server.ts
|
|
410
|
+
var plugin = {
|
|
411
|
+
id: "kiro",
|
|
412
|
+
async setup(context) {
|
|
413
|
+
const state = createServerState();
|
|
414
|
+
const cleanup = buildCleanup(state);
|
|
415
|
+
try {
|
|
416
|
+
state.disposers.push(await registerAuth(context, state.auth));
|
|
417
|
+
state.disposers.push(await registerDiscovery(context, state.discovery));
|
|
418
|
+
state.disposers.push(await registerAisdkHook(context, state.aisdk));
|
|
419
|
+
} catch (error) {
|
|
420
|
+
await Promise.resolve(cleanup()).catch(() => {
|
|
421
|
+
});
|
|
422
|
+
throw error;
|
|
423
|
+
}
|
|
424
|
+
return cleanup;
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
var server_default = plugin;
|
|
428
|
+
var KiroAuthPlugin = plugin;
|
|
251
429
|
export {
|
|
252
430
|
KiroAuthPlugin,
|
|
253
|
-
server_default as default
|
|
254
|
-
enableSidebarConfig,
|
|
255
|
-
kiroTokenPath,
|
|
256
|
-
notifyIfTokenExpired,
|
|
257
|
-
readToken
|
|
431
|
+
server_default as default
|
|
258
432
|
};
|