@cortexkit/aft-opencode 0.36.0 → 0.37.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/bg-notifications.d.ts +5 -1
- package/dist/bg-notifications.d.ts.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1594 -1159
- package/dist/shared/rpc-client.d.ts +13 -0
- package/dist/shared/rpc-client.d.ts.map +1 -1
- package/dist/shared/rpc-server.d.ts +7 -0
- package/dist/shared/rpc-server.d.ts.map +1 -1
- package/dist/shared/rpc-utils.d.ts +23 -0
- package/dist/shared/rpc-utils.d.ts.map +1 -1
- package/dist/shared/session-directory.d.ts +1 -0
- package/dist/shared/session-directory.d.ts.map +1 -1
- package/dist/status-bar-inject.d.ts +1 -1
- package/dist/status-bar-inject.d.ts.map +1 -1
- package/dist/tool-perf.d.ts +17 -0
- package/dist/tool-perf.d.ts.map +1 -0
- package/dist/tools/_shared.d.ts +1 -11
- package/dist/tools/_shared.d.ts.map +1 -1
- package/dist/tools/bash.d.ts +21 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/conflicts.d.ts.map +1 -1
- package/dist/tools/hoisted.d.ts.map +1 -1
- package/dist/tools/reading.d.ts.map +1 -1
- package/dist/tools/refactoring.d.ts.map +1 -1
- package/dist/tools/safety.d.ts.map +1 -1
- package/dist/tools/semantic.d.ts.map +1 -1
- package/dist/tui.js +118 -95
- package/dist/workflow-hints.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/shared/rpc-client.ts +79 -26
- package/src/shared/rpc-server.ts +64 -6
- package/src/shared/rpc-utils.ts +62 -0
- package/src/shared/session-directory.ts +56 -0
- package/src/tui/index.tsx +26 -2
- package/src/tui/sidebar.tsx +64 -1
- package/dist/metadata-store.d.ts +0 -29
- package/dist/metadata-store.d.ts.map +0 -1
- package/dist/tools/structure.d.ts +0 -8
- package/dist/tools/structure.d.ts.map +0 -1
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
export interface AftRpcCallOptions {
|
|
2
2
|
signal?: AbortSignal;
|
|
3
|
+
/**
|
|
4
|
+
* Optional gate over WARM (non-placeholder) responses. With multiple RPC
|
|
5
|
+
* servers alive for one project hash (multi-project hosts, stale long-lived
|
|
6
|
+
* processes), a warm response can describe ANOTHER project's bridge
|
|
7
|
+
* (cross-project contamination). Return false to skip that response and
|
|
8
|
+
* keep trying other ports instead of returning it — so a stray server can't
|
|
9
|
+
* mask the right one. Skipped responses are never cached as the good port
|
|
10
|
+
* and never returned; if only strays and placeholders answer, the
|
|
11
|
+
* placeholder wins.
|
|
12
|
+
*/
|
|
13
|
+
accept?: (result: unknown) => boolean;
|
|
3
14
|
}
|
|
4
15
|
export declare class AftRpcClient {
|
|
5
16
|
private port;
|
|
@@ -26,6 +37,8 @@ export declare class AftRpcClient {
|
|
|
26
37
|
*/
|
|
27
38
|
private resolvePortInfos;
|
|
28
39
|
private readAllPortFiles;
|
|
40
|
+
/** Delete a port file whose owning process is provably dead (best-effort). */
|
|
41
|
+
private reclaimDeadPortFile;
|
|
29
42
|
private parsePortFile;
|
|
30
43
|
private portFailureKey;
|
|
31
44
|
private clearPortFailure;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-client.d.ts","sourceRoot":"","sources":["../../src/shared/rpc-client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rpc-client.d.ts","sourceRoot":"","sources":["../../src/shared/rpc-client.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;CACvC;AA4BD,qBAAa,YAAY;IACvB,OAAO,CAAC,IAAI,CAAuB;IACnC,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,iBAAiB,CAA6B;gBAE1C,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAKjD,iFAAiF;IAC3E,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,CAAC,CAAC;YA8CC,OAAO;IAsBrB;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAM5B,4CAA4C;IACtC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IASrC;;;;OAIG;YACW,gBAAgB;IAwB9B,OAAO,CAAC,gBAAgB;IAwDxB,8EAA8E;IAC9E,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,iBAAiB;YAsBX,WAAW;YAkCX,gBAAgB;IAmB9B,KAAK,IAAI,IAAI;CAKd"}
|
|
@@ -13,6 +13,13 @@ export declare class AftRpcServer {
|
|
|
13
13
|
handle(method: string, handler: RpcHandler): void;
|
|
14
14
|
/** Start the server on a random port, write port to disk. */
|
|
15
15
|
start(): Promise<number>;
|
|
16
|
+
/**
|
|
17
|
+
* Remove sibling port files whose owning process is provably dead.
|
|
18
|
+
* Only files with a recorded pid that no longer maps to a live process are
|
|
19
|
+
* removed; pid-less (legacy) files and live entries are left untouched.
|
|
20
|
+
* Never touches our own freshly written file.
|
|
21
|
+
*/
|
|
22
|
+
private sweepDeadPortFiles;
|
|
16
23
|
/** Stop the server and clean up port file. */
|
|
17
24
|
stop(): void;
|
|
18
25
|
private dispatch;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-server.d.ts","sourceRoot":"","sources":["../../src/shared/rpc-server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rpc-server.d.ts","sourceRoot":"","sources":["../../src/shared/rpc-server.ts"],"names":[],"mappings":"AAcA,KAAK,UAAU,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAExF,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAS;IACzB,oFAAoF;IACpF,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAMjD,sCAAsC;IACtC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI;IAIjD,6DAA6D;IACvD,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IA0D9B;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IA6B1B,8CAA8C;IAC9C,IAAI,IAAI,IAAI;IAaZ,OAAO,CAAC,QAAQ;CAoEjB"}
|
|
@@ -26,4 +26,27 @@ export declare function rpcPortFilePath(storageDir: string, directory: string):
|
|
|
26
26
|
* last-write-wins racing under `--port 0`).
|
|
27
27
|
*/
|
|
28
28
|
export declare function rpcPortFileDir(storageDir: string, directory: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Contents of a per-instance RPC port file. `pid` + `started_at` let the client
|
|
31
|
+
* skip files whose owning process is dead (no health-check round-trip) and pick
|
|
32
|
+
* the freshest live server, instead of wading through every crash/restart
|
|
33
|
+
* leftover. Older files carry only `{ port, token }` (no pid); those are treated
|
|
34
|
+
* as "can't prove dead" and fall back to the health-check path.
|
|
35
|
+
*/
|
|
36
|
+
export interface RpcPortRecord {
|
|
37
|
+
port: number;
|
|
38
|
+
token: string | null;
|
|
39
|
+
/** PID of the plugin process that owns this server, if recorded. */
|
|
40
|
+
pid?: number;
|
|
41
|
+
/** `Date.now()` when this server started, for newest-first ordering. */
|
|
42
|
+
started_at?: number;
|
|
43
|
+
}
|
|
44
|
+
/** True if `pid` names a live process. `process.kill(pid, 0)` sends no signal. */
|
|
45
|
+
export declare function isPidAlive(pid: number | undefined): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Parse a port file's contents into a record. Accepts the current JSON shape
|
|
48
|
+
* (`{ port, token, pid?, started_at? }`) and the legacy bare-integer format
|
|
49
|
+
* (unauthenticated, pre-v0.28.2). Returns `null` for unusable contents.
|
|
50
|
+
*/
|
|
51
|
+
export declare function parseRpcPortRecord(content: string): RpcPortRecord | null;
|
|
29
52
|
//# sourceMappingURL=rpc-utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-utils.d.ts","sourceRoot":"","sources":["../../src/shared/rpc-utils.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAIrD;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAG7E;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAG5E"}
|
|
1
|
+
{"version":3,"file":"rpc-utils.d.ts","sourceRoot":"","sources":["../../src/shared/rpc-utils.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAIrD;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAG7E;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAG5E;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,oEAAoE;IACpE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAS3D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CA2BxE"}
|
|
@@ -28,6 +28,7 @@ export declare function getSessionDirectoryCached(sessionId: string | undefined)
|
|
|
28
28
|
* will return the resolved directory once the lookup completes.
|
|
29
29
|
*/
|
|
30
30
|
export declare function warmSessionDirectory(client: unknown, sessionId: string | undefined, fallbackDirectory: string): void;
|
|
31
|
+
export declare function verifySessionDirectory(client: unknown, sessionId: string): Promise<string | null>;
|
|
31
32
|
/** Test-only: clear the cache between unit tests. */
|
|
32
33
|
export declare function _resetSessionDirectoryCacheForTest(): void;
|
|
33
34
|
//# sourceMappingURL=session-directory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-directory.d.ts","sourceRoot":"","sources":["../../src/shared/session-directory.ts"],"names":[],"mappings":"AA+CA;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA8CxB;AAWD;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,MAAM,GAAG,IAAI,GAAG,SAAS,CAK3B;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,iBAAiB,EAAE,MAAM,GACxB,IAAI,CAIN;AAED,qDAAqD;AACrD,wBAAgB,kCAAkC,IAAI,IAAI,
|
|
1
|
+
{"version":3,"file":"session-directory.d.ts","sourceRoot":"","sources":["../../src/shared/session-directory.ts"],"names":[],"mappings":"AA+CA;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA8CxB;AAWD;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,MAAM,GAAG,IAAI,GAAG,SAAS,CAK3B;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,iBAAiB,EAAE,MAAM,GACxB,IAAI,CAIN;AAoBD,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAgCxB;AAED,qDAAqD;AACrD,wBAAgB,kCAAkC,IAAI,IAAI,CAGzD"}
|
|
@@ -5,7 +5,7 @@ import { type StatusBarCounts } from "@cortexkit/aft-bridge";
|
|
|
5
5
|
* (unchanged since last emit and heartbeat not elapsed) or when counts are
|
|
6
6
|
* absent (no inspect scan has populated Tier-2 yet).
|
|
7
7
|
*/
|
|
8
|
-
export declare function statusBarSuffixForSession(sessionID: string, counts: StatusBarCounts | undefined): string;
|
|
8
|
+
export declare function statusBarSuffixForSession(sessionID: string, counts: StatusBarCounts | undefined, force?: boolean): string;
|
|
9
9
|
/** Drop a session's emit state (on session delete/shutdown). */
|
|
10
10
|
export declare function clearStatusBarSession(sessionID: string): void;
|
|
11
11
|
//# sourceMappingURL=status-bar-inject.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status-bar-inject.d.ts","sourceRoot":"","sources":["../src/status-bar-inject.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,eAAe,EAIrB,MAAM,uBAAuB,CAAC;AAI/B;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,eAAe,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"status-bar-inject.d.ts","sourceRoot":"","sources":["../src/status-bar-inject.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,eAAe,EAIrB,MAAM,uBAAuB,CAAC;AAI/B;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,eAAe,GAAG,SAAS,EACnC,KAAK,UAAQ,GACZ,MAAM,CAkBR;AAED,gEAAgE;AAChE,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE7D"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ToolDefinition } from "@opencode-ai/plugin";
|
|
2
|
+
/**
|
|
3
|
+
* Mark the instant just before a bridge request is sent. First mark wins so a
|
|
4
|
+
* tool that issues several bridge requests still reports one bridge window
|
|
5
|
+
* (first send -> last response); the intervening plugin work folds into it.
|
|
6
|
+
*/
|
|
7
|
+
export declare function markBridgeStart(): void;
|
|
8
|
+
/** Mark the instant just after the bridge responds (last response wins). */
|
|
9
|
+
export declare function markBridgeEnd(): void;
|
|
10
|
+
/**
|
|
11
|
+
* Wrap every tool's execute() so each invocation logs a one-line latency
|
|
12
|
+
* breakdown: total, pre-bridge (arg/permission/session-dir work), bridge
|
|
13
|
+
* round-trip, and post-bridge (result formatting). Mutates execute in place;
|
|
14
|
+
* call after the final tool surface is built so disabled tools aren't wrapped.
|
|
15
|
+
*/
|
|
16
|
+
export declare function instrumentToolMap(tools: Record<string, ToolDefinition>): Record<string, ToolDefinition>;
|
|
17
|
+
//# sourceMappingURL=tool-perf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-perf.d.ts","sourceRoot":"","sources":["../src/tool-perf.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAmB1D;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAKtC;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,IAAI,IAAI,CAKpC;AAmBD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,GACpC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAoBhC"}
|
package/dist/tools/_shared.d.ts
CHANGED
|
@@ -69,18 +69,8 @@ export declare function coerceOptionalInt(v: unknown, paramName: string, min: nu
|
|
|
69
69
|
* collection sentinels qualify.
|
|
70
70
|
*/
|
|
71
71
|
export declare function isEmptyParam(value: unknown): boolean;
|
|
72
|
-
/**
|
|
73
|
-
* Per-command timeout overrides (milliseconds).
|
|
74
|
-
*
|
|
75
|
-
* Commands not listed fall back to the bridge-wide default (30s). Only
|
|
76
|
-
* extend budgets for operations that legitimately walk the project
|
|
77
|
-
* file tree or wait on external I/O (embedding API, index build). The
|
|
78
|
-
* goal is to absorb slow first-call spikes without masking real hangs.
|
|
79
|
-
*/
|
|
80
72
|
export declare const BASH_TRANSPORT_TIMEOUT_MS = 30000;
|
|
81
|
-
export
|
|
82
|
-
/** Returns the per-command timeout override, or undefined to use the bridge default. */
|
|
83
|
-
export declare function timeoutForCommand(command: string): number | undefined;
|
|
73
|
+
export { LONG_RUNNING_COMMAND_TIMEOUT_MS, timeoutForCommand } from "@cortexkit/aft-bridge";
|
|
84
74
|
/** Format bridge failure envelopes without dropping structured error data. */
|
|
85
75
|
export declare function formatBridgeErrorMessage(command: string, response: Record<string, unknown>, params?: Record<string, unknown>): string;
|
|
86
76
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_shared.d.ts","sourceRoot":"","sources":["../../src/tools/_shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"_shared.d.ts","sourceRoot":"","sources":["../../src/tools/_shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAUhF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,EAAE,KAAK,MAAM,KAAG,GACR,CAAC;AAEhD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,OAAO,EACV,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,SAAS,CAWpB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAMpD;AAMD,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAIhD,OAAO,EAAE,+BAA+B,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AA2B3F,8EAA8E;AAC9E,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACnC,MAAM,CAsDR;AAsBD;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAkBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAW3D;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,CAAC,CAKjB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQjD;AAED;;2BAE2B;AAC3B,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGtF;AAED,wBAAsB,cAAc,CAClC,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,GAAG,YAAY,CAEhF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAgClC;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAMlC;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI,CAE9F"}
|
package/dist/tools/bash.d.ts
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
import type { ToolDefinition } from "@opencode-ai/plugin";
|
|
2
2
|
import type { PluginContext } from "../types.js";
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Agent-facing tool description, selected from the live configuration so it
|
|
5
|
+
* never advertises behavior this project doesn't have:
|
|
6
|
+
* - code-search prohibition steers to `aft_search` when registered, else the
|
|
7
|
+
* `grep` tool (same surface logic as the Rust grep-rewrite footer); the
|
|
8
|
+
* registration variant is selected late in index.ts once the final tool map
|
|
9
|
+
* is known.
|
|
10
|
+
* - the compression sentence only appears when output compression is on —
|
|
11
|
+
* advertising `compressed: false` otherwise would describe a no-op.
|
|
12
|
+
* - the background/PTY sentences only appear when `bash.background` is on —
|
|
13
|
+
* with it off, explicit `background: true`/`pty: true` is a guaranteed
|
|
14
|
+
* `feature_disabled` error from Rust. Foreground promotion still happens
|
|
15
|
+
* regardless (the flag gates explicit spawning only), so the no-background
|
|
16
|
+
* variant still explains promoted tasks and bash_status/bash_kill.
|
|
17
|
+
*
|
|
18
|
+
* Wording rules: this is read by AGENTS choosing a tool, not by users reading
|
|
19
|
+
* docs. No internal vocabulary ("hoisted", "command rewriting", "unified bash
|
|
20
|
+
* schema") — describe what the tool does and what NOT to use it for.
|
|
21
|
+
*/
|
|
22
|
+
export declare function bashToolDescription(aftSearchRegistered: boolean, compressionOn: boolean, backgroundOn: boolean): string;
|
|
23
|
+
export declare function createBashTool(ctx: PluginContext, aftSearchRegisteredOverride?: boolean): ToolDefinition;
|
|
4
24
|
export declare function createBashStatusTool(ctx: PluginContext): ToolDefinition;
|
|
5
25
|
export declare function createBashKillTool(ctx: PluginContext): ToolDefinition;
|
|
6
26
|
//# sourceMappingURL=bash.d.ts.map
|
package/dist/tools/bash.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAYvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAiCjD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CACjC,mBAAmB,EAAE,OAAO,EAC5B,aAAa,EAAE,OAAO,EACtB,YAAY,EAAE,OAAO,GACpB,MAAM,CAaR;AAgDD,wBAAgB,cAAc,CAC5B,GAAG,EAAE,aAAa,EAClB,2BAA2B,CAAC,EAAE,OAAO,GACpC,cAAc,CAgRhB;AAMD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CAyBvE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CAuBrE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conflicts.d.ts","sourceRoot":"","sources":["../../src/tools/conflicts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"conflicts.d.ts","sourceRoot":"","sources":["../../src/tools/conflicts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAYjD;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAwChF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hoisted.d.ts","sourceRoot":"","sources":["../../src/tools/hoisted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"hoisted.d.ts","sourceRoot":"","sources":["../../src/tools/hoisted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,qBAAqB,CAAC;AAItE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAwEjD,wEAAwE;AACxE,eAAO,MAAM,wBAAwB,GAAI,IAAI,MAAM,EAAE,QAAQ,MAAM,EAAE,OAAO,MAAM,KAAG,MAChD,CAAC;AA4RtC;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CAwJjE;AA+mCD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CA0B/E;AAMD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CA+FnF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reading.d.ts","sourceRoot":"","sources":["../../src/tools/reading.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAe,cAAc,
|
|
1
|
+
{"version":3,"file":"reading.d.ts","sourceRoot":"","sources":["../../src/tools/reading.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAe,cAAc,EAAc,MAAM,qBAAqB,CAAC;AAEnF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAoCjD,UAAU,qBAAqB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,eAAe;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,qBAAqB,EAAE,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAqX/E;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GACnC,eAAe,CAyBjB;AA+CD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CA2ChF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refactoring.d.ts","sourceRoot":"","sources":["../../src/tools/refactoring.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAG1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAajD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"refactoring.d.ts","sourceRoot":"","sources":["../../src/tools/refactoring.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAG1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAajD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CA6InF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../src/tools/safety.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAEvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAwCjD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../src/tools/safety.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAEvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAwCjD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CA2J9E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"semantic.d.ts","sourceRoot":"","sources":["../../src/tools/semantic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAiCjD,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"semantic.d.ts","sourceRoot":"","sources":["../../src/tools/semantic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAiCjD,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAkFhF"}
|
package/dist/tui.js
CHANGED
|
@@ -1,85 +1,61 @@
|
|
|
1
1
|
// src/tui/index.tsx
|
|
2
2
|
import { createMemo as createMemo2, createSignal as createSignal2, onCleanup as onCleanup2 } from "solid-js";
|
|
3
3
|
// package.json
|
|
4
|
-
var version = "0.
|
|
4
|
+
var version = "0.37.0";
|
|
5
5
|
|
|
6
6
|
// src/shared/rpc-client.ts
|
|
7
7
|
import { existsSync, readdirSync, readFileSync, unlinkSync } from "node:fs";
|
|
8
|
-
import { join as
|
|
9
|
-
|
|
10
|
-
// src/logger.ts
|
|
11
|
-
import * as fs from "node:fs";
|
|
12
|
-
import * as os from "node:os";
|
|
13
|
-
import * as path from "node:path";
|
|
14
|
-
var TAG = "[aft-plugin]";
|
|
15
|
-
var isTestEnv = process.env.BUN_TEST === "1" || false;
|
|
16
|
-
var logFile = path.join(os.tmpdir(), isTestEnv ? "aft-plugin-test.log" : "aft-plugin.log");
|
|
17
|
-
var useStderr = process.env.AFT_LOG_STDERR === "1";
|
|
18
|
-
var buffer = [];
|
|
19
|
-
var flushTimer = null;
|
|
20
|
-
var FLUSH_INTERVAL_MS = 500;
|
|
21
|
-
var BUFFER_SIZE_LIMIT = 50;
|
|
22
|
-
function flush() {
|
|
23
|
-
if (buffer.length === 0)
|
|
24
|
-
return;
|
|
25
|
-
const data = buffer.join("");
|
|
26
|
-
buffer = [];
|
|
27
|
-
try {
|
|
28
|
-
if (useStderr) {
|
|
29
|
-
process.stderr.write(data);
|
|
30
|
-
} else {
|
|
31
|
-
fs.appendFileSync(logFile, data);
|
|
32
|
-
}
|
|
33
|
-
} catch {}
|
|
34
|
-
}
|
|
35
|
-
function scheduleFlush() {
|
|
36
|
-
if (flushTimer)
|
|
37
|
-
return;
|
|
38
|
-
flushTimer = setTimeout(() => {
|
|
39
|
-
flushTimer = null;
|
|
40
|
-
flush();
|
|
41
|
-
}, FLUSH_INTERVAL_MS);
|
|
42
|
-
if (flushTimer && typeof flushTimer === "object" && "unref" in flushTimer) {
|
|
43
|
-
flushTimer.unref();
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
function write(level, message, data, sessionId) {
|
|
47
|
-
try {
|
|
48
|
-
const timestamp = new Date().toISOString();
|
|
49
|
-
const serialized = data === undefined ? "" : ` ${JSON.stringify(data)}`;
|
|
50
|
-
const sessionPrefix = sessionId ? ` [${sessionId}]` : "";
|
|
51
|
-
const line = `[${timestamp}] ${level} ${TAG}${sessionPrefix} ${message}${serialized}
|
|
52
|
-
`;
|
|
53
|
-
if (useStderr) {
|
|
54
|
-
process.stderr.write(line);
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
buffer.push(line);
|
|
58
|
-
if (buffer.length >= BUFFER_SIZE_LIMIT) {
|
|
59
|
-
flush();
|
|
60
|
-
} else {
|
|
61
|
-
scheduleFlush();
|
|
62
|
-
}
|
|
63
|
-
} catch {}
|
|
64
|
-
}
|
|
65
|
-
function warn(message, data) {
|
|
66
|
-
write("WARN", message, data);
|
|
67
|
-
}
|
|
8
|
+
import { join as join2 } from "node:path";
|
|
68
9
|
|
|
69
10
|
// src/shared/rpc-utils.ts
|
|
70
11
|
import { createHash } from "node:crypto";
|
|
71
|
-
import { join
|
|
12
|
+
import { join } from "node:path";
|
|
72
13
|
function projectHash(directory) {
|
|
73
14
|
const normalized = directory.replace(/\/+$/, "");
|
|
74
15
|
return createHash("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
75
16
|
}
|
|
76
17
|
function rpcPortFilePath(storageDir, directory) {
|
|
77
18
|
const hash = projectHash(directory);
|
|
78
|
-
return
|
|
19
|
+
return join(storageDir, "rpc", hash, "port");
|
|
79
20
|
}
|
|
80
21
|
function rpcPortFileDir(storageDir, directory) {
|
|
81
22
|
const hash = projectHash(directory);
|
|
82
|
-
return
|
|
23
|
+
return join(storageDir, "rpc", hash, "ports");
|
|
24
|
+
}
|
|
25
|
+
function isPidAlive(pid) {
|
|
26
|
+
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0)
|
|
27
|
+
return false;
|
|
28
|
+
try {
|
|
29
|
+
process.kill(pid, 0);
|
|
30
|
+
return true;
|
|
31
|
+
} catch (err) {
|
|
32
|
+
return err.code === "EPERM";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function parseRpcPortRecord(content) {
|
|
36
|
+
const trimmed = content.trim();
|
|
37
|
+
if (trimmed.length === 0)
|
|
38
|
+
return null;
|
|
39
|
+
if (trimmed.startsWith("{")) {
|
|
40
|
+
try {
|
|
41
|
+
const parsed = JSON.parse(trimmed);
|
|
42
|
+
const port2 = typeof parsed.port === "number" ? parsed.port : Number.NaN;
|
|
43
|
+
if (!Number.isInteger(port2) || port2 <= 0 || port2 > 65535)
|
|
44
|
+
return null;
|
|
45
|
+
return {
|
|
46
|
+
port: port2,
|
|
47
|
+
token: typeof parsed.token === "string" ? parsed.token : null,
|
|
48
|
+
pid: typeof parsed.pid === "number" && Number.isInteger(parsed.pid) ? parsed.pid : undefined,
|
|
49
|
+
started_at: typeof parsed.started_at === "number" ? parsed.started_at : undefined
|
|
50
|
+
};
|
|
51
|
+
} catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const port = Number.parseInt(trimmed, 10);
|
|
56
|
+
if (!Number.isInteger(port) || port <= 0 || port > 65535)
|
|
57
|
+
return null;
|
|
58
|
+
return { port, token: null };
|
|
83
59
|
}
|
|
84
60
|
|
|
85
61
|
// src/shared/rpc-client.ts
|
|
@@ -139,6 +115,9 @@ class AftRpcClient {
|
|
|
139
115
|
placeholder = result;
|
|
140
116
|
continue;
|
|
141
117
|
}
|
|
118
|
+
if (options.accept && !options.accept(result)) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
142
121
|
this.port = info.port;
|
|
143
122
|
this.token = info.token;
|
|
144
123
|
return result;
|
|
@@ -185,7 +164,7 @@ class AftRpcClient {
|
|
|
185
164
|
const alive = [];
|
|
186
165
|
for (const info of infos) {
|
|
187
166
|
throwIfAborted(signal);
|
|
188
|
-
if (await this.healthCheck(info.port, signal)) {
|
|
167
|
+
if (await this.healthCheck(info.port, info.pid, signal)) {
|
|
189
168
|
this.clearPortFailure(info);
|
|
190
169
|
alive.push(info);
|
|
191
170
|
} else {
|
|
@@ -212,15 +191,23 @@ class AftRpcClient {
|
|
|
212
191
|
};
|
|
213
192
|
if (existsSync(this.portsDir)) {
|
|
214
193
|
try {
|
|
215
|
-
const
|
|
216
|
-
for (const entry of
|
|
194
|
+
const live = [];
|
|
195
|
+
for (const entry of readdirSync(this.portsDir)) {
|
|
217
196
|
if (!entry.endsWith(".json"))
|
|
218
197
|
continue;
|
|
219
|
-
const filePath =
|
|
198
|
+
const filePath = join2(this.portsDir, entry);
|
|
220
199
|
const info = this.parsePortFile(filePath);
|
|
221
|
-
if (info)
|
|
222
|
-
|
|
200
|
+
if (!info)
|
|
201
|
+
continue;
|
|
202
|
+
if (info.pid !== undefined && !isPidAlive(info.pid)) {
|
|
203
|
+
this.reclaimDeadPortFile(filePath);
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
live.push({ ...info, source: "instance", path: filePath });
|
|
223
207
|
}
|
|
208
|
+
live.sort((a, b) => (b.started_at ?? 0) - (a.started_at ?? 0) || (b.pid ?? 0) - (a.pid ?? 0) || (b.port ?? 0) - (a.port ?? 0));
|
|
209
|
+
for (const info of live)
|
|
210
|
+
add(info);
|
|
224
211
|
} catch {}
|
|
225
212
|
}
|
|
226
213
|
const legacyInfo = this.parsePortFile(this.legacyPortFile);
|
|
@@ -228,24 +215,15 @@ class AftRpcClient {
|
|
|
228
215
|
add({ ...legacyInfo, source: "legacy", path: this.legacyPortFile });
|
|
229
216
|
return collected;
|
|
230
217
|
}
|
|
218
|
+
reclaimDeadPortFile(filePath) {
|
|
219
|
+
try {
|
|
220
|
+
unlinkSync(filePath);
|
|
221
|
+
} catch {}
|
|
222
|
+
}
|
|
231
223
|
parsePortFile(filePath) {
|
|
232
224
|
try {
|
|
233
|
-
const content = readFileSync(filePath, "utf-8")
|
|
234
|
-
|
|
235
|
-
let token;
|
|
236
|
-
if (content.startsWith("{")) {
|
|
237
|
-
const parsed = JSON.parse(content);
|
|
238
|
-
port = typeof parsed.port === "number" ? parsed.port : Number.NaN;
|
|
239
|
-
token = typeof parsed.token === "string" ? parsed.token : null;
|
|
240
|
-
} else {
|
|
241
|
-
warn("RPC port file uses legacy integer format; unauthenticated RPC is deprecated");
|
|
242
|
-
port = Number.parseInt(content, 10);
|
|
243
|
-
token = null;
|
|
244
|
-
}
|
|
245
|
-
if (Number.isNaN(port) || port <= 0 || port > 65535) {
|
|
246
|
-
return null;
|
|
247
|
-
}
|
|
248
|
-
return { port, token };
|
|
225
|
+
const content = readFileSync(filePath, "utf-8");
|
|
226
|
+
return parseRpcPortRecord(content);
|
|
249
227
|
} catch {
|
|
250
228
|
return null;
|
|
251
229
|
}
|
|
@@ -277,10 +255,21 @@ class AftRpcClient {
|
|
|
277
255
|
}
|
|
278
256
|
} catch {}
|
|
279
257
|
}
|
|
280
|
-
async healthCheck(port, signal) {
|
|
258
|
+
async healthCheck(port, expectedPid, signal) {
|
|
281
259
|
try {
|
|
282
260
|
const response = await this.fetchWithTimeout(`http://127.0.0.1:${port}/health`, { method: "GET" }, signal);
|
|
283
|
-
|
|
261
|
+
if (!response.ok)
|
|
262
|
+
return false;
|
|
263
|
+
if (expectedPid !== undefined) {
|
|
264
|
+
try {
|
|
265
|
+
const body = await response.json();
|
|
266
|
+
if (typeof body?.pid === "number" && body.pid !== expectedPid)
|
|
267
|
+
return false;
|
|
268
|
+
} catch {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return true;
|
|
284
273
|
} catch {
|
|
285
274
|
throwIfAborted(signal);
|
|
286
275
|
return false;
|
|
@@ -454,7 +443,7 @@ import { createEffect, createMemo, createSignal, on, onCleanup } from "solid-js"
|
|
|
454
443
|
|
|
455
444
|
// src/shared/storage-paths.ts
|
|
456
445
|
import { homedir } from "node:os";
|
|
457
|
-
import { join as
|
|
446
|
+
import { join as join3 } from "node:path";
|
|
458
447
|
function homeDir() {
|
|
459
448
|
if (process.platform === "win32")
|
|
460
449
|
return process.env.USERPROFILE || process.env.HOME || homedir();
|
|
@@ -464,12 +453,12 @@ function dataHome() {
|
|
|
464
453
|
if (process.env.XDG_DATA_HOME)
|
|
465
454
|
return process.env.XDG_DATA_HOME;
|
|
466
455
|
if (process.platform === "win32") {
|
|
467
|
-
return process.env.LOCALAPPDATA || process.env.APPDATA ||
|
|
456
|
+
return process.env.LOCALAPPDATA || process.env.APPDATA || join3(homeDir(), "AppData", "Local");
|
|
468
457
|
}
|
|
469
|
-
return
|
|
458
|
+
return join3(homeDir(), ".local", "share");
|
|
470
459
|
}
|
|
471
460
|
function resolveCortexKitStorageRoot() {
|
|
472
|
-
return
|
|
461
|
+
return join3(dataHome(), "cortexkit", "aft");
|
|
473
462
|
}
|
|
474
463
|
|
|
475
464
|
// src/tui/sidebar.tsx
|
|
@@ -636,6 +625,20 @@ function scopedSidebarSnapshot(scoped, directory, sessionID) {
|
|
|
636
625
|
function shouldSuppressUninitializedDowngrade(incomingCacheRole, haveInitializedForContext) {
|
|
637
626
|
return incomingCacheRole === "not_initialized" && haveInitializedForContext;
|
|
638
627
|
}
|
|
628
|
+
function isSnapshotForContext(snapshot, directory, servedDirectory) {
|
|
629
|
+
const stripSlash = (p) => p.replace(/\/+$/, "");
|
|
630
|
+
const roots = [snapshot.project_root, snapshot.canonical_root].filter((r) => typeof r === "string" && r.length > 0);
|
|
631
|
+
if (roots.length === 0)
|
|
632
|
+
return true;
|
|
633
|
+
const dir = stripSlash(directory);
|
|
634
|
+
if (roots.some((r) => stripSlash(r) === dir))
|
|
635
|
+
return true;
|
|
636
|
+
if (typeof servedDirectory === "string" && servedDirectory.length > 0) {
|
|
637
|
+
const served = stripSlash(servedDirectory);
|
|
638
|
+
return roots.some((r) => stripSlash(r) === served);
|
|
639
|
+
}
|
|
640
|
+
return false;
|
|
641
|
+
}
|
|
639
642
|
var SidebarContent = (props) => {
|
|
640
643
|
const [status, setStatus] = createSignal(null);
|
|
641
644
|
const [collapsed, setCollapsed] = createSignal(false);
|
|
@@ -688,13 +691,24 @@ var SidebarContent = (props) => {
|
|
|
688
691
|
inflight = { controller, generation: requestGeneration, directory, sessionID: sid };
|
|
689
692
|
try {
|
|
690
693
|
const client = getClient(directory);
|
|
691
|
-
const response = await client.call("status", { sessionID: sid }, {
|
|
694
|
+
const response = await client.call("status", { sessionID: sid }, {
|
|
695
|
+
signal: controller.signal,
|
|
696
|
+
accept: (result) => {
|
|
697
|
+
const rec = result;
|
|
698
|
+
if (rec?.success === false)
|
|
699
|
+
return true;
|
|
700
|
+
return isSnapshotForContext(coerceAftStatus(rec), directory, rec?.served_directory);
|
|
701
|
+
}
|
|
702
|
+
});
|
|
692
703
|
if (controller.signal.aborted || requestGeneration !== generation)
|
|
693
704
|
return;
|
|
694
705
|
if (currentDirectory() !== directory || props.sessionID() !== sid)
|
|
695
706
|
return;
|
|
696
707
|
if (response && response.success !== false) {
|
|
697
708
|
const snapshot = coerceAftStatus(response);
|
|
709
|
+
const servedDirectory = response.served_directory;
|
|
710
|
+
if (!isSnapshotForContext(snapshot, directory, servedDirectory))
|
|
711
|
+
return;
|
|
698
712
|
const current = status();
|
|
699
713
|
const haveGoodForContext = current !== null && current.directory === directory && current.sessionID === sid && current.snapshot.cache_role !== "not_initialized";
|
|
700
714
|
if (shouldSuppressUninitializedDowngrade(snapshot.cache_role, haveGoodForContext))
|
|
@@ -1156,6 +1170,14 @@ var R = (props) => {
|
|
|
1156
1170
|
]
|
|
1157
1171
|
}, undefined, true, undefined, this);
|
|
1158
1172
|
};
|
|
1173
|
+
function statusAcceptGate(directory) {
|
|
1174
|
+
return (result) => {
|
|
1175
|
+
const rec = result;
|
|
1176
|
+
if (rec?.success === false)
|
|
1177
|
+
return true;
|
|
1178
|
+
return isSnapshotForContext(coerceAftStatus(rec), directory, rec?.served_directory);
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1159
1181
|
var StatusDialog = (props) => {
|
|
1160
1182
|
const theme = createMemo2(() => props.api.theme.current);
|
|
1161
1183
|
const t = () => theme();
|
|
@@ -1170,7 +1192,7 @@ var StatusDialog = (props) => {
|
|
|
1170
1192
|
const requestGeneration = ++pollGeneration;
|
|
1171
1193
|
pollController = controller;
|
|
1172
1194
|
try {
|
|
1173
|
-
const response = await props.client.call("status", { sessionID: props.sessionID }, { signal: controller.signal });
|
|
1195
|
+
const response = await props.client.call("status", { sessionID: props.sessionID }, { signal: controller.signal, accept: statusAcceptGate(props.directory) });
|
|
1174
1196
|
if (controller.signal.aborted || requestGeneration !== pollGeneration)
|
|
1175
1197
|
return;
|
|
1176
1198
|
if (response.success !== false) {
|
|
@@ -1575,7 +1597,7 @@ async function showStatusDialog(api) {
|
|
|
1575
1597
|
let initial = null;
|
|
1576
1598
|
let initialError = null;
|
|
1577
1599
|
try {
|
|
1578
|
-
const response = await client.call("status", { sessionID });
|
|
1600
|
+
const response = await client.call("status", { sessionID }, { accept: statusAcceptGate(directory) });
|
|
1579
1601
|
if (response.success !== false) {
|
|
1580
1602
|
initial = coerceAftStatus(response);
|
|
1581
1603
|
} else {
|
|
@@ -1588,6 +1610,7 @@ async function showStatusDialog(api) {
|
|
|
1588
1610
|
api.ui.dialog.replace(() => /* @__PURE__ */ jsxDEV2(StatusDialog, {
|
|
1589
1611
|
api,
|
|
1590
1612
|
client,
|
|
1613
|
+
directory,
|
|
1591
1614
|
sessionID,
|
|
1592
1615
|
initial,
|
|
1593
1616
|
initialError,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-hints.d.ts","sourceRoot":"","sources":["../src/workflow-hints.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,SAAS,EAAqB,MAAM,aAAa,CAAC;AAEhE,MAAM,WAAW,iBAAiB;IAChC,oEAAoE;IACpE,WAAW,EAAE,SAAS,GAAG,aAAa,GAAG,KAAK,CAAC;IAC/C,4EAA4E;IAC5E,aAAa,EAAE,OAAO,CAAC;IACvB,mEAAmE;IACnE,eAAe,EAAE,OAAO,CAAC;IACzB,wEAAwE;IACxE,qBAAqB,EAAE,OAAO,CAAC;IAC/B,sCAAsC;IACtC,sBAAsB,EAAE,OAAO,CAAC;IAChC,4DAA4D;IAC5D,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC5B;AAID;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"workflow-hints.d.ts","sourceRoot":"","sources":["../src/workflow-hints.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,SAAS,EAAqB,MAAM,aAAa,CAAC;AAEhE,MAAM,WAAW,iBAAiB;IAChC,oEAAoE;IACpE,WAAW,EAAE,SAAS,GAAG,aAAa,GAAG,KAAK,CAAC;IAC/C,4EAA4E;IAC5E,aAAa,EAAE,OAAO,CAAC;IACvB,mEAAmE;IACnE,eAAe,EAAE,OAAO,CAAC;IACzB,wEAAwE;IACxE,qBAAqB,EAAE,OAAO,CAAC;IAC/B,sCAAsC;IACtC,sBAAsB,EAAE,OAAO,CAAC;IAChC,4DAA4D;IAC5D,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC5B;AAID;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI,CAuIzE;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,CASjG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/aft-opencode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.37.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenCode plugin for Agent File Tools (AFT) — tree-sitter and lsp powered code analysis",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,19 +30,19 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@clack/prompts": "^1.2.0",
|
|
33
|
-
"@cortexkit/aft-bridge": "0.
|
|
33
|
+
"@cortexkit/aft-bridge": "0.37.0",
|
|
34
34
|
"@xterm/headless": "^5.5.0",
|
|
35
35
|
"comment-json": "^4.6.2",
|
|
36
36
|
"undici": "^7.25.0",
|
|
37
37
|
"zod": "^4.1.8"
|
|
38
38
|
},
|
|
39
39
|
"optionalDependencies": {
|
|
40
|
-
"@cortexkit/aft-darwin-arm64": "0.
|
|
41
|
-
"@cortexkit/aft-darwin-x64": "0.
|
|
42
|
-
"@cortexkit/aft-linux-arm64": "0.
|
|
43
|
-
"@cortexkit/aft-linux-x64": "0.
|
|
44
|
-
"@cortexkit/aft-win32-arm64": "0.
|
|
45
|
-
"@cortexkit/aft-win32-x64": "0.
|
|
40
|
+
"@cortexkit/aft-darwin-arm64": "0.37.0",
|
|
41
|
+
"@cortexkit/aft-darwin-x64": "0.37.0",
|
|
42
|
+
"@cortexkit/aft-linux-arm64": "0.37.0",
|
|
43
|
+
"@cortexkit/aft-linux-x64": "0.37.0",
|
|
44
|
+
"@cortexkit/aft-win32-arm64": "0.37.0",
|
|
45
|
+
"@cortexkit/aft-win32-x64": "0.37.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@opencode-ai/plugin": "^1.15.11",
|