@cortexkit/aft-opencode 0.45.0 → 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 -22
- package/dist/config.d.ts.map +1 -1
- package/dist/hooks/auto-update-checker/types.d.ts +0 -3
- package/dist/hooks/auto-update-checker/types.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +347 -127
- package/dist/lsp-github-table.d.ts +0 -8
- package/dist/lsp-github-table.d.ts.map +1 -1
- package/dist/notifications.d.ts +2 -9
- package/dist/notifications.d.ts.map +1 -1
- 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/_shared.d.ts +0 -7
- package/dist/tools/_shared.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
|
-
}
|
|
13344
|
-
throw err;
|
|
13345
|
-
}
|
|
13346
|
-
try {
|
|
13347
|
-
const reply = await client.request(channel, body, { timeoutMs, onProgress });
|
|
13348
|
-
if (this.isCurrentSession(key, record) && this.client === client) {
|
|
13349
|
-
this.transportFailures = 0;
|
|
13350
13456
|
}
|
|
13351
|
-
|
|
13352
|
-
|
|
13353
|
-
|
|
13354
|
-
|
|
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 {
|
|
@@ -28810,9 +28942,6 @@ var LspServerEntrySchema = exports_external.object({
|
|
|
28810
28942
|
env: exports_external.record(exports_external.string().min(1), exports_external.string()).optional(),
|
|
28811
28943
|
initialization_options: exports_external.unknown().optional()
|
|
28812
28944
|
});
|
|
28813
|
-
var LspServerSchema = LspServerEntrySchema.extend({
|
|
28814
|
-
id: exports_external.string().trim().min(1)
|
|
28815
|
-
});
|
|
28816
28945
|
var LspConfigSchema = exports_external.object({
|
|
28817
28946
|
servers: exports_external.record(exports_external.string().trim().min(1), LspServerEntrySchema).optional(),
|
|
28818
28947
|
disabled: exports_external.array(exports_external.string().trim().min(1)).optional(),
|
|
@@ -28856,16 +28985,7 @@ var InspectConfigSchema = exports_external.object({
|
|
|
28856
28985
|
tier2_soft_deadline_ms: exports_external.number().int().positive().optional(),
|
|
28857
28986
|
max_drill_down_items: exports_external.number().int().positive().max(100).optional(),
|
|
28858
28987
|
duplicates: exports_external.object({
|
|
28859
|
-
|
|
28860
|
-
discard_cost: exports_external.number().int().min(0).optional(),
|
|
28861
|
-
expected_mirrors: exports_external.array(exports_external.tuple([exports_external.string().trim().min(1), exports_external.string().trim().min(1)])).optional(),
|
|
28862
|
-
anonymize: exports_external.object({
|
|
28863
|
-
variables: exports_external.boolean().optional(),
|
|
28864
|
-
fields: exports_external.boolean().optional(),
|
|
28865
|
-
methods: exports_external.boolean().optional(),
|
|
28866
|
-
types: exports_external.boolean().optional(),
|
|
28867
|
-
literals: exports_external.boolean().optional()
|
|
28868
|
-
}).optional()
|
|
28988
|
+
expected_mirrors: exports_external.array(exports_external.tuple([exports_external.string().trim().min(1), exports_external.string().trim().min(1)])).optional()
|
|
28869
28989
|
}).optional()
|
|
28870
28990
|
});
|
|
28871
28991
|
var BackupConfigSchema = exports_external.object({
|
|
@@ -29217,16 +29337,9 @@ function mergeInspectConfig(baseInspect, overrideInspect) {
|
|
|
29217
29337
|
...overrideInspect,
|
|
29218
29338
|
duplicates: baseInspect?.duplicates || overrideInspect?.duplicates ? {
|
|
29219
29339
|
...baseInspect?.duplicates,
|
|
29220
|
-
...overrideInspect?.duplicates
|
|
29221
|
-
anonymize: baseInspect?.duplicates?.anonymize || overrideInspect?.duplicates?.anonymize ? {
|
|
29222
|
-
...baseInspect?.duplicates?.anonymize,
|
|
29223
|
-
...overrideInspect?.duplicates?.anonymize
|
|
29224
|
-
} : undefined
|
|
29340
|
+
...overrideInspect?.duplicates
|
|
29225
29341
|
} : undefined
|
|
29226
29342
|
};
|
|
29227
|
-
if (inspect.duplicates && inspect.duplicates.anonymize === undefined) {
|
|
29228
|
-
delete inspect.duplicates.anonymize;
|
|
29229
|
-
}
|
|
29230
29343
|
if (Object.values(inspect).every((value) => value === undefined)) {
|
|
29231
29344
|
return;
|
|
29232
29345
|
}
|
|
@@ -29441,7 +29554,6 @@ async function showTuiToast(client, title, message, variant = "info", duration3
|
|
|
29441
29554
|
var AFT_MARKER = "\uD83D\uDD27 AFT:";
|
|
29442
29555
|
var FEATURE_MARKER = `${AFT_MARKER} New in`;
|
|
29443
29556
|
var WARNING_MARKER = `${AFT_MARKER} ⚠️`;
|
|
29444
|
-
var STATUS_MARKER = `${AFT_MARKER} ✅`;
|
|
29445
29557
|
function getDesktopStatePath() {
|
|
29446
29558
|
const os3 = platform();
|
|
29447
29559
|
const home = homedir9();
|
|
@@ -32372,28 +32484,44 @@ function normalizeToolMap(tools) {
|
|
|
32372
32484
|
async function sendIgnoredMessage2(client, sessionID, text) {
|
|
32373
32485
|
const typedClient = client;
|
|
32374
32486
|
let agent;
|
|
32487
|
+
let model;
|
|
32488
|
+
let variant;
|
|
32375
32489
|
try {
|
|
32376
32490
|
const ctx = await resolvePromptContext(client, sessionID);
|
|
32377
32491
|
agent = ctx?.agent;
|
|
32492
|
+
model = ctx?.model;
|
|
32493
|
+
variant = ctx?.variant;
|
|
32378
32494
|
} catch {
|
|
32379
32495
|
agent = undefined;
|
|
32380
32496
|
}
|
|
32381
|
-
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 = {
|
|
32382
32510
|
noReply: true,
|
|
32383
32511
|
parts: [{ type: "text", text, ignored: true }]
|
|
32384
32512
|
};
|
|
32385
32513
|
if (agent)
|
|
32386
|
-
|
|
32387
|
-
|
|
32388
|
-
|
|
32389
|
-
|
|
32390
|
-
|
|
32391
|
-
|
|
32392
|
-
|
|
32393
|
-
|
|
32394
|
-
|
|
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 {}
|
|
32395
32523
|
}
|
|
32396
|
-
|
|
32524
|
+
await send(base);
|
|
32397
32525
|
}
|
|
32398
32526
|
|
|
32399
32527
|
// src/shared/rpc-notifications.ts
|
|
@@ -33438,12 +33566,15 @@ async function callBashBridge(ctx, runtime, command, params = {}, options) {
|
|
|
33438
33566
|
}
|
|
33439
33567
|
|
|
33440
33568
|
// src/tools/permissions.ts
|
|
33569
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
33441
33570
|
import * as fs4 from "node:fs";
|
|
33442
33571
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
33443
33572
|
import * as path4 from "node:path";
|
|
33444
33573
|
var UNSUPPORTED_ASK_HOST = "AFT requires OpenCode 1.15.5 or newer for permission asks; please upgrade OpenCode";
|
|
33445
33574
|
var RESTRICT_NOTICE_THROTTLE_MS = 5 * 60 * 1000;
|
|
33446
33575
|
var restrictNoticeLastSentAt = new Map;
|
|
33576
|
+
var aftSearchExternalDecisionCache = new Map;
|
|
33577
|
+
var aftSearchExternalPendingAsks = new Map;
|
|
33447
33578
|
var POSIX_SYSTEM_TEMP_ROOTS = ["/tmp", "/var/tmp", "/private/tmp", "/private/var/tmp"];
|
|
33448
33579
|
var MACOS_SYSTEM_TEMP_ROOTS = ["/var/folders", "/private/var/folders"];
|
|
33449
33580
|
function restrictNoticeWording(target) {
|
|
@@ -33614,6 +33745,78 @@ async function assertExternalDirectoryPermission(ctx, context, target, options)
|
|
|
33614
33745
|
return "Permission denied (external directory).";
|
|
33615
33746
|
}
|
|
33616
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
|
+
}
|
|
33617
33820
|
async function askSearchPatternPermission(context, permission, pattern, metadata = {}) {
|
|
33618
33821
|
if (typeof context.ask !== "function")
|
|
33619
33822
|
return UNSUPPORTED_ASK_HOST;
|
|
@@ -34886,6 +35089,7 @@ function createWriteTool(ctx, editToolName = "edit") {
|
|
|
34886
35089
|
const diff = data.diff;
|
|
34887
35090
|
if (!diff)
|
|
34888
35091
|
return output;
|
|
35092
|
+
const truncated = diff.truncated === true;
|
|
34889
35093
|
const dp = relativeToWorktree(filePath, projectRoot);
|
|
34890
35094
|
const beforeContent = diff.before ?? "";
|
|
34891
35095
|
const afterContent = diff.after ?? content;
|
|
@@ -34893,13 +35097,15 @@ function createWriteTool(ctx, editToolName = "edit") {
|
|
|
34893
35097
|
output,
|
|
34894
35098
|
title: dp,
|
|
34895
35099
|
metadata: {
|
|
34896
|
-
diff: buildUnifiedDiff(filePath, beforeContent, afterContent),
|
|
34897
|
-
|
|
34898
|
-
|
|
34899
|
-
|
|
34900
|
-
|
|
34901
|
-
|
|
34902
|
-
|
|
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
|
+
}
|
|
34903
35109
|
},
|
|
34904
35110
|
diagnostics: {}
|
|
34905
35111
|
}
|
|
@@ -35020,16 +35226,19 @@ function createEditTool(ctx, writeToolName = "write") {
|
|
|
35020
35226
|
const diff = data.diff;
|
|
35021
35227
|
if (!diff)
|
|
35022
35228
|
return output;
|
|
35229
|
+
const truncated = diff.truncated === true;
|
|
35023
35230
|
const beforeContent = diff.before ?? "";
|
|
35024
35231
|
const afterContent = diff.after ?? "";
|
|
35025
35232
|
const uiMeta = {
|
|
35026
|
-
diff: buildUnifiedDiff(filePath, beforeContent, afterContent),
|
|
35027
|
-
|
|
35028
|
-
|
|
35029
|
-
|
|
35030
|
-
|
|
35031
|
-
|
|
35032
|
-
|
|
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
|
+
}
|
|
35033
35242
|
},
|
|
35034
35243
|
diagnostics: {}
|
|
35035
35244
|
};
|
|
@@ -36287,7 +36496,8 @@ function semanticTools(ctx) {
|
|
|
36287
36496
|
query: arg3(z15.string().describe("Concept, regex, literal text, filename, or capability to find. Examples: 'fuzzy match with whitespace tolerance', '^export', 'Cargo.lock'.")),
|
|
36288
36497
|
topK: arg3(optionalInt(1, 100).describe("Number of results (default: 10, max: 100)")),
|
|
36289
36498
|
hint: arg3(z15.enum(["regex", "literal", "semantic", "auto"]).optional().describe("Optional routing hint. Defaults to 'auto'.")),
|
|
36290
|
-
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."))
|
|
36291
36501
|
},
|
|
36292
36502
|
execute: async (args, context) => {
|
|
36293
36503
|
if (isEmptyParam(args.query) || typeof args.query !== "string" || args.query.trim().length === 0) {
|
|
@@ -36295,11 +36505,17 @@ function semanticTools(ctx) {
|
|
|
36295
36505
|
}
|
|
36296
36506
|
const query = args.query;
|
|
36297
36507
|
const hint = typeof args.hint === "string" ? args.hint : undefined;
|
|
36508
|
+
const pathArg = typeof args.path === "string" && args.path.trim() ? args.path.trim() : undefined;
|
|
36298
36509
|
if (hint !== "semantic") {
|
|
36299
36510
|
const denied = await askSearchPermission(context, query);
|
|
36300
36511
|
if (denied)
|
|
36301
36512
|
return permissionDeniedResponse(denied);
|
|
36302
36513
|
}
|
|
36514
|
+
if (pathArg) {
|
|
36515
|
+
const denied = await assertAftSearchExternalPermission(ctx, context, pathArg);
|
|
36516
|
+
if (denied)
|
|
36517
|
+
return permissionDeniedResponse(denied);
|
|
36518
|
+
}
|
|
36303
36519
|
const rawArgs = { query };
|
|
36304
36520
|
const topK = coerceOptionalInt(args.topK, "topK", 1, 100);
|
|
36305
36521
|
if (topK !== undefined)
|
|
@@ -36308,6 +36524,8 @@ function semanticTools(ctx) {
|
|
|
36308
36524
|
rawArgs.hint = hint;
|
|
36309
36525
|
if (typeof args.includeTests === "boolean")
|
|
36310
36526
|
rawArgs.includeTests = args.includeTests;
|
|
36527
|
+
if (pathArg)
|
|
36528
|
+
rawArgs.path = pathArg;
|
|
36311
36529
|
const response = await callToolCall(ctx, context, "search", rawArgs);
|
|
36312
36530
|
if (response.success === false) {
|
|
36313
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";
|
|
@@ -36435,13 +36653,13 @@ var PLUGIN_VERSION = (() => {
|
|
|
36435
36653
|
return "0.0.0";
|
|
36436
36654
|
}
|
|
36437
36655
|
})();
|
|
36438
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
36656
|
+
var ANNOUNCEMENT_VERSION = "0.46.0";
|
|
36439
36657
|
var ANNOUNCEMENT_FEATURES = [
|
|
36440
|
-
"
|
|
36441
|
-
"
|
|
36442
|
-
"
|
|
36443
|
-
"
|
|
36444
|
-
"
|
|
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."
|
|
36445
36663
|
];
|
|
36446
36664
|
var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/DSa65w8wuf";
|
|
36447
36665
|
var plugin = async (input) => initializePluginForDirectory(input);
|
|
@@ -36759,6 +36977,7 @@ ${lines}
|
|
|
36759
36977
|
return {
|
|
36760
36978
|
success: true,
|
|
36761
36979
|
status: "not_initialized",
|
|
36980
|
+
verified_directory: verifiedDir,
|
|
36762
36981
|
message: "AFT bridge is now spawned lazily, information here will be populated after first tool call."
|
|
36763
36982
|
};
|
|
36764
36983
|
}
|
|
@@ -36771,6 +36990,7 @@ ${lines}
|
|
|
36771
36990
|
return {
|
|
36772
36991
|
success: true,
|
|
36773
36992
|
status: "not_initialized",
|
|
36993
|
+
...verifiedDir ? { verified_directory: verifiedDir } : {},
|
|
36774
36994
|
message: "AFT bridge is now spawned lazily, information here will be populated after first tool call."
|
|
36775
36995
|
};
|
|
36776
36996
|
}
|