@cortexkit/aft-opencode 0.15.1 → 0.15.4
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/bridge.d.ts +5 -0
- package/dist/bridge.d.ts.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/downloader.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +316 -80
- package/dist/onnx-runtime.d.ts.map +1 -1
- package/dist/pool.d.ts.map +1 -1
- package/dist/resolver.d.ts.map +1 -1
- package/dist/shared/rpc-client.d.ts +2 -0
- package/dist/shared/rpc-client.d.ts.map +1 -1
- package/dist/shared/rpc-server.d.ts +1 -0
- package/dist/shared/rpc-server.d.ts.map +1 -1
- package/dist/shared/url-fetch.d.ts +7 -1
- package/dist/shared/url-fetch.d.ts.map +1 -1
- package/dist/tools/hoisted.d.ts.map +1 -1
- package/dist/tools/reading.d.ts.map +1 -1
- package/dist/tui.js +89 -15
- package/package.json +6 -6
- package/src/shared/rpc-client.ts +33 -14
- package/src/shared/rpc-server.ts +15 -3
- package/src/shared/url-fetch.ts +206 -23
- package/src/tui/index.tsx +5 -0
package/dist/index.js
CHANGED
|
@@ -7803,7 +7803,7 @@ var require_src2 = __commonJS((exports, module) => {
|
|
|
7803
7803
|
});
|
|
7804
7804
|
|
|
7805
7805
|
// src/index.ts
|
|
7806
|
-
import { existsSync as
|
|
7806
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync8, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
7807
7807
|
import { createRequire as createRequire2 } from "module";
|
|
7808
7808
|
import { homedir as homedir7 } from "os";
|
|
7809
7809
|
import { join as join13 } from "path";
|
|
@@ -21454,6 +21454,7 @@ var AftConfigSchema = exports_external.object({
|
|
|
21454
21454
|
restrict_to_project_root: exports_external.boolean().optional(),
|
|
21455
21455
|
experimental_search_index: exports_external.boolean().optional(),
|
|
21456
21456
|
experimental_semantic_search: exports_external.boolean().optional(),
|
|
21457
|
+
url_fetch_allow_private: exports_external.boolean().optional(),
|
|
21457
21458
|
semantic: SemanticConfigSchema.optional(),
|
|
21458
21459
|
max_callgraph_files: exports_external.number().int().positive().optional()
|
|
21459
21460
|
});
|
|
@@ -21696,11 +21697,6 @@ async function ensureBinary(version2) {
|
|
|
21696
21697
|
log(`No cached binary for ${version2}, downloading...`);
|
|
21697
21698
|
return downloadBinary(version2);
|
|
21698
21699
|
}
|
|
21699
|
-
const legacyCached = getCachedBinaryPath();
|
|
21700
|
-
if (legacyCached) {
|
|
21701
|
-
log(`Found cached binary: ${legacyCached}`);
|
|
21702
|
-
return legacyCached;
|
|
21703
|
-
}
|
|
21704
21700
|
log("No cached binary found, downloading latest...");
|
|
21705
21701
|
return downloadBinary();
|
|
21706
21702
|
}
|
|
@@ -22093,14 +22089,13 @@ async function downloadOnnxRuntime(info, targetDir) {
|
|
|
22093
22089
|
const tmpDir = `${targetDir}.tmp.${process.pid}`;
|
|
22094
22090
|
mkdirSync3(tmpDir, { recursive: true });
|
|
22095
22091
|
const archivePath = join5(tmpDir, `onnxruntime.${info.archiveType}`);
|
|
22096
|
-
const {
|
|
22097
|
-
|
|
22092
|
+
const { execFileSync } = await import("child_process");
|
|
22093
|
+
execFileSync("curl", ["-fsSL", url2, "-o", archivePath], {
|
|
22098
22094
|
stdio: "pipe",
|
|
22099
22095
|
timeout: 120000
|
|
22100
22096
|
});
|
|
22101
22097
|
if (info.archiveType === "tgz") {
|
|
22102
|
-
|
|
22103
|
-
execSync(`tar xzf "${archivePath}" -C "${tmpDir}"`, { stdio: "pipe" });
|
|
22098
|
+
execFileSync("tar", ["xzf", archivePath, "-C", tmpDir], { stdio: "pipe" });
|
|
22104
22099
|
} else {
|
|
22105
22100
|
await extractZipArchive(archivePath, tmpDir);
|
|
22106
22101
|
}
|
|
@@ -22199,13 +22194,46 @@ import { homedir as homedir4 } from "os";
|
|
|
22199
22194
|
import { join as join6 } from "path";
|
|
22200
22195
|
var DEFAULT_BRIDGE_TIMEOUT_MS = 30000;
|
|
22201
22196
|
var SEMANTIC_TIMEOUT_SAFETY_MARGIN_MS = 5000;
|
|
22197
|
+
var MAX_STDOUT_BUFFER = 64 * 1024 * 1024;
|
|
22202
22198
|
function compareSemver(a, b) {
|
|
22203
|
-
const
|
|
22204
|
-
const
|
|
22199
|
+
const [aMain, aPre] = a.split("-", 2);
|
|
22200
|
+
const [bMain, bPre] = b.split("-", 2);
|
|
22201
|
+
const aParts = aMain.split(".").map(Number);
|
|
22202
|
+
const bParts = bMain.split(".").map(Number);
|
|
22205
22203
|
for (let i = 0;i < 3; i++) {
|
|
22206
|
-
|
|
22207
|
-
|
|
22208
|
-
|
|
22204
|
+
if (aParts[i] !== bParts[i])
|
|
22205
|
+
return (aParts[i] ?? 0) - (bParts[i] ?? 0);
|
|
22206
|
+
}
|
|
22207
|
+
if (!aPre && !bPre)
|
|
22208
|
+
return 0;
|
|
22209
|
+
if (!aPre)
|
|
22210
|
+
return 1;
|
|
22211
|
+
if (!bPre)
|
|
22212
|
+
return -1;
|
|
22213
|
+
const aIds = aPre.split(".");
|
|
22214
|
+
const bIds = bPre.split(".");
|
|
22215
|
+
for (let i = 0;i < Math.max(aIds.length, bIds.length); i++) {
|
|
22216
|
+
const ai = aIds[i];
|
|
22217
|
+
const bi = bIds[i];
|
|
22218
|
+
if (ai === undefined)
|
|
22219
|
+
return -1;
|
|
22220
|
+
if (bi === undefined)
|
|
22221
|
+
return 1;
|
|
22222
|
+
const aNum = /^\d+$/.test(ai);
|
|
22223
|
+
const bNum = /^\d+$/.test(bi);
|
|
22224
|
+
if (aNum && bNum) {
|
|
22225
|
+
const diff = Number.parseInt(ai, 10) - Number.parseInt(bi, 10);
|
|
22226
|
+
if (diff !== 0)
|
|
22227
|
+
return diff;
|
|
22228
|
+
} else if (aNum) {
|
|
22229
|
+
return -1;
|
|
22230
|
+
} else if (bNum) {
|
|
22231
|
+
return 1;
|
|
22232
|
+
} else {
|
|
22233
|
+
const cmp = ai.localeCompare(bi);
|
|
22234
|
+
if (cmp !== 0)
|
|
22235
|
+
return cmp;
|
|
22236
|
+
}
|
|
22209
22237
|
}
|
|
22210
22238
|
return 0;
|
|
22211
22239
|
}
|
|
@@ -22402,6 +22430,7 @@ class BinaryBridge {
|
|
|
22402
22430
|
stdio: ["pipe", "pipe", "pipe"],
|
|
22403
22431
|
env
|
|
22404
22432
|
});
|
|
22433
|
+
const currentChild = child;
|
|
22405
22434
|
child.stdout?.on("data", (chunk) => {
|
|
22406
22435
|
this.onStdoutData(chunk.toString("utf-8"));
|
|
22407
22436
|
});
|
|
@@ -22417,10 +22446,14 @@ class BinaryBridge {
|
|
|
22417
22446
|
}
|
|
22418
22447
|
});
|
|
22419
22448
|
child.on("error", (err) => {
|
|
22449
|
+
if (this.process !== currentChild)
|
|
22450
|
+
return;
|
|
22420
22451
|
error48(`Process error: ${err.message}${this.formatStderrTail()}`);
|
|
22421
22452
|
this.handleCrash();
|
|
22422
22453
|
});
|
|
22423
22454
|
child.on("exit", (code, signal) => {
|
|
22455
|
+
if (this.process !== currentChild)
|
|
22456
|
+
return;
|
|
22424
22457
|
if (this._shuttingDown)
|
|
22425
22458
|
return;
|
|
22426
22459
|
log(`Process exited: code=${code}, signal=${signal}`);
|
|
@@ -22454,6 +22487,10 @@ class BinaryBridge {
|
|
|
22454
22487
|
}
|
|
22455
22488
|
onStdoutData(data) {
|
|
22456
22489
|
this.stdoutBuffer += data;
|
|
22490
|
+
if (this.stdoutBuffer.length > MAX_STDOUT_BUFFER) {
|
|
22491
|
+
this.handleCrash(new Error(`aft bridge stdout buffer exceeded ${MAX_STDOUT_BUFFER} bytes \u2014 killing bridge`));
|
|
22492
|
+
return;
|
|
22493
|
+
}
|
|
22457
22494
|
let newlineIdx;
|
|
22458
22495
|
while ((newlineIdx = this.stdoutBuffer.indexOf(`
|
|
22459
22496
|
`)) !== -1) {
|
|
@@ -22489,12 +22526,16 @@ class BinaryBridge {
|
|
|
22489
22526
|
this.stderrTail = [];
|
|
22490
22527
|
this.rejectAllPending(new Error(`[aft-plugin] Bridge restarted after timeout${tail}`));
|
|
22491
22528
|
}
|
|
22492
|
-
handleCrash() {
|
|
22529
|
+
handleCrash(cause) {
|
|
22530
|
+
const proc = this.process;
|
|
22493
22531
|
this.process = null;
|
|
22532
|
+
if (proc && proc.exitCode === null && !proc.killed) {
|
|
22533
|
+
proc.kill("SIGKILL");
|
|
22534
|
+
}
|
|
22494
22535
|
this.clearRestartResetTimer();
|
|
22495
22536
|
this.configured = false;
|
|
22496
22537
|
const tail = this.formatStderrTail();
|
|
22497
|
-
this.rejectAllPending(new Error(`[aft-plugin] Binary crashed (restarts: ${this._restartCount})${tail}`));
|
|
22538
|
+
this.rejectAllPending(new Error(`[aft-plugin] Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""}${tail}`));
|
|
22498
22539
|
if (this._restartCount < this.maxRestarts) {
|
|
22499
22540
|
const delay = 100 * 2 ** this._restartCount;
|
|
22500
22541
|
this._restartCount++;
|
|
@@ -22508,8 +22549,10 @@ class BinaryBridge {
|
|
|
22508
22549
|
}
|
|
22509
22550
|
}
|
|
22510
22551
|
}, delay);
|
|
22552
|
+
this.scheduleRestartCountReset();
|
|
22511
22553
|
} else {
|
|
22512
22554
|
error48(`Max restarts (${this.maxRestarts}) reached, giving up. Logs: ${getLogFilePath()}${tail}`);
|
|
22555
|
+
this.scheduleRestartCountReset();
|
|
22513
22556
|
}
|
|
22514
22557
|
}
|
|
22515
22558
|
rejectAllPending(error49) {
|
|
@@ -22627,12 +22670,9 @@ class BridgePool {
|
|
|
22627
22670
|
}
|
|
22628
22671
|
async replaceBinary(newPath) {
|
|
22629
22672
|
this.binaryPath = newPath;
|
|
22630
|
-
|
|
22631
|
-
try {
|
|
22632
|
-
entry.bridge.shutdown();
|
|
22633
|
-
} catch {}
|
|
22634
|
-
}
|
|
22673
|
+
const shutdowns = Array.from(this.bridges.values()).map((entry) => entry.bridge.shutdown());
|
|
22635
22674
|
this.bridges.clear();
|
|
22675
|
+
await Promise.allSettled(shutdowns);
|
|
22636
22676
|
log(`Binary path updated to ${newPath}. All bridges cleared \u2014 next calls will use the new binary.`);
|
|
22637
22677
|
}
|
|
22638
22678
|
get size() {
|
|
@@ -22645,7 +22685,7 @@ function normalizeKey(projectRoot) {
|
|
|
22645
22685
|
|
|
22646
22686
|
// src/resolver.ts
|
|
22647
22687
|
import { execSync, spawnSync } from "child_process";
|
|
22648
|
-
import { chmodSync as chmodSync3, copyFileSync, existsSync as existsSync5, mkdirSync as mkdirSync4 } from "fs";
|
|
22688
|
+
import { chmodSync as chmodSync3, copyFileSync, existsSync as existsSync5, mkdirSync as mkdirSync4, renameSync } from "fs";
|
|
22649
22689
|
import { createRequire } from "module";
|
|
22650
22690
|
import { homedir as homedir5 } from "os";
|
|
22651
22691
|
import { join as join7 } from "path";
|
|
@@ -22673,7 +22713,6 @@ function copyToVersionedCache(npmBinaryPath) {
|
|
|
22673
22713
|
if (process.platform !== "win32") {
|
|
22674
22714
|
chmodSync3(tmpPath, 493);
|
|
22675
22715
|
}
|
|
22676
|
-
const { renameSync } = __require("fs");
|
|
22677
22716
|
renameSync(tmpPath, cachedPath);
|
|
22678
22717
|
log(`Copied npm binary to versioned cache: ${cachedPath}`);
|
|
22679
22718
|
return cachedPath;
|
|
@@ -22754,7 +22793,7 @@ async function findBinary() {
|
|
|
22754
22793
|
"",
|
|
22755
22794
|
"Install it using one of these methods:",
|
|
22756
22795
|
" npm install @cortexkit/aft-opencode # installs platform-specific binary via npm",
|
|
22757
|
-
" cargo install
|
|
22796
|
+
" cargo install agent-file-tools # from crates.io",
|
|
22758
22797
|
" cargo build --release # from source (binary at target/release/aft)",
|
|
22759
22798
|
"",
|
|
22760
22799
|
"Or add the aft directory to your PATH."
|
|
@@ -22763,7 +22802,8 @@ async function findBinary() {
|
|
|
22763
22802
|
}
|
|
22764
22803
|
|
|
22765
22804
|
// src/shared/rpc-server.ts
|
|
22766
|
-
import {
|
|
22805
|
+
import { randomBytes } from "crypto";
|
|
22806
|
+
import { mkdirSync as mkdirSync5, renameSync as renameSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
22767
22807
|
import { createServer } from "http";
|
|
22768
22808
|
import { dirname } from "path";
|
|
22769
22809
|
|
|
@@ -22783,6 +22823,7 @@ function rpcPortFilePath(storageDir, directory) {
|
|
|
22783
22823
|
class AftRpcServer {
|
|
22784
22824
|
server = null;
|
|
22785
22825
|
port = 0;
|
|
22826
|
+
token = null;
|
|
22786
22827
|
handlers = new Map;
|
|
22787
22828
|
portFilePath;
|
|
22788
22829
|
constructor(storageDir, directory) {
|
|
@@ -22805,13 +22846,14 @@ class AftRpcServer {
|
|
|
22805
22846
|
return;
|
|
22806
22847
|
}
|
|
22807
22848
|
this.port = addr.port;
|
|
22849
|
+
this.token = randomBytes(32).toString("hex");
|
|
22808
22850
|
this.server = server;
|
|
22809
22851
|
try {
|
|
22810
22852
|
const dir = dirname(this.portFilePath);
|
|
22811
22853
|
mkdirSync5(dir, { recursive: true });
|
|
22812
22854
|
const tmpPath = `${this.portFilePath}.tmp`;
|
|
22813
|
-
writeFileSync2(tmpPath,
|
|
22814
|
-
|
|
22855
|
+
writeFileSync2(tmpPath, JSON.stringify({ port: this.port, token: this.token }), "utf-8");
|
|
22856
|
+
renameSync2(tmpPath, this.portFilePath);
|
|
22815
22857
|
log(`RPC server listening on 127.0.0.1:${this.port}`);
|
|
22816
22858
|
} catch (err) {
|
|
22817
22859
|
warn(`Failed to write RPC port file: ${err}`);
|
|
@@ -22826,6 +22868,7 @@ class AftRpcServer {
|
|
|
22826
22868
|
this.server.close();
|
|
22827
22869
|
this.server = null;
|
|
22828
22870
|
}
|
|
22871
|
+
this.token = null;
|
|
22829
22872
|
try {
|
|
22830
22873
|
unlinkSync3(this.portFilePath);
|
|
22831
22874
|
} catch {}
|
|
@@ -22869,8 +22912,14 @@ class AftRpcServer {
|
|
|
22869
22912
|
res.end(JSON.stringify({ error: "Invalid JSON" }));
|
|
22870
22913
|
return;
|
|
22871
22914
|
}
|
|
22872
|
-
|
|
22873
|
-
|
|
22915
|
+
if (params.token !== this.token) {
|
|
22916
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
22917
|
+
res.end(JSON.stringify({ error: "Forbidden" }));
|
|
22918
|
+
return;
|
|
22919
|
+
}
|
|
22920
|
+
const { token: _token, ...handlerParams } = params;
|
|
22921
|
+
log(`RPC call: ${method} params=${JSON.stringify(handlerParams).slice(0, 200)}`);
|
|
22922
|
+
handler(handlerParams).then((result) => {
|
|
22874
22923
|
log(`RPC result: ${method} => ${JSON.stringify(result).slice(0, 200)}`);
|
|
22875
22924
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
22876
22925
|
res.end(JSON.stringify(result));
|
|
@@ -23112,6 +23161,7 @@ function ensureTuiPluginEntry() {
|
|
|
23112
23161
|
|
|
23113
23162
|
// src/shared/url-fetch.ts
|
|
23114
23163
|
import { createHash as createHash2 } from "crypto";
|
|
23164
|
+
import { lookup } from "dns/promises";
|
|
23115
23165
|
import {
|
|
23116
23166
|
existsSync as existsSync7,
|
|
23117
23167
|
mkdirSync as mkdirSync7,
|
|
@@ -23120,10 +23170,12 @@ import {
|
|
|
23120
23170
|
unlinkSync as unlinkSync4,
|
|
23121
23171
|
writeFileSync as writeFileSync4
|
|
23122
23172
|
} from "fs";
|
|
23173
|
+
import { isIP } from "net";
|
|
23123
23174
|
import { join as join11 } from "path";
|
|
23124
23175
|
var MAX_RESPONSE_BYTES = 10 * 1024 * 1024;
|
|
23125
23176
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
23126
23177
|
var FETCH_TIMEOUT_MS = 30000;
|
|
23178
|
+
var MAX_REDIRECTS = 5;
|
|
23127
23179
|
function cacheDir(storageDir) {
|
|
23128
23180
|
return join11(storageDir, "url_cache");
|
|
23129
23181
|
}
|
|
@@ -23136,6 +23188,138 @@ function metaPath(storageDir, hash2) {
|
|
|
23136
23188
|
function contentPath(storageDir, hash2, extension) {
|
|
23137
23189
|
return join11(cacheDir(storageDir), `${hash2}${extension}`);
|
|
23138
23190
|
}
|
|
23191
|
+
function _isPrivateIpv4(address) {
|
|
23192
|
+
const parts = address.split(".").map((part) => Number.parseInt(part, 10));
|
|
23193
|
+
if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part)))
|
|
23194
|
+
return true;
|
|
23195
|
+
const [a, b] = parts;
|
|
23196
|
+
return a === 0 || a === 10 || a === 127 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a === 169 && b === 254 || a >= 224;
|
|
23197
|
+
}
|
|
23198
|
+
function expandIpv6(addr) {
|
|
23199
|
+
if (addr === "::")
|
|
23200
|
+
return [0, 0, 0, 0, 0, 0, 0, 0];
|
|
23201
|
+
const dcMatches = addr.match(/::/g);
|
|
23202
|
+
if (dcMatches && dcMatches.length > 1)
|
|
23203
|
+
return null;
|
|
23204
|
+
let normalized = addr;
|
|
23205
|
+
const lastColon = normalized.lastIndexOf(":");
|
|
23206
|
+
if (lastColon !== -1) {
|
|
23207
|
+
const tail = normalized.slice(lastColon + 1);
|
|
23208
|
+
if (tail.includes(".")) {
|
|
23209
|
+
const octets = tail.split(".").map((p) => Number.parseInt(p, 10));
|
|
23210
|
+
if (octets.length !== 4 || octets.some((o) => Number.isNaN(o) || o < 0 || o > 255)) {
|
|
23211
|
+
return null;
|
|
23212
|
+
}
|
|
23213
|
+
const h1 = (octets[0] << 8 | octets[1]).toString(16);
|
|
23214
|
+
const h2 = (octets[2] << 8 | octets[3]).toString(16);
|
|
23215
|
+
normalized = `${normalized.slice(0, lastColon)}:${h1}:${h2}`;
|
|
23216
|
+
}
|
|
23217
|
+
}
|
|
23218
|
+
let parts;
|
|
23219
|
+
if (normalized.includes("::")) {
|
|
23220
|
+
const [left, right] = normalized.split("::");
|
|
23221
|
+
const leftParts = left ? left.split(":") : [];
|
|
23222
|
+
const rightParts = right ? right.split(":") : [];
|
|
23223
|
+
const fill = 8 - leftParts.length - rightParts.length;
|
|
23224
|
+
if (fill < 0)
|
|
23225
|
+
return null;
|
|
23226
|
+
parts = [...leftParts, ...Array(fill).fill("0"), ...rightParts];
|
|
23227
|
+
} else {
|
|
23228
|
+
parts = normalized.split(":");
|
|
23229
|
+
}
|
|
23230
|
+
if (parts.length !== 8)
|
|
23231
|
+
return null;
|
|
23232
|
+
const hextets = parts.map((p) => {
|
|
23233
|
+
const n = Number.parseInt(p, 16);
|
|
23234
|
+
return Number.isNaN(n) || n < 0 || n > 65535 ? -1 : n;
|
|
23235
|
+
});
|
|
23236
|
+
if (hextets.some((h) => h === -1))
|
|
23237
|
+
return null;
|
|
23238
|
+
return hextets;
|
|
23239
|
+
}
|
|
23240
|
+
function isPrivateIp(address) {
|
|
23241
|
+
if (!address.includes(":")) {
|
|
23242
|
+
return _isPrivateIpv4(address);
|
|
23243
|
+
}
|
|
23244
|
+
const lower = address.toLowerCase();
|
|
23245
|
+
const noZone = lower.split("%")[0];
|
|
23246
|
+
const hextets = expandIpv6(noZone);
|
|
23247
|
+
if (hextets) {
|
|
23248
|
+
const top6Zero = hextets.slice(0, 6).every((h) => h === 0);
|
|
23249
|
+
const isMapped = hextets[0] === 0 && hextets[1] === 0 && hextets[2] === 0 && hextets[3] === 0 && hextets[4] === 0 && hextets[5] === 65535;
|
|
23250
|
+
if (isMapped || top6Zero) {
|
|
23251
|
+
const a = hextets[6] >> 8 & 255;
|
|
23252
|
+
const b = hextets[6] & 255;
|
|
23253
|
+
const c = hextets[7] >> 8 & 255;
|
|
23254
|
+
const d = hextets[7] & 255;
|
|
23255
|
+
const ipv43 = `${a}.${b}.${c}.${d}`;
|
|
23256
|
+
if (top6Zero && hextets[6] === 0 && hextets[7] <= 1) {
|
|
23257
|
+
return true;
|
|
23258
|
+
}
|
|
23259
|
+
return _isPrivateIpv4(ipv43);
|
|
23260
|
+
}
|
|
23261
|
+
const firstHextet = hextets[0];
|
|
23262
|
+
return firstHextet >= 65152 && firstHextet <= 65215 || firstHextet >= 64512 && firstHextet <= 65023 || firstHextet >= 65280;
|
|
23263
|
+
}
|
|
23264
|
+
return true;
|
|
23265
|
+
}
|
|
23266
|
+
async function assertPublicUrl(url2, allowPrivate) {
|
|
23267
|
+
if (url2.protocol !== "http:" && url2.protocol !== "https:") {
|
|
23268
|
+
throw new Error(`Only http:// and https:// URLs are supported, got: ${url2.protocol}`);
|
|
23269
|
+
}
|
|
23270
|
+
if (allowPrivate)
|
|
23271
|
+
return;
|
|
23272
|
+
const hostname3 = url2.hostname.replace(/^\[|\]$/g, "");
|
|
23273
|
+
if (isIP(hostname3) || hostname3.includes(":")) {
|
|
23274
|
+
if (isPrivateIp(hostname3)) {
|
|
23275
|
+
throw new Error(`Blocked private URL host ${url2.hostname} (${hostname3})`);
|
|
23276
|
+
}
|
|
23277
|
+
return;
|
|
23278
|
+
}
|
|
23279
|
+
const addresses = await lookup(hostname3, { all: true, verbatim: true });
|
|
23280
|
+
for (const { address } of addresses) {
|
|
23281
|
+
if (isPrivateIp(address)) {
|
|
23282
|
+
throw new Error(`Blocked private URL host ${url2.hostname} (${address})`);
|
|
23283
|
+
}
|
|
23284
|
+
}
|
|
23285
|
+
}
|
|
23286
|
+
function resolveRedirectUrl(currentUrl, location) {
|
|
23287
|
+
if (!location) {
|
|
23288
|
+
throw new Error(`Redirect from ${currentUrl.href} missing Location header`);
|
|
23289
|
+
}
|
|
23290
|
+
return new URL(location, currentUrl);
|
|
23291
|
+
}
|
|
23292
|
+
async function fetchWithRedirects(startUrl, allowPrivate) {
|
|
23293
|
+
let currentUrl = startUrl;
|
|
23294
|
+
for (let redirectCount = 0;redirectCount <= MAX_REDIRECTS; redirectCount++) {
|
|
23295
|
+
await assertPublicUrl(currentUrl, allowPrivate);
|
|
23296
|
+
const controller = new AbortController;
|
|
23297
|
+
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
23298
|
+
let response;
|
|
23299
|
+
try {
|
|
23300
|
+
response = await fetch(currentUrl.href, {
|
|
23301
|
+
signal: controller.signal,
|
|
23302
|
+
redirect: "manual",
|
|
23303
|
+
headers: {
|
|
23304
|
+
"user-agent": "aft-opencode-plugin",
|
|
23305
|
+
accept: "application/vnd.github.raw, text/markdown, text/x-markdown, text/html;q=0.9, text/plain;q=0.5"
|
|
23306
|
+
}
|
|
23307
|
+
});
|
|
23308
|
+
} catch (err) {
|
|
23309
|
+
throw new Error(`Failed to fetch ${currentUrl.href}: ${err.message}`);
|
|
23310
|
+
} finally {
|
|
23311
|
+
clearTimeout(timer);
|
|
23312
|
+
}
|
|
23313
|
+
if (response.status < 300 || response.status >= 400) {
|
|
23314
|
+
return response;
|
|
23315
|
+
}
|
|
23316
|
+
if (redirectCount === MAX_REDIRECTS) {
|
|
23317
|
+
throw new Error(`Too many redirects fetching ${startUrl.href}`);
|
|
23318
|
+
}
|
|
23319
|
+
currentUrl = resolveRedirectUrl(currentUrl, response.headers.get("location"));
|
|
23320
|
+
}
|
|
23321
|
+
throw new Error(`Too many redirects fetching ${startUrl.href}`);
|
|
23322
|
+
}
|
|
23139
23323
|
function resolveExtension(contentType) {
|
|
23140
23324
|
const lower = contentType.toLowerCase().split(";")[0].split(",")[0].trim();
|
|
23141
23325
|
if (lower === "text/html" || lower === "application/xhtml+xml" || lower === "application/vnd.github.html" || lower === "application/vnd.github+html") {
|
|
@@ -23149,7 +23333,7 @@ function resolveExtension(contentType) {
|
|
|
23149
23333
|
}
|
|
23150
23334
|
return null;
|
|
23151
23335
|
}
|
|
23152
|
-
async function fetchUrlToTempFile(url2, storageDir) {
|
|
23336
|
+
async function fetchUrlToTempFile(url2, storageDir, options = {}) {
|
|
23153
23337
|
let parsed;
|
|
23154
23338
|
try {
|
|
23155
23339
|
parsed = new URL(url2);
|
|
@@ -23159,6 +23343,7 @@ async function fetchUrlToTempFile(url2, storageDir) {
|
|
|
23159
23343
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
23160
23344
|
throw new Error(`Only http:// and https:// URLs are supported, got: ${parsed.protocol}`);
|
|
23161
23345
|
}
|
|
23346
|
+
const allowPrivate = options.allowPrivate === true;
|
|
23162
23347
|
const dir = cacheDir(storageDir);
|
|
23163
23348
|
mkdirSync7(dir, { recursive: true });
|
|
23164
23349
|
const hash2 = hashUrl(url2);
|
|
@@ -23175,23 +23360,7 @@ async function fetchUrlToTempFile(url2, storageDir) {
|
|
|
23175
23360
|
} catch {}
|
|
23176
23361
|
}
|
|
23177
23362
|
log(`Fetching URL: ${url2}`);
|
|
23178
|
-
const
|
|
23179
|
-
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
23180
|
-
let response;
|
|
23181
|
-
try {
|
|
23182
|
-
response = await fetch(url2, {
|
|
23183
|
-
signal: controller.signal,
|
|
23184
|
-
redirect: "follow",
|
|
23185
|
-
headers: {
|
|
23186
|
-
"user-agent": "aft-opencode-plugin",
|
|
23187
|
-
accept: "application/vnd.github.raw, text/markdown, text/x-markdown, text/html;q=0.9, text/plain;q=0.5"
|
|
23188
|
-
}
|
|
23189
|
-
});
|
|
23190
|
-
} catch (err) {
|
|
23191
|
-
throw new Error(`Failed to fetch ${url2}: ${err.message}`);
|
|
23192
|
-
} finally {
|
|
23193
|
-
clearTimeout(timer);
|
|
23194
|
-
}
|
|
23363
|
+
const response = await fetchWithRedirects(parsed, allowPrivate);
|
|
23195
23364
|
if (!response.ok) {
|
|
23196
23365
|
throw new Error(`HTTP ${response.status} ${response.statusText} fetching ${url2}`);
|
|
23197
23366
|
}
|
|
@@ -23230,8 +23399,8 @@ async function fetchUrlToTempFile(url2, storageDir) {
|
|
|
23230
23399
|
const contentFile = contentPath(storageDir, hash2, extension);
|
|
23231
23400
|
const tmpContent = `${contentFile}.tmp-${process.pid}`;
|
|
23232
23401
|
writeFileSync4(tmpContent, body);
|
|
23233
|
-
const { renameSync:
|
|
23234
|
-
|
|
23402
|
+
const { renameSync: renameSync3 } = await import("fs");
|
|
23403
|
+
renameSync3(tmpContent, contentFile);
|
|
23235
23404
|
const meta3 = {
|
|
23236
23405
|
url: url2,
|
|
23237
23406
|
contentType,
|
|
@@ -23240,7 +23409,7 @@ async function fetchUrlToTempFile(url2, storageDir) {
|
|
|
23240
23409
|
};
|
|
23241
23410
|
const tmpMeta = `${metaFile}.tmp-${process.pid}`;
|
|
23242
23411
|
writeFileSync4(tmpMeta, JSON.stringify(meta3));
|
|
23243
|
-
|
|
23412
|
+
renameSync3(tmpMeta, metaFile);
|
|
23244
23413
|
log(`URL cached (${total} bytes): ${url2}`);
|
|
23245
23414
|
return contentFile;
|
|
23246
23415
|
}
|
|
@@ -24380,22 +24549,41 @@ function createApplyPatchTool(ctx) {
|
|
|
24380
24549
|
if (hunks.length === 0) {
|
|
24381
24550
|
throw new Error("Empty patch: no file operations found");
|
|
24382
24551
|
}
|
|
24383
|
-
const
|
|
24552
|
+
const affectedAbs = new Set;
|
|
24553
|
+
const newlyCreatedAbs = new Set;
|
|
24554
|
+
for (const h of hunks) {
|
|
24555
|
+
const srcAbs = path4.resolve(context.directory, h.path);
|
|
24556
|
+
affectedAbs.add(srcAbs);
|
|
24557
|
+
if (h.type === "add") {
|
|
24558
|
+
newlyCreatedAbs.add(srcAbs);
|
|
24559
|
+
}
|
|
24560
|
+
if (h.type === "update" && h.move_path) {
|
|
24561
|
+
const dstAbs = path4.resolve(context.directory, h.move_path);
|
|
24562
|
+
affectedAbs.add(dstAbs);
|
|
24563
|
+
if (!fs3.existsSync(dstAbs)) {
|
|
24564
|
+
newlyCreatedAbs.add(dstAbs);
|
|
24565
|
+
}
|
|
24566
|
+
}
|
|
24567
|
+
}
|
|
24568
|
+
const relPaths = Array.from(affectedAbs).map((abs) => path4.relative(context.worktree, abs));
|
|
24384
24569
|
await context.ask({
|
|
24385
24570
|
permission: "edit",
|
|
24386
|
-
patterns:
|
|
24571
|
+
patterns: relPaths,
|
|
24387
24572
|
always: ["*"],
|
|
24388
24573
|
metadata: {}
|
|
24389
24574
|
});
|
|
24575
|
+
const checkpointPaths = Array.from(affectedAbs).filter((abs) => !newlyCreatedAbs.has(abs));
|
|
24390
24576
|
const checkpointName = `apply_patch_${Date.now()}`;
|
|
24391
24577
|
let checkpointCreated = false;
|
|
24392
|
-
|
|
24393
|
-
|
|
24394
|
-
|
|
24395
|
-
|
|
24396
|
-
|
|
24397
|
-
|
|
24398
|
-
|
|
24578
|
+
if (checkpointPaths.length > 0) {
|
|
24579
|
+
try {
|
|
24580
|
+
await callBridge(ctx, context, "checkpoint", {
|
|
24581
|
+
name: checkpointName,
|
|
24582
|
+
files: checkpointPaths
|
|
24583
|
+
});
|
|
24584
|
+
checkpointCreated = true;
|
|
24585
|
+
} catch {}
|
|
24586
|
+
}
|
|
24399
24587
|
const results = [];
|
|
24400
24588
|
const perFileDiffs = [];
|
|
24401
24589
|
let patchFailed = false;
|
|
@@ -24472,27 +24660,70 @@ ${diagLines}`);
|
|
|
24472
24660
|
}
|
|
24473
24661
|
}
|
|
24474
24662
|
if (patchFailed) {
|
|
24663
|
+
const rollbackNotes = [];
|
|
24475
24664
|
if (checkpointCreated) {
|
|
24476
24665
|
try {
|
|
24477
24666
|
await callBridge(ctx, context, "restore_checkpoint", { name: checkpointName });
|
|
24478
|
-
|
|
24667
|
+
rollbackNotes.push("restored pre-existing files from checkpoint");
|
|
24479
24668
|
} catch {
|
|
24480
|
-
|
|
24669
|
+
rollbackNotes.push("checkpoint restore FAILED, pre-existing files may be inconsistent");
|
|
24670
|
+
}
|
|
24671
|
+
} else if (checkpointPaths.length > 0) {
|
|
24672
|
+
rollbackNotes.push("no checkpoint was created, pre-existing files may be inconsistent");
|
|
24673
|
+
}
|
|
24674
|
+
let newlyDeleted = 0;
|
|
24675
|
+
for (const createdAbs of newlyCreatedAbs) {
|
|
24676
|
+
if (!fs3.existsSync(createdAbs))
|
|
24677
|
+
continue;
|
|
24678
|
+
try {
|
|
24679
|
+
await callBridge(ctx, context, "delete_file", { file: createdAbs });
|
|
24680
|
+
newlyDeleted++;
|
|
24681
|
+
} catch {
|
|
24682
|
+
rollbackNotes.push(`failed to delete newly-created ${path4.relative(context.worktree, createdAbs)}`);
|
|
24481
24683
|
}
|
|
24482
|
-
} else {
|
|
24483
|
-
results.push("Patch failed \u2014 no checkpoint was created, files may be inconsistent.");
|
|
24484
24684
|
}
|
|
24685
|
+
if (newlyDeleted > 0) {
|
|
24686
|
+
rollbackNotes.push(`removed ${newlyDeleted} newly-created file(s)`);
|
|
24687
|
+
}
|
|
24688
|
+
results.push(rollbackNotes.length > 0 ? `Patch failed \u2014 ${rollbackNotes.join("; ")}.` : "Patch failed \u2014 nothing to roll back.");
|
|
24485
24689
|
return results.join(`
|
|
24486
24690
|
`);
|
|
24487
24691
|
}
|
|
24488
24692
|
const callID = getCallID(context);
|
|
24489
24693
|
if (callID) {
|
|
24694
|
+
const diffByPath = new Map(perFileDiffs.map((d) => [d.filePath, d]));
|
|
24695
|
+
const countAddDel = (patch) => {
|
|
24696
|
+
let additions = 0;
|
|
24697
|
+
let deletions = 0;
|
|
24698
|
+
for (const line of patch.split(`
|
|
24699
|
+
`)) {
|
|
24700
|
+
if (line.startsWith("---") || line.startsWith("+++"))
|
|
24701
|
+
continue;
|
|
24702
|
+
if (line.startsWith("+"))
|
|
24703
|
+
additions++;
|
|
24704
|
+
else if (line.startsWith("-"))
|
|
24705
|
+
deletions++;
|
|
24706
|
+
}
|
|
24707
|
+
return { additions, deletions };
|
|
24708
|
+
};
|
|
24490
24709
|
const files = hunks.map((h) => {
|
|
24491
|
-
const
|
|
24710
|
+
const filePath = path4.resolve(context.directory, h.path);
|
|
24711
|
+
const rawMovePath = h.type === "update" ? h.move_path : undefined;
|
|
24712
|
+
const movePath = rawMovePath ? path4.resolve(context.directory, rawMovePath) : undefined;
|
|
24713
|
+
const displayPath = movePath ?? filePath;
|
|
24714
|
+
const relPath = path4.relative(context.worktree, displayPath);
|
|
24715
|
+
const diffEntry = diffByPath.get(filePath);
|
|
24716
|
+
const patch = diffEntry ? buildUnifiedDiff(displayPath, diffEntry.before, diffEntry.after) : "";
|
|
24717
|
+
const { additions, deletions } = countAddDel(patch);
|
|
24718
|
+
const uiType = h.type === "update" && rawMovePath ? "move" : h.type;
|
|
24492
24719
|
return {
|
|
24493
|
-
filePath
|
|
24720
|
+
filePath,
|
|
24494
24721
|
relativePath: relPath,
|
|
24495
|
-
type:
|
|
24722
|
+
type: uiType,
|
|
24723
|
+
patch,
|
|
24724
|
+
additions,
|
|
24725
|
+
deletions,
|
|
24726
|
+
...movePath ? { movePath } : {}
|
|
24496
24727
|
};
|
|
24497
24728
|
});
|
|
24498
24729
|
const fileList = files.map((f) => {
|
|
@@ -24502,7 +24733,7 @@ ${diagLines}`);
|
|
|
24502
24733
|
`);
|
|
24503
24734
|
const title = `Success. Updated the following files:
|
|
24504
24735
|
${fileList}`;
|
|
24505
|
-
const diffText =
|
|
24736
|
+
const diffText = files.map((f) => f.patch).filter(Boolean).join(`
|
|
24506
24737
|
`);
|
|
24507
24738
|
storeToolMetadata(context.sessionID, callID, {
|
|
24508
24739
|
title,
|
|
@@ -24825,7 +25056,9 @@ function readingTools(ctx) {
|
|
|
24825
25056
|
throw new Error("Provide exactly ONE of 'filePath', 'files', 'directory', or 'url' \u2014 not multiple");
|
|
24826
25057
|
}
|
|
24827
25058
|
if (hasUrl) {
|
|
24828
|
-
const cachedPath = await fetchUrlToTempFile(args.url, ctx.storageDir
|
|
25059
|
+
const cachedPath = await fetchUrlToTempFile(args.url, ctx.storageDir, {
|
|
25060
|
+
allowPrivate: ctx.config.url_fetch_allow_private === true
|
|
25061
|
+
});
|
|
24829
25062
|
const response2 = await callBridge(ctx, context, "outline", { file: cachedPath });
|
|
24830
25063
|
if (response2.success === false) {
|
|
24831
25064
|
throw new Error(response2.message || "outline failed");
|
|
@@ -24892,7 +25125,9 @@ Provide exactly ONE of 'filePath' or 'url'. Pass either 'symbol' for a single lo
|
|
|
24892
25125
|
if (hasFilePath && hasUrl) {
|
|
24893
25126
|
throw new Error("Provide exactly ONE of 'filePath' or 'url' \u2014 not both");
|
|
24894
25127
|
}
|
|
24895
|
-
const file2 = hasUrl ? await fetchUrlToTempFile(args.url, ctx.storageDir
|
|
25128
|
+
const file2 = hasUrl ? await fetchUrlToTempFile(args.url, ctx.storageDir, {
|
|
25129
|
+
allowPrivate: ctx.config.url_fetch_allow_private === true
|
|
25130
|
+
}) : args.filePath;
|
|
24896
25131
|
if (Array.isArray(args.symbols) && args.symbols.length > 0) {
|
|
24897
25132
|
const results = await Promise.all(args.symbols.map((sym) => {
|
|
24898
25133
|
const params2 = { file: file2, symbol: sym };
|
|
@@ -25497,8 +25732,7 @@ var plugin = async (input) => {
|
|
|
25497
25732
|
configOverrides.formatter = aftConfig.formatter;
|
|
25498
25733
|
if (aftConfig.checker !== undefined)
|
|
25499
25734
|
configOverrides.checker = aftConfig.checker;
|
|
25500
|
-
|
|
25501
|
-
configOverrides.restrict_to_project_root = aftConfig.restrict_to_project_root;
|
|
25735
|
+
configOverrides.restrict_to_project_root = aftConfig.restrict_to_project_root ?? true;
|
|
25502
25736
|
if (aftConfig.experimental_search_index !== undefined)
|
|
25503
25737
|
configOverrides.experimental_search_index = aftConfig.experimental_search_index;
|
|
25504
25738
|
if (aftConfig.experimental_semantic_search !== undefined)
|
|
@@ -25512,13 +25746,15 @@ var plugin = async (input) => {
|
|
|
25512
25746
|
configOverrides.storage_dir = join13(dataHome, "opencode", "storage", "plugin", "aft");
|
|
25513
25747
|
if (aftConfig.experimental_semantic_search && isFastembedSemanticBackend) {
|
|
25514
25748
|
const storageDir2 = configOverrides.storage_dir;
|
|
25515
|
-
ensureOnnxRuntime(storageDir2).
|
|
25516
|
-
|
|
25517
|
-
|
|
25518
|
-
|
|
25519
|
-
|
|
25520
|
-
|
|
25521
|
-
}
|
|
25749
|
+
const ortDylibDir = await ensureOnnxRuntime(storageDir2).catch((err) => {
|
|
25750
|
+
warn(`ONNX Runtime setup failed: ${err instanceof Error ? err.message : String(err)}. Semantic search will be unavailable.`);
|
|
25751
|
+
return null;
|
|
25752
|
+
});
|
|
25753
|
+
if (ortDylibDir) {
|
|
25754
|
+
configOverrides._ort_dylib_dir = ortDylibDir;
|
|
25755
|
+
} else if (!isOrtAutoDownloadSupported()) {
|
|
25756
|
+
warn(`Semantic search requires ONNX Runtime. Install: ${getManualInstallHint()}`);
|
|
25757
|
+
}
|
|
25522
25758
|
}
|
|
25523
25759
|
let versionUpgradeAttempted = null;
|
|
25524
25760
|
const pool = new BridgePool(binaryPath, {
|
|
@@ -25571,7 +25807,7 @@ var plugin = async (input) => {
|
|
|
25571
25807
|
if (storageDir) {
|
|
25572
25808
|
const versionFile = join13(storageDir, "last_announced_version");
|
|
25573
25809
|
try {
|
|
25574
|
-
if (
|
|
25810
|
+
if (existsSync9(versionFile)) {
|
|
25575
25811
|
const lastVersion = readFileSync5(versionFile, "utf-8").trim();
|
|
25576
25812
|
if (lastVersion === ANNOUNCEMENT_VERSION)
|
|
25577
25813
|
return { show: false };
|
|
@@ -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;AA6LD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAU3D"}
|