@cortexkit/aft-opencode 0.55.1 → 0.56.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.
Files changed (77) hide show
  1. package/dist/bg-notifications.d.ts +56 -10
  2. package/dist/bg-notifications.d.ts.map +1 -1
  3. package/dist/cancellation/effect-abort.d.ts +13 -0
  4. package/dist/cancellation/effect-abort.d.ts.map +1 -0
  5. package/dist/config.d.ts +85 -2
  6. package/dist/config.d.ts.map +1 -1
  7. package/dist/entry/server.js +45488 -0
  8. package/dist/index.d.ts +0 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +20437 -16564
  11. package/dist/lsp-cache.d.ts +5 -0
  12. package/dist/lsp-cache.d.ts.map +1 -1
  13. package/dist/lsp-github-install.d.ts +2 -1
  14. package/dist/lsp-github-install.d.ts.map +1 -1
  15. package/dist/permissions/v2.d.ts +51 -0
  16. package/dist/permissions/v2.d.ts.map +1 -0
  17. package/dist/plugin-version.d.ts +15 -0
  18. package/dist/plugin-version.d.ts.map +1 -0
  19. package/dist/rpc/contract.d.ts +2 -0
  20. package/dist/rpc/contract.d.ts.map +1 -0
  21. package/dist/rpc/register.d.ts +33 -0
  22. package/dist/rpc/register.d.ts.map +1 -0
  23. package/dist/shutdown-hooks.d.ts +13 -4
  24. package/dist/shutdown-hooks.d.ts.map +1 -1
  25. package/dist/subc-tool-schemas.d.ts +1 -1
  26. package/dist/subc-tool-schemas.d.ts.map +1 -1
  27. package/dist/tool-registration.d.ts +46 -1
  28. package/dist/tool-registration.d.ts.map +1 -1
  29. package/dist/tools/_shared.d.ts +2 -0
  30. package/dist/tools/_shared.d.ts.map +1 -1
  31. package/dist/tools/ast.d.ts.map +1 -1
  32. package/dist/tools/bash/executor.d.ts +10 -0
  33. package/dist/tools/bash/executor.d.ts.map +1 -0
  34. package/dist/tools/bash.d.ts +1 -1
  35. package/dist/tools/bash.d.ts.map +1 -1
  36. package/dist/tools/bash_watch.d.ts.map +1 -1
  37. package/dist/tools/definitions/v2.d.ts +57 -0
  38. package/dist/tools/definitions/v2.d.ts.map +1 -0
  39. package/dist/tools/hoisted/v2.d.ts +8 -0
  40. package/dist/tools/hoisted/v2.d.ts.map +1 -0
  41. package/dist/tools/hoisted.d.ts +2 -0
  42. package/dist/tools/hoisted.d.ts.map +1 -1
  43. package/dist/tools/inspect.d.ts.map +1 -1
  44. package/dist/tools/navigation.d.ts.map +1 -1
  45. package/dist/tools/permissions.d.ts +21 -3
  46. package/dist/tools/permissions.d.ts.map +1 -1
  47. package/dist/tools/reading.d.ts.map +1 -1
  48. package/dist/tools/semantic.d.ts.map +1 -1
  49. package/dist/tui/aft-rpc.d.ts +48 -0
  50. package/dist/tui/aft-rpc.d.ts.map +1 -0
  51. package/dist/tui/v2-status.d.ts +11 -0
  52. package/dist/tui/v2-status.d.ts.map +1 -0
  53. package/dist/wakes/runtime-consumer.d.ts +19 -0
  54. package/dist/wakes/runtime-consumer.d.ts.map +1 -0
  55. package/dist/wakes/session-delivery.d.ts +45 -0
  56. package/dist/wakes/session-delivery.d.ts.map +1 -0
  57. package/dist/workflow-hints.d.ts +12 -1
  58. package/dist/workflow-hints.d.ts.map +1 -1
  59. package/package.json +21 -16
  60. package/src/entry/server-runtime.mjs +109 -0
  61. package/src/entry/server.d.ts +10 -0
  62. package/src/entry/server.mjs +10 -0
  63. package/src/entry/tui.d.ts +8 -0
  64. package/src/entry/tui.mjs +9 -0
  65. package/src/tui/aft-rpc.ts +43 -0
  66. package/src/tui/index.tsx +3 -1
  67. package/src/tui/sidebar.tsx +1 -1
  68. package/src/tui/types/opencode-plugin-tui.d.ts +4 -3
  69. package/src/tui/v2-status.ts +56 -0
  70. package/src/tui/v2.tsx +209 -0
  71. package/src/tui-compiled/aft-rpc.ts +43 -0
  72. package/src/tui-compiled/index.tsx +3 -1
  73. package/src/tui-compiled/types/opencode-plugin-tui.d.ts +4 -3
  74. package/src/tui-compiled/v2-status.ts +56 -0
  75. package/src/tui-compiled/v2.tsx +181 -0
  76. package/dist/tools/refactoring.d.ts +0 -7
  77. package/dist/tools/refactoring.d.ts.map +0 -1
package/src/tui/v2.tsx ADDED
@@ -0,0 +1,209 @@
1
+ /** @jsxImportSource @opentui/solid */
2
+ // @ts-nocheck
3
+
4
+ import { createEffect, createSignal, onCleanup } from "solid-js";
5
+ import {
6
+ type AftStatusSnapshot,
7
+ coerceAftStatus,
8
+ formatStatusDialogMessage,
9
+ } from "../shared/status";
10
+ import { AftRpc } from "./aft-rpc";
11
+ import { formatAftStatusSegment, summarizeAftSidebar } from "./v2-status";
12
+
13
+ type AftRpcClient = {
14
+ getStatus(
15
+ input: { sessionID?: string },
16
+ options?: { location?: unknown; signal?: AbortSignal },
17
+ ): Promise<Record<string, unknown>>;
18
+ events: {
19
+ on(
20
+ name: "statusInvalidated" | "showStatusDialog" | "indexProgress",
21
+ handler: (event: { data: { sessionID?: string } }) => void | Promise<void>,
22
+ options?: { signal?: AbortSignal },
23
+ ): () => void;
24
+ };
25
+ };
26
+
27
+ type V2TuiContext = {
28
+ location?: unknown;
29
+ client: { rpc(definition: typeof AftRpc): AftRpcClient };
30
+ keymap: {
31
+ layer(input: () => { commands: Array<Record<string, unknown>>; bindings: string[] }): void;
32
+ };
33
+ ui: {
34
+ dialog: { alert(input: { title: string; message: string }): Promise<void> };
35
+ router: { current(): { type: string; sessionID?: string } };
36
+ slot(claim: {
37
+ append: "prompt.footer.status" | "sidebar.content";
38
+ render(input: { sessionID?: string }): unknown;
39
+ }): () => void;
40
+ };
41
+ };
42
+
43
+ function eventMatchesSession(
44
+ eventSessionID: string | undefined,
45
+ sessionID: string | undefined,
46
+ ): boolean {
47
+ return eventSessionID === undefined || eventSessionID === sessionID;
48
+ }
49
+
50
+ async function fetchStatus(
51
+ context: V2TuiContext,
52
+ rpc: AftRpcClient,
53
+ sessionID: string | undefined,
54
+ signal?: AbortSignal,
55
+ ): Promise<AftStatusSnapshot> {
56
+ const response = await rpc.getStatus(sessionID ? { sessionID } : {}, {
57
+ ...(context.location ? { location: context.location } : {}),
58
+ ...(signal ? { signal } : {}),
59
+ });
60
+ return coerceAftStatus(response);
61
+ }
62
+
63
+ export function subscribeV2StatusRefresh(
64
+ rpc: AftRpcClient,
65
+ sessionID: () => string | undefined,
66
+ refresh: () => void,
67
+ ): () => void {
68
+ const unsubscribes = [
69
+ rpc.events.on("statusInvalidated", (event) => {
70
+ if (eventMatchesSession(event.data.sessionID, sessionID())) refresh();
71
+ }),
72
+ rpc.events.on("indexProgress", (event) => {
73
+ if (eventMatchesSession(event.data.sessionID, sessionID())) refresh();
74
+ }),
75
+ ];
76
+ return () => {
77
+ for (const unsubscribe of unsubscribes) unsubscribe();
78
+ };
79
+ }
80
+
81
+ function useAftStatus(
82
+ context: V2TuiContext,
83
+ rpc: AftRpcClient,
84
+ sessionID: () => string | undefined,
85
+ ): () => AftStatusSnapshot | null {
86
+ const [status, setStatus] = createSignal<AftStatusSnapshot | null>(null);
87
+ let refreshGeneration = 0;
88
+ let refreshController: AbortController | undefined;
89
+
90
+ const refresh = async (): Promise<void> => {
91
+ const requestedSessionID = sessionID();
92
+ const generation = ++refreshGeneration;
93
+ refreshController?.abort();
94
+ const controller = new AbortController();
95
+ refreshController = controller;
96
+ try {
97
+ const next = await fetchStatus(context, rpc, requestedSessionID, controller.signal);
98
+ if (controller.signal.aborted || generation !== refreshGeneration) return;
99
+ if (sessionID() !== requestedSessionID) return;
100
+ setStatus(next);
101
+ } catch {
102
+ // Status is best-effort UI data; the next typed invalidation retries it.
103
+ }
104
+ };
105
+
106
+ createEffect(() => {
107
+ sessionID();
108
+ void refresh();
109
+ });
110
+ const unsubscribe = subscribeV2StatusRefresh(rpc, sessionID, () => {
111
+ void refresh();
112
+ });
113
+ onCleanup(() => {
114
+ refreshGeneration += 1;
115
+ refreshController?.abort();
116
+ unsubscribe();
117
+ });
118
+ return status;
119
+ }
120
+
121
+ function FooterStatus(props: { context: V2TuiContext; rpc: AftRpcClient; sessionID?: string }) {
122
+ const status = useAftStatus(props.context, props.rpc, () => props.sessionID);
123
+ return <text>{formatAftStatusSegment(status())}</text>;
124
+ }
125
+
126
+ function SidebarStatus(props: { context: V2TuiContext; rpc: AftRpcClient; sessionID: string }) {
127
+ const status = useAftStatus(props.context, props.rpc, () => props.sessionID);
128
+ const summary = () => summarizeAftSidebar(status());
129
+ return (
130
+ <box width="100%" flexDirection="column">
131
+ <text>
132
+ <b>{summary().title}</b>
133
+ {summary().version ? ` v${summary().version}` : ""}
134
+ </text>
135
+ <text>Search: {summary().search}</text>
136
+ <text>Semantic: {summary().semantic}</text>
137
+ <text>Health: {summary().health}</text>
138
+ </box>
139
+ );
140
+ }
141
+
142
+ function activeSessionID(context: V2TuiContext): string | undefined {
143
+ const route = context.ui.router.current();
144
+ return route.type === "session" ? route.sessionID : undefined;
145
+ }
146
+
147
+ async function showStatusDialog(
148
+ context: V2TuiContext,
149
+ rpc: AftRpcClient,
150
+ sessionID: string | undefined,
151
+ ): Promise<void> {
152
+ try {
153
+ const status = await fetchStatus(context, rpc, sessionID);
154
+ await context.ui.dialog.alert({
155
+ title: "AFT Status",
156
+ message: formatStatusDialogMessage(status),
157
+ });
158
+ } catch {
159
+ await context.ui.dialog.alert({
160
+ title: "AFT Status",
161
+ message: "AFT is starting up. Status will refresh automatically.",
162
+ });
163
+ }
164
+ }
165
+
166
+ export async function setupV2Tui(context: V2TuiContext): Promise<() => void> {
167
+ const rpc = context.client.rpc(AftRpc);
168
+ const controller = new AbortController();
169
+ const slotCleanups = [
170
+ context.ui.slot({
171
+ append: "prompt.footer.status",
172
+ render: (input) => <FooterStatus context={context} rpc={rpc} sessionID={input.sessionID} />,
173
+ }),
174
+ context.ui.slot({
175
+ append: "sidebar.content",
176
+ render: (input) => <SidebarStatus context={context} rpc={rpc} sessionID={input.sessionID!} />,
177
+ }),
178
+ ];
179
+
180
+ const stopDialogEvents = rpc.events.on(
181
+ "showStatusDialog",
182
+ (event) => showStatusDialog(context, rpc, event.data.sessionID ?? activeSessionID(context)),
183
+ { signal: controller.signal },
184
+ );
185
+
186
+ context.keymap.layer(() => ({
187
+ commands: [
188
+ {
189
+ id: "aft.status",
190
+ title: "AFT: Status",
191
+ description: "Show AFT status, index health, and cache usage",
192
+ group: "AFT",
193
+ palette: true,
194
+ // V2's KeymapCommand contract (plugin/tui/context.ts:379-385) dispatches
195
+ // slash entries unless `arguments: true`; omitting it prevents this text
196
+ // from remaining in the prompt or being submitted to the model.
197
+ slash: { name: "aft-status" },
198
+ run: () => showStatusDialog(context, rpc, activeSessionID(context)),
199
+ },
200
+ ],
201
+ bindings: [],
202
+ }));
203
+
204
+ return () => {
205
+ controller.abort();
206
+ stopDialogEvents();
207
+ for (const cleanup of slotCleanups) cleanup();
208
+ };
209
+ }
@@ -0,0 +1,43 @@
1
+ import { Schema } from "effect";
2
+
3
+ /**
4
+ * The V2 host's Rpc.define returns its input after checking reserved custom
5
+ * error names. AFT defines no custom RPC errors, so this local identity has the
6
+ * same result and also loads on V1, where @opencode-ai/schema is unavailable.
7
+ */
8
+ const Rpc = {
9
+ define<const Definition>(definition: Definition): Definition {
10
+ return definition;
11
+ },
12
+ };
13
+
14
+ export const RpcSession = Schema.Struct({
15
+ sessionID: Schema.optional(Schema.String),
16
+ });
17
+
18
+ export const IndexProgress = Schema.Struct({
19
+ index: Schema.Literals(["search", "semantic"]),
20
+ status: Schema.String,
21
+ sessionID: Schema.optional(Schema.String),
22
+ stage: Schema.optional(Schema.NullOr(Schema.String)),
23
+ completed: Schema.optional(Schema.Number),
24
+ total: Schema.optional(Schema.Number),
25
+ });
26
+
27
+ export type AftRpcSession = typeof RpcSession.Type;
28
+ export type AftIndexProgress = typeof IndexProgress.Type;
29
+
30
+ export const AftRpc = Rpc.define({
31
+ id: "aft",
32
+ methods: {
33
+ getStatus: {
34
+ input: RpcSession,
35
+ output: Schema.Record(Schema.String, Schema.Unknown),
36
+ },
37
+ },
38
+ events: {
39
+ statusInvalidated: { schema: RpcSession },
40
+ showStatusDialog: { schema: RpcSession },
41
+ indexProgress: { schema: IndexProgress },
42
+ },
43
+ });
@@ -15,6 +15,7 @@ import { AftRpcClient } from "../shared/rpc-client";
15
15
  import { coerceAftStatus, formatBytes, formatCacheRoleLabel, formatSemanticIndexStatus, formatSemanticRefreshing } from "../shared/status";
16
16
  import { createDebouncedStatusRefresh, refreshAftTuiSocketScope, startAftTuiSocket, stopAftTuiSocket, subscribeStatusInvalidations } from "./notification-socket";
17
17
  import { createAftSidebarSlot, formatCompressionSidebarRows, isSnapshotForContext, resolveTuiStorageDir, shouldSuppressUninitializedDowngrade } from "./sidebar";
18
+ import { setupV2Tui } from "./v2";
18
19
 
19
20
  // The TUI talks to the server plugin via AftRpcClient. The client reads the
20
21
  // JSON port file written by AftRpcServer ({ port, token }) and includes that
@@ -1018,5 +1019,6 @@ const tui = async api => {
1018
1019
  const id = "aft-opencode";
1019
1020
  export default {
1020
1021
  id,
1021
- tui
1022
+ tui,
1023
+ setup: setupV2Tui
1022
1024
  };
@@ -1,7 +1,8 @@
1
- // Type declarations for @opencode-ai/plugin/tui
2
- // These types are not yet exported by the installed @opencode-ai/plugin package
1
+ // Compatibility declarations for the GA @opencode/plugin/tui entrypoint.
2
+ // AFT's shared TUI still consumes the legacy callback surface while its V2 setup
3
+ // export uses the GA setup context directly.
3
4
 
4
- declare module "@opencode-ai/plugin/tui" {
5
+ declare module "@opencode/plugin/tui" {
5
6
  import type {
6
7
  createOpencodeClient as createOpencodeClientV2,
7
8
  Event as TuiEvent,
@@ -0,0 +1,56 @@
1
+ import type { AftStatusSnapshot, StatusBar } from "../shared/status";
2
+
3
+ function count(value: number | undefined): string {
4
+ return value === undefined ? "?" : String(value);
5
+ }
6
+
7
+ export function formatAftStatusSegment(status: AftStatusSnapshot | null): string {
8
+ const bar = status?.status_bar;
9
+ if (!bar) return "AFT starting…";
10
+ const stale = bar.tier2_stale ? "~" : "";
11
+ return (
12
+ `AFT E${count(bar.errors)} W${count(bar.warnings)} | ` +
13
+ `${stale}D${count(bar.dead_code)} U${count(bar.unused_exports)} ` +
14
+ `C${count(bar.duplicates)} | T${count(bar.todos)}`
15
+ );
16
+ }
17
+
18
+ export type AftSidebarSummary = {
19
+ title: string;
20
+ version?: string;
21
+ search: string;
22
+ semantic: string;
23
+ health: string;
24
+ };
25
+
26
+ function healthSummary(bar: StatusBar | undefined): string {
27
+ if (!bar) return "health pending";
28
+ const stale = bar.tier2_stale ? "~" : "";
29
+ return (
30
+ `E${count(bar.errors)} W${count(bar.warnings)} ` +
31
+ `${stale}D${count(bar.dead_code)} U${count(bar.unused_exports)} ` +
32
+ `C${count(bar.duplicates)} T${count(bar.todos)}`
33
+ );
34
+ }
35
+
36
+ export function summarizeAftSidebar(status: AftStatusSnapshot | null): AftSidebarSummary {
37
+ if (!status || status.cache_role === "not_initialized") {
38
+ return {
39
+ title: "AFT",
40
+ search: "not initialized",
41
+ semantic: "not initialized",
42
+ health: "health pending",
43
+ };
44
+ }
45
+
46
+ const semantic = status.semantic_index.stage
47
+ ? `${status.semantic_index.status} (${status.semantic_index.stage})`
48
+ : status.semantic_index.status;
49
+ return {
50
+ title: status.degraded ? "AFT · DEGRADED" : "AFT",
51
+ version: status.version || undefined,
52
+ search: status.search_index.status,
53
+ semantic,
54
+ health: healthSummary(status.status_bar),
55
+ };
56
+ }
@@ -0,0 +1,181 @@
1
+ import { createComponent as _$createComponent } from "opentui:runtime-module:%40opentui%2Fsolid";
2
+ import { createTextNode as _$createTextNode } from "opentui:runtime-module:%40opentui%2Fsolid";
3
+ import { insertNode as _$insertNode } from "opentui:runtime-module:%40opentui%2Fsolid";
4
+ import { memo as _$memo } from "opentui:runtime-module:%40opentui%2Fsolid";
5
+ import { setProp as _$setProp } from "opentui:runtime-module:%40opentui%2Fsolid";
6
+ import { insert as _$insert } from "opentui:runtime-module:%40opentui%2Fsolid";
7
+ import { createElement as _$createElement } from "opentui:runtime-module:%40opentui%2Fsolid";
8
+ /** @jsxImportSource @opentui/solid */
9
+ // @ts-nocheck
10
+
11
+ import { createEffect, createSignal, onCleanup } from "opentui:runtime-module:solid-js";
12
+ import { coerceAftStatus, formatStatusDialogMessage } from "../shared/status";
13
+ import { AftRpc } from "./aft-rpc";
14
+ import { formatAftStatusSegment, summarizeAftSidebar } from "./v2-status";
15
+ function eventMatchesSession(eventSessionID, sessionID) {
16
+ return eventSessionID === undefined || eventSessionID === sessionID;
17
+ }
18
+ async function fetchStatus(context, rpc, sessionID, signal) {
19
+ const response = await rpc.getStatus(sessionID ? {
20
+ sessionID
21
+ } : {}, {
22
+ ...(context.location ? {
23
+ location: context.location
24
+ } : {}),
25
+ ...(signal ? {
26
+ signal
27
+ } : {})
28
+ });
29
+ return coerceAftStatus(response);
30
+ }
31
+ export function subscribeV2StatusRefresh(rpc, sessionID, refresh) {
32
+ const unsubscribes = [rpc.events.on("statusInvalidated", event => {
33
+ if (eventMatchesSession(event.data.sessionID, sessionID())) refresh();
34
+ }), rpc.events.on("indexProgress", event => {
35
+ if (eventMatchesSession(event.data.sessionID, sessionID())) refresh();
36
+ })];
37
+ return () => {
38
+ for (const unsubscribe of unsubscribes) unsubscribe();
39
+ };
40
+ }
41
+ function useAftStatus(context, rpc, sessionID) {
42
+ const [status, setStatus] = createSignal(null);
43
+ let refreshGeneration = 0;
44
+ let refreshController;
45
+ const refresh = async () => {
46
+ const requestedSessionID = sessionID();
47
+ const generation = ++refreshGeneration;
48
+ refreshController?.abort();
49
+ const controller = new AbortController();
50
+ refreshController = controller;
51
+ try {
52
+ const next = await fetchStatus(context, rpc, requestedSessionID, controller.signal);
53
+ if (controller.signal.aborted || generation !== refreshGeneration) return;
54
+ if (sessionID() !== requestedSessionID) return;
55
+ setStatus(next);
56
+ } catch {
57
+ // Status is best-effort UI data; the next typed invalidation retries it.
58
+ }
59
+ };
60
+ createEffect(() => {
61
+ sessionID();
62
+ void refresh();
63
+ });
64
+ const unsubscribe = subscribeV2StatusRefresh(rpc, sessionID, () => {
65
+ void refresh();
66
+ });
67
+ onCleanup(() => {
68
+ refreshGeneration += 1;
69
+ refreshController?.abort();
70
+ unsubscribe();
71
+ });
72
+ return status;
73
+ }
74
+ function FooterStatus(props) {
75
+ const status = useAftStatus(props.context, props.rpc, () => props.sessionID);
76
+ return (() => {
77
+ var _el$ = _$createElement("text");
78
+ _$insert(_el$, () => formatAftStatusSegment(status()));
79
+ return _el$;
80
+ })();
81
+ }
82
+ function SidebarStatus(props) {
83
+ const status = useAftStatus(props.context, props.rpc, () => props.sessionID);
84
+ const summary = () => summarizeAftSidebar(status());
85
+ return (() => {
86
+ var _el$2 = _$createElement("box"),
87
+ _el$3 = _$createElement("text"),
88
+ _el$4 = _$createElement("b"),
89
+ _el$5 = _$createElement("text"),
90
+ _el$6 = _$createTextNode(`Search: `),
91
+ _el$7 = _$createElement("text"),
92
+ _el$8 = _$createTextNode(`Semantic: `),
93
+ _el$9 = _$createElement("text"),
94
+ _el$0 = _$createTextNode(`Health: `);
95
+ _$insertNode(_el$2, _el$3);
96
+ _$insertNode(_el$2, _el$5);
97
+ _$insertNode(_el$2, _el$7);
98
+ _$insertNode(_el$2, _el$9);
99
+ _$setProp(_el$2, "width", "100%");
100
+ _$setProp(_el$2, "flexDirection", "column");
101
+ _$insertNode(_el$3, _el$4);
102
+ _$insert(_el$4, () => summary().title);
103
+ _$insert(_el$3, (() => {
104
+ var _c$ = _$memo(() => !!summary().version);
105
+ return () => _c$() ? ` v${summary().version}` : "";
106
+ })(), null);
107
+ _$insertNode(_el$5, _el$6);
108
+ _$insert(_el$5, () => summary().search, null);
109
+ _$insertNode(_el$7, _el$8);
110
+ _$insert(_el$7, () => summary().semantic, null);
111
+ _$insertNode(_el$9, _el$0);
112
+ _$insert(_el$9, () => summary().health, null);
113
+ return _el$2;
114
+ })();
115
+ }
116
+ function activeSessionID(context) {
117
+ const route = context.ui.router.current();
118
+ return route.type === "session" ? route.sessionID : undefined;
119
+ }
120
+ async function showStatusDialog(context, rpc, sessionID) {
121
+ try {
122
+ const status = await fetchStatus(context, rpc, sessionID);
123
+ await context.ui.dialog.alert({
124
+ title: "AFT Status",
125
+ message: formatStatusDialogMessage(status)
126
+ });
127
+ } catch {
128
+ await context.ui.dialog.alert({
129
+ title: "AFT Status",
130
+ message: "AFT is starting up. Status will refresh automatically."
131
+ });
132
+ }
133
+ }
134
+ export async function setupV2Tui(context) {
135
+ const rpc = context.client.rpc(AftRpc);
136
+ const controller = new AbortController();
137
+ const slotCleanups = [context.ui.slot({
138
+ append: "prompt.footer.status",
139
+ render: input => _$createComponent(FooterStatus, {
140
+ context: context,
141
+ rpc: rpc,
142
+ get sessionID() {
143
+ return input.sessionID;
144
+ }
145
+ })
146
+ }), context.ui.slot({
147
+ append: "sidebar.content",
148
+ render: input => _$createComponent(SidebarStatus, {
149
+ context: context,
150
+ rpc: rpc,
151
+ get sessionID() {
152
+ return input.sessionID;
153
+ }
154
+ })
155
+ })];
156
+ const stopDialogEvents = rpc.events.on("showStatusDialog", event => showStatusDialog(context, rpc, event.data.sessionID ?? activeSessionID(context)), {
157
+ signal: controller.signal
158
+ });
159
+ context.keymap.layer(() => ({
160
+ commands: [{
161
+ id: "aft.status",
162
+ title: "AFT: Status",
163
+ description: "Show AFT status, index health, and cache usage",
164
+ group: "AFT",
165
+ palette: true,
166
+ // V2's KeymapCommand contract (plugin/tui/context.ts:379-385) dispatches
167
+ // slash entries unless `arguments: true`; omitting it prevents this text
168
+ // from remaining in the prompt or being submitted to the model.
169
+ slash: {
170
+ name: "aft-status"
171
+ },
172
+ run: () => showStatusDialog(context, rpc, activeSessionID(context))
173
+ }],
174
+ bindings: []
175
+ }));
176
+ return () => {
177
+ controller.abort();
178
+ stopDialogEvents();
179
+ for (const cleanup of slotCleanups) cleanup();
180
+ };
181
+ }
@@ -1,7 +0,0 @@
1
- import type { ToolDefinition } from "@opencode-ai/plugin";
2
- import type { PluginContext } from "../types.js";
3
- /**
4
- * Tool definitions for refactoring commands: move_symbol, extract_function, inline_symbol.
5
- */
6
- export declare function refactoringTools(ctx: PluginContext): Record<string, ToolDefinition>;
7
- //# sourceMappingURL=refactoring.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"refactoring.d.ts","sourceRoot":"","sources":["../../src/tools/refactoring.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAI1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAmBjD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAuJnF"}