@cortexkit/aft-opencode 0.45.1 → 0.46.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.
- package/dist/config.d.ts +0 -9
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +347 -123
- package/dist/shared/ignored-message.d.ts +9 -7
- package/dist/shared/ignored-message.d.ts.map +1 -1
- package/dist/shared/rpc-client.d.ts +23 -1
- package/dist/shared/rpc-client.d.ts.map +1 -1
- package/dist/subc-tool-schemas.d.ts.map +1 -1
- package/dist/tools/hoisted.d.ts.map +1 -1
- package/dist/tools/permissions.d.ts +7 -0
- package/dist/tools/permissions.d.ts.map +1 -1
- package/dist/tools/semantic.d.ts.map +1 -1
- package/dist/tui/notification-socket.d.ts.map +1 -1
- package/package.json +17 -14
- package/src/shared/ignored-message.ts +38 -19
- package/src/shared/rpc-client.ts +116 -4
- package/src/tui/entry.mjs +16 -0
- package/src/tui/notification-socket.ts +28 -1
- package/src/tui-compiled/badge-contrast.ts +43 -0
- package/src/tui-compiled/index.tsx +992 -0
- package/src/tui-compiled/notification-socket.ts +448 -0
- package/src/tui-compiled/preferences.ts +243 -0
- package/src/tui-compiled/sidebar.tsx +936 -0
- package/src/tui-compiled/types/opencode-plugin-tui.d.ts +239 -0
- package/dist/tui.js +0 -13462
package/dist/index.js
CHANGED
|
@@ -11442,11 +11442,11 @@ class BridgePool {
|
|
|
11442
11442
|
function normalizeKey(projectRoot) {
|
|
11443
11443
|
return canonicalizeProjectRoot(projectRoot);
|
|
11444
11444
|
}
|
|
11445
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.
|
|
11445
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/client.js
|
|
11446
11446
|
import { promises as fs2 } from "node:fs";
|
|
11447
11447
|
import { debuglog } from "node:util";
|
|
11448
11448
|
|
|
11449
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.
|
|
11449
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/auth.js
|
|
11450
11450
|
import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
11451
11451
|
var NONCE_LEN = 32;
|
|
11452
11452
|
var MAX_AUTH_MESSAGE_LEN = 4096;
|
|
@@ -11510,7 +11510,7 @@ async function authenticateClient(sock, conn, deadlineMs) {
|
|
|
11510
11510
|
await writeMessage(sock, { client_auth: Array.from(clientAuth) }, deadlineMs);
|
|
11511
11511
|
}
|
|
11512
11512
|
|
|
11513
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.
|
|
11513
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/connection-file.js
|
|
11514
11514
|
import { promises as fs } from "node:fs";
|
|
11515
11515
|
var SCHEMA_VERSION = 1;
|
|
11516
11516
|
var MIN_KEY_LEN = 32;
|
|
@@ -11579,13 +11579,13 @@ async function readConnectionFile(path2) {
|
|
|
11579
11579
|
return info;
|
|
11580
11580
|
}
|
|
11581
11581
|
|
|
11582
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.
|
|
11582
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/envelope.js
|
|
11583
11583
|
var PROTOCOL_VERSION = 1;
|
|
11584
11584
|
var HEADER_LEN = 17;
|
|
11585
11585
|
var FROZEN_PREFIX_LEN = 5;
|
|
11586
11586
|
var MAX_FRAME_BODY_LEN = 64 * 1024 * 1024;
|
|
11587
11587
|
var FrameType;
|
|
11588
|
-
((FrameType2)
|
|
11588
|
+
(function(FrameType2) {
|
|
11589
11589
|
FrameType2[FrameType2["Request"] = 0] = "Request";
|
|
11590
11590
|
FrameType2[FrameType2["Response"] = 1] = "Response";
|
|
11591
11591
|
FrameType2[FrameType2["Push"] = 2] = "Push";
|
|
@@ -11598,11 +11598,17 @@ var FrameType;
|
|
|
11598
11598
|
FrameType2[FrameType2["Hello"] = 9] = "Hello";
|
|
11599
11599
|
FrameType2[FrameType2["HelloAck"] = 10] = "HelloAck";
|
|
11600
11600
|
FrameType2[FrameType2["Goodbye"] = 11] = "Goodbye";
|
|
11601
|
-
})(FrameType
|
|
11602
|
-
var FRAME_TYPE_MAX =
|
|
11601
|
+
})(FrameType || (FrameType = {}));
|
|
11602
|
+
var FRAME_TYPE_MAX = FrameType.Goodbye;
|
|
11603
11603
|
function isPureHeader(ty) {
|
|
11604
|
-
return ty ===
|
|
11605
|
-
}
|
|
11604
|
+
return ty === FrameType.Cancel || ty === FrameType.Ping || ty === FrameType.Pong || ty === FrameType.Goodbye;
|
|
11605
|
+
}
|
|
11606
|
+
var Priority;
|
|
11607
|
+
(function(Priority2) {
|
|
11608
|
+
Priority2[Priority2["Passive"] = 0] = "Passive";
|
|
11609
|
+
Priority2[Priority2["Interactive"] = 1] = "Interactive";
|
|
11610
|
+
Priority2[Priority2["Background"] = 2] = "Background";
|
|
11611
|
+
})(Priority || (Priority = {}));
|
|
11606
11612
|
var FLAG_BINARY = 1;
|
|
11607
11613
|
var FLAG_PRIORITY_MASK = 6;
|
|
11608
11614
|
var FLAG_PRIORITY_SHIFT = 1;
|
|
@@ -11686,7 +11692,7 @@ function encodeFrame(frame) {
|
|
|
11686
11692
|
return out;
|
|
11687
11693
|
}
|
|
11688
11694
|
|
|
11689
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.
|
|
11695
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/socket.js
|
|
11690
11696
|
import net from "node:net";
|
|
11691
11697
|
|
|
11692
11698
|
class SocketClosedError extends Error {
|
|
@@ -11878,14 +11884,14 @@ class SubcSocket {
|
|
|
11878
11884
|
}
|
|
11879
11885
|
}
|
|
11880
11886
|
|
|
11881
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.
|
|
11887
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/client.js
|
|
11882
11888
|
var debug = debuglog("subc-client");
|
|
11883
11889
|
var DEFAULT_HANDSHAKE_TIMEOUT_MS = 1e4;
|
|
11884
11890
|
var DEFAULT_REQUEST_TIMEOUT_MS = 30000;
|
|
11885
11891
|
var TIMEOUT_ARBITRATION_GRACE_MS = 50;
|
|
11886
11892
|
var REQUEST_DEADLINE_MARKER = "request_deadline";
|
|
11887
11893
|
var DEADLINE_NO_DROP_CODE = "deadline_exceeded_no_drop_observed";
|
|
11888
|
-
var ROUTE_OPEN_RETRY_DEADLINE_MS =
|
|
11894
|
+
var ROUTE_OPEN_RETRY_DEADLINE_MS = 30000;
|
|
11889
11895
|
var BODY_READ_TIMEOUT_MS = 30000;
|
|
11890
11896
|
var EMPTY_BODY = new Uint8Array(0);
|
|
11891
11897
|
var DEFAULT_MANAGED_TARGET_KIND = "management_surface";
|
|
@@ -11967,12 +11973,13 @@ class SubcClient {
|
|
|
11967
11973
|
}
|
|
11968
11974
|
async request(routeChannel, body, opts = {}) {
|
|
11969
11975
|
const bytes = body instanceof Uint8Array ? body : this.encode(body);
|
|
11970
|
-
const priority = opts.priority ??
|
|
11976
|
+
const priority = opts.priority ?? Priority.Interactive;
|
|
11971
11977
|
const reply = await this.send(routeChannel, bytes, priority, opts.timeoutMs, opts.onProgress);
|
|
11972
11978
|
return this.parseJson(reply);
|
|
11973
11979
|
}
|
|
11974
11980
|
async call(moduleId, method, params, opts = {}) {
|
|
11975
11981
|
const body = params === undefined ? { method } : { method, params };
|
|
11982
|
+
let retriedUnknownChannel = false;
|
|
11976
11983
|
for (;; ) {
|
|
11977
11984
|
const routeChannel = await this.cachedRouteChannel(moduleId, opts);
|
|
11978
11985
|
try {
|
|
@@ -11980,6 +11987,11 @@ class SubcClient {
|
|
|
11980
11987
|
} catch (err) {
|
|
11981
11988
|
if (!(err instanceof SubcCallError))
|
|
11982
11989
|
throw this.terminalCallError("managed call failed", err);
|
|
11990
|
+
if (err.code === "unknown_channel" && !retriedUnknownChannel && !this.closeStarted) {
|
|
11991
|
+
retriedUnknownChannel = true;
|
|
11992
|
+
this.evictRouteChannel(routeChannel);
|
|
11993
|
+
continue;
|
|
11994
|
+
}
|
|
11983
11995
|
if (err.kind === "not_sent") {
|
|
11984
11996
|
try {
|
|
11985
11997
|
await this.reconnectAfterDrop(err);
|
|
@@ -11997,7 +12009,7 @@ class SubcClient {
|
|
|
11997
12009
|
}
|
|
11998
12010
|
subscribe(routeChannel, body, onEvent, opts = {}) {
|
|
11999
12011
|
const bytes = body instanceof Uint8Array ? body : this.encode(body);
|
|
12000
|
-
const priority = opts.priority ??
|
|
12012
|
+
const priority = opts.priority ?? Priority.Interactive;
|
|
12001
12013
|
const corr = this.nextCorr++;
|
|
12002
12014
|
const key = `${routeChannel}:${corr}`;
|
|
12003
12015
|
const closed = new Promise((resolve7, reject) => {
|
|
@@ -12013,7 +12025,7 @@ class SubcClient {
|
|
|
12013
12025
|
timer: null,
|
|
12014
12026
|
subscription: true
|
|
12015
12027
|
});
|
|
12016
|
-
const frame = buildFrame(
|
|
12028
|
+
const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false), routeChannel, corr, bytes);
|
|
12017
12029
|
this.sock.write(encodeFrame(frame), Date.now() + DEFAULT_REQUEST_TIMEOUT_MS).catch((err) => {
|
|
12018
12030
|
const p = this.pending.get(key);
|
|
12019
12031
|
if (p)
|
|
@@ -12025,7 +12037,7 @@ class SubcClient {
|
|
|
12025
12037
|
if (cancelled)
|
|
12026
12038
|
return;
|
|
12027
12039
|
cancelled = true;
|
|
12028
|
-
const cancel = buildFrame(
|
|
12040
|
+
const cancel = buildFrame(FrameType.Cancel, buildFlags(false, priority, false), routeChannel, corr, EMPTY_BODY);
|
|
12029
12041
|
this.sock.write(encodeFrame(cancel), Date.now() + DEFAULT_REQUEST_TIMEOUT_MS).catch(() => {});
|
|
12030
12042
|
};
|
|
12031
12043
|
return { unsubscribe, closed };
|
|
@@ -12076,7 +12088,7 @@ class SubcClient {
|
|
|
12076
12088
|
sendRouteGoodbye(channel) {
|
|
12077
12089
|
if (this.closedErr)
|
|
12078
12090
|
return;
|
|
12079
|
-
const goodbye = buildFrame(
|
|
12091
|
+
const goodbye = buildFrame(FrameType.Goodbye, buildFlags(false, Priority.Interactive, false), channel, 0n, EMPTY_BODY);
|
|
12080
12092
|
this.sock.write(encodeFrame(goodbye), Date.now() + DEFAULT_REQUEST_TIMEOUT_MS).catch(() => {});
|
|
12081
12093
|
}
|
|
12082
12094
|
static async openConnection(opts) {
|
|
@@ -12093,14 +12105,14 @@ class SubcClient {
|
|
|
12093
12105
|
return { sock, conn };
|
|
12094
12106
|
}
|
|
12095
12107
|
async controlRpc(body) {
|
|
12096
|
-
return this.send(0, body,
|
|
12108
|
+
return this.send(0, body, Priority.Interactive, undefined, undefined);
|
|
12097
12109
|
}
|
|
12098
12110
|
send(channel, body, priority, timeoutMs, onProgress) {
|
|
12099
12111
|
if (this.closedErr)
|
|
12100
12112
|
return Promise.reject(this.closedErr);
|
|
12101
12113
|
const corr = this.nextCorr++;
|
|
12102
12114
|
const key = `${channel}:${corr}`;
|
|
12103
|
-
const frame = buildFrame(
|
|
12115
|
+
const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false), channel, corr, body);
|
|
12104
12116
|
return new Promise((resolve7, reject) => {
|
|
12105
12117
|
const ms = timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
12106
12118
|
const pending = {
|
|
@@ -12140,7 +12152,7 @@ class SubcClient {
|
|
|
12140
12152
|
}
|
|
12141
12153
|
async managedRequest(routeChannel, body, opts) {
|
|
12142
12154
|
const bytes = body instanceof Uint8Array ? body : this.encode(body);
|
|
12143
|
-
const priority = opts.priority ??
|
|
12155
|
+
const priority = opts.priority ?? Priority.Interactive;
|
|
12144
12156
|
try {
|
|
12145
12157
|
const reply = await this.sendManaged(routeChannel, bytes, priority, opts.timeoutMs, opts.onProgress);
|
|
12146
12158
|
return this.parseJson(reply);
|
|
@@ -12156,7 +12168,7 @@ class SubcClient {
|
|
|
12156
12168
|
}
|
|
12157
12169
|
const corr = this.nextCorr++;
|
|
12158
12170
|
const key = `${channel}:${corr}`;
|
|
12159
|
-
const frame = buildFrame(
|
|
12171
|
+
const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false), channel, corr, body);
|
|
12160
12172
|
let handedToSocket = false;
|
|
12161
12173
|
const classifyFailure = (err) => {
|
|
12162
12174
|
if (!handedToSocket) {
|
|
@@ -12315,6 +12327,9 @@ class SubcClient {
|
|
|
12315
12327
|
return;
|
|
12316
12328
|
} catch (err) {
|
|
12317
12329
|
if (!isConsumerReconnectTransient(err) || attempt >= this.opts.reconnectBackoff.maxAttempts) {
|
|
12330
|
+
if (err instanceof AuthError && attempt > 1) {
|
|
12331
|
+
throw new AuthError(`reconnect gave up after ${attempt} attempts: ${err.message} — the connection file and the daemon's key disagree persistently ` + `(daemon restarting in a loop, split connection-file paths, or a genuinely foreign daemon on this port); ` + `check the daemon, then restart this host app`);
|
|
12332
|
+
}
|
|
12318
12333
|
throw err;
|
|
12319
12334
|
}
|
|
12320
12335
|
await this.opts.sleep(delay);
|
|
@@ -12383,26 +12398,27 @@ class SubcClient {
|
|
|
12383
12398
|
const pending = this.pending.get(key);
|
|
12384
12399
|
if (pending) {
|
|
12385
12400
|
switch (frame.header.ty) {
|
|
12386
|
-
case
|
|
12387
|
-
case
|
|
12401
|
+
case FrameType.Push:
|
|
12402
|
+
case FrameType.StreamData:
|
|
12388
12403
|
pending.onProgress?.(frame.body);
|
|
12389
12404
|
return;
|
|
12390
|
-
case
|
|
12391
|
-
case
|
|
12405
|
+
case FrameType.Response:
|
|
12406
|
+
case FrameType.StreamEnd:
|
|
12392
12407
|
this.settle(key, pending, () => pending.resolve(frame));
|
|
12393
12408
|
return;
|
|
12394
|
-
case
|
|
12409
|
+
case FrameType.Error:
|
|
12395
12410
|
this.settle(key, pending, () => pending.reject(this.errorFromFrame(frame)));
|
|
12396
12411
|
return;
|
|
12397
12412
|
default:
|
|
12398
12413
|
return;
|
|
12399
12414
|
}
|
|
12400
12415
|
}
|
|
12401
|
-
if (frame.header.ty ===
|
|
12416
|
+
if (frame.header.ty === FrameType.Goodbye) {
|
|
12402
12417
|
this.failChannel(frame.header.channel, new SubcError("route closed by subc (GOODBYE)"));
|
|
12418
|
+
this.evictRouteChannel(frame.header.channel);
|
|
12403
12419
|
return;
|
|
12404
12420
|
}
|
|
12405
|
-
if (frame.header.ty ===
|
|
12421
|
+
if (frame.header.ty === FrameType.Response || frame.header.ty === FrameType.Error || frame.header.ty === FrameType.StreamEnd) {
|
|
12406
12422
|
debug("dropped terminal frame with no waiter: type=%d channel=%d corr=%s port=%s", frame.header.ty, frame.header.channel, frame.header.corr, this.sock.localPort() ?? "?");
|
|
12407
12423
|
return;
|
|
12408
12424
|
}
|
|
@@ -12428,6 +12444,13 @@ class SubcClient {
|
|
|
12428
12444
|
return new SubcError(Buffer.from(frame.body).toString("utf8") || "subc error");
|
|
12429
12445
|
}
|
|
12430
12446
|
}
|
|
12447
|
+
evictRouteChannel(channel) {
|
|
12448
|
+
for (const cached of this.routes.values()) {
|
|
12449
|
+
if (cached.channel === channel && cached.generation === this.generation) {
|
|
12450
|
+
cached.channel = null;
|
|
12451
|
+
}
|
|
12452
|
+
}
|
|
12453
|
+
}
|
|
12431
12454
|
failChannel(channel, err) {
|
|
12432
12455
|
for (const [key, pending] of this.pending) {
|
|
12433
12456
|
if (pending.channel === channel) {
|
|
@@ -12474,7 +12497,9 @@ function isConsumerReconnectTransient(err) {
|
|
|
12474
12497
|
return true;
|
|
12475
12498
|
if (err instanceof SubcCallError)
|
|
12476
12499
|
return err.kind === "not_sent" || err.kind === "outcome_unknown";
|
|
12477
|
-
if (err instanceof
|
|
12500
|
+
if (err instanceof AuthError)
|
|
12501
|
+
return true;
|
|
12502
|
+
if (err instanceof SubcError || err instanceof ConnectionFileError)
|
|
12478
12503
|
return false;
|
|
12479
12504
|
const code = errorCode(err);
|
|
12480
12505
|
return code === "ECONNREFUSED" || code === "ECONNRESET" || code === "EPIPE" || code === "ETIMEDOUT" || code === "ENOENT";
|
|
@@ -12527,14 +12552,51 @@ function causeMessage(cause) {
|
|
|
12527
12552
|
return "";
|
|
12528
12553
|
return `: ${cause instanceof Error ? cause.message : String(cause)}`;
|
|
12529
12554
|
}
|
|
12530
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.
|
|
12555
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.4/node_modules/@cortexkit/subc-client/dist/provider.js
|
|
12531
12556
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
12532
12557
|
var DEFAULT_HANDSHAKE_TIMEOUT_MS2 = 1e4;
|
|
12533
12558
|
var BODY_READ_TIMEOUT_MS2 = 30000;
|
|
12534
12559
|
var WRITE_TIMEOUT_MS = 30000;
|
|
12535
12560
|
var DEFAULT_RESTORED_DEBOUNCE_MS = 250;
|
|
12561
|
+
var DEFAULT_PROVIDER_HANDLER_CAPACITY = 64;
|
|
12562
|
+
var HEALTH_CHECK_OP = "health.check";
|
|
12536
12563
|
var HELLO_CORR = 1n;
|
|
12537
12564
|
|
|
12565
|
+
class AsyncPermitPool {
|
|
12566
|
+
available;
|
|
12567
|
+
waiters = [];
|
|
12568
|
+
constructor(capacity) {
|
|
12569
|
+
if (!Number.isInteger(capacity) || capacity <= 0) {
|
|
12570
|
+
throw new SubcProviderError("provider handler capacity must be a positive integer", "invalid_handler_capacity");
|
|
12571
|
+
}
|
|
12572
|
+
this.available = capacity;
|
|
12573
|
+
}
|
|
12574
|
+
async acquire() {
|
|
12575
|
+
if (this.available > 0) {
|
|
12576
|
+
this.available -= 1;
|
|
12577
|
+
return this.releaseOnce();
|
|
12578
|
+
}
|
|
12579
|
+
await new Promise((resolve7) => {
|
|
12580
|
+
this.waiters.push(resolve7);
|
|
12581
|
+
});
|
|
12582
|
+
return this.releaseOnce();
|
|
12583
|
+
}
|
|
12584
|
+
releaseOnce() {
|
|
12585
|
+
let released = false;
|
|
12586
|
+
return () => {
|
|
12587
|
+
if (released)
|
|
12588
|
+
return;
|
|
12589
|
+
released = true;
|
|
12590
|
+
const next = this.waiters.shift();
|
|
12591
|
+
if (next) {
|
|
12592
|
+
next();
|
|
12593
|
+
} else {
|
|
12594
|
+
this.available += 1;
|
|
12595
|
+
}
|
|
12596
|
+
};
|
|
12597
|
+
}
|
|
12598
|
+
}
|
|
12599
|
+
|
|
12538
12600
|
class SubcProviderError extends Error {
|
|
12539
12601
|
code;
|
|
12540
12602
|
constructor(message, code) {
|
|
@@ -12553,6 +12615,7 @@ class SubcProvider {
|
|
|
12553
12615
|
closeStarted = false;
|
|
12554
12616
|
closedErr = null;
|
|
12555
12617
|
inflight = new Map;
|
|
12618
|
+
requestGate = new AsyncPermitPool(DEFAULT_PROVIDER_HANDLER_CAPACITY);
|
|
12556
12619
|
reconnecting = null;
|
|
12557
12620
|
generation = 1;
|
|
12558
12621
|
connectionEpoch = 1;
|
|
@@ -12591,7 +12654,7 @@ class SubcProvider {
|
|
|
12591
12654
|
this.cancelRestoredDebounce();
|
|
12592
12655
|
const sock = this.sock;
|
|
12593
12656
|
try {
|
|
12594
|
-
await sendFrame(sock, buildFrame(
|
|
12657
|
+
await sendFrame(sock, buildFrame(FrameType.Goodbye, controlFlags(), 0, 0n, new Uint8Array(0)));
|
|
12595
12658
|
} catch {} finally {
|
|
12596
12659
|
sock.close();
|
|
12597
12660
|
this.finishClosed();
|
|
@@ -12642,21 +12705,21 @@ class SubcProvider {
|
|
|
12642
12705
|
}
|
|
12643
12706
|
async dispatch(frame, sock, generation) {
|
|
12644
12707
|
switch (frame.header.ty) {
|
|
12645
|
-
case
|
|
12708
|
+
case FrameType.Ping:
|
|
12646
12709
|
if (frame.header.channel === 0) {
|
|
12647
|
-
await this.sendOn(sock, generation, buildFrameWithVersion(frame.header.ver,
|
|
12710
|
+
await this.sendOn(sock, generation, buildFrameWithVersion(frame.header.ver, FrameType.Pong, frame.header.flags, 0, frame.header.corr, new Uint8Array(0)));
|
|
12648
12711
|
}
|
|
12649
12712
|
return true;
|
|
12650
|
-
case
|
|
12713
|
+
case FrameType.Goodbye:
|
|
12651
12714
|
if (frame.header.channel === 0)
|
|
12652
12715
|
return false;
|
|
12653
12716
|
this.abortChannel(generation, frame.header.channel);
|
|
12654
12717
|
await this.opts.onRouteGone?.(frame.header.channel);
|
|
12655
12718
|
return true;
|
|
12656
|
-
case
|
|
12719
|
+
case FrameType.Cancel:
|
|
12657
12720
|
this.inflight.get(routeKey(generation, frame.header.channel, frame.header.corr))?.abort();
|
|
12658
12721
|
return true;
|
|
12659
|
-
case
|
|
12722
|
+
case FrameType.Request:
|
|
12660
12723
|
if (frame.header.channel === 0) {
|
|
12661
12724
|
await this.handleControlRequest(frame, sock, generation);
|
|
12662
12725
|
} else {
|
|
@@ -12691,6 +12754,14 @@ class SubcProvider {
|
|
|
12691
12754
|
}
|
|
12692
12755
|
async handleControlRequest(frame, sock, generation) {
|
|
12693
12756
|
const request = parseJson(frame.body);
|
|
12757
|
+
if (request.op === HEALTH_CHECK_OP) {
|
|
12758
|
+
this.handleHealthRequest(frame, sock, generation).catch((err) => {
|
|
12759
|
+
if (!this.closeStarted && this.sock === sock && this.generation === generation) {
|
|
12760
|
+
console.warn("SubcProvider health handler failed after its request was dispatched", err);
|
|
12761
|
+
}
|
|
12762
|
+
});
|
|
12763
|
+
return;
|
|
12764
|
+
}
|
|
12694
12765
|
if (request.op !== "route.bind") {
|
|
12695
12766
|
throw new SubcProviderError(`unsupported module control request ${request.op ?? "<missing op>"}`);
|
|
12696
12767
|
}
|
|
@@ -12706,41 +12777,67 @@ class SubcProvider {
|
|
|
12706
12777
|
await this.sendError(frame, rejection.code, rejection.message, controlFlags(), sock, generation);
|
|
12707
12778
|
return;
|
|
12708
12779
|
}
|
|
12709
|
-
await this.sendOn(sock, generation, buildFrameWithVersion(frame.header.ver,
|
|
12780
|
+
await this.sendOn(sock, generation, buildFrameWithVersion(frame.header.ver, FrameType.Response, controlFlags(), 0, frame.header.corr, encodeJson({ op: "route.bind" })));
|
|
12710
12781
|
}
|
|
12711
12782
|
async handleDataRequest(frame, sock, generation) {
|
|
12712
12783
|
const { channel, corr, ver } = frame.header;
|
|
12713
12784
|
const key = routeKey(generation, channel, corr);
|
|
12714
12785
|
const controller = new AbortController;
|
|
12715
12786
|
this.inflight.set(key, controller);
|
|
12716
|
-
const dataFlags = buildFlags(false,
|
|
12787
|
+
const dataFlags = buildFlags(false, Priority.Interactive, false);
|
|
12717
12788
|
const ctx = {
|
|
12718
12789
|
signal: controller.signal,
|
|
12719
12790
|
currentEpoch: () => this.connectionEpoch,
|
|
12720
12791
|
emit: async (eventBody) => {
|
|
12721
12792
|
if (controller.signal.aborted)
|
|
12722
12793
|
return;
|
|
12723
|
-
await this.sendOn(sock, generation, buildFrameWithVersion(ver,
|
|
12794
|
+
await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.StreamData, dataFlags, channel, corr, eventBody));
|
|
12724
12795
|
}
|
|
12725
12796
|
};
|
|
12797
|
+
const releasePermit = await (this.requestGate ?? new AsyncPermitPool(DEFAULT_PROVIDER_HANDLER_CAPACITY)).acquire();
|
|
12726
12798
|
try {
|
|
12727
12799
|
const body = await this.opts.handler(channel, frame.body, ctx);
|
|
12728
12800
|
if (body === undefined) {
|
|
12729
|
-
await this.sendOn(sock, generation, buildFrameWithVersion(ver,
|
|
12801
|
+
await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.StreamEnd, dataFlags, channel, corr, new Uint8Array(0)));
|
|
12730
12802
|
} else if (body instanceof Uint8Array) {
|
|
12731
|
-
await this.sendOn(sock, generation, buildFrameWithVersion(ver,
|
|
12803
|
+
await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.Response, dataFlags, channel, corr, body));
|
|
12732
12804
|
} else {
|
|
12733
12805
|
throw new SubcProviderError("provider handler must return a Uint8Array or void", "invalid_handler_response");
|
|
12734
12806
|
}
|
|
12735
12807
|
} catch (err) {
|
|
12736
12808
|
await this.sendError(frame, err instanceof SubcProviderError && err.code ? err.code : "handler_error", err instanceof Error ? err.message : String(err), dataFlags, sock, generation);
|
|
12737
12809
|
} finally {
|
|
12810
|
+
releasePermit();
|
|
12811
|
+
if (this.inflight.get(key) === controller)
|
|
12812
|
+
this.inflight.delete(key);
|
|
12813
|
+
}
|
|
12814
|
+
}
|
|
12815
|
+
async handleHealthRequest(frame, sock, generation) {
|
|
12816
|
+
const { channel, corr, ver } = frame.header;
|
|
12817
|
+
const key = routeKey(generation, channel, corr);
|
|
12818
|
+
const controller = new AbortController;
|
|
12819
|
+
this.inflight.set(key, controller);
|
|
12820
|
+
const releasePermit = await (this.requestGate ?? new AsyncPermitPool(DEFAULT_PROVIDER_HANDLER_CAPACITY)).acquire();
|
|
12821
|
+
try {
|
|
12822
|
+
if (controller.signal.aborted)
|
|
12823
|
+
return;
|
|
12824
|
+
const report = await this.opts.health();
|
|
12825
|
+
await this.sendOn(sock, generation, buildFrameWithVersion(ver, FrameType.Response, controlFlags(), channel, corr, encodeJson({
|
|
12826
|
+
op: HEALTH_CHECK_OP,
|
|
12827
|
+
status: report.status,
|
|
12828
|
+
...report.detail === undefined ? {} : { detail: report.detail },
|
|
12829
|
+
...report.metrics === undefined ? {} : { metrics: report.metrics }
|
|
12830
|
+
})));
|
|
12831
|
+
} catch (err) {
|
|
12832
|
+
await this.sendError(frame, err instanceof SubcProviderError && err.code ? err.code : "health_error", err instanceof Error ? err.message : String(err), controlFlags(), sock, generation);
|
|
12833
|
+
} finally {
|
|
12834
|
+
releasePermit();
|
|
12738
12835
|
if (this.inflight.get(key) === controller)
|
|
12739
12836
|
this.inflight.delete(key);
|
|
12740
12837
|
}
|
|
12741
12838
|
}
|
|
12742
12839
|
async sendError(frame, code, message, flags, sock, generation) {
|
|
12743
|
-
await this.sendOn(sock, generation, buildFrameWithVersion(frame.header.ver,
|
|
12840
|
+
await this.sendOn(sock, generation, buildFrameWithVersion(frame.header.ver, FrameType.Error, flags, frame.header.channel, frame.header.corr, encodeJson({ code, message })));
|
|
12744
12841
|
}
|
|
12745
12842
|
async sendOn(sock, generation, frame) {
|
|
12746
12843
|
if (this.sock !== sock || this.generation !== generation || this.closeStarted || this.closedErr)
|
|
@@ -12880,6 +12977,7 @@ function normalizeProviderConnectOptions(opts) {
|
|
|
12880
12977
|
connectionFile: opts.connectionFile,
|
|
12881
12978
|
manifest: opts.manifest,
|
|
12882
12979
|
handler: opts.handler,
|
|
12980
|
+
health: opts.health ?? (() => ({ status: "ok" })),
|
|
12883
12981
|
handshakeTimeoutMs: opts.handshakeTimeoutMs,
|
|
12884
12982
|
controlOps: opts.controlOps,
|
|
12885
12983
|
onBind: opts.onBind,
|
|
@@ -12891,12 +12989,19 @@ function normalizeProviderConnectOptions(opts) {
|
|
|
12891
12989
|
launchNonce: opts.launchNonce
|
|
12892
12990
|
};
|
|
12893
12991
|
}
|
|
12992
|
+
function normalizedControlOps(controlOps) {
|
|
12993
|
+
if (controlOps === null)
|
|
12994
|
+
return null;
|
|
12995
|
+
const merged = new Set(controlOps ?? []);
|
|
12996
|
+
merged.add(HEALTH_CHECK_OP);
|
|
12997
|
+
return [...merged];
|
|
12998
|
+
}
|
|
12894
12999
|
function buildHelloFrame(opts) {
|
|
12895
13000
|
const nonce = launchNonce(opts);
|
|
12896
|
-
return buildFrame(
|
|
13001
|
+
return buildFrame(FrameType.Hello, controlFlags(), 0, HELLO_CORR, encodeJson({
|
|
12897
13002
|
manifest: normalizeManifest(opts.manifest),
|
|
12898
13003
|
protocol_ver: PROTOCOL_VERSION,
|
|
12899
|
-
control_ops: opts.controlOps
|
|
13004
|
+
control_ops: normalizedControlOps(opts.controlOps),
|
|
12900
13005
|
...nonce ? { launch_nonce: nonce } : {}
|
|
12901
13006
|
}));
|
|
12902
13007
|
}
|
|
@@ -12907,7 +13012,9 @@ function isProviderReconnectTransient(err) {
|
|
|
12907
13012
|
return true;
|
|
12908
13013
|
if (err instanceof SocketWriteNotQueuedError || err instanceof SocketWriteQueuedError)
|
|
12909
13014
|
return true;
|
|
12910
|
-
if (err instanceof
|
|
13015
|
+
if (err instanceof AuthError)
|
|
13016
|
+
return true;
|
|
13017
|
+
if (err instanceof ConnectionFileError)
|
|
12911
13018
|
return false;
|
|
12912
13019
|
const code = errorCode2(err);
|
|
12913
13020
|
return code === "ECONNREFUSED" || code === "ECONNRESET" || code === "EPIPE" || code === "ETIMEDOUT" || code === "ENOENT";
|
|
@@ -12924,7 +13031,7 @@ async function pauseBeforeStateRetry() {
|
|
|
12924
13031
|
await new Promise((resolve7) => setTimeout(resolve7, 0));
|
|
12925
13032
|
}
|
|
12926
13033
|
function controlFlags() {
|
|
12927
|
-
return buildFlags(false,
|
|
13034
|
+
return buildFlags(false, Priority.Passive, false);
|
|
12928
13035
|
}
|
|
12929
13036
|
async function sendFrame(sock, frame) {
|
|
12930
13037
|
await sock.write(encodeFrame(frame), Date.now() + WRITE_TIMEOUT_MS);
|
|
@@ -12934,9 +13041,9 @@ async function expectHelloAck(sock, deadline) {
|
|
|
12934
13041
|
const body = header.len === 0 ? new Uint8Array(0) : await sock.readExact(header.len, deadline);
|
|
12935
13042
|
const frame = { header, body };
|
|
12936
13043
|
switch (header.ty) {
|
|
12937
|
-
case
|
|
13044
|
+
case FrameType.HelloAck:
|
|
12938
13045
|
return parseJson(body);
|
|
12939
|
-
case
|
|
13046
|
+
case FrameType.Error: {
|
|
12940
13047
|
const error2 = parseJson(body);
|
|
12941
13048
|
throw new SubcProviderError(`subc rejected HELLO: ${error2.code ?? "unknown"} — ${error2.message ?? "subc error"}`, error2.code);
|
|
12942
13049
|
}
|
|
@@ -13002,6 +13109,7 @@ function normalizeProviderRole(role) {
|
|
|
13002
13109
|
role: "tool_provider",
|
|
13003
13110
|
tools: role.tools.map((tool) => ({
|
|
13004
13111
|
name: tool.name,
|
|
13112
|
+
...tool.description === undefined ? {} : { description: tool.description },
|
|
13005
13113
|
execution_mode: tool.execution_mode,
|
|
13006
13114
|
schema: tool.schema
|
|
13007
13115
|
})),
|
|
@@ -13176,6 +13284,9 @@ class BgSubscription {
|
|
|
13176
13284
|
function isRecord(value) {
|
|
13177
13285
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13178
13286
|
}
|
|
13287
|
+
function isUnknownChannelError(err) {
|
|
13288
|
+
return err instanceof SubcError && err.code === "unknown_channel";
|
|
13289
|
+
}
|
|
13179
13290
|
function safeCloseRoute(client, channel) {
|
|
13180
13291
|
try {
|
|
13181
13292
|
client.closeRouteChannel(channel).catch(() => {
|
|
@@ -13255,7 +13366,7 @@ class SubcTransport {
|
|
|
13255
13366
|
if (!options)
|
|
13256
13367
|
return {};
|
|
13257
13368
|
const preview = options.preview;
|
|
13258
|
-
const timeoutMs = options.timeoutMs;
|
|
13369
|
+
const timeoutMs = options.transportTimeoutMs ?? options.timeoutMs;
|
|
13259
13370
|
const onProgress = options.onProgress;
|
|
13260
13371
|
return { preview, timeoutMs, onProgress };
|
|
13261
13372
|
}
|
|
@@ -13325,45 +13436,66 @@ class SubcTransportPool {
|
|
|
13325
13436
|
record.inflight += 1;
|
|
13326
13437
|
try {
|
|
13327
13438
|
const client = await this.ensureClient();
|
|
13328
|
-
|
|
13329
|
-
throw new RouteTornDownError("subc session closed");
|
|
13330
|
-
}
|
|
13331
|
-
let channel;
|
|
13332
|
-
let entry;
|
|
13333
|
-
try {
|
|
13334
|
-
({ channel, entry } = await this.routeChannel(client, identity, record));
|
|
13439
|
+
const openRoute = async () => {
|
|
13335
13440
|
if (!this.isCurrentSession(key, record)) {
|
|
13336
13441
|
throw new RouteTornDownError("subc session closed");
|
|
13337
13442
|
}
|
|
13338
|
-
|
|
13339
|
-
|
|
13443
|
+
try {
|
|
13444
|
+
const opened = await this.routeChannel(client, identity, record);
|
|
13445
|
+
if (!this.isCurrentSession(key, record)) {
|
|
13446
|
+
throw new RouteTornDownError("subc session closed");
|
|
13447
|
+
}
|
|
13448
|
+
return opened;
|
|
13449
|
+
} catch (err) {
|
|
13450
|
+
if (err instanceof RouteTornDownError)
|
|
13451
|
+
throw err;
|
|
13452
|
+
if (isConsumerReconnectTransient(err) && this.isCurrentSession(key, record) && this.client === client) {
|
|
13453
|
+
this.dropClient(client);
|
|
13454
|
+
}
|
|
13340
13455
|
throw err;
|
|
13341
|
-
if (isConsumerReconnectTransient(err) && this.isCurrentSession(key, record) && this.client === client) {
|
|
13342
|
-
this.dropClient(client);
|
|
13343
13456
|
}
|
|
13344
|
-
|
|
13345
|
-
|
|
13346
|
-
|
|
13347
|
-
|
|
13348
|
-
if (this.isCurrentSession(key, record) && this.client === client) {
|
|
13349
|
-
this.transportFailures = 0;
|
|
13350
|
-
}
|
|
13351
|
-
this.ensureBgSubscription(identity, record);
|
|
13352
|
-
return reply;
|
|
13353
|
-
} catch (err) {
|
|
13354
|
-
if (record.routeEntry === entry) {
|
|
13355
|
-
entry.closed = true;
|
|
13457
|
+
};
|
|
13458
|
+
const clearRouteEntry = (entry2) => {
|
|
13459
|
+
if (record.routeEntry === entry2) {
|
|
13460
|
+
entry2.closed = true;
|
|
13356
13461
|
record.routeEntry = null;
|
|
13357
13462
|
}
|
|
13463
|
+
};
|
|
13464
|
+
const handleRequestFailure = (err, entry2) => {
|
|
13465
|
+
clearRouteEntry(entry2);
|
|
13358
13466
|
if (this.isCurrentSession(key, record) && this.client === client) {
|
|
13359
13467
|
if (isConsumerReconnectTransient(err)) {
|
|
13360
13468
|
this.transportFailures = 0;
|
|
13361
13469
|
this.dropClient(client);
|
|
13362
|
-
} else if (++this.transportFailures >= MAX_CONSECUTIVE_TRANSPORT_FAILURES) {
|
|
13470
|
+
} else if (!isUnknownChannelError(err) && ++this.transportFailures >= MAX_CONSECUTIVE_TRANSPORT_FAILURES) {
|
|
13363
13471
|
this.transportFailures = 0;
|
|
13364
13472
|
this.dropClient(client);
|
|
13365
13473
|
}
|
|
13366
13474
|
}
|
|
13475
|
+
};
|
|
13476
|
+
const requestOnRoute = async (channel2) => {
|
|
13477
|
+
const reply = await client.request(channel2, body, { timeoutMs, onProgress });
|
|
13478
|
+
if (this.isCurrentSession(key, record) && this.client === client) {
|
|
13479
|
+
this.transportFailures = 0;
|
|
13480
|
+
}
|
|
13481
|
+
this.ensureBgSubscription(identity, record);
|
|
13482
|
+
return reply;
|
|
13483
|
+
};
|
|
13484
|
+
let { channel, entry } = await openRoute();
|
|
13485
|
+
try {
|
|
13486
|
+
return await requestOnRoute(channel);
|
|
13487
|
+
} catch (err) {
|
|
13488
|
+
if (isUnknownChannelError(err) && this.isCurrentSession(key, record) && this.client === client) {
|
|
13489
|
+
clearRouteEntry(entry);
|
|
13490
|
+
({ channel, entry } = await openRoute());
|
|
13491
|
+
try {
|
|
13492
|
+
return await requestOnRoute(channel);
|
|
13493
|
+
} catch (retryErr) {
|
|
13494
|
+
handleRequestFailure(retryErr, entry);
|
|
13495
|
+
throw retryErr;
|
|
13496
|
+
}
|
|
13497
|
+
}
|
|
13498
|
+
handleRequestFailure(err, entry);
|
|
13367
13499
|
throw err;
|
|
13368
13500
|
}
|
|
13369
13501
|
} finally {
|
|
@@ -28853,16 +28985,7 @@ var InspectConfigSchema = exports_external.object({
|
|
|
28853
28985
|
tier2_soft_deadline_ms: exports_external.number().int().positive().optional(),
|
|
28854
28986
|
max_drill_down_items: exports_external.number().int().positive().max(100).optional(),
|
|
28855
28987
|
duplicates: exports_external.object({
|
|
28856
|
-
|
|
28857
|
-
discard_cost: exports_external.number().int().min(0).optional(),
|
|
28858
|
-
expected_mirrors: exports_external.array(exports_external.tuple([exports_external.string().trim().min(1), exports_external.string().trim().min(1)])).optional(),
|
|
28859
|
-
anonymize: exports_external.object({
|
|
28860
|
-
variables: exports_external.boolean().optional(),
|
|
28861
|
-
fields: exports_external.boolean().optional(),
|
|
28862
|
-
methods: exports_external.boolean().optional(),
|
|
28863
|
-
types: exports_external.boolean().optional(),
|
|
28864
|
-
literals: exports_external.boolean().optional()
|
|
28865
|
-
}).optional()
|
|
28988
|
+
expected_mirrors: exports_external.array(exports_external.tuple([exports_external.string().trim().min(1), exports_external.string().trim().min(1)])).optional()
|
|
28866
28989
|
}).optional()
|
|
28867
28990
|
});
|
|
28868
28991
|
var BackupConfigSchema = exports_external.object({
|
|
@@ -29214,16 +29337,9 @@ function mergeInspectConfig(baseInspect, overrideInspect) {
|
|
|
29214
29337
|
...overrideInspect,
|
|
29215
29338
|
duplicates: baseInspect?.duplicates || overrideInspect?.duplicates ? {
|
|
29216
29339
|
...baseInspect?.duplicates,
|
|
29217
|
-
...overrideInspect?.duplicates
|
|
29218
|
-
anonymize: baseInspect?.duplicates?.anonymize || overrideInspect?.duplicates?.anonymize ? {
|
|
29219
|
-
...baseInspect?.duplicates?.anonymize,
|
|
29220
|
-
...overrideInspect?.duplicates?.anonymize
|
|
29221
|
-
} : undefined
|
|
29340
|
+
...overrideInspect?.duplicates
|
|
29222
29341
|
} : undefined
|
|
29223
29342
|
};
|
|
29224
|
-
if (inspect.duplicates && inspect.duplicates.anonymize === undefined) {
|
|
29225
|
-
delete inspect.duplicates.anonymize;
|
|
29226
|
-
}
|
|
29227
29343
|
if (Object.values(inspect).every((value) => value === undefined)) {
|
|
29228
29344
|
return;
|
|
29229
29345
|
}
|
|
@@ -32368,28 +32484,44 @@ function normalizeToolMap(tools) {
|
|
|
32368
32484
|
async function sendIgnoredMessage2(client, sessionID, text) {
|
|
32369
32485
|
const typedClient = client;
|
|
32370
32486
|
let agent;
|
|
32487
|
+
let model;
|
|
32488
|
+
let variant;
|
|
32371
32489
|
try {
|
|
32372
32490
|
const ctx = await resolvePromptContext(client, sessionID);
|
|
32373
32491
|
agent = ctx?.agent;
|
|
32492
|
+
model = ctx?.model;
|
|
32493
|
+
variant = ctx?.variant;
|
|
32374
32494
|
} catch {
|
|
32375
32495
|
agent = undefined;
|
|
32376
32496
|
}
|
|
32377
|
-
const
|
|
32497
|
+
const send = async (body) => {
|
|
32498
|
+
const promptInput = { path: { id: sessionID }, body };
|
|
32499
|
+
if (typeof typedClient.session?.prompt === "function") {
|
|
32500
|
+
await Promise.resolve(typedClient.session.prompt(promptInput));
|
|
32501
|
+
return;
|
|
32502
|
+
}
|
|
32503
|
+
if (typeof typedClient.session?.promptAsync === "function") {
|
|
32504
|
+
await typedClient.session.promptAsync(promptInput);
|
|
32505
|
+
return;
|
|
32506
|
+
}
|
|
32507
|
+
throw new Error("[aft-plugin] client.session.prompt is unavailable");
|
|
32508
|
+
};
|
|
32509
|
+
const base = {
|
|
32378
32510
|
noReply: true,
|
|
32379
32511
|
parts: [{ type: "text", text, ignored: true }]
|
|
32380
32512
|
};
|
|
32381
32513
|
if (agent)
|
|
32382
|
-
|
|
32383
|
-
|
|
32384
|
-
|
|
32385
|
-
|
|
32386
|
-
|
|
32387
|
-
|
|
32388
|
-
|
|
32389
|
-
|
|
32390
|
-
|
|
32514
|
+
base.agent = agent;
|
|
32515
|
+
if (model) {
|
|
32516
|
+
const withModel = { ...base, model };
|
|
32517
|
+
if (variant)
|
|
32518
|
+
withModel.variant = variant;
|
|
32519
|
+
try {
|
|
32520
|
+
await send(withModel);
|
|
32521
|
+
return;
|
|
32522
|
+
} catch {}
|
|
32391
32523
|
}
|
|
32392
|
-
|
|
32524
|
+
await send(base);
|
|
32393
32525
|
}
|
|
32394
32526
|
|
|
32395
32527
|
// src/shared/rpc-notifications.ts
|
|
@@ -33434,12 +33566,15 @@ async function callBashBridge(ctx, runtime, command, params = {}, options) {
|
|
|
33434
33566
|
}
|
|
33435
33567
|
|
|
33436
33568
|
// src/tools/permissions.ts
|
|
33569
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
33437
33570
|
import * as fs4 from "node:fs";
|
|
33438
33571
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
33439
33572
|
import * as path4 from "node:path";
|
|
33440
33573
|
var UNSUPPORTED_ASK_HOST = "AFT requires OpenCode 1.15.5 or newer for permission asks; please upgrade OpenCode";
|
|
33441
33574
|
var RESTRICT_NOTICE_THROTTLE_MS = 5 * 60 * 1000;
|
|
33442
33575
|
var restrictNoticeLastSentAt = new Map;
|
|
33576
|
+
var aftSearchExternalDecisionCache = new Map;
|
|
33577
|
+
var aftSearchExternalPendingAsks = new Map;
|
|
33443
33578
|
var POSIX_SYSTEM_TEMP_ROOTS = ["/tmp", "/var/tmp", "/private/tmp", "/private/var/tmp"];
|
|
33444
33579
|
var MACOS_SYSTEM_TEMP_ROOTS = ["/var/folders", "/private/var/folders"];
|
|
33445
33580
|
function restrictNoticeWording(target) {
|
|
@@ -33610,6 +33745,78 @@ async function assertExternalDirectoryPermission(ctx, context, target, options)
|
|
|
33610
33745
|
return "Permission denied (external directory).";
|
|
33611
33746
|
}
|
|
33612
33747
|
}
|
|
33748
|
+
function gitRootForNearestExistingParent(resolved) {
|
|
33749
|
+
const nearest = normalizeNearestExistingParent(resolved);
|
|
33750
|
+
let cwd = nearest;
|
|
33751
|
+
try {
|
|
33752
|
+
if (fs4.statSync(nearest).isFile())
|
|
33753
|
+
cwd = path4.dirname(nearest);
|
|
33754
|
+
} catch {}
|
|
33755
|
+
try {
|
|
33756
|
+
const out = execFileSync3("git", ["rev-parse", "--show-toplevel"], {
|
|
33757
|
+
cwd,
|
|
33758
|
+
encoding: "utf8",
|
|
33759
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
33760
|
+
}).trim();
|
|
33761
|
+
return out ? normalizePath(out) : undefined;
|
|
33762
|
+
} catch {
|
|
33763
|
+
return;
|
|
33764
|
+
}
|
|
33765
|
+
}
|
|
33766
|
+
async function assertAftSearchExternalPermission(ctx, context, target) {
|
|
33767
|
+
if (!target)
|
|
33768
|
+
return;
|
|
33769
|
+
const resolved = resolveAbsolutePath(context, target);
|
|
33770
|
+
const absoluteTarget = normalizePath(resolved);
|
|
33771
|
+
const externalRoot = gitRootForNearestExistingParent(resolved) ?? normalizeNearestExistingParent(resolved);
|
|
33772
|
+
const root = projectRootFor(context);
|
|
33773
|
+
const directory = root ? normalizePath(root) : root;
|
|
33774
|
+
const rawWorktree = context.worktree;
|
|
33775
|
+
const worktree = rawWorktree && rawWorktree !== "/" ? normalizePath(rawWorktree) : rawWorktree;
|
|
33776
|
+
if (directory && containsPath(directory, externalRoot))
|
|
33777
|
+
return;
|
|
33778
|
+
if (worktree && worktree !== "/" && worktree !== directory && containsPath(worktree, externalRoot)) {
|
|
33779
|
+
return;
|
|
33780
|
+
}
|
|
33781
|
+
if (ctx.config.restrict_to_project_root === true) {
|
|
33782
|
+
notifyRestrictBlocked(ctx, context, externalRoot);
|
|
33783
|
+
return restrictDenialMessage(externalRoot);
|
|
33784
|
+
}
|
|
33785
|
+
if (typeof context.ask !== "function")
|
|
33786
|
+
return UNSUPPORTED_ASK_HOST;
|
|
33787
|
+
const sessionKey = context.sessionID ?? "unknown-session";
|
|
33788
|
+
const cacheKey = `${sessionKey}\x00${externalRoot}`;
|
|
33789
|
+
if (aftSearchExternalDecisionCache.has(cacheKey)) {
|
|
33790
|
+
return aftSearchExternalDecisionCache.get(cacheKey);
|
|
33791
|
+
}
|
|
33792
|
+
const pending = aftSearchExternalPendingAsks.get(cacheKey);
|
|
33793
|
+
if (pending)
|
|
33794
|
+
return pending;
|
|
33795
|
+
const rawGlob = process.platform === "win32" ? normalizePathPattern(path4.join(externalRoot, "*")) : path4.join(externalRoot, "*").replaceAll("\\", "/");
|
|
33796
|
+
const askPromise = (async () => {
|
|
33797
|
+
try {
|
|
33798
|
+
await runAsk(context.ask({
|
|
33799
|
+
permission: "aft_search_external",
|
|
33800
|
+
patterns: [rawGlob],
|
|
33801
|
+
always: [rawGlob],
|
|
33802
|
+
metadata: {
|
|
33803
|
+
filepath: absoluteTarget,
|
|
33804
|
+
root: externalRoot
|
|
33805
|
+
}
|
|
33806
|
+
}));
|
|
33807
|
+
aftSearchExternalDecisionCache.set(cacheKey, undefined);
|
|
33808
|
+
return;
|
|
33809
|
+
} catch (error53) {
|
|
33810
|
+
const message = error53 instanceof Error && error53.message ? error53.message : "Permission denied (aft_search_external).";
|
|
33811
|
+
aftSearchExternalDecisionCache.set(cacheKey, message);
|
|
33812
|
+
return message;
|
|
33813
|
+
} finally {
|
|
33814
|
+
aftSearchExternalPendingAsks.delete(cacheKey);
|
|
33815
|
+
}
|
|
33816
|
+
})();
|
|
33817
|
+
aftSearchExternalPendingAsks.set(cacheKey, askPromise);
|
|
33818
|
+
return askPromise;
|
|
33819
|
+
}
|
|
33613
33820
|
async function askSearchPatternPermission(context, permission, pattern, metadata = {}) {
|
|
33614
33821
|
if (typeof context.ask !== "function")
|
|
33615
33822
|
return UNSUPPORTED_ASK_HOST;
|
|
@@ -34882,6 +35089,7 @@ function createWriteTool(ctx, editToolName = "edit") {
|
|
|
34882
35089
|
const diff = data.diff;
|
|
34883
35090
|
if (!diff)
|
|
34884
35091
|
return output;
|
|
35092
|
+
const truncated = diff.truncated === true;
|
|
34885
35093
|
const dp = relativeToWorktree(filePath, projectRoot);
|
|
34886
35094
|
const beforeContent = diff.before ?? "";
|
|
34887
35095
|
const afterContent = diff.after ?? content;
|
|
@@ -34889,13 +35097,15 @@ function createWriteTool(ctx, editToolName = "edit") {
|
|
|
34889
35097
|
output,
|
|
34890
35098
|
title: dp,
|
|
34891
35099
|
metadata: {
|
|
34892
|
-
diff: buildUnifiedDiff(filePath, beforeContent, afterContent),
|
|
34893
|
-
|
|
34894
|
-
|
|
34895
|
-
|
|
34896
|
-
|
|
34897
|
-
|
|
34898
|
-
|
|
35100
|
+
diff: truncated ? typeof preview2.preview_diff === "string" ? preview2.preview_diff : "" : buildUnifiedDiff(filePath, beforeContent, afterContent),
|
|
35101
|
+
...truncated ? {} : {
|
|
35102
|
+
filediff: {
|
|
35103
|
+
file: filePath,
|
|
35104
|
+
before: beforeContent,
|
|
35105
|
+
after: afterContent,
|
|
35106
|
+
additions: diff?.additions ?? 0,
|
|
35107
|
+
deletions: diff?.deletions ?? 0
|
|
35108
|
+
}
|
|
34899
35109
|
},
|
|
34900
35110
|
diagnostics: {}
|
|
34901
35111
|
}
|
|
@@ -35016,16 +35226,19 @@ function createEditTool(ctx, writeToolName = "write") {
|
|
|
35016
35226
|
const diff = data.diff;
|
|
35017
35227
|
if (!diff)
|
|
35018
35228
|
return output;
|
|
35229
|
+
const truncated = diff.truncated === true;
|
|
35019
35230
|
const beforeContent = diff.before ?? "";
|
|
35020
35231
|
const afterContent = diff.after ?? "";
|
|
35021
35232
|
const uiMeta = {
|
|
35022
|
-
diff: buildUnifiedDiff(filePath, beforeContent, afterContent),
|
|
35023
|
-
|
|
35024
|
-
|
|
35025
|
-
|
|
35026
|
-
|
|
35027
|
-
|
|
35028
|
-
|
|
35233
|
+
diff: truncated ? typeof preview2.preview_diff === "string" ? preview2.preview_diff : "" : buildUnifiedDiff(filePath, beforeContent, afterContent),
|
|
35234
|
+
...truncated ? {} : {
|
|
35235
|
+
filediff: {
|
|
35236
|
+
file: filePath,
|
|
35237
|
+
before: beforeContent,
|
|
35238
|
+
after: afterContent,
|
|
35239
|
+
additions: diff.additions ?? 0,
|
|
35240
|
+
deletions: diff.deletions ?? 0
|
|
35241
|
+
}
|
|
35029
35242
|
},
|
|
35030
35243
|
diagnostics: {}
|
|
35031
35244
|
};
|
|
@@ -36283,7 +36496,8 @@ function semanticTools(ctx) {
|
|
|
36283
36496
|
query: arg3(z15.string().describe("Concept, regex, literal text, filename, or capability to find. Examples: 'fuzzy match with whitespace tolerance', '^export', 'Cargo.lock'.")),
|
|
36284
36497
|
topK: arg3(optionalInt(1, 100).describe("Number of results (default: 10, max: 100)")),
|
|
36285
36498
|
hint: arg3(z15.enum(["regex", "literal", "semantic", "auto"]).optional().describe("Optional routing hint. Defaults to 'auto'.")),
|
|
36286
|
-
includeTests: arg3(z15.boolean().optional().describe("Include test files (*.test.*, *_test.rs, __tests__/, …) plus test-support, fixture, mock, snapshot, and corpus files. Defaults to false."))
|
|
36499
|
+
includeTests: arg3(z15.boolean().optional().describe("Include test files (*.test.*, *_test.rs, __tests__/, …) plus test-support, fixture, mock, snapshot, and corpus files. Defaults to false.")),
|
|
36500
|
+
path: arg3(z15.string().optional().describe("Search a different project root (absolute or ~ path). Requires that project to have been indexed by AFT."))
|
|
36287
36501
|
},
|
|
36288
36502
|
execute: async (args, context) => {
|
|
36289
36503
|
if (isEmptyParam(args.query) || typeof args.query !== "string" || args.query.trim().length === 0) {
|
|
@@ -36291,11 +36505,17 @@ function semanticTools(ctx) {
|
|
|
36291
36505
|
}
|
|
36292
36506
|
const query = args.query;
|
|
36293
36507
|
const hint = typeof args.hint === "string" ? args.hint : undefined;
|
|
36508
|
+
const pathArg = typeof args.path === "string" && args.path.trim() ? args.path.trim() : undefined;
|
|
36294
36509
|
if (hint !== "semantic") {
|
|
36295
36510
|
const denied = await askSearchPermission(context, query);
|
|
36296
36511
|
if (denied)
|
|
36297
36512
|
return permissionDeniedResponse(denied);
|
|
36298
36513
|
}
|
|
36514
|
+
if (pathArg) {
|
|
36515
|
+
const denied = await assertAftSearchExternalPermission(ctx, context, pathArg);
|
|
36516
|
+
if (denied)
|
|
36517
|
+
return permissionDeniedResponse(denied);
|
|
36518
|
+
}
|
|
36299
36519
|
const rawArgs = { query };
|
|
36300
36520
|
const topK = coerceOptionalInt(args.topK, "topK", 1, 100);
|
|
36301
36521
|
if (topK !== undefined)
|
|
@@ -36304,6 +36524,8 @@ function semanticTools(ctx) {
|
|
|
36304
36524
|
rawArgs.hint = hint;
|
|
36305
36525
|
if (typeof args.includeTests === "boolean")
|
|
36306
36526
|
rawArgs.includeTests = args.includeTests;
|
|
36527
|
+
if (pathArg)
|
|
36528
|
+
rawArgs.path = pathArg;
|
|
36307
36529
|
const response = await callToolCall(ctx, context, "search", rawArgs);
|
|
36308
36530
|
if (response.success === false) {
|
|
36309
36531
|
const message = typeof response.text === "string" && response.text.length > 0 ? response.text : typeof response.message === "string" && response.message.length > 0 ? response.message : "semantic_search failed";
|
|
@@ -36431,13 +36653,13 @@ var PLUGIN_VERSION = (() => {
|
|
|
36431
36653
|
return "0.0.0";
|
|
36432
36654
|
}
|
|
36433
36655
|
})();
|
|
36434
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
36656
|
+
var ANNOUNCEMENT_VERSION = "0.46.0";
|
|
36435
36657
|
var ANNOUNCEMENT_FEATURES = [
|
|
36436
|
-
"
|
|
36437
|
-
"
|
|
36438
|
-
"
|
|
36439
|
-
"
|
|
36440
|
-
"
|
|
36658
|
+
"TUI sidebar fixed on OpenCode 1.17.x: the panel is precompiled against the host runtime (no more import failures or frozen values), and it now works when the TUI is attached to a serve/Desktop host from another directory.",
|
|
36659
|
+
"Search index changes persist on clean shutdown, so restarts and cross-worktree searches see current results.",
|
|
36660
|
+
"Cross-project search: sessions can search sibling checkouts read-only, serving borrowed indexes with drift warnings instead of failing.",
|
|
36661
|
+
"Duplicate detection requires a 10-line minimum span, ending flags on 3-4 line idiomatic blocks.",
|
|
36662
|
+
"Pi edit tool supports batch edits[] arrays, matching OpenCode."
|
|
36441
36663
|
];
|
|
36442
36664
|
var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/DSa65w8wuf";
|
|
36443
36665
|
var plugin = async (input) => initializePluginForDirectory(input);
|
|
@@ -36755,6 +36977,7 @@ ${lines}
|
|
|
36755
36977
|
return {
|
|
36756
36978
|
success: true,
|
|
36757
36979
|
status: "not_initialized",
|
|
36980
|
+
verified_directory: verifiedDir,
|
|
36758
36981
|
message: "AFT bridge is now spawned lazily, information here will be populated after first tool call."
|
|
36759
36982
|
};
|
|
36760
36983
|
}
|
|
@@ -36767,6 +36990,7 @@ ${lines}
|
|
|
36767
36990
|
return {
|
|
36768
36991
|
success: true,
|
|
36769
36992
|
status: "not_initialized",
|
|
36993
|
+
...verifiedDir ? { verified_directory: verifiedDir } : {},
|
|
36770
36994
|
message: "AFT bridge is now spawned lazily, information here will be populated after first tool call."
|
|
36771
36995
|
};
|
|
36772
36996
|
}
|