@cortexkit/aft-opencode 0.9.1 → 0.10.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.
Files changed (70) hide show
  1. package/dist/bridge.d.ts.map +1 -1
  2. package/dist/bridge.js +18 -4
  3. package/dist/bridge.js.map +1 -1
  4. package/dist/config.d.ts +1 -0
  5. package/dist/config.d.ts.map +1 -1
  6. package/dist/config.js +2 -0
  7. package/dist/config.js.map +1 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +182 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/notifications.d.ts +48 -0
  12. package/dist/notifications.d.ts.map +1 -0
  13. package/dist/notifications.js +307 -0
  14. package/dist/notifications.js.map +1 -0
  15. package/dist/onnx-runtime.d.ts +35 -0
  16. package/dist/onnx-runtime.d.ts.map +1 -0
  17. package/dist/onnx-runtime.js +203 -0
  18. package/dist/onnx-runtime.js.map +1 -0
  19. package/dist/pool.d.ts +2 -0
  20. package/dist/pool.d.ts.map +1 -1
  21. package/dist/pool.js +25 -6
  22. package/dist/pool.js.map +1 -1
  23. package/dist/resolver.d.ts.map +1 -1
  24. package/dist/resolver.js +15 -4
  25. package/dist/resolver.js.map +1 -1
  26. package/dist/shared/opencode-config-dir.d.ts +16 -0
  27. package/dist/shared/opencode-config-dir.d.ts.map +1 -0
  28. package/dist/shared/opencode-config-dir.js +26 -0
  29. package/dist/shared/opencode-config-dir.js.map +1 -0
  30. package/dist/shared/rpc-client.d.ts +16 -0
  31. package/dist/shared/rpc-client.d.ts.map +1 -0
  32. package/dist/shared/rpc-client.js +108 -0
  33. package/dist/shared/rpc-client.js.map +1 -0
  34. package/dist/shared/rpc-server.d.ts +17 -0
  35. package/dist/shared/rpc-server.d.ts.map +1 -0
  36. package/dist/shared/rpc-server.js +120 -0
  37. package/dist/shared/rpc-server.js.map +1 -0
  38. package/dist/shared/rpc-utils.d.ts +11 -0
  39. package/dist/shared/rpc-utils.d.ts.map +1 -0
  40. package/dist/shared/rpc-utils.js +20 -0
  41. package/dist/shared/rpc-utils.js.map +1 -0
  42. package/dist/shared/runtime.d.ts +10 -0
  43. package/dist/shared/runtime.d.ts.map +1 -0
  44. package/dist/shared/runtime.js +14 -0
  45. package/dist/shared/runtime.js.map +1 -0
  46. package/dist/shared/status.d.ts +37 -0
  47. package/dist/shared/status.d.ts.map +1 -0
  48. package/dist/shared/status.js +135 -0
  49. package/dist/shared/status.js.map +1 -0
  50. package/dist/shared/tui-config.d.ts +2 -0
  51. package/dist/shared/tui-config.d.ts.map +1 -0
  52. package/dist/shared/tui-config.js +134 -0
  53. package/dist/shared/tui-config.js.map +1 -0
  54. package/dist/tools/search.d.ts.map +1 -1
  55. package/dist/tools/search.js +23 -3
  56. package/dist/tools/search.js.map +1 -1
  57. package/dist/tools/semantic.d.ts +4 -0
  58. package/dist/tools/semantic.d.ts.map +1 -0
  59. package/dist/tools/semantic.js +35 -0
  60. package/dist/tools/semantic.js.map +1 -0
  61. package/package.json +26 -6
  62. package/src/shared/opencode-config-dir.ts +46 -0
  63. package/src/shared/rpc-client.ts +123 -0
  64. package/src/shared/rpc-server.ts +135 -0
  65. package/src/shared/rpc-utils.ts +21 -0
  66. package/src/shared/runtime.ts +26 -0
  67. package/src/shared/status.ts +206 -0
  68. package/src/shared/tui-config.ts +155 -0
  69. package/src/tui/index.tsx +209 -0
  70. package/src/tui/types/opencode-plugin-tui.d.ts +232 -0
@@ -0,0 +1,135 @@
1
+ function asRecord(value) {
2
+ return typeof value === "object" && value !== null ? value : {};
3
+ }
4
+ function readString(value, fallback = "") {
5
+ return typeof value === "string" ? value : fallback;
6
+ }
7
+ function readNullableString(value) {
8
+ return typeof value === "string" ? value : null;
9
+ }
10
+ function readBoolean(value, fallback = false) {
11
+ return typeof value === "boolean" ? value : fallback;
12
+ }
13
+ function readNumber(value, fallback = 0) {
14
+ return typeof value === "number" && Number.isFinite(value) ? value : fallback;
15
+ }
16
+ function readOptionalNumber(value) {
17
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
18
+ }
19
+ function formatFlag(enabled) {
20
+ return enabled ? "enabled" : "disabled";
21
+ }
22
+ function formatCount(value) {
23
+ return value == null ? "—" : value.toLocaleString("en-US");
24
+ }
25
+ export function formatBytes(bytes) {
26
+ if (!Number.isFinite(bytes) || bytes <= 0)
27
+ return "0 B";
28
+ const units = ["B", "KB", "MB", "GB", "TB"];
29
+ let value = bytes;
30
+ let unitIndex = 0;
31
+ while (value >= 1024 && unitIndex < units.length - 1) {
32
+ value /= 1024;
33
+ unitIndex++;
34
+ }
35
+ const decimals = value >= 10 || unitIndex === 0 ? 0 : 1;
36
+ return `${value.toFixed(decimals)} ${units[unitIndex]}`;
37
+ }
38
+ export function coerceAftStatus(response) {
39
+ const features = asRecord(response.features);
40
+ const searchIndex = asRecord(response.search_index);
41
+ const semanticIndex = asRecord(response.semantic_index);
42
+ const disk = asRecord(response.disk);
43
+ const symbolCache = asRecord(response.symbol_cache);
44
+ return {
45
+ version: readString(response.version, "unknown"),
46
+ project_root: readNullableString(response.project_root),
47
+ features: {
48
+ format_on_edit: readBoolean(features.format_on_edit),
49
+ validate_on_edit: readString(features.validate_on_edit, "off"),
50
+ restrict_to_project_root: readBoolean(features.restrict_to_project_root),
51
+ experimental_search_index: readBoolean(features.experimental_search_index),
52
+ experimental_semantic_search: readBoolean(features.experimental_semantic_search),
53
+ },
54
+ search_index: {
55
+ status: readString(searchIndex.status, "unknown"),
56
+ files: readOptionalNumber(searchIndex.files),
57
+ trigrams: readOptionalNumber(searchIndex.trigrams),
58
+ },
59
+ semantic_index: {
60
+ status: readString(semanticIndex.status, "unknown"),
61
+ entries: readOptionalNumber(semanticIndex.entries),
62
+ dimension: readOptionalNumber(semanticIndex.dimension),
63
+ },
64
+ disk: {
65
+ storage_dir: readNullableString(disk.storage_dir),
66
+ trigram_disk_bytes: readNumber(disk.trigram_disk_bytes),
67
+ semantic_disk_bytes: readNumber(disk.semantic_disk_bytes),
68
+ },
69
+ lsp_servers: readNumber(response.lsp_servers),
70
+ symbol_cache: {
71
+ local_entries: readNumber(symbolCache.local_entries),
72
+ warm_entries: readNumber(symbolCache.warm_entries),
73
+ },
74
+ storage_dir: readNullableString(response.storage_dir),
75
+ };
76
+ }
77
+ export function formatStatusDialogMessage(status) {
78
+ const lines = [
79
+ `AFT version: ${status.version}`,
80
+ `Project root: ${status.project_root ?? "(not configured)"}`,
81
+ "",
82
+ "Enabled features",
83
+ `- format_on_edit: ${formatFlag(status.features.format_on_edit)}`,
84
+ `- experimental_search_index: ${formatFlag(status.features.experimental_search_index)}`,
85
+ `- experimental_semantic_search: ${formatFlag(status.features.experimental_semantic_search)}`,
86
+ "",
87
+ "Search index",
88
+ `- status: ${status.search_index.status}`,
89
+ `- files: ${formatCount(status.search_index.files)}`,
90
+ `- trigrams: ${formatCount(status.search_index.trigrams)}`,
91
+ "",
92
+ "Semantic index",
93
+ `- status: ${status.semantic_index.status}`,
94
+ `- entries: ${formatCount(status.semantic_index.entries)}`,
95
+ ];
96
+ if (status.semantic_index.dimension != null) {
97
+ lines.push(`- dimension: ${formatCount(status.semantic_index.dimension)}`);
98
+ }
99
+ lines.push("", "Disk usage", `- trigram index: ${formatBytes(status.disk.trigram_disk_bytes)}`, `- semantic index: ${formatBytes(status.disk.semantic_disk_bytes)}`, "", "Runtime", `- LSP servers: ${formatCount(status.lsp_servers)}`, `- symbol cache: ${formatCount(status.symbol_cache.local_entries)} local / ${formatCount(status.symbol_cache.warm_entries)} warm`);
100
+ if (status.storage_dir ?? status.disk.storage_dir) {
101
+ lines.push(`- storage dir: ${status.storage_dir ?? status.disk.storage_dir}`);
102
+ }
103
+ return lines.join("\n");
104
+ }
105
+ export function formatStatusMarkdown(status) {
106
+ const lines = [
107
+ "## AFT Status",
108
+ "",
109
+ `- **Version:** \`${status.version}\``,
110
+ `- **Project root:** \`${status.project_root ?? "(not configured)"}\``,
111
+ "",
112
+ "### Enabled features",
113
+ `- \`format_on_edit\`: ${formatFlag(status.features.format_on_edit)}`,
114
+ `- \`experimental_search_index\`: ${formatFlag(status.features.experimental_search_index)}`,
115
+ `- \`experimental_semantic_search\`: ${formatFlag(status.features.experimental_semantic_search)}`,
116
+ "",
117
+ "### Search index",
118
+ `- **Status:** \`${status.search_index.status}\``,
119
+ `- **Files:** ${formatCount(status.search_index.files)}`,
120
+ `- **Trigrams:** ${formatCount(status.search_index.trigrams)}`,
121
+ "",
122
+ "### Semantic index",
123
+ `- **Status:** \`${status.semantic_index.status}\``,
124
+ `- **Entries:** ${formatCount(status.semantic_index.entries)}`,
125
+ ];
126
+ if (status.semantic_index.dimension != null) {
127
+ lines.push(`- **Dimension:** ${formatCount(status.semantic_index.dimension)}`);
128
+ }
129
+ lines.push("", "### Disk usage", `- **Trigram index:** ${formatBytes(status.disk.trigram_disk_bytes)}`, `- **Semantic index:** ${formatBytes(status.disk.semantic_disk_bytes)}`, "", "### Runtime", `- **LSP servers:** ${formatCount(status.lsp_servers)}`, `- **Symbol cache:** ${formatCount(status.symbol_cache.local_entries)} local / ${formatCount(status.symbol_cache.warm_entries)} warm`);
130
+ if (status.storage_dir ?? status.disk.storage_dir) {
131
+ lines.push(`- **Storage dir:** \`${status.storage_dir ?? status.disk.storage_dir}\``);
132
+ }
133
+ return lines.join("\n");
134
+ }
135
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/shared/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function ensureTuiPluginEntry(): boolean;
2
+ //# sourceMappingURL=tui-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui-config.d.ts","sourceRoot":"","sources":["../../src/shared/tui-config.ts"],"names":[],"mappings":"AAoHA,wBAAgB,oBAAoB,IAAI,OAAO,CAsC9C"}
@@ -0,0 +1,134 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { log } from "../logger.js";
4
+ import { getOpenCodeConfigPaths } from "./opencode-config-dir.js";
5
+ const PLUGIN_NAME = "@cortexkit/aft-opencode";
6
+ const PLUGIN_ENTRY = `${PLUGIN_NAME}@latest`;
7
+ function stripJsoncComments(text) {
8
+ let result = "";
9
+ let i = 0;
10
+ let inString = false;
11
+ let escaped = false;
12
+ while (i < text.length) {
13
+ const ch = text[i];
14
+ if (inString) {
15
+ result += ch;
16
+ if (escaped) {
17
+ escaped = false;
18
+ }
19
+ else if (ch === "\\") {
20
+ escaped = true;
21
+ }
22
+ else if (ch === '"') {
23
+ inString = false;
24
+ }
25
+ i++;
26
+ continue;
27
+ }
28
+ if (ch === '"') {
29
+ inString = true;
30
+ result += ch;
31
+ i++;
32
+ continue;
33
+ }
34
+ if (ch === "/" && text[i + 1] === "/") {
35
+ i += 2;
36
+ while (i < text.length && text[i] !== "\n")
37
+ i++;
38
+ continue;
39
+ }
40
+ if (ch === "/" && text[i + 1] === "*") {
41
+ i += 2;
42
+ while (i < text.length && !(text[i] === "*" && text[i + 1] === "/"))
43
+ i++;
44
+ i += 2;
45
+ continue;
46
+ }
47
+ result += ch;
48
+ i++;
49
+ }
50
+ return result;
51
+ }
52
+ function stripTrailingCommas(text) {
53
+ let result = "";
54
+ let i = 0;
55
+ let inString = false;
56
+ let escaped = false;
57
+ while (i < text.length) {
58
+ const ch = text[i];
59
+ if (inString) {
60
+ result += ch;
61
+ if (escaped) {
62
+ escaped = false;
63
+ }
64
+ else if (ch === "\\") {
65
+ escaped = true;
66
+ }
67
+ else if (ch === '"') {
68
+ inString = false;
69
+ }
70
+ i++;
71
+ continue;
72
+ }
73
+ if (ch === '"') {
74
+ inString = true;
75
+ result += ch;
76
+ i++;
77
+ continue;
78
+ }
79
+ if (ch === ",") {
80
+ let j = i + 1;
81
+ while (j < text.length && /\s/.test(text[j]))
82
+ j++;
83
+ if (text[j] === "}" || text[j] === "]") {
84
+ i++;
85
+ continue;
86
+ }
87
+ }
88
+ result += ch;
89
+ i++;
90
+ }
91
+ return result;
92
+ }
93
+ function parseJsonc(content) {
94
+ return JSON.parse(stripTrailingCommas(stripJsoncComments(content)));
95
+ }
96
+ function resolveTuiConfigPath() {
97
+ const configDir = getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
98
+ const jsoncPath = join(configDir, "tui.jsonc");
99
+ const jsonPath = join(configDir, "tui.json");
100
+ if (existsSync(jsoncPath))
101
+ return jsoncPath;
102
+ if (existsSync(jsonPath))
103
+ return jsonPath;
104
+ return jsonPath;
105
+ }
106
+ export function ensureTuiPluginEntry() {
107
+ try {
108
+ const configPath = resolveTuiConfigPath();
109
+ let config = {};
110
+ if (existsSync(configPath)) {
111
+ config = parseJsonc(readFileSync(configPath, "utf-8")) ?? {};
112
+ }
113
+ const plugins = Array.isArray(config.plugin)
114
+ ? config.plugin.filter((value) => typeof value === "string")
115
+ : [];
116
+ if (plugins.some((plugin) => plugin === PLUGIN_NAME ||
117
+ plugin.startsWith(`${PLUGIN_NAME}@`) ||
118
+ plugin.includes("opencode-plugin") ||
119
+ plugin.includes("aft-opencode"))) {
120
+ return false;
121
+ }
122
+ plugins.push(PLUGIN_ENTRY);
123
+ config.plugin = plugins;
124
+ mkdirSync(dirname(configPath), { recursive: true });
125
+ writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
126
+ log(`[aft-plugin] added TUI plugin entry to ${configPath}`);
127
+ return true;
128
+ }
129
+ catch (error) {
130
+ log(`[aft-plugin] failed to update tui.json: ${error instanceof Error ? error.message : String(error)}`);
131
+ return false;
132
+ }
133
+ }
134
+ //# sourceMappingURL=tui-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui-config.js","sourceRoot":"","sources":["../../src/shared/tui-config.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAuDjD;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAkE9E"}
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAuDjD;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAyF9E"}
@@ -45,7 +45,12 @@ export function searchTools(ctx) {
45
45
  const response = await bridge.send("grep", {
46
46
  pattern: args.pattern,
47
47
  case_sensitive: true,
48
- include: args.include ? [normalizeGlob(String(args.include))] : undefined,
48
+ include: args.include
49
+ ? String(args.include)
50
+ .split(",")
51
+ .map((s) => normalizeGlob(s.trim()))
52
+ .filter(Boolean)
53
+ : undefined,
49
54
  path: args.path,
50
55
  max_results: 100,
51
56
  });
@@ -63,9 +68,24 @@ export function searchTools(ctx) {
63
68
  },
64
69
  execute: async (args, context) => {
65
70
  const bridge = ctx.pool.getBridge(context.directory, context.sessionID);
71
+ // Handle absolute paths embedded in the pattern (e.g. "/abs/path/src/**/*.ts")
72
+ // Split into path (directory prefix) and pattern (glob suffix)
73
+ let globPattern = String(args.pattern);
74
+ let globPath = args.path ? String(args.path) : undefined;
75
+ if (!globPath && globPattern.startsWith("/")) {
76
+ // Find the last directory component before any glob metacharacters
77
+ const metaIdx = globPattern.search(/[*?{}[\]]/);
78
+ if (metaIdx > 0) {
79
+ const lastSlash = globPattern.lastIndexOf("/", metaIdx);
80
+ if (lastSlash > 0) {
81
+ globPath = globPattern.slice(0, lastSlash);
82
+ globPattern = `**/${globPattern.slice(lastSlash + 1)}`;
83
+ }
84
+ }
85
+ }
66
86
  const response = await bridge.send("glob", {
67
- pattern: args.pattern,
68
- path: args.path,
87
+ pattern: globPattern,
88
+ path: globPath,
69
89
  });
70
90
  if (response.success === false) {
71
91
  throw new Error(response.message || "glob failed");
@@ -1 +1 @@
1
- {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ToolDefinition } from "@opencode-ai/plugin";
2
+ import type { PluginContext } from "../types.js";
3
+ export declare function semanticTools(ctx: PluginContext): Record<string, ToolDefinition>;
4
+ //# sourceMappingURL=semantic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic.d.ts","sourceRoot":"","sources":["../../src/tools/semantic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAQjD,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAqChF"}
@@ -0,0 +1,35 @@
1
+ import { z } from "zod";
2
+ function arg(schema) {
3
+ return schema;
4
+ }
5
+ export function semanticTools(ctx) {
6
+ const searchTool = {
7
+ description: "Search code by meaning using semantic similarity. Use when you don't know the exact name or text — describe what you're looking for in natural language and get the most relevant symbols, functions, and types.",
8
+ args: {
9
+ query: arg(z.string().describe("Natural language search query")),
10
+ topK: arg(z.number().optional().describe("Number of results (default: 10)")),
11
+ },
12
+ execute: async (args, context) => {
13
+ const bridge = ctx.pool.getBridge(context.directory, context.sessionID);
14
+ const response = await bridge.send("semantic_search", {
15
+ query: args.query,
16
+ top_k: args.topK ?? 10,
17
+ });
18
+ if (response.success === false) {
19
+ if (response.code === "semantic_search_unavailable" &&
20
+ typeof response.message === "string") {
21
+ return response.message;
22
+ }
23
+ throw new Error(response.message || "semantic_search failed");
24
+ }
25
+ if (typeof response.text === "string") {
26
+ return response.text;
27
+ }
28
+ return JSON.stringify(response);
29
+ },
30
+ };
31
+ return {
32
+ aft_search: searchTool,
33
+ };
34
+ }
35
+ //# sourceMappingURL=semantic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic.js","sourceRoot":"","sources":["../../src/tools/semantic.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,SAAS,GAAG,CAAC,MAAe;IAC1B,OAAO,MAAiB,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAkB;IAC9C,MAAM,UAAU,GAAmB;QACjC,WAAW,EACT,kNAAkN;QACpN,IAAI,EAAE;YACJ,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC,CAAC;YAChE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC,CAAC;SAC7E;QACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAmB,EAAE;YAChD,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;YACxE,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE;gBACpD,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE;aACvB,CAAC,CAAC;YAEH,IAAI,QAAQ,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;gBAC/B,IACE,QAAQ,CAAC,IAAI,KAAK,6BAA6B;oBAC/C,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ,EACpC,CAAC;oBACD,OAAO,QAAQ,CAAC,OAAO,CAAC;gBAC1B,CAAC;gBAED,MAAM,IAAI,KAAK,CAAE,QAAQ,CAAC,OAAkB,IAAI,wBAAwB,CAAC,CAAC;YAC5E,CAAC;YAED,IAAI,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACtC,OAAO,QAAQ,CAAC,IAAI,CAAC;YACvB,CAAC;YAED,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAClC,CAAC;KACF,CAAC;IAEF,OAAO;QACL,UAAU,EAAE,UAAU;KACvB,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/aft-opencode",
3
- "version": "0.9.1",
3
+ "version": "0.10.1",
4
4
  "type": "module",
5
5
  "description": "OpenCode plugin for Agent File Tools (AFT) — tree-sitter and lsp powered code analysis",
6
6
  "main": "dist/index.js",
@@ -12,6 +12,8 @@
12
12
  },
13
13
  "files": [
14
14
  "dist",
15
+ "src/tui",
16
+ "src/shared",
15
17
  "README.md"
16
18
  ],
17
19
  "scripts": {
@@ -24,18 +26,36 @@
24
26
  },
25
27
  "dependencies": {
26
28
  "@opencode-ai/plugin": "^1.2.26",
29
+ "@opencode-ai/sdk": "^1.2.26",
27
30
  "jsonc-parser": "^3.3.1",
28
31
  "zod": "^4.1.8"
29
32
  },
30
33
  "optionalDependencies": {
31
- "@cortexkit/aft-darwin-arm64": "0.9.1",
32
- "@cortexkit/aft-darwin-x64": "0.9.1",
33
- "@cortexkit/aft-linux-arm64": "0.9.1",
34
- "@cortexkit/aft-linux-x64": "0.9.1",
35
- "@cortexkit/aft-win32-x64": "0.9.1"
34
+ "@cortexkit/aft-darwin-arm64": "0.10.1",
35
+ "@cortexkit/aft-darwin-x64": "0.10.1",
36
+ "@cortexkit/aft-linux-arm64": "0.10.1",
37
+ "@cortexkit/aft-linux-x64": "0.10.1",
38
+ "@cortexkit/aft-win32-x64": "0.10.1"
36
39
  },
37
40
  "devDependencies": {
38
41
  "@types/node": "^22.0.0",
39
42
  "typescript": "^5.8.0"
43
+ },
44
+ "exports": {
45
+ ".": {
46
+ "types": "./dist/index.d.ts",
47
+ "import": "./dist/index.js"
48
+ },
49
+ "./tui": {
50
+ "types": "./src/tui/index.tsx",
51
+ "import": "./src/tui/index.tsx"
52
+ }
53
+ },
54
+ "oc-plugin": [
55
+ "server",
56
+ "tui"
57
+ ],
58
+ "peerDependencies": {
59
+ "@opencode-ai/plugin": ">=1.2.0"
40
60
  }
41
61
  }
@@ -0,0 +1,46 @@
1
+ import { homedir } from "node:os";
2
+ import { join, resolve } from "node:path";
3
+
4
+ export type OpenCodeBinaryType = "opencode" | "opencode-desktop";
5
+
6
+ export interface OpenCodeConfigDirOptions {
7
+ binary: OpenCodeBinaryType;
8
+ version?: string | null;
9
+ checkExisting?: boolean;
10
+ }
11
+
12
+ export interface OpenCodeConfigPaths {
13
+ configDir: string;
14
+ configJson: string;
15
+ configJsonc: string;
16
+ packageJson: string;
17
+ omoConfig: string;
18
+ }
19
+
20
+ function getCliConfigDir(): string {
21
+ const envConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim();
22
+ if (envConfigDir) {
23
+ return resolve(envConfigDir);
24
+ }
25
+
26
+ if (process.platform === "win32") {
27
+ return join(homedir(), ".config", "opencode");
28
+ }
29
+
30
+ return join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), "opencode");
31
+ }
32
+
33
+ export function getOpenCodeConfigDir(_options: OpenCodeConfigDirOptions): string {
34
+ return getCliConfigDir();
35
+ }
36
+
37
+ export function getOpenCodeConfigPaths(options: OpenCodeConfigDirOptions): OpenCodeConfigPaths {
38
+ const configDir = getOpenCodeConfigDir(options);
39
+ return {
40
+ configDir,
41
+ configJson: join(configDir, "opencode.json"),
42
+ configJsonc: join(configDir, "opencode.jsonc"),
43
+ packageJson: join(configDir, "package.json"),
44
+ omoConfig: join(configDir, "magic-context.jsonc"),
45
+ };
46
+ }
@@ -0,0 +1,123 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { rpcPortFilePath } from "./rpc-utils.js";
3
+
4
+ const MAX_RETRIES = 10;
5
+ const RETRY_DELAY_MS = 500;
6
+ const REQUEST_TIMEOUT_MS = 5000;
7
+
8
+ export class AftRpcClient {
9
+ private port: number | null = null;
10
+ private portFilePath: string;
11
+ private healthChecked = false;
12
+
13
+ constructor(storageDir: string, directory: string) {
14
+ this.portFilePath = rpcPortFilePath(storageDir, directory);
15
+ }
16
+
17
+ /** Call an RPC method. Retries port resolution if the server isn't ready yet. */
18
+ async call<T = Record<string, unknown>>(
19
+ method: string,
20
+ params: Record<string, unknown> = {},
21
+ ): Promise<T> {
22
+ const port = await this.resolvePort();
23
+ if (!port) {
24
+ throw new Error("AFT RPC server not available");
25
+ }
26
+
27
+ const response = await this.fetchWithTimeout(`http://127.0.0.1:${port}/rpc/${method}`, {
28
+ method: "POST",
29
+ headers: { "Content-Type": "application/json" },
30
+ body: JSON.stringify(params),
31
+ });
32
+
33
+ if (!response.ok) {
34
+ const text = await response.text();
35
+ throw new Error(`RPC ${method} failed (${response.status}): ${text}`);
36
+ }
37
+
38
+ return (await response.json()) as T;
39
+ }
40
+
41
+ /** Check if the RPC server is reachable. */
42
+ async isAvailable(): Promise<boolean> {
43
+ try {
44
+ const port = await this.resolvePort();
45
+ return port !== null;
46
+ } catch {
47
+ return false;
48
+ }
49
+ }
50
+
51
+ private async resolvePort(): Promise<number | null> {
52
+ if (this.port && this.healthChecked) {
53
+ return this.port;
54
+ }
55
+
56
+ if (this.port) {
57
+ const alive = await this.healthCheck(this.port);
58
+ if (alive) {
59
+ this.healthChecked = true;
60
+ return this.port;
61
+ }
62
+ this.port = null;
63
+ this.healthChecked = false;
64
+ }
65
+
66
+ for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
67
+ const port = this.readPortFile();
68
+ if (port) {
69
+ const alive = await this.healthCheck(port);
70
+ if (alive) {
71
+ this.port = port;
72
+ this.healthChecked = true;
73
+ return port;
74
+ }
75
+ }
76
+
77
+ if (attempt < MAX_RETRIES - 1) {
78
+ await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
79
+ }
80
+ }
81
+
82
+ return null;
83
+ }
84
+
85
+ private readPortFile(): number | null {
86
+ try {
87
+ const content = readFileSync(this.portFilePath, "utf-8").trim();
88
+ const port = Number.parseInt(content, 10);
89
+ if (Number.isNaN(port) || port <= 0 || port > 65535) {
90
+ return null;
91
+ }
92
+ return port;
93
+ } catch {
94
+ return null;
95
+ }
96
+ }
97
+
98
+ private async healthCheck(port: number): Promise<boolean> {
99
+ try {
100
+ const response = await this.fetchWithTimeout(`http://127.0.0.1:${port}/health`, {
101
+ method: "GET",
102
+ });
103
+ return response.ok;
104
+ } catch {
105
+ return false;
106
+ }
107
+ }
108
+
109
+ private async fetchWithTimeout(url: string, options: RequestInit): Promise<Response> {
110
+ const controller = new AbortController();
111
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
112
+ try {
113
+ return await fetch(url, { ...options, signal: controller.signal });
114
+ } finally {
115
+ clearTimeout(timeout);
116
+ }
117
+ }
118
+
119
+ reset(): void {
120
+ this.port = null;
121
+ this.healthChecked = false;
122
+ }
123
+ }