@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.
Files changed (40) hide show
  1. package/dist/bg-notifications.d.ts +5 -1
  2. package/dist/bg-notifications.d.ts.map +1 -1
  3. package/dist/index.d.ts +0 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +1594 -1159
  6. package/dist/shared/rpc-client.d.ts +13 -0
  7. package/dist/shared/rpc-client.d.ts.map +1 -1
  8. package/dist/shared/rpc-server.d.ts +7 -0
  9. package/dist/shared/rpc-server.d.ts.map +1 -1
  10. package/dist/shared/rpc-utils.d.ts +23 -0
  11. package/dist/shared/rpc-utils.d.ts.map +1 -1
  12. package/dist/shared/session-directory.d.ts +1 -0
  13. package/dist/shared/session-directory.d.ts.map +1 -1
  14. package/dist/status-bar-inject.d.ts +1 -1
  15. package/dist/status-bar-inject.d.ts.map +1 -1
  16. package/dist/tool-perf.d.ts +17 -0
  17. package/dist/tool-perf.d.ts.map +1 -0
  18. package/dist/tools/_shared.d.ts +1 -11
  19. package/dist/tools/_shared.d.ts.map +1 -1
  20. package/dist/tools/bash.d.ts +21 -1
  21. package/dist/tools/bash.d.ts.map +1 -1
  22. package/dist/tools/conflicts.d.ts.map +1 -1
  23. package/dist/tools/hoisted.d.ts.map +1 -1
  24. package/dist/tools/reading.d.ts.map +1 -1
  25. package/dist/tools/refactoring.d.ts.map +1 -1
  26. package/dist/tools/safety.d.ts.map +1 -1
  27. package/dist/tools/semantic.d.ts.map +1 -1
  28. package/dist/tui.js +118 -95
  29. package/dist/workflow-hints.d.ts.map +1 -1
  30. package/package.json +8 -8
  31. package/src/shared/rpc-client.ts +79 -26
  32. package/src/shared/rpc-server.ts +64 -6
  33. package/src/shared/rpc-utils.ts +62 -0
  34. package/src/shared/session-directory.ts +56 -0
  35. package/src/tui/index.tsx +26 -2
  36. package/src/tui/sidebar.tsx +64 -1
  37. package/dist/metadata-store.d.ts +0 -29
  38. package/dist/metadata-store.d.ts.map +0 -1
  39. package/dist/tools/structure.d.ts +0 -8
  40. 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":"AAaA,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;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;YAyCC,OAAO;IAsBrB;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAM5B,4CAA4C;IACtC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IASrC;;;;OAIG;YACW,gBAAgB;IAwB9B,OAAO,CAAC,gBAAgB;IAiCxB,OAAO,CAAC,aAAa;IAuBrB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,iBAAiB;YAsBX,WAAW;YAcX,gBAAgB;IAmB9B,KAAK,IAAI,IAAI;CAKd"}
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":"AAOA,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;IA0C9B,8CAA8C;IAC9C,IAAI,IAAI,IAAI;IAaZ,OAAO,CAAC,QAAQ;CAoEjB"}
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,CAEzD"}
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,GAClC,MAAM,CAQR;AAED,gEAAgE;AAChE,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE7D"}
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"}
@@ -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 declare const LONG_RUNNING_COMMAND_TIMEOUT_MS: Record<string, number>;
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":"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"}
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"}
@@ -1,6 +1,26 @@
1
1
  import type { ToolDefinition } from "@opencode-ai/plugin";
2
2
  import type { PluginContext } from "../types.js";
3
- export declare function createBashTool(ctx: PluginContext): ToolDefinition;
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
@@ -1 +1 @@
1
- {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAavE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAiFjD,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CAsRjE;AAMD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CAyBvE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CAuBrE"}
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;AAKjD;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAwBhF"}
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,EAAE,MAAM,qBAAqB,CAAC;AAK1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA8EjD,wEAAwE;AACxE,eAAO,MAAM,wBAAwB,GAAI,IAAI,MAAM,EAAE,QAAQ,MAAM,EAAE,OAAO,MAAM,KAAG,MAChD,CAAC;AA0RtC;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CAmKjE;AAwnCD;;;;;;;;;;;;;;;;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
+ {"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,EAAE,MAAM,qBAAqB,CAAC;AAGvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA0CjD,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,CAiX/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
+ {"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,CA8InF"}
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,CAkJ9E"}
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,CAyFhF"}
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.36.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 join3 } from "node:path";
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 as join2 } from "node:path";
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 join2(storageDir, "rpc", hash, "port");
19
+ return join(storageDir, "rpc", hash, "port");
79
20
  }
80
21
  function rpcPortFileDir(storageDir, directory) {
81
22
  const hash = projectHash(directory);
82
- return join2(storageDir, "rpc", hash, "ports");
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 entries = readdirSync(this.portsDir).sort();
216
- for (const entry of entries) {
194
+ const live = [];
195
+ for (const entry of readdirSync(this.portsDir)) {
217
196
  if (!entry.endsWith(".json"))
218
197
  continue;
219
- const filePath = join3(this.portsDir, entry);
198
+ const filePath = join2(this.portsDir, entry);
220
199
  const info = this.parsePortFile(filePath);
221
- if (info)
222
- add({ ...info, source: "instance", path: filePath });
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").trim();
234
- let port;
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
- return response.ok;
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 join4 } from "node:path";
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 || join4(homeDir(), "AppData", "Local");
456
+ return process.env.LOCALAPPDATA || process.env.APPDATA || join3(homeDir(), "AppData", "Local");
468
457
  }
469
- return join4(homeDir(), ".local", "share");
458
+ return join3(homeDir(), ".local", "share");
470
459
  }
471
460
  function resolveCortexKitStorageRoot() {
472
- return join4(dataHome(), "cortexkit", "aft");
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 }, { signal: controller.signal });
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,CA8GzE;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,CASjG"}
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.36.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.36.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.36.0",
41
- "@cortexkit/aft-darwin-x64": "0.36.0",
42
- "@cortexkit/aft-linux-arm64": "0.36.0",
43
- "@cortexkit/aft-linux-x64": "0.36.0",
44
- "@cortexkit/aft-win32-arm64": "0.36.0",
45
- "@cortexkit/aft-win32-x64": "0.36.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",