@cortexkit/aft-opencode 0.20.1 → 0.22.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 +0 -2
- package/dist/bg-notifications.d.ts.map +1 -1
- package/dist/configure-warnings.d.ts +2 -0
- package/dist/configure-warnings.d.ts.map +1 -1
- package/dist/hooks/auto-update-checker/cache.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +933 -284
- package/dist/lsp-auto-install.d.ts.map +1 -1
- package/dist/lsp-github-install.d.ts +12 -1
- package/dist/lsp-github-install.d.ts.map +1 -1
- package/dist/notifications.d.ts.map +1 -1
- package/dist/shared/rpc-server.d.ts.map +1 -1
- package/dist/shared/subagent-detect.d.ts +13 -0
- package/dist/shared/subagent-detect.d.ts.map +1 -0
- package/dist/tools/ast.d.ts.map +1 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/hoisted.d.ts.map +1 -1
- package/dist/tools/imports.d.ts.map +1 -1
- package/dist/tools/permissions.d.ts +69 -0
- package/dist/tools/permissions.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/search.d.ts.map +1 -1
- package/dist/tools/structure.d.ts.map +1 -1
- package/dist/tui.js +43 -18
- package/package.json +7 -7
- package/src/shared/rpc-server.ts +5 -2
- package/src/shared/subagent-detect.ts +150 -0
- package/src/tui/index.tsx +72 -11
- package/dist/shared/runtime.d.ts +0 -10
- package/dist/shared/runtime.d.ts.map +0 -1
- package/src/shared/runtime.ts +0 -26
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lsp-auto-install.d.ts","sourceRoot":"","sources":["../src/lsp-auto-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;
|
|
1
|
+
{"version":3,"file":"lsp-auto-install.d.ts","sourceRoot":"","sources":["../src/lsp-auto-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAwBH,+DAA+D;AAC/D,MAAM,WAAW,iBAAiB;IAChC,oCAAoC;IACpC,WAAW,EAAE,OAAO,CAAC;IACrB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3C,kGAAkG;IAClG,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC/B;AAED,qCAAqC;AACrC,MAAM,WAAW,iBAAiB;IAChC,mFAAmF;IACnF,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gDAAgD;IAChD,eAAe,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B;;;;;;;OAOG;IACH,OAAO,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C;;;;;;;;;OASG;IACH,gBAAgB,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAkDD,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAM/D;AA0WD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,iBAAiB,EACzB,SAAS,GAAE,OAAO,KAAa,GAC9B,iBAAiB,CAwEnB"}
|
|
@@ -40,6 +40,7 @@ export interface GithubInstallConfig {
|
|
|
40
40
|
disabled: ReadonlySet<string>;
|
|
41
41
|
}
|
|
42
42
|
declare function assertAllowedDownloadUrl(rawUrl: string): URL;
|
|
43
|
+
declare function downloadFile(url: string, destPath: string, fetchImpl: typeof fetch, assetSize?: number, signal?: AbortSignal): Promise<void>;
|
|
43
44
|
/**
|
|
44
45
|
* Recursively validate that every entry under `stagingRoot` is contained
|
|
45
46
|
* within it (audit #3: zip-slip + symlink containment).
|
|
@@ -58,6 +59,16 @@ declare function assertAllowedDownloadUrl(rawUrl: string): URL;
|
|
|
58
59
|
* Throws on any violation. The caller cleans up the staging dir.
|
|
59
60
|
*/
|
|
60
61
|
export declare function validateExtraction(stagingRoot: string): void;
|
|
62
|
+
/**
|
|
63
|
+
* Extract `archivePath` into `destDir` safely:
|
|
64
|
+
*
|
|
65
|
+
* 1. Stage extraction in `<destDir>.staging-<rand>/`.
|
|
66
|
+
* 2. Run the platform extractor against the staging dir.
|
|
67
|
+
* 3. Validate the staging tree (no symlinks, no escapes).
|
|
68
|
+
* 4. Atomic rename: `staging → destDir`. Any prior `destDir` is removed first.
|
|
69
|
+
* 5. Always cleanup staging on any failure.
|
|
70
|
+
*/
|
|
71
|
+
declare function precheckArchiveSize(archivePath: string, archiveType: string): void;
|
|
61
72
|
export interface GithubAutoInstallResult {
|
|
62
73
|
cachedBinDirs: string[];
|
|
63
74
|
installsStarted: number;
|
|
@@ -97,5 +108,5 @@ export declare function discoverRelevantGithubServers(projectRoot: string): Set<
|
|
|
97
108
|
* of `downloadFile`. We expose it here so the test suite can verify the
|
|
98
109
|
* allowlist independently of full network mocking.
|
|
99
110
|
*/
|
|
100
|
-
export { type Arch, assertAllowedDownloadUrl as _assertAllowedDownloadUrlForTesting, detectHostPlatform, findGithubServerById, GITHUB_LSP_TABLE, type GithubServerSpec, type Platform, };
|
|
111
|
+
export { type Arch, assertAllowedDownloadUrl as _assertAllowedDownloadUrlForTesting, detectHostPlatform, downloadFile as _downloadFileForTesting, findGithubServerById, GITHUB_LSP_TABLE, type GithubServerSpec, type Platform, precheckArchiveSize as _precheckArchiveSizeForTesting, };
|
|
101
112
|
//# sourceMappingURL=lsp-github-install.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lsp-github-install.d.ts","sourceRoot":"","sources":["../src/lsp-github-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;
|
|
1
|
+
{"version":3,"file":"lsp-github-install.d.ts","sourceRoot":"","sources":["../src/lsp-github-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAuCH,OAAO,EACL,KAAK,IAAI,EACT,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,QAAQ,EACd,MAAM,uBAAuB,CAAC;AAqB/B,yCAAyC;AACzC,wBAAgB,YAAY,CAAC,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAG/E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CASrF;AASD,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3C,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC/B;AAoVD,iBAAS,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAgBrD;AAED,iBAAe,YAAY,CACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,OAAO,KAAK,EACvB,SAAS,CAAC,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAuDf;AA6BD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CA0E5D;AAED;;;;;;;;GAQG;AACH,iBAAS,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAqB3E;AAmVD,MAAM,WAAW,uBAAuB;IACtC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,OAAO,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C;;;;OAIG;IACH,gBAAgB,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAsBD,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC,CAMjE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,EACpC,MAAM,EAAE,mBAAmB,EAC3B,SAAS,GAAE,OAAO,KAAa,GAC9B,uBAAuB,CAwFzB;AAID;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,WAAW,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAyC9E;AAID;;;;;;;GAOG;AACH,OAAO,EACL,KAAK,IAAI,EACT,wBAAwB,IAAI,mCAAmC,EAC/D,kBAAkB,EAClB,YAAY,IAAI,uBAAuB,EACvC,oBAAoB,EACpB,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,QAAQ,EACb,mBAAmB,IAAI,8BAA8B,GACtD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../src/notifications.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAyOH,MAAM,WAAW,mBAAmB;IAClC,8BAA8B;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,yBAAyB,GAAG,uBAAuB,GAAG,oBAAoB,CAAC;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW3F;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0C1F;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAAE,EAClB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAqCf;
|
|
1
|
+
{"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../src/notifications.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAyOH,MAAM,WAAW,mBAAmB;IAClC,8BAA8B;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,yBAAyB,GAAG,uBAAuB,GAAG,oBAAoB,CAAC;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW3F;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0C1F;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAAE,EAClB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAqCf;AA8FD,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,uBAAuB,EAC7B,QAAQ,EAAE,gBAAgB,EAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CAmCf;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0C9E"}
|
|
@@ -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;gBAEjB,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAIjD,sCAAsC;IACtC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI;IAIjD,6DAA6D;IACvD,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;
|
|
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;gBAEjB,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAIjD,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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns `true` when the given session has a non-empty `parentID`
|
|
3
|
+
* (subagent). Returns `false` for primary sessions, when the SDK is
|
|
4
|
+
* unavailable, or when any error occurs — the false default keeps
|
|
5
|
+
* primary sessions working exactly as before.
|
|
6
|
+
*
|
|
7
|
+
* First call per session: one SDK round-trip. All subsequent calls:
|
|
8
|
+
* O(1) cache lookup.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveIsSubagent(client: unknown, sessionId: string | undefined, _fallbackDirectory?: string): Promise<boolean>;
|
|
11
|
+
/** Test-only cache reset. Not exported from the public surface. */
|
|
12
|
+
export declare function _resetSubagentCacheForTest(): void;
|
|
13
|
+
//# sourceMappingURL=subagent-detect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent-detect.d.ts","sourceRoot":"","sources":["../../src/shared/subagent-detect.ts"],"names":[],"mappings":"AAqDA;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,OAAO,CAAC,CAqElB;AAWD,mEAAmE;AACnE,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD"}
|
package/dist/tools/ast.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/tools/ast.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/tools/ast.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAkDjD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CA6S3E"}
|
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":"AACA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAMvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA0EjD,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CAwOjE;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CAqCvE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CAmBrE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hoisted.d.ts","sourceRoot":"","sources":["../../src/tools/hoisted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAI1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"hoisted.d.ts","sourceRoot":"","sources":["../../src/tools/hoisted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAI1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAuEjD,wEAAwE;AACxE,eAAO,MAAM,wBAAwB,GAAI,IAAI,MAAM,EAAE,QAAQ,MAAM,EAAE,OAAO,MAAM,KAAG,MAChD,CAAC;AAqRtC;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CA+JjE;AAkkCD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAwB/E;AAMD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CA6EnF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../../src/tools/imports.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":"imports.d.ts","sourceRoot":"","sources":["../../src/tools/imports.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,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAiF9E"}
|
|
@@ -25,5 +25,74 @@ export declare function resolveRelativePattern(context: ToolContext, target: str
|
|
|
25
25
|
export declare function resolveRelativePatterns(context: ToolContext, targets: string[]): string[];
|
|
26
26
|
export declare function workspacePattern(_context: ToolContext): string;
|
|
27
27
|
export declare function askEditPermission(context: ToolContext, patterns: string[], metadata?: Record<string, unknown>): Promise<string | undefined>;
|
|
28
|
+
/**
|
|
29
|
+
* Check if `child` is inside `parent`. Mirrors `AppFileSystem.contains` in
|
|
30
|
+
* opencode core (uses `path.relative` and ensures it doesn't start with `..`).
|
|
31
|
+
*/
|
|
32
|
+
declare function containsPath(parent: string, child: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Normalize a path pattern (which may end in `*`) for the same reasons
|
|
35
|
+
* normalizePath() exists, but without trying to realpath a pattern that
|
|
36
|
+
* doesn't correspond to a real entry.
|
|
37
|
+
*
|
|
38
|
+
* Mirrors `AppFileSystem.normalizePathPattern` in opencode core.
|
|
39
|
+
*
|
|
40
|
+
* `*` → `*`
|
|
41
|
+
* `~/projects/*` → `~/projects/*` (`~` is expanded by opencode's matcher)
|
|
42
|
+
* `C:\some\dir\*` → `C:\some\dir\*` (drive case canonicalized via realpath of the dir part)
|
|
43
|
+
*
|
|
44
|
+
* No-op on non-Windows.
|
|
45
|
+
*/
|
|
46
|
+
declare function normalizePathPattern(p: string): string;
|
|
47
|
+
export declare const _permissionsInternalsForTest: {
|
|
48
|
+
containsPath: typeof containsPath;
|
|
49
|
+
normalizePathPattern: typeof normalizePathPattern;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Trigger OpenCode's host-side `external_directory` permission check when the
|
|
53
|
+
* target path falls outside the current project's directory and worktree.
|
|
54
|
+
* Mirrors `opencode/src/tool/external-directory.ts::assertExternalDirectoryEffect`.
|
|
55
|
+
*
|
|
56
|
+
* Why this exists: AFT hoisted tools previously only called `permission: "edit"`,
|
|
57
|
+
* which bypassed OpenCode's separate `external_directory` rule (default `ask`).
|
|
58
|
+
* That meant `/tmp/anything` writes routed through AFT silently bypassed the
|
|
59
|
+
* prompt OpenCode native `write`/`edit`/`apply_patch`/`read` show. This helper
|
|
60
|
+
* closes that gap so AFT's hoisted surface matches native behavior.
|
|
61
|
+
*
|
|
62
|
+
* Returns `undefined` on allow (or when target is inside project), or a
|
|
63
|
+
* denial message string on deny so callers can wrap with
|
|
64
|
+
* `permissionDeniedResponse(...)`.
|
|
65
|
+
*
|
|
66
|
+
* Always call this BEFORE the regular `askEditPermission` so the user sees the
|
|
67
|
+
* external-directory prompt first (matching opencode native ordering). When the
|
|
68
|
+
* external-directory rule is `allow` (e.g. for `${os.tmpdir()}/opencode/*`), the
|
|
69
|
+
* call short-circuits and the regular permission flow continues normally.
|
|
70
|
+
*/
|
|
71
|
+
export declare function assertExternalDirectoryPermission(context: ToolContext, target: string, options?: {
|
|
72
|
+
kind?: "file" | "directory";
|
|
73
|
+
}): Promise<string | undefined>;
|
|
74
|
+
/**
|
|
75
|
+
* Trigger OpenCode's host-side `grep` permission check.
|
|
76
|
+
*
|
|
77
|
+
* Mirrors `opencode/src/tool/grep.ts` shape exactly so users with
|
|
78
|
+
* `"permission": { "grep": { "*": "ask" } }` (or "deny") see the same
|
|
79
|
+
* prompt regardless of whether they're using AFT's hoisted `grep` or
|
|
80
|
+
* OpenCode's built-in.
|
|
81
|
+
*/
|
|
82
|
+
export declare function askGrepPermission(context: ToolContext, pattern: string, metadata?: {
|
|
83
|
+
path?: string;
|
|
84
|
+
include?: string;
|
|
85
|
+
}): Promise<string | undefined>;
|
|
86
|
+
/**
|
|
87
|
+
* Trigger OpenCode's host-side `glob` permission check.
|
|
88
|
+
*
|
|
89
|
+
* Mirrors `opencode/src/tool/glob.ts` shape exactly so users with
|
|
90
|
+
* `"permission": { "glob": { "*": "ask" } }` see the same prompt
|
|
91
|
+
* regardless of which glob tool is used.
|
|
92
|
+
*/
|
|
93
|
+
export declare function askGlobPermission(context: ToolContext, pattern: string, metadata?: {
|
|
94
|
+
path?: string;
|
|
95
|
+
}): Promise<string | undefined>;
|
|
28
96
|
export declare function permissionDeniedResponse(message: string): string;
|
|
97
|
+
export {};
|
|
29
98
|
//# sourceMappingURL=permissions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/tools/permissions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/tools/permissions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAKhC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEhF;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnF;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAazF;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,CAE9D;AAED,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,MAAM,EAAE,EAClB,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACrC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAkB7B;AAED;;;GAGG;AACH,iBAAS,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAI5D;AA6CD;;;;;;;;;;;;GAYG;AACH,iBAAS,oBAAoB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAO/C;AAED,eAAO,MAAM,4BAA4B;;;CAAyC,CAAC;AAEnF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,iCAAiC,CACrD,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,CAAA;CAAE,GACxC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAqD7B;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GACjD,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAkB7B;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAkB7B;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAOhE"}
|
|
@@ -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;
|
|
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;AAcjD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CA0InF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../src/tools/safety.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../src/tools/safety.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAajD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAoH9E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA8DjD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CA0BrD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAoI9E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"structure.d.ts","sourceRoot":"","sources":["../../src/tools/structure.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":"structure.d.ts","sourceRoot":"","sources":["../../src/tools/structure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAYjD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAkKjF"}
|
package/dist/tui.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// package.json
|
|
3
3
|
var package_default = {
|
|
4
4
|
name: "@cortexkit/aft-opencode",
|
|
5
|
-
version: "0.
|
|
5
|
+
version: "0.22.0",
|
|
6
6
|
type: "module",
|
|
7
7
|
description: "OpenCode plugin for Agent File Tools (AFT) \u2014 tree-sitter and lsp powered code analysis",
|
|
8
8
|
main: "dist/index.js",
|
|
@@ -30,7 +30,7 @@ var package_default = {
|
|
|
30
30
|
},
|
|
31
31
|
dependencies: {
|
|
32
32
|
"@clack/prompts": "^1.2.0",
|
|
33
|
-
"@cortexkit/aft-bridge": "0.
|
|
33
|
+
"@cortexkit/aft-bridge": "0.22.0",
|
|
34
34
|
"@opencode-ai/plugin": "^1.14.39",
|
|
35
35
|
"@opencode-ai/sdk": "^1.14.39",
|
|
36
36
|
"comment-json": "^4.6.2",
|
|
@@ -38,11 +38,11 @@ var package_default = {
|
|
|
38
38
|
zod: "^4.1.8"
|
|
39
39
|
},
|
|
40
40
|
optionalDependencies: {
|
|
41
|
-
"@cortexkit/aft-darwin-arm64": "0.
|
|
42
|
-
"@cortexkit/aft-darwin-x64": "0.
|
|
43
|
-
"@cortexkit/aft-linux-arm64": "0.
|
|
44
|
-
"@cortexkit/aft-linux-x64": "0.
|
|
45
|
-
"@cortexkit/aft-win32-x64": "0.
|
|
41
|
+
"@cortexkit/aft-darwin-arm64": "0.22.0",
|
|
42
|
+
"@cortexkit/aft-darwin-x64": "0.22.0",
|
|
43
|
+
"@cortexkit/aft-linux-arm64": "0.22.0",
|
|
44
|
+
"@cortexkit/aft-linux-x64": "0.22.0",
|
|
45
|
+
"@cortexkit/aft-win32-x64": "0.22.0"
|
|
46
46
|
},
|
|
47
47
|
devDependencies: {
|
|
48
48
|
"@types/node": "^22.0.0",
|
|
@@ -827,6 +827,41 @@ async function showStatusDialog(api) {
|
|
|
827
827
|
api.ui.dialog.setSize("medium");
|
|
828
828
|
});
|
|
829
829
|
}
|
|
830
|
+
function registerStatusCommand(api) {
|
|
831
|
+
const apiAny = api;
|
|
832
|
+
if (typeof apiAny.keymap?.registerLayer === "function") {
|
|
833
|
+
apiAny.keymap.registerLayer({
|
|
834
|
+
commands: [
|
|
835
|
+
{
|
|
836
|
+
namespace: "palette",
|
|
837
|
+
name: "aft.status",
|
|
838
|
+
title: "AFT: Status",
|
|
839
|
+
category: "AFT",
|
|
840
|
+
slashName: STATUS_COMMAND,
|
|
841
|
+
run() {
|
|
842
|
+
showStatusDialog(api);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
],
|
|
846
|
+
bindings: []
|
|
847
|
+
});
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
if (typeof apiAny.command?.register === "function") {
|
|
851
|
+
apiAny.command.register(() => [
|
|
852
|
+
{
|
|
853
|
+
title: "AFT: Status",
|
|
854
|
+
value: "aft.status",
|
|
855
|
+
category: "AFT",
|
|
856
|
+
slash: { name: STATUS_COMMAND },
|
|
857
|
+
onSelect() {
|
|
858
|
+
showStatusDialog(api);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
]);
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
830
865
|
async function showStartupNotifications(api) {
|
|
831
866
|
const directory = api.state.path.directory ?? "";
|
|
832
867
|
if (!directory)
|
|
@@ -869,17 +904,7 @@ var tui = async (api) => {
|
|
|
869
904
|
try {
|
|
870
905
|
api.slots.register(createAftSidebarSlot(api, package_default.version));
|
|
871
906
|
} catch {}
|
|
872
|
-
api
|
|
873
|
-
{
|
|
874
|
-
title: "AFT: Status",
|
|
875
|
-
value: "aft.status",
|
|
876
|
-
category: "AFT",
|
|
877
|
-
slash: { name: STATUS_COMMAND },
|
|
878
|
-
onSelect() {
|
|
879
|
-
showStatusDialog(api);
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
]);
|
|
907
|
+
registerStatusCommand(api);
|
|
883
908
|
showStartupNotifications(api);
|
|
884
909
|
};
|
|
885
910
|
var id = "aft-opencode";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/aft-opencode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.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",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@clack/prompts": "^1.2.0",
|
|
31
|
-
"@cortexkit/aft-bridge": "0.
|
|
31
|
+
"@cortexkit/aft-bridge": "0.22.0",
|
|
32
32
|
"@opencode-ai/plugin": "^1.14.39",
|
|
33
33
|
"@opencode-ai/sdk": "^1.14.39",
|
|
34
34
|
"comment-json": "^4.6.2",
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"zod": "^4.1.8"
|
|
37
37
|
},
|
|
38
38
|
"optionalDependencies": {
|
|
39
|
-
"@cortexkit/aft-darwin-arm64": "0.
|
|
40
|
-
"@cortexkit/aft-darwin-x64": "0.
|
|
41
|
-
"@cortexkit/aft-linux-arm64": "0.
|
|
42
|
-
"@cortexkit/aft-linux-x64": "0.
|
|
43
|
-
"@cortexkit/aft-win32-x64": "0.
|
|
39
|
+
"@cortexkit/aft-darwin-arm64": "0.22.0",
|
|
40
|
+
"@cortexkit/aft-darwin-x64": "0.22.0",
|
|
41
|
+
"@cortexkit/aft-linux-arm64": "0.22.0",
|
|
42
|
+
"@cortexkit/aft-linux-x64": "0.22.0",
|
|
43
|
+
"@cortexkit/aft-win32-x64": "0.22.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/node": "^22.0.0",
|
package/src/shared/rpc-server.ts
CHANGED
|
@@ -46,9 +46,12 @@ export class AftRpcServer {
|
|
|
46
46
|
// Write port file atomically
|
|
47
47
|
try {
|
|
48
48
|
const dir = dirname(this.portFilePath);
|
|
49
|
-
mkdirSync(dir, { recursive: true });
|
|
49
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
50
50
|
const tmpPath = `${this.portFilePath}.tmp`;
|
|
51
|
-
writeFileSync(tmpPath, JSON.stringify({ port: this.port, token: this.token }),
|
|
51
|
+
writeFileSync(tmpPath, JSON.stringify({ port: this.port, token: this.token }), {
|
|
52
|
+
encoding: "utf-8",
|
|
53
|
+
mode: 0o600,
|
|
54
|
+
});
|
|
52
55
|
renameSync(tmpPath, this.portFilePath);
|
|
53
56
|
log(`RPC server listening on 127.0.0.1:${this.port}`);
|
|
54
57
|
} catch (err) {
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagent detection via OpenCode SDK.
|
|
3
|
+
*
|
|
4
|
+
* AFT bash auto-promotes anything that takes more than ~5s to a background
|
|
5
|
+
* task. For the main agent (Alfonso), promotion is fine — the completion
|
|
6
|
+
* reminder fires back into the conversation and the agent picks it up on
|
|
7
|
+
* its next idle. For SUBAGENTS, promotion is fatal: a subagent waiting for
|
|
8
|
+
* a background-bash completion must end its turn to receive the reminder,
|
|
9
|
+
* which closes the subagent session permanently. The subagent never gets
|
|
10
|
+
* to commit its work.
|
|
11
|
+
*
|
|
12
|
+
* This module detects whether a session is a subagent (has a non-empty
|
|
13
|
+
* `parentID`) so the bash tool can:
|
|
14
|
+
* 1. Refuse `background: true` outright for subagents.
|
|
15
|
+
* 2. Disable auto-promotion: the foreground poll window extends to the
|
|
16
|
+
* task's full hard-kill timeout instead of the default 5s.
|
|
17
|
+
*
|
|
18
|
+
* Detection is via the OpenCode SDK `client.session.get`. The result is
|
|
19
|
+
* cached per sessionID for the lifetime of the plugin process — subagent
|
|
20
|
+
* identity is sticky (parentID never changes after session creation), so
|
|
21
|
+
* the cache never needs invalidation.
|
|
22
|
+
*
|
|
23
|
+
* Errors are not cached. If the SDK is briefly unavailable on the first
|
|
24
|
+
* call, we retry on the next bash invocation rather than permanently
|
|
25
|
+
* misclassifying. This is cheap because the cache is hit on every
|
|
26
|
+
* subsequent call within the same session.
|
|
27
|
+
*
|
|
28
|
+
* Mirrors the pattern in `session-directory.ts`.
|
|
29
|
+
*/
|
|
30
|
+
import { sessionLog, sessionWarn } from "../logger.js";
|
|
31
|
+
|
|
32
|
+
interface SessionInfo {
|
|
33
|
+
parentID?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface OpenCodeClientShape {
|
|
37
|
+
session?: {
|
|
38
|
+
get?: (input: {
|
|
39
|
+
path: { id: string };
|
|
40
|
+
query?: { directory?: string };
|
|
41
|
+
throwOnError?: boolean;
|
|
42
|
+
}) => Promise<{ data?: SessionInfo } | SessionInfo | undefined>;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface CacheEntry {
|
|
47
|
+
isSubagent: boolean;
|
|
48
|
+
recordedAt: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const CACHE_MAX_ENTRIES = 200;
|
|
52
|
+
const cache = new Map<string, CacheEntry>();
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Returns `true` when the given session has a non-empty `parentID`
|
|
56
|
+
* (subagent). Returns `false` for primary sessions, when the SDK is
|
|
57
|
+
* unavailable, or when any error occurs — the false default keeps
|
|
58
|
+
* primary sessions working exactly as before.
|
|
59
|
+
*
|
|
60
|
+
* First call per session: one SDK round-trip. All subsequent calls:
|
|
61
|
+
* O(1) cache lookup.
|
|
62
|
+
*/
|
|
63
|
+
export async function resolveIsSubagent(
|
|
64
|
+
client: unknown,
|
|
65
|
+
sessionId: string | undefined,
|
|
66
|
+
_fallbackDirectory?: string,
|
|
67
|
+
): Promise<boolean> {
|
|
68
|
+
if (!sessionId) {
|
|
69
|
+
sessionLog(undefined, "[subagent-detect] no sessionId provided → primary");
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const cached = cache.get(sessionId);
|
|
74
|
+
if (cached) {
|
|
75
|
+
// Refresh LRU position
|
|
76
|
+
cache.delete(sessionId);
|
|
77
|
+
cache.set(sessionId, cached);
|
|
78
|
+
sessionLog(sessionId, `[subagent-detect] cache hit: isSubagent=${cached.isSubagent}`);
|
|
79
|
+
return cached.isSubagent;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const c = client as OpenCodeClientShape;
|
|
83
|
+
const sessionApi = c?.session;
|
|
84
|
+
if (!sessionApi || typeof sessionApi.get !== "function") {
|
|
85
|
+
// SDK shape unavailable. Cache as not-subagent so we don't retry
|
|
86
|
+
// every call when the host doesn't expose session.get.
|
|
87
|
+
sessionLog(
|
|
88
|
+
sessionId,
|
|
89
|
+
`[subagent-detect] client.session.get unavailable (client=${typeof client}, session=${typeof sessionApi}, get=${typeof sessionApi?.get}) → caching as primary`,
|
|
90
|
+
);
|
|
91
|
+
setCache(sessionId, false);
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
sessionLog(
|
|
96
|
+
sessionId,
|
|
97
|
+
`[subagent-detect] cache miss, calling client.session.get(id=${sessionId})`,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
let isSubagent = false;
|
|
101
|
+
let parentIdRaw: unknown;
|
|
102
|
+
try {
|
|
103
|
+
// Call as a method so the SDK's `this._client` reference resolves
|
|
104
|
+
// correctly. Extracting `sessionApi.get` into a local would lose
|
|
105
|
+
// the binding and crash the SDK with "undefined is not an object".
|
|
106
|
+
// SDK schema: SessionGetData uses `path: { id }`, NOT a flat `sessionID`.
|
|
107
|
+
// We do NOT pass `directory` — looking up a session by ID is an identity
|
|
108
|
+
// query, not a directory-scoped one. Passing the wrong shape returned a
|
|
109
|
+
// different session whose `parentID` was undefined, defeating the gate.
|
|
110
|
+
const result = await sessionApi.get({
|
|
111
|
+
path: { id: sessionId },
|
|
112
|
+
});
|
|
113
|
+
// SDK responses come either as `{ data: Session }` or directly as
|
|
114
|
+
// `Session` depending on `ThrowOnError`. Handle both shapes.
|
|
115
|
+
const session: SessionInfo | undefined =
|
|
116
|
+
(result as { data?: SessionInfo } | undefined)?.data ?? (result as SessionInfo | undefined);
|
|
117
|
+
parentIdRaw = session?.parentID;
|
|
118
|
+
isSubagent =
|
|
119
|
+
session !== undefined && typeof session.parentID === "string" && session.parentID.length > 0;
|
|
120
|
+
sessionLog(
|
|
121
|
+
sessionId,
|
|
122
|
+
`[subagent-detect] SDK returned session=${session !== undefined ? "present" : "undefined"}, parentID=${JSON.stringify(parentIdRaw)} → isSubagent=${isSubagent}`,
|
|
123
|
+
);
|
|
124
|
+
} catch (err) {
|
|
125
|
+
// Don't poison the cache on transient errors — but do log once.
|
|
126
|
+
// Return false so primary-session behavior is preserved.
|
|
127
|
+
sessionWarn(
|
|
128
|
+
sessionId,
|
|
129
|
+
`[subagent-detect] SDK lookup failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
130
|
+
);
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
setCache(sessionId, isSubagent);
|
|
135
|
+
return isSubagent;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function setCache(sessionId: string, isSubagent: boolean): void {
|
|
139
|
+
if (cache.has(sessionId)) cache.delete(sessionId);
|
|
140
|
+
cache.set(sessionId, { isSubagent, recordedAt: Date.now() });
|
|
141
|
+
if (cache.size > CACHE_MAX_ENTRIES) {
|
|
142
|
+
const oldest = cache.keys().next().value;
|
|
143
|
+
if (oldest !== undefined) cache.delete(oldest);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Test-only cache reset. Not exported from the public surface. */
|
|
148
|
+
export function _resetSubagentCacheForTest(): void {
|
|
149
|
+
cache.clear();
|
|
150
|
+
}
|
package/src/tui/index.tsx
CHANGED
|
@@ -138,6 +138,69 @@ async function showStatusDialog(api: TuiPluginApi): Promise<void> {
|
|
|
138
138
|
);
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Register the `/aft-status` slash command, preferring the v1.14.42+ keymap
|
|
143
|
+
* API and falling back to the legacy `api.command.register` for older hosts.
|
|
144
|
+
*
|
|
145
|
+
* The `keymap.registerLayer` shape uses `name`/`title`/`run`/`namespace`/
|
|
146
|
+
* `slashName` (see `@opencode-ai/plugin/tui` types) and is what the host's
|
|
147
|
+
* own legacy command-shim translates into. Calling it directly skips the
|
|
148
|
+
* deprecation warning and works without depending on the (now-deprecated)
|
|
149
|
+
* `api.command` namespace existing at all.
|
|
150
|
+
*/
|
|
151
|
+
function registerStatusCommand(api: TuiPluginApi): void {
|
|
152
|
+
type ApiAny = {
|
|
153
|
+
keymap?: {
|
|
154
|
+
registerLayer?: (layer: {
|
|
155
|
+
commands: Array<Record<string, unknown>>;
|
|
156
|
+
bindings: Array<Record<string, unknown>>;
|
|
157
|
+
}) => unknown;
|
|
158
|
+
};
|
|
159
|
+
command?: {
|
|
160
|
+
register?: (cb: () => Array<Record<string, unknown>>) => unknown;
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
const apiAny = api as unknown as ApiAny;
|
|
164
|
+
|
|
165
|
+
if (typeof apiAny.keymap?.registerLayer === "function") {
|
|
166
|
+
apiAny.keymap.registerLayer({
|
|
167
|
+
commands: [
|
|
168
|
+
{
|
|
169
|
+
namespace: "palette",
|
|
170
|
+
name: "aft.status",
|
|
171
|
+
title: "AFT: Status",
|
|
172
|
+
category: "AFT",
|
|
173
|
+
slashName: STATUS_COMMAND,
|
|
174
|
+
run() {
|
|
175
|
+
void showStatusDialog(api);
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
],
|
|
179
|
+
bindings: [],
|
|
180
|
+
});
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (typeof apiAny.command?.register === "function") {
|
|
185
|
+
apiAny.command.register(() => [
|
|
186
|
+
{
|
|
187
|
+
title: "AFT: Status",
|
|
188
|
+
value: "aft.status",
|
|
189
|
+
category: "AFT",
|
|
190
|
+
slash: { name: STATUS_COMMAND },
|
|
191
|
+
onSelect() {
|
|
192
|
+
void showStatusDialog(api);
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
]);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Neither API surface is present. The TUI host can still load — we only
|
|
200
|
+
// lose the slash-command entry point. The sidebar (registered above)
|
|
201
|
+
// remains available so users can still see AFT status visually.
|
|
202
|
+
}
|
|
203
|
+
|
|
141
204
|
async function showStartupNotifications(api: TuiPluginApi): Promise<void> {
|
|
142
205
|
const directory = api.state.path.directory ?? "";
|
|
143
206
|
if (!directory) return;
|
|
@@ -203,17 +266,15 @@ const tui: TuiPlugin = async (api) => {
|
|
|
203
266
|
// and keep the slash command working.
|
|
204
267
|
}
|
|
205
268
|
|
|
206
|
-
api.command.register
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
},
|
|
216
|
-
]);
|
|
269
|
+
// OpenCode 1.14.42 removed `api.command.register` entirely
|
|
270
|
+
// (anomalyco/opencode PR #26053). Later patches reinstated it as a
|
|
271
|
+
// deprecated shim that translates to `api.keymap.registerLayer`. To work
|
|
272
|
+
// across the whole 1.14.x line — including the brief 1.14.42 / 1.14.43
|
|
273
|
+
// window where neither the legacy API nor a shim was present — we prefer
|
|
274
|
+
// `api.keymap.registerLayer` and fall back to `api.command.register` only
|
|
275
|
+
// when the keymap surface is missing (older hosts that predate keymap).
|
|
276
|
+
// See https://github.com/cortexkit/aft/issues/33.
|
|
277
|
+
registerStatusCommand(api);
|
|
217
278
|
|
|
218
279
|
// Show startup notifications — RPC server is already running by the time TUI loads
|
|
219
280
|
void showStartupNotifications(api);
|
package/dist/shared/runtime.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
type BridgeLike = {
|
|
2
|
-
getBridge: (directory: string, sessionID: string) => {
|
|
3
|
-
send: (command: string, params?: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
4
|
-
};
|
|
5
|
-
};
|
|
6
|
-
export declare function setSharedBridgePool(pool: BridgeLike): void;
|
|
7
|
-
export declare function getSharedBridgePool(): BridgeLike | null;
|
|
8
|
-
export declare function clearSharedBridgePool(): void;
|
|
9
|
-
export {};
|
|
10
|
-
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/shared/runtime.ts"],"names":[],"mappings":"AAAA,KAAK,UAAU,GAAG;IAChB,SAAS,EAAE,CACT,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,KACd;QACH,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;KAC/F,CAAC;CACH,CAAC;AAQF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAE1D;AAED,wBAAgB,mBAAmB,IAAI,UAAU,GAAG,IAAI,CAEvD;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C"}
|