@cortexkit/aft-opencode 0.12.0 → 0.12.2
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/config.d.ts.map +1 -1
- package/dist/index.js +53 -17
- package/dist/onnx-runtime.d.ts.map +1 -1
- package/dist/tui.js +386 -0
- package/package.json +7 -7
- package/src/shared/rpc-client.ts +1 -1
- package/src/shared/rpc-server.ts +2 -2
- package/src/shared/tui-config.ts +2 -2
- package/src/shared/url-fetch.ts +1 -1
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA8BxB,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwC1B,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAmIxD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAwBjE"}
|
package/dist/index.js
CHANGED
|
@@ -7805,12 +7805,13 @@ var require_src2 = __commonJS((exports, module) => {
|
|
|
7805
7805
|
// src/index.ts
|
|
7806
7806
|
import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
7807
7807
|
import { createRequire as createRequire2 } from "module";
|
|
7808
|
-
import { homedir as
|
|
7808
|
+
import { homedir as homedir7 } from "os";
|
|
7809
7809
|
import { join as join13 } from "path";
|
|
7810
7810
|
|
|
7811
7811
|
// src/config.ts
|
|
7812
7812
|
var import_comment_json = __toESM(require_src2(), 1);
|
|
7813
7813
|
import { existsSync, readFileSync } from "fs";
|
|
7814
|
+
import { homedir } from "os";
|
|
7814
7815
|
import { join as join2 } from "path";
|
|
7815
7816
|
|
|
7816
7817
|
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
|
|
@@ -21514,7 +21515,11 @@ function mergeConfigs(base, override) {
|
|
|
21514
21515
|
};
|
|
21515
21516
|
}
|
|
21516
21517
|
function getOpenCodeConfigDir() {
|
|
21517
|
-
const
|
|
21518
|
+
const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
21519
|
+
if (envDir) {
|
|
21520
|
+
return envDir;
|
|
21521
|
+
}
|
|
21522
|
+
const xdgConfig = process.env.XDG_CONFIG_HOME || join2(homedir(), ".config");
|
|
21518
21523
|
return join2(xdgConfig, "opencode");
|
|
21519
21524
|
}
|
|
21520
21525
|
function loadAftConfig(projectDirectory) {
|
|
@@ -21535,7 +21540,7 @@ function loadAftConfig(projectDirectory) {
|
|
|
21535
21540
|
|
|
21536
21541
|
// src/downloader.ts
|
|
21537
21542
|
import { chmodSync, existsSync as existsSync2, mkdirSync, unlinkSync } from "fs";
|
|
21538
|
-
import { homedir } from "os";
|
|
21543
|
+
import { homedir as homedir2 } from "os";
|
|
21539
21544
|
import { join as join3 } from "path";
|
|
21540
21545
|
|
|
21541
21546
|
// src/platform.ts
|
|
@@ -21557,10 +21562,10 @@ var REPO = "cortexkit/aft";
|
|
|
21557
21562
|
function getCacheDir() {
|
|
21558
21563
|
if (process.platform === "win32") {
|
|
21559
21564
|
const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
|
|
21560
|
-
const base2 = localAppData || join3(
|
|
21565
|
+
const base2 = localAppData || join3(homedir2(), "AppData", "Local");
|
|
21561
21566
|
return join3(base2, "aft", "bin");
|
|
21562
21567
|
}
|
|
21563
|
-
const base = process.env.XDG_CACHE_HOME || join3(
|
|
21568
|
+
const base = process.env.XDG_CACHE_HOME || join3(homedir2(), ".cache");
|
|
21564
21569
|
return join3(base, "aft", "bin");
|
|
21565
21570
|
}
|
|
21566
21571
|
function getBinaryName() {
|
|
@@ -21755,7 +21760,7 @@ function normalizeToolMap(tools) {
|
|
|
21755
21760
|
|
|
21756
21761
|
// src/notifications.ts
|
|
21757
21762
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
21758
|
-
import { homedir as
|
|
21763
|
+
import { homedir as homedir3, platform } from "os";
|
|
21759
21764
|
import { join as join4 } from "path";
|
|
21760
21765
|
function isTuiMode() {
|
|
21761
21766
|
return process.env.OPENCODE_CLIENT === "cli";
|
|
@@ -21777,7 +21782,7 @@ var WARNING_MARKER = `${AFT_MARKER} \u26A0\uFE0F`;
|
|
|
21777
21782
|
var STATUS_MARKER = `${AFT_MARKER} \u2705`;
|
|
21778
21783
|
function getDesktopStatePath() {
|
|
21779
21784
|
const os2 = platform();
|
|
21780
|
-
const home =
|
|
21785
|
+
const home = homedir3();
|
|
21781
21786
|
if (os2 === "darwin") {
|
|
21782
21787
|
return join4(home, "Library", "Application Support", "ai.opencode.desktop", "opencode.global.dat");
|
|
21783
21788
|
}
|
|
@@ -22059,8 +22064,7 @@ async function downloadOnnxRuntime(info, targetDir) {
|
|
|
22059
22064
|
const { execSync } = await import("child_process");
|
|
22060
22065
|
execSync(`tar xzf "${archivePath}" -C "${tmpDir}"`, { stdio: "pipe" });
|
|
22061
22066
|
} else {
|
|
22062
|
-
|
|
22063
|
-
execSync(`unzip -q "${archivePath}" -d "${tmpDir}"`, { stdio: "pipe" });
|
|
22067
|
+
await extractZipArchive(archivePath, tmpDir);
|
|
22064
22068
|
}
|
|
22065
22069
|
const extractedDir = join5(tmpDir, info.assetName, "lib");
|
|
22066
22070
|
if (!existsSync4(extractedDir)) {
|
|
@@ -22118,10 +22122,42 @@ async function downloadOnnxRuntime(info, targetDir) {
|
|
|
22118
22122
|
return null;
|
|
22119
22123
|
}
|
|
22120
22124
|
}
|
|
22125
|
+
async function extractZipArchive(archivePath, destinationDir) {
|
|
22126
|
+
const { execFileSync } = await import("child_process");
|
|
22127
|
+
if (process.platform === "win32") {
|
|
22128
|
+
let powershellError;
|
|
22129
|
+
try {
|
|
22130
|
+
execFileSync("powershell.exe", [
|
|
22131
|
+
"-NoProfile",
|
|
22132
|
+
"-NonInteractive",
|
|
22133
|
+
"-ExecutionPolicy",
|
|
22134
|
+
"Bypass",
|
|
22135
|
+
"-Command",
|
|
22136
|
+
"& { Expand-Archive -LiteralPath $args[0] -DestinationPath $args[1] -Force }",
|
|
22137
|
+
archivePath,
|
|
22138
|
+
destinationDir
|
|
22139
|
+
], { stdio: "pipe", timeout: 120000 });
|
|
22140
|
+
return;
|
|
22141
|
+
} catch (err) {
|
|
22142
|
+
powershellError = err;
|
|
22143
|
+
warn(`PowerShell Expand-Archive failed, falling back to cmd/tar: ${String(err)}`);
|
|
22144
|
+
}
|
|
22145
|
+
try {
|
|
22146
|
+
execFileSync("cmd.exe", ["/d", "/s", "/c", `tar -xf "${archivePath}" -C "${destinationDir}"`], { stdio: "pipe", timeout: 120000 });
|
|
22147
|
+
return;
|
|
22148
|
+
} catch (cmdError) {
|
|
22149
|
+
throw new Error(`ZIP extraction failed via PowerShell and cmd/tar. PowerShell: ${String(powershellError)} | cmd/tar: ${String(cmdError)}`);
|
|
22150
|
+
}
|
|
22151
|
+
}
|
|
22152
|
+
execFileSync("unzip", ["-q", archivePath, "-d", destinationDir], {
|
|
22153
|
+
stdio: "pipe",
|
|
22154
|
+
timeout: 120000
|
|
22155
|
+
});
|
|
22156
|
+
}
|
|
22121
22157
|
|
|
22122
22158
|
// src/bridge.ts
|
|
22123
22159
|
import { spawn } from "child_process";
|
|
22124
|
-
import { homedir as
|
|
22160
|
+
import { homedir as homedir4 } from "os";
|
|
22125
22161
|
import { join as join6 } from "path";
|
|
22126
22162
|
function compareSemver(a, b) {
|
|
22127
22163
|
const pa = a.split(".").map(Number);
|
|
@@ -22279,7 +22315,7 @@ class BinaryBridge {
|
|
|
22279
22315
|
stdio: ["pipe", "pipe", "pipe"],
|
|
22280
22316
|
env: {
|
|
22281
22317
|
...process.env,
|
|
22282
|
-
FASTEMBED_CACHE_DIR: process.env.FASTEMBED_CACHE_DIR || (typeof this.configOverrides.storage_dir === "string" ? join6(this.configOverrides.storage_dir, "semantic", "models") : join6(
|
|
22318
|
+
FASTEMBED_CACHE_DIR: process.env.FASTEMBED_CACHE_DIR || (typeof this.configOverrides.storage_dir === "string" ? join6(this.configOverrides.storage_dir, "semantic", "models") : join6(homedir4() || "", ".cache", "fastembed")),
|
|
22283
22319
|
...typeof this.configOverrides._ort_dylib_dir === "string" && {
|
|
22284
22320
|
ORT_DYLIB_PATH: join6(this.configOverrides._ort_dylib_dir, process.platform === "win32" ? "onnxruntime.dll" : process.platform === "darwin" ? "libonnxruntime.dylib" : "libonnxruntime.so")
|
|
22285
22321
|
}
|
|
@@ -22493,7 +22529,7 @@ class BridgePool {
|
|
|
22493
22529
|
import { execSync, spawnSync } from "child_process";
|
|
22494
22530
|
import { chmodSync as chmodSync3, copyFileSync, existsSync as existsSync5, mkdirSync as mkdirSync4 } from "fs";
|
|
22495
22531
|
import { createRequire } from "module";
|
|
22496
|
-
import { homedir as
|
|
22532
|
+
import { homedir as homedir5 } from "os";
|
|
22497
22533
|
import { join as join7 } from "path";
|
|
22498
22534
|
function copyToVersionedCache(npmBinaryPath) {
|
|
22499
22535
|
try {
|
|
@@ -22573,7 +22609,7 @@ function findBinarySync() {
|
|
|
22573
22609
|
if (result)
|
|
22574
22610
|
return result;
|
|
22575
22611
|
} catch {}
|
|
22576
|
-
const cargoPath = join7(
|
|
22612
|
+
const cargoPath = join7(homedir5(), ".cargo", "bin", `aft${ext}`);
|
|
22577
22613
|
if (existsSync5(cargoPath))
|
|
22578
22614
|
return cargoPath;
|
|
22579
22615
|
return null;
|
|
@@ -22856,7 +22892,7 @@ import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as rea
|
|
|
22856
22892
|
import { dirname as dirname2, join as join10 } from "path";
|
|
22857
22893
|
|
|
22858
22894
|
// src/shared/opencode-config-dir.ts
|
|
22859
|
-
import { homedir as
|
|
22895
|
+
import { homedir as homedir6 } from "os";
|
|
22860
22896
|
import { join as join9, resolve } from "path";
|
|
22861
22897
|
function getCliConfigDir() {
|
|
22862
22898
|
const envConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
@@ -22864,9 +22900,9 @@ function getCliConfigDir() {
|
|
|
22864
22900
|
return resolve(envConfigDir);
|
|
22865
22901
|
}
|
|
22866
22902
|
if (process.platform === "win32") {
|
|
22867
|
-
return join9(
|
|
22903
|
+
return join9(homedir6(), ".config", "opencode");
|
|
22868
22904
|
}
|
|
22869
|
-
return join9(process.env.XDG_CONFIG_HOME || join9(
|
|
22905
|
+
return join9(process.env.XDG_CONFIG_HOME || join9(homedir6(), ".config"), "opencode");
|
|
22870
22906
|
}
|
|
22871
22907
|
function getOpenCodeConfigDir2(_options) {
|
|
22872
22908
|
return getCliConfigDir();
|
|
@@ -25234,7 +25270,7 @@ var plugin = async (input) => {
|
|
|
25234
25270
|
configOverrides.experimental_search_index = aftConfig.experimental_search_index;
|
|
25235
25271
|
if (aftConfig.experimental_semantic_search !== undefined)
|
|
25236
25272
|
configOverrides.experimental_semantic_search = aftConfig.experimental_semantic_search;
|
|
25237
|
-
const dataHome = process.env.XDG_DATA_HOME || join13(
|
|
25273
|
+
const dataHome = process.env.XDG_DATA_HOME || join13(homedir7(), ".local", "share");
|
|
25238
25274
|
configOverrides.storage_dir = join13(dataHome, "opencode", "storage", "plugin", "aft");
|
|
25239
25275
|
if (aftConfig.experimental_semantic_search) {
|
|
25240
25276
|
const storageDir2 = configOverrides.storage_dir;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"onnx-runtime.d.ts","sourceRoot":"","sources":["../src/onnx-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AA0DH,4DAA4D;AAC5D,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,IAAI,MAAM,CAQ7C;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA4BlF;
|
|
1
|
+
{"version":3,"file":"onnx-runtime.d.ts","sourceRoot":"","sources":["../src/onnx-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AA0DH,4DAA4D;AAC5D,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,IAAI,MAAM,CAQ7C;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA4BlF;AA8LD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAU3D"}
|
package/dist/tui.js
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/shared/rpc-client.ts
|
|
3
|
+
import { readFileSync } from "fs";
|
|
4
|
+
|
|
5
|
+
// src/shared/rpc-utils.ts
|
|
6
|
+
import { createHash } from "crypto";
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
function projectHash(directory) {
|
|
9
|
+
const normalized = directory.replace(/\/+$/, "");
|
|
10
|
+
return createHash("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
11
|
+
}
|
|
12
|
+
function rpcPortFilePath(storageDir, directory) {
|
|
13
|
+
const hash = projectHash(directory);
|
|
14
|
+
return join(storageDir, "rpc", hash, "port");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/shared/rpc-client.ts
|
|
18
|
+
var MAX_RETRIES = 10;
|
|
19
|
+
var RETRY_DELAY_MS = 500;
|
|
20
|
+
var REQUEST_TIMEOUT_MS = 5000;
|
|
21
|
+
|
|
22
|
+
class AftRpcClient {
|
|
23
|
+
port = null;
|
|
24
|
+
portFilePath;
|
|
25
|
+
healthChecked = false;
|
|
26
|
+
constructor(storageDir, directory) {
|
|
27
|
+
this.portFilePath = rpcPortFilePath(storageDir, directory);
|
|
28
|
+
}
|
|
29
|
+
async call(method, params = {}) {
|
|
30
|
+
const port = await this.resolvePort();
|
|
31
|
+
if (!port) {
|
|
32
|
+
throw new Error("AFT RPC server not available");
|
|
33
|
+
}
|
|
34
|
+
const response = await this.fetchWithTimeout(`http://127.0.0.1:${port}/rpc/${method}`, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: { "Content-Type": "application/json" },
|
|
37
|
+
body: JSON.stringify(params)
|
|
38
|
+
});
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
const text = await response.text();
|
|
41
|
+
throw new Error(`RPC ${method} failed (${response.status}): ${text}`);
|
|
42
|
+
}
|
|
43
|
+
return await response.json();
|
|
44
|
+
}
|
|
45
|
+
async isAvailable() {
|
|
46
|
+
try {
|
|
47
|
+
const port = await this.resolvePort();
|
|
48
|
+
return port !== null;
|
|
49
|
+
} catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async resolvePort() {
|
|
54
|
+
if (this.port && this.healthChecked) {
|
|
55
|
+
return this.port;
|
|
56
|
+
}
|
|
57
|
+
if (this.port) {
|
|
58
|
+
const alive = await this.healthCheck(this.port);
|
|
59
|
+
if (alive) {
|
|
60
|
+
this.healthChecked = true;
|
|
61
|
+
return this.port;
|
|
62
|
+
}
|
|
63
|
+
this.port = null;
|
|
64
|
+
this.healthChecked = false;
|
|
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
|
+
if (attempt < MAX_RETRIES - 1) {
|
|
77
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
readPortFile() {
|
|
83
|
+
try {
|
|
84
|
+
const content = readFileSync(this.portFilePath, "utf-8").trim();
|
|
85
|
+
const port = Number.parseInt(content, 10);
|
|
86
|
+
if (Number.isNaN(port) || port <= 0 || port > 65535) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
return port;
|
|
90
|
+
} catch {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async healthCheck(port) {
|
|
95
|
+
try {
|
|
96
|
+
const response = await this.fetchWithTimeout(`http://127.0.0.1:${port}/health`, {
|
|
97
|
+
method: "GET"
|
|
98
|
+
});
|
|
99
|
+
return response.ok;
|
|
100
|
+
} catch {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async fetchWithTimeout(url, options) {
|
|
105
|
+
const controller = new AbortController;
|
|
106
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
107
|
+
try {
|
|
108
|
+
return await fetch(url, { ...options, signal: controller.signal });
|
|
109
|
+
} finally {
|
|
110
|
+
clearTimeout(timeout);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
reset() {
|
|
114
|
+
this.port = null;
|
|
115
|
+
this.healthChecked = false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/shared/status.ts
|
|
120
|
+
function asRecord(value) {
|
|
121
|
+
return typeof value === "object" && value !== null ? value : {};
|
|
122
|
+
}
|
|
123
|
+
function readString(value, fallback = "") {
|
|
124
|
+
return typeof value === "string" ? value : fallback;
|
|
125
|
+
}
|
|
126
|
+
function readNullableString(value) {
|
|
127
|
+
return typeof value === "string" ? value : null;
|
|
128
|
+
}
|
|
129
|
+
function readBoolean(value, fallback = false) {
|
|
130
|
+
return typeof value === "boolean" ? value : fallback;
|
|
131
|
+
}
|
|
132
|
+
function readNumber(value, fallback = 0) {
|
|
133
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
134
|
+
}
|
|
135
|
+
function readOptionalNumber(value) {
|
|
136
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
137
|
+
}
|
|
138
|
+
function formatFlag(enabled) {
|
|
139
|
+
return enabled ? "enabled" : "disabled";
|
|
140
|
+
}
|
|
141
|
+
function formatCount(value) {
|
|
142
|
+
return value == null ? "\u2014" : value.toLocaleString("en-US");
|
|
143
|
+
}
|
|
144
|
+
function formatBytes(bytes) {
|
|
145
|
+
if (!Number.isFinite(bytes) || bytes <= 0)
|
|
146
|
+
return "0 B";
|
|
147
|
+
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
148
|
+
let value = bytes;
|
|
149
|
+
let unitIndex = 0;
|
|
150
|
+
while (value >= 1024 && unitIndex < units.length - 1) {
|
|
151
|
+
value /= 1024;
|
|
152
|
+
unitIndex++;
|
|
153
|
+
}
|
|
154
|
+
const decimals = value >= 10 || unitIndex === 0 ? 0 : 1;
|
|
155
|
+
return `${value.toFixed(decimals)} ${units[unitIndex]}`;
|
|
156
|
+
}
|
|
157
|
+
function coerceAftStatus(response) {
|
|
158
|
+
const features = asRecord(response.features);
|
|
159
|
+
const searchIndex = asRecord(response.search_index);
|
|
160
|
+
const semanticIndex = asRecord(response.semantic_index);
|
|
161
|
+
const disk = asRecord(response.disk);
|
|
162
|
+
const symbolCache = asRecord(response.symbol_cache);
|
|
163
|
+
return {
|
|
164
|
+
version: readString(response.version, "unknown"),
|
|
165
|
+
project_root: readNullableString(response.project_root),
|
|
166
|
+
features: {
|
|
167
|
+
format_on_edit: readBoolean(features.format_on_edit),
|
|
168
|
+
validate_on_edit: readString(features.validate_on_edit, "off"),
|
|
169
|
+
restrict_to_project_root: readBoolean(features.restrict_to_project_root),
|
|
170
|
+
experimental_search_index: readBoolean(features.experimental_search_index),
|
|
171
|
+
experimental_semantic_search: readBoolean(features.experimental_semantic_search)
|
|
172
|
+
},
|
|
173
|
+
search_index: {
|
|
174
|
+
status: readString(searchIndex.status, "unknown"),
|
|
175
|
+
files: readOptionalNumber(searchIndex.files),
|
|
176
|
+
trigrams: readOptionalNumber(searchIndex.trigrams)
|
|
177
|
+
},
|
|
178
|
+
semantic_index: {
|
|
179
|
+
status: readString(semanticIndex.status, "unknown"),
|
|
180
|
+
entries: readOptionalNumber(semanticIndex.entries),
|
|
181
|
+
dimension: readOptionalNumber(semanticIndex.dimension)
|
|
182
|
+
},
|
|
183
|
+
disk: {
|
|
184
|
+
storage_dir: readNullableString(disk.storage_dir),
|
|
185
|
+
trigram_disk_bytes: readNumber(disk.trigram_disk_bytes),
|
|
186
|
+
semantic_disk_bytes: readNumber(disk.semantic_disk_bytes)
|
|
187
|
+
},
|
|
188
|
+
lsp_servers: readNumber(response.lsp_servers),
|
|
189
|
+
symbol_cache: {
|
|
190
|
+
local_entries: readNumber(symbolCache.local_entries),
|
|
191
|
+
warm_entries: readNumber(symbolCache.warm_entries)
|
|
192
|
+
},
|
|
193
|
+
storage_dir: readNullableString(response.storage_dir)
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function formatStatusDialogMessage(status) {
|
|
197
|
+
const lines = [
|
|
198
|
+
`AFT version: ${status.version}`,
|
|
199
|
+
`Project root: ${status.project_root ?? "(not configured)"}`,
|
|
200
|
+
"",
|
|
201
|
+
"Enabled features",
|
|
202
|
+
`- format_on_edit: ${formatFlag(status.features.format_on_edit)}`,
|
|
203
|
+
`- experimental_search_index: ${formatFlag(status.features.experimental_search_index)}`,
|
|
204
|
+
`- experimental_semantic_search: ${formatFlag(status.features.experimental_semantic_search)}`,
|
|
205
|
+
"",
|
|
206
|
+
"Search index",
|
|
207
|
+
`- status: ${status.search_index.status}`,
|
|
208
|
+
`- files: ${formatCount(status.search_index.files)}`,
|
|
209
|
+
`- trigrams: ${formatCount(status.search_index.trigrams)}`,
|
|
210
|
+
"",
|
|
211
|
+
"Semantic index",
|
|
212
|
+
`- status: ${status.semantic_index.status}`,
|
|
213
|
+
`- entries: ${formatCount(status.semantic_index.entries)}`
|
|
214
|
+
];
|
|
215
|
+
if (status.semantic_index.dimension != null) {
|
|
216
|
+
lines.push(`- dimension: ${formatCount(status.semantic_index.dimension)}`);
|
|
217
|
+
}
|
|
218
|
+
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`);
|
|
219
|
+
if (status.storage_dir ?? status.disk.storage_dir) {
|
|
220
|
+
lines.push(`- storage dir: ${status.storage_dir ?? status.disk.storage_dir}`);
|
|
221
|
+
}
|
|
222
|
+
return lines.join(`
|
|
223
|
+
`);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// src/tui/index.tsx
|
|
227
|
+
import { jsxDEV } from "@opentui/solid/jsx-dev-runtime";
|
|
228
|
+
var STATUS_COMMAND = "aft-status";
|
|
229
|
+
var rpcClients = new Map;
|
|
230
|
+
function getRpcClient(directory) {
|
|
231
|
+
let client = rpcClients.get(directory);
|
|
232
|
+
if (client)
|
|
233
|
+
return client;
|
|
234
|
+
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
235
|
+
const dataHome = process.env.XDG_DATA_HOME || `${home}/.local/share`;
|
|
236
|
+
const storageDir = `${dataHome}/opencode/storage/plugin/aft`;
|
|
237
|
+
client = new AftRpcClient(storageDir, directory);
|
|
238
|
+
rpcClients.set(directory, client);
|
|
239
|
+
return client;
|
|
240
|
+
}
|
|
241
|
+
function getSessionId(api) {
|
|
242
|
+
try {
|
|
243
|
+
const route = api.route.current;
|
|
244
|
+
if (route?.name === "session" && route.params?.sessionID) {
|
|
245
|
+
return route.params.sessionID;
|
|
246
|
+
}
|
|
247
|
+
} catch {}
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
async function showStatusDialog(api) {
|
|
251
|
+
const sessionID = getSessionId(api);
|
|
252
|
+
if (!sessionID) {
|
|
253
|
+
api.ui.toast({ message: "No active session", variant: "warning", duration: 5000 });
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const directory = api.state.path.directory ?? "";
|
|
257
|
+
if (!directory) {
|
|
258
|
+
api.ui.toast({ message: "No project directory", variant: "warning", duration: 5000 });
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
const client = getRpcClient(directory);
|
|
262
|
+
let currentMessage = "Connecting to AFT...";
|
|
263
|
+
try {
|
|
264
|
+
const response = await client.call("status", { sessionID });
|
|
265
|
+
if (response.success !== false) {
|
|
266
|
+
const status = coerceAftStatus(response);
|
|
267
|
+
currentMessage = formatStatusDialogMessage(status);
|
|
268
|
+
}
|
|
269
|
+
} catch {
|
|
270
|
+
currentMessage = "AFT is starting up. Status will refresh automatically...";
|
|
271
|
+
}
|
|
272
|
+
let dialogOpen = true;
|
|
273
|
+
let pollTimer = null;
|
|
274
|
+
api.ui.dialog.setSize("large");
|
|
275
|
+
api.ui.dialog.replace(() => {
|
|
276
|
+
if (!pollTimer) {
|
|
277
|
+
pollTimer = setInterval(async () => {
|
|
278
|
+
if (!dialogOpen) {
|
|
279
|
+
if (pollTimer)
|
|
280
|
+
clearInterval(pollTimer);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
try {
|
|
284
|
+
const response = await client.call("status", { sessionID });
|
|
285
|
+
if (response.success !== false) {
|
|
286
|
+
const status = coerceAftStatus(response);
|
|
287
|
+
const newMessage = formatStatusDialogMessage(status);
|
|
288
|
+
if (newMessage !== currentMessage) {
|
|
289
|
+
currentMessage = newMessage;
|
|
290
|
+
api.ui.dialog.replace(() => /* @__PURE__ */ jsxDEV(api.ui.DialogAlert, {
|
|
291
|
+
title: "AFT Status",
|
|
292
|
+
message: currentMessage,
|
|
293
|
+
onConfirm: () => {
|
|
294
|
+
dialogOpen = false;
|
|
295
|
+
if (pollTimer)
|
|
296
|
+
clearInterval(pollTimer);
|
|
297
|
+
api.ui.dialog.setSize("medium");
|
|
298
|
+
}
|
|
299
|
+
}, undefined, false, undefined, this), () => {
|
|
300
|
+
dialogOpen = false;
|
|
301
|
+
if (pollTimer)
|
|
302
|
+
clearInterval(pollTimer);
|
|
303
|
+
api.ui.dialog.setSize("medium");
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
} catch {}
|
|
308
|
+
}, 1500);
|
|
309
|
+
}
|
|
310
|
+
return /* @__PURE__ */ jsxDEV(api.ui.DialogAlert, {
|
|
311
|
+
title: "AFT Status",
|
|
312
|
+
message: currentMessage,
|
|
313
|
+
onConfirm: () => {
|
|
314
|
+
dialogOpen = false;
|
|
315
|
+
if (pollTimer)
|
|
316
|
+
clearInterval(pollTimer);
|
|
317
|
+
api.ui.dialog.setSize("medium");
|
|
318
|
+
}
|
|
319
|
+
}, undefined, false, undefined, this);
|
|
320
|
+
}, () => {
|
|
321
|
+
dialogOpen = false;
|
|
322
|
+
if (pollTimer)
|
|
323
|
+
clearInterval(pollTimer);
|
|
324
|
+
api.ui.dialog.setSize("medium");
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
async function showStartupNotifications(api) {
|
|
328
|
+
const directory = api.state.path.directory ?? "";
|
|
329
|
+
if (!directory)
|
|
330
|
+
return;
|
|
331
|
+
const client = getRpcClient(directory);
|
|
332
|
+
try {
|
|
333
|
+
const announcement = await client.call("get-announcement", {});
|
|
334
|
+
if (announcement.show && announcement.version && announcement.features?.length) {
|
|
335
|
+
const featureText = announcement.features.map((f) => ` \u2022 ${f}`).join(`
|
|
336
|
+
`);
|
|
337
|
+
api.ui.dialog.replace(() => /* @__PURE__ */ jsxDEV(api.ui.DialogAlert, {
|
|
338
|
+
title: `AFT v${announcement.version}`,
|
|
339
|
+
message: `What's new:
|
|
340
|
+
|
|
341
|
+
${featureText}`,
|
|
342
|
+
onConfirm: () => {
|
|
343
|
+
client.call("mark-announced", {});
|
|
344
|
+
}
|
|
345
|
+
}, undefined, false, undefined, this), () => {
|
|
346
|
+
client.call("mark-announced", {});
|
|
347
|
+
});
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
} catch {}
|
|
351
|
+
try {
|
|
352
|
+
const result = await client.call("get-warnings", {});
|
|
353
|
+
if (result.warnings?.length) {
|
|
354
|
+
const warningText = result.warnings.join(`
|
|
355
|
+
|
|
356
|
+
`);
|
|
357
|
+
api.ui.dialog.replace(() => /* @__PURE__ */ jsxDEV(api.ui.DialogAlert, {
|
|
358
|
+
title: "AFT Warning",
|
|
359
|
+
message: warningText,
|
|
360
|
+
onConfirm: () => {}
|
|
361
|
+
}, undefined, false, undefined, this), () => {});
|
|
362
|
+
}
|
|
363
|
+
} catch {}
|
|
364
|
+
}
|
|
365
|
+
var tui = async (api) => {
|
|
366
|
+
api.command.register(() => [
|
|
367
|
+
{
|
|
368
|
+
title: "AFT: Status",
|
|
369
|
+
value: "aft.status",
|
|
370
|
+
category: "AFT",
|
|
371
|
+
slash: { name: STATUS_COMMAND },
|
|
372
|
+
onSelect() {
|
|
373
|
+
showStatusDialog(api);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
]);
|
|
377
|
+
showStartupNotifications(api);
|
|
378
|
+
};
|
|
379
|
+
var id = "aft-opencode";
|
|
380
|
+
var tui_default = {
|
|
381
|
+
id,
|
|
382
|
+
tui
|
|
383
|
+
};
|
|
384
|
+
export {
|
|
385
|
+
tui_default as default
|
|
386
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/aft-opencode",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.2",
|
|
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",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"README.md"
|
|
21
21
|
],
|
|
22
22
|
"scripts": {
|
|
23
|
-
"build": "bun build src/index.ts --outdir dist --target bun --format esm --external @opencode-ai/plugin && bun build src/cli/index.ts --outfile dist/cli.js --target node --format esm && tsc --emitDeclarationOnly",
|
|
23
|
+
"build": "bun build src/index.ts --outdir dist --target bun --format esm --external @opencode-ai/plugin && bun build src/tui/index.tsx --outfile dist/tui.js --target bun --format esm --external @opencode-ai/plugin --external @opencode-ai/plugin/tui --external @opentui/solid --external solid-js && bun build src/cli/index.ts --outfile dist/cli.js --target node --format esm && tsc --emitDeclarationOnly",
|
|
24
24
|
"typecheck": "tsc --noEmit",
|
|
25
25
|
"pretest": "cd ../.. && cargo build",
|
|
26
26
|
"test": "bun test",
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
"zod": "^4.1.8"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|
|
38
|
-
"@cortexkit/aft-darwin-arm64": "0.12.
|
|
39
|
-
"@cortexkit/aft-darwin-x64": "0.12.
|
|
40
|
-
"@cortexkit/aft-linux-arm64": "0.12.
|
|
41
|
-
"@cortexkit/aft-linux-x64": "0.12.
|
|
42
|
-
"@cortexkit/aft-win32-x64": "0.12.
|
|
38
|
+
"@cortexkit/aft-darwin-arm64": "0.12.2",
|
|
39
|
+
"@cortexkit/aft-darwin-x64": "0.12.2",
|
|
40
|
+
"@cortexkit/aft-linux-arm64": "0.12.2",
|
|
41
|
+
"@cortexkit/aft-linux-x64": "0.12.2",
|
|
42
|
+
"@cortexkit/aft-win32-x64": "0.12.2"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/node": "^22.0.0",
|
package/src/shared/rpc-client.ts
CHANGED
package/src/shared/rpc-server.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { mkdirSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { createServer, type IncomingMessage, type Server, type ServerResponse } from "node:http";
|
|
3
3
|
import { dirname } from "node:path";
|
|
4
|
-
import { log, warn } from "../logger
|
|
5
|
-
import { rpcPortFilePath } from "./rpc-utils
|
|
4
|
+
import { log, warn } from "../logger";
|
|
5
|
+
import { rpcPortFilePath } from "./rpc-utils";
|
|
6
6
|
|
|
7
7
|
type RpcHandler = (params: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
8
8
|
|
package/src/shared/tui-config.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { parse, stringify } from "comment-json";
|
|
4
|
-
import { log } from "../logger
|
|
5
|
-
import { getOpenCodeConfigPaths } from "./opencode-config-dir
|
|
4
|
+
import { log } from "../logger";
|
|
5
|
+
import { getOpenCodeConfigPaths } from "./opencode-config-dir";
|
|
6
6
|
|
|
7
7
|
const PLUGIN_NAME = "@cortexkit/aft-opencode";
|
|
8
8
|
const PLUGIN_ENTRY = `${PLUGIN_NAME}@latest`;
|
package/src/shared/url-fetch.ts
CHANGED