@cortexkit/aft-opencode 0.30.1 → 0.30.3
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/dist/bg-notifications.d.ts +2 -0
- package/dist/bg-notifications.d.ts.map +1 -1
- package/dist/hooks/auto-update-checker/index.d.ts +1 -1
- package/dist/hooks/auto-update-checker/index.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +894 -23175
- package/dist/notifications.d.ts +8 -5
- package/dist/notifications.d.ts.map +1 -1
- package/dist/shared/last-assistant-model.d.ts +5 -6
- package/dist/shared/last-assistant-model.d.ts.map +1 -1
- package/dist/shared/live-server-client.d.ts +24 -22
- package/dist/shared/live-server-client.d.ts.map +1 -1
- package/dist/shared/rpc-client.d.ts +10 -3
- package/dist/shared/rpc-client.d.ts.map +1 -1
- package/dist/shared/storage-paths.d.ts +2 -0
- package/dist/shared/storage-paths.d.ts.map +1 -0
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash_watch.d.ts +4 -0
- package/dist/tools/bash_watch.d.ts.map +1 -1
- package/dist/tools/reading.d.ts.map +1 -1
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tui.js +222 -123
- package/package.json +8 -8
- package/src/shared/last-assistant-model.ts +9 -27
- package/src/shared/live-server-client.ts +80 -48
- package/src/shared/rpc-client.ts +132 -28
- package/src/shared/storage-paths.ts +22 -0
- package/src/tui/index.tsx +39 -17
- package/src/tui/sidebar.tsx +94 -27
package/src/tui/sidebar.tsx
CHANGED
|
@@ -12,6 +12,7 @@ import { createEffect, createMemo, createSignal, on, onCleanup } from "solid-js"
|
|
|
12
12
|
|
|
13
13
|
import { AftRpcClient } from "../shared/rpc-client";
|
|
14
14
|
import { type AftStatusSnapshot, coerceAftStatus, type StatusCompression } from "../shared/status";
|
|
15
|
+
import { resolveCortexKitStorageRoot } from "../shared/storage-paths";
|
|
15
16
|
|
|
16
17
|
const SINGLE_BORDER = { type: "single" } as any;
|
|
17
18
|
const REFRESH_DEBOUNCE_MS = 200;
|
|
@@ -135,6 +136,13 @@ const SectionHeader = (props: { theme: TuiThemeCurrent; title: string; marginTop
|
|
|
135
136
|
</box>
|
|
136
137
|
);
|
|
137
138
|
|
|
139
|
+
// v0.27 moved AFT storage to the CortexKit root. TUI code must use a
|
|
140
|
+
// lightweight local path helper rather than the shared bridge barrel, which
|
|
141
|
+
// also exports URL-fetch helpers unsuitable for Bun's TUI runtime.
|
|
142
|
+
export function resolveTuiStorageDir(): string {
|
|
143
|
+
return resolveCortexKitStorageRoot();
|
|
144
|
+
}
|
|
145
|
+
|
|
138
146
|
// One RPC client per project directory — same pattern as the /aft-status
|
|
139
147
|
// dialog handler in tui/index.tsx. Sharing the map avoids opening a second
|
|
140
148
|
// connection just for the sidebar.
|
|
@@ -142,56 +150,111 @@ const sidebarClients = new Map<string, AftRpcClient>();
|
|
|
142
150
|
function getClient(directory: string): AftRpcClient {
|
|
143
151
|
let client = sidebarClients.get(directory);
|
|
144
152
|
if (client) return client;
|
|
145
|
-
|
|
146
|
-
const dataHome = process.env.XDG_DATA_HOME || `${home}/.local/share`;
|
|
147
|
-
// v0.27 moved AFT storage to the CortexKit root. Must match the server
|
|
148
|
-
// plugin's `resolveCortexKitStorageRoot()` or the sidebar will poll a
|
|
149
|
-
// stale legacy port file and never connect to the live RPC server.
|
|
150
|
-
const storageDir = `${dataHome}/cortexkit/aft`;
|
|
151
|
-
client = new AftRpcClient(storageDir, directory);
|
|
153
|
+
client = new AftRpcClient(resolveTuiStorageDir(), directory);
|
|
152
154
|
sidebarClients.set(directory, client);
|
|
153
155
|
return client;
|
|
154
156
|
}
|
|
155
157
|
|
|
158
|
+
export type ScopedSidebarStatus = {
|
|
159
|
+
directory: string;
|
|
160
|
+
sessionID: string;
|
|
161
|
+
snapshot: AftStatusSnapshot;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export function scopedSidebarSnapshot(
|
|
165
|
+
scoped: ScopedSidebarStatus | null,
|
|
166
|
+
directory: string,
|
|
167
|
+
sessionID: string,
|
|
168
|
+
): AftStatusSnapshot | null {
|
|
169
|
+
if (!scoped) return null;
|
|
170
|
+
if (scoped.directory !== directory || scoped.sessionID !== sessionID) return null;
|
|
171
|
+
return scoped.snapshot;
|
|
172
|
+
}
|
|
173
|
+
|
|
156
174
|
const SidebarContent = (props: {
|
|
157
175
|
api: TuiPluginApi;
|
|
158
176
|
sessionID: () => string;
|
|
159
177
|
theme: TuiThemeCurrent;
|
|
160
178
|
pluginVersion: string;
|
|
161
179
|
}) => {
|
|
162
|
-
const [status, setStatus] = createSignal<
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
180
|
+
const [status, setStatus] = createSignal<ScopedSidebarStatus | null>(null);
|
|
181
|
+
let inflight: {
|
|
182
|
+
controller: AbortController;
|
|
183
|
+
generation: number;
|
|
184
|
+
directory: string;
|
|
185
|
+
sessionID: string;
|
|
186
|
+
} | null = null;
|
|
187
|
+
let generation = 0;
|
|
166
188
|
let debounceTimer: ReturnType<typeof setTimeout> | undefined;
|
|
167
189
|
let pollTimer: ReturnType<typeof setInterval> | undefined;
|
|
168
190
|
|
|
191
|
+
const currentDirectory = () => props.api.state.path.directory ?? "";
|
|
192
|
+
const requestRender = () => {
|
|
193
|
+
try {
|
|
194
|
+
props.api.renderer.requestRender();
|
|
195
|
+
} catch {
|
|
196
|
+
// renderer may not be available during teardown; safe to ignore
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
const abortInflight = () => {
|
|
200
|
+
if (!inflight) return;
|
|
201
|
+
inflight.controller.abort();
|
|
202
|
+
inflight = null;
|
|
203
|
+
};
|
|
204
|
+
const clearStatusForContext = (directory: string, sessionID: string) => {
|
|
205
|
+
const current = status();
|
|
206
|
+
if (!current) return;
|
|
207
|
+
if (current.directory === directory && current.sessionID === sessionID) return;
|
|
208
|
+
setStatus(null);
|
|
209
|
+
requestRender();
|
|
210
|
+
};
|
|
211
|
+
|
|
169
212
|
const refresh = async () => {
|
|
170
213
|
const sid = props.sessionID();
|
|
171
|
-
|
|
172
|
-
if (
|
|
173
|
-
|
|
174
|
-
|
|
214
|
+
const directory = currentDirectory();
|
|
215
|
+
if (!sid || !directory) {
|
|
216
|
+
generation++;
|
|
217
|
+
abortInflight();
|
|
218
|
+
if (status()) {
|
|
219
|
+
setStatus(null);
|
|
220
|
+
requestRender();
|
|
221
|
+
}
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
clearStatusForContext(directory, sid);
|
|
226
|
+
|
|
227
|
+
if (inflight) {
|
|
228
|
+
if (inflight.directory === directory && inflight.sessionID === sid) return;
|
|
229
|
+
generation++;
|
|
230
|
+
abortInflight();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const requestGeneration = ++generation;
|
|
234
|
+
const controller = new AbortController();
|
|
235
|
+
inflight = { controller, generation: requestGeneration, directory, sessionID: sid };
|
|
175
236
|
|
|
176
|
-
inflight = true;
|
|
177
237
|
try {
|
|
178
238
|
const client = getClient(directory);
|
|
179
|
-
const response = await client.call(
|
|
239
|
+
const response = await client.call(
|
|
240
|
+
"status",
|
|
241
|
+
{ sessionID: sid },
|
|
242
|
+
{ signal: controller.signal },
|
|
243
|
+
);
|
|
244
|
+
if (controller.signal.aborted || requestGeneration !== generation) return;
|
|
245
|
+
if (currentDirectory() !== directory || props.sessionID() !== sid) return;
|
|
180
246
|
if (response && (response as Record<string, unknown>).success !== false) {
|
|
181
247
|
const snapshot = coerceAftStatus(response as Record<string, unknown>);
|
|
182
|
-
setStatus(snapshot);
|
|
183
|
-
|
|
184
|
-
props.api.renderer.requestRender();
|
|
185
|
-
} catch {
|
|
186
|
-
// renderer may not be available during teardown; safe to ignore
|
|
187
|
-
}
|
|
248
|
+
setStatus({ directory, sessionID: sid, snapshot });
|
|
249
|
+
requestRender();
|
|
188
250
|
}
|
|
189
251
|
} catch {
|
|
252
|
+
if (controller.signal.aborted || requestGeneration !== generation) return;
|
|
190
253
|
// RPC server may not be ready yet, or the bridge may be respawning
|
|
191
|
-
// after a binary swap
|
|
192
|
-
//
|
|
254
|
+
// after a binary swap. Keep the previous snapshot only when it belongs
|
|
255
|
+
// to the current project/session; mismatched snapshots were cleared above.
|
|
193
256
|
} finally {
|
|
194
|
-
inflight =
|
|
257
|
+
if (inflight?.generation === requestGeneration) inflight = null;
|
|
195
258
|
}
|
|
196
259
|
};
|
|
197
260
|
|
|
@@ -204,6 +267,8 @@ const SidebarContent = (props: {
|
|
|
204
267
|
};
|
|
205
268
|
|
|
206
269
|
onCleanup(() => {
|
|
270
|
+
generation++;
|
|
271
|
+
abortInflight();
|
|
207
272
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
208
273
|
if (pollTimer) clearInterval(pollTimer);
|
|
209
274
|
});
|
|
@@ -250,6 +315,8 @@ const SidebarContent = (props: {
|
|
|
250
315
|
// best effort
|
|
251
316
|
}
|
|
252
317
|
}
|
|
318
|
+
generation++;
|
|
319
|
+
abortInflight();
|
|
253
320
|
if (pollTimer) {
|
|
254
321
|
clearInterval(pollTimer);
|
|
255
322
|
pollTimer = undefined;
|
|
@@ -260,7 +327,7 @@ const SidebarContent = (props: {
|
|
|
260
327
|
),
|
|
261
328
|
);
|
|
262
329
|
|
|
263
|
-
const s =
|
|
330
|
+
const s = () => scopedSidebarSnapshot(status(), currentDirectory(), props.sessionID());
|
|
264
331
|
|
|
265
332
|
// Lazy-bridge: while AFT has no live bridge yet, the RPC server returns a
|
|
266
333
|
// synthetic snapshot with `cache_role === "not_initialized"`. In that state
|