@cortexkit/aft-opencode 0.29.0 → 0.29.1
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 +22 -7
- package/dist/bg-notifications.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -35
- package/dist/shared/live-server-client.d.ts +30 -11
- package/dist/shared/live-server-client.d.ts.map +1 -1
- package/dist/tui.js +8 -8
- package/package.json +8 -8
- package/src/shared/live-server-client.ts +56 -14
|
@@ -46,13 +46,28 @@ interface DrainContext {
|
|
|
46
46
|
directory: string;
|
|
47
47
|
sessionID: string;
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* live listener
|
|
52
|
-
*
|
|
53
|
-
* the
|
|
54
|
-
*
|
|
55
|
-
*
|
|
49
|
+
* Plugin-provided OpenCode SDK client (`input.client`). The wake path
|
|
50
|
+
* uses this as a fallback when `useLiveServerWake()` is false — i.e.
|
|
51
|
+
* the live HTTP listener was unreachable when probed at plugin init,
|
|
52
|
+
* so `getLiveServerClient(...)` cannot be built. Falling back here
|
|
53
|
+
* accepts the upstream `promptAsync` runner-split bug
|
|
54
|
+
* (anomalyco/opencode#28202; duplicate "stop" messages) in exchange
|
|
55
|
+
* for wakes still arriving at all in plain-TUI sessions.
|
|
56
|
+
*
|
|
57
|
+
* Typed `unknown` because the real `@opencode-ai/sdk` `OpencodeClient`
|
|
58
|
+
* has a narrower, generated `promptAsync` signature than the loose
|
|
59
|
+
* structural `OpenCodeClient` shape used by the live-server factory
|
|
60
|
+
* and test stubs. The wake closure asserts to `OpenCodeClient` after
|
|
61
|
+
* deciding which transport to use.
|
|
62
|
+
*/
|
|
63
|
+
client?: unknown;
|
|
64
|
+
/**
|
|
65
|
+
* Live OpenCode HTTP listener URL (from `input.serverUrl`). When the
|
|
66
|
+
* listener was reachable at startup, the wake path builds a separate
|
|
67
|
+
* `createOpencodeClient` from this URL so requests hit the same Effect
|
|
68
|
+
* memoMap as the live UI — works around the runner-split bug
|
|
69
|
+
* (anomalyco/opencode#28202). When the listener was unreachable, the
|
|
70
|
+
* wake path falls back to `client` above; this URL is unused.
|
|
56
71
|
*/
|
|
57
72
|
serverUrl?: string;
|
|
58
73
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bg-notifications.d.ts","sourceRoot":"","sources":["../src/bg-notifications.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAWhD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAG3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,KAAK,cAAc,GAAG;IACpB,kBAAkB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAChC,kBAAkB,EAAE,YAAY,EAAE,CAAC;IACnC,kBAAkB,EAAE,qBAAqB,EAAE,CAAC;IAC5C,aAAa,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IACrC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,wBAAwB,EAAE,MAAM,CAAC;IACjC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,OAAO,CAAC;IACzB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,kBAAkB,EAAE,KAAK,CAAC;QAAE,UAAU,EAAE,YAAY,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5E,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAa,CAAC;AAGtE,eAAO,MAAM,4BAA4B,QAAiB,CAAC;AAS3D,UAAU,YAAY;IACpB,GAAG,EAAE,aAAa,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB
|
|
1
|
+
{"version":3,"file":"bg-notifications.d.ts","sourceRoot":"","sources":["../src/bg-notifications.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAqKlD;;;;;;;;;;;;;;;;;;GAkBG;AAQH,QAAA,MAAM,MAAM,EAAE,MAA6D,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAqKlD;;;;;;;;;;;;;;;;;;GAkBG;AAQH,QAAA,MAAM,MAAM,EAAE,MAA6D,CAAC;AAqyB5E,eAAe,MAAM,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -31001,6 +31001,7 @@ import { chmodSync as chmodSync2, copyFileSync, existsSync as existsSync2, mkdir
|
|
|
31001
31001
|
import { createRequire as createRequire2 } from "node:module";
|
|
31002
31002
|
import { homedir as homedir3 } from "node:os";
|
|
31003
31003
|
import { join as join3 } from "node:path";
|
|
31004
|
+
var ensureBinaryForResolver = ensureBinary;
|
|
31004
31005
|
function readBinaryVersion(binaryPath) {
|
|
31005
31006
|
try {
|
|
31006
31007
|
const result = spawnSync(binaryPath, ["--version"], {
|
|
@@ -31141,7 +31142,7 @@ async function findBinary(expectedVersion) {
|
|
|
31141
31142
|
return syncResult;
|
|
31142
31143
|
}
|
|
31143
31144
|
log("Binary not found locally, attempting auto-download...");
|
|
31144
|
-
const downloaded = await
|
|
31145
|
+
const downloaded = await ensureBinaryForResolver(expectedVersion);
|
|
31145
31146
|
if (downloaded)
|
|
31146
31147
|
return downloaded;
|
|
31147
31148
|
throw new Error([
|
|
@@ -31165,6 +31166,7 @@ async function findBinary(expectedVersion) {
|
|
|
31165
31166
|
}
|
|
31166
31167
|
|
|
31167
31168
|
// ../aft-bridge/dist/migration.js
|
|
31169
|
+
var spawnSyncForMigration = spawnSync2;
|
|
31168
31170
|
var TARGET_MARKER = ".migrated_from_legacy";
|
|
31169
31171
|
var DEFAULT_TIMEOUT_MS = 30 * 60 * 1000;
|
|
31170
31172
|
function dataHome() {
|
|
@@ -31236,7 +31238,7 @@ async function ensureStorageMigrated(opts) {
|
|
|
31236
31238
|
|
|
31237
31239
|
`);
|
|
31238
31240
|
} catch {}
|
|
31239
|
-
const result =
|
|
31241
|
+
const result = spawnSyncForMigration(binaryPath, [
|
|
31240
31242
|
"migrate-storage",
|
|
31241
31243
|
"--from",
|
|
31242
31244
|
legacyRoot,
|
|
@@ -32692,9 +32694,6 @@ function getLiveServerClient(serverUrl, directory) {
|
|
|
32692
32694
|
clientCache.set(key, client);
|
|
32693
32695
|
return client;
|
|
32694
32696
|
}
|
|
32695
|
-
function isBunRuntime() {
|
|
32696
|
-
return typeof globalThis.Bun !== "undefined";
|
|
32697
|
-
}
|
|
32698
32697
|
async function probeServerReachable(serverUrl, timeoutMs = 1500) {
|
|
32699
32698
|
if (!serverUrl)
|
|
32700
32699
|
return false;
|
|
@@ -32713,6 +32712,13 @@ async function probeServerReachable(serverUrl, timeoutMs = 1500) {
|
|
|
32713
32712
|
clearTimeout(timer);
|
|
32714
32713
|
}
|
|
32715
32714
|
}
|
|
32715
|
+
var liveServerWakeAvailable = false;
|
|
32716
|
+
function setLiveServerWakeAvailable(available) {
|
|
32717
|
+
liveServerWakeAvailable = available;
|
|
32718
|
+
}
|
|
32719
|
+
function useLiveServerWake() {
|
|
32720
|
+
return liveServerWakeAvailable;
|
|
32721
|
+
}
|
|
32716
32722
|
|
|
32717
32723
|
// src/bg-notifications.ts
|
|
32718
32724
|
function hashReminder(text) {
|
|
@@ -32819,18 +32825,26 @@ async function triggerWakeIfPending(drainContext, skipDrain) {
|
|
|
32819
32825
|
if (state.pendingCompletions.length === 0 && state.pendingLongRunning.length === 0)
|
|
32820
32826
|
return;
|
|
32821
32827
|
scheduleWake(state, async (reminder, deliveredCompletions) => {
|
|
32822
|
-
|
|
32823
|
-
|
|
32824
|
-
|
|
32825
|
-
|
|
32826
|
-
|
|
32827
|
-
|
|
32828
|
-
|
|
32829
|
-
|
|
32828
|
+
let client;
|
|
32829
|
+
let clientPath;
|
|
32830
|
+
if (useLiveServerWake() && drainContext.serverUrl) {
|
|
32831
|
+
client = getLiveServerClient(drainContext.serverUrl, drainContext.directory);
|
|
32832
|
+
clientPath = "live-server";
|
|
32833
|
+
} else {
|
|
32834
|
+
if (!drainContext.client) {
|
|
32835
|
+
sessionWarn(drainContext.sessionID, `${LOG_PREFIX} wake client unavailable`, {
|
|
32836
|
+
event: "bash_completion_wake_client_unavailable",
|
|
32837
|
+
task_ids: deliveredCompletions.map((c) => c.task_id),
|
|
32838
|
+
directory: drainContext.directory,
|
|
32839
|
+
attempt: state.wakeRetryAttempts + 1
|
|
32840
|
+
});
|
|
32841
|
+
throw new Error("no wake transport available: live-server unreachable and input.client absent");
|
|
32842
|
+
}
|
|
32843
|
+
client = drainContext.client;
|
|
32844
|
+
clientPath = "in-process-fallback";
|
|
32830
32845
|
}
|
|
32831
|
-
const client = getLiveServerClient(drainContext.serverUrl, drainContext.directory);
|
|
32832
32846
|
if (typeof client.session?.promptAsync !== "function") {
|
|
32833
|
-
throw new Error(
|
|
32847
|
+
throw new Error(`wake client.session.promptAsync is unavailable (path=${clientPath})`);
|
|
32834
32848
|
}
|
|
32835
32849
|
const promptContext = await resolvePromptContext(client, drainContext.sessionID);
|
|
32836
32850
|
const body = {
|
|
@@ -32856,7 +32870,7 @@ async function triggerWakeIfPending(drainContext, skipDrain) {
|
|
|
32856
32870
|
directory: drainContext.directory,
|
|
32857
32871
|
reminder_sha256: hashReminder(reminder),
|
|
32858
32872
|
reminder_chars: reminder.length,
|
|
32859
|
-
wake_client_path:
|
|
32873
|
+
wake_client_path: clientPath,
|
|
32860
32874
|
prompt_context: promptContext ? {
|
|
32861
32875
|
agent: promptContext.agent,
|
|
32862
32876
|
model: promptContext.model ? {
|
|
@@ -54012,18 +54026,12 @@ ${lines}
|
|
|
54012
54026
|
config: aftConfig,
|
|
54013
54027
|
storageDir: configOverrides.storage_dir
|
|
54014
54028
|
};
|
|
54015
|
-
|
|
54016
|
-
|
|
54017
|
-
|
|
54018
|
-
|
|
54019
|
-
|
|
54020
|
-
|
|
54021
|
-
}
|
|
54022
|
-
}).catch(() => {
|
|
54023
|
-
tuiPortZeroNudgeNeeded = true;
|
|
54024
|
-
});
|
|
54025
|
-
}
|
|
54026
|
-
const tuiNudgeSentSessions = new Set;
|
|
54029
|
+
probeServerReachable(input.serverUrl?.toString()).then((reachable) => {
|
|
54030
|
+
setLiveServerWakeAvailable(reachable);
|
|
54031
|
+
log2(reachable ? "Live OpenCode HTTP listener reachable; bg-notifications wake path = live-server (anomalyco/opencode#28202 workaround active)." : "Live OpenCode HTTP listener unreachable; bg-notifications wake path = in-process-fallback. Wakes will still arrive but the upstream duplicate-runner bug (anomalyco/opencode#28202) is not worked around. Launch with `opencode --port 0` in TUI mode to activate the workaround.");
|
|
54032
|
+
}).catch(() => {
|
|
54033
|
+
setLiveServerWakeAvailable(false);
|
|
54034
|
+
});
|
|
54027
54035
|
if (onnxRuntimePromise) {
|
|
54028
54036
|
onnxRuntimePromise.then((ortDylibDir) => {
|
|
54029
54037
|
if (ortDylibDir) {
|
|
@@ -54237,13 +54245,6 @@ Install: ${getManualInstallHint()}`).catch(() => {});
|
|
|
54237
54245
|
"chat.message": async (messageInput) => {
|
|
54238
54246
|
const sid = messageInput.sessionID ?? messageInput.sessionId ?? messageInput.id;
|
|
54239
54247
|
warmSessionDirectory(input.client, sid, input.directory);
|
|
54240
|
-
if (tuiPortZeroNudgeNeeded && typeof sid === "string" && sid.length > 0) {
|
|
54241
|
-
if (!tuiNudgeSentSessions.has(sid)) {
|
|
54242
|
-
tuiNudgeSentSessions.add(sid);
|
|
54243
|
-
const nudge = "Due to a bug in opencode (https://github.com/anomalyco/opencode/issues/28202), background bash notifications are now using a workaround which needs opencode to be run via `opencode --port 0` in TUI mode. Opencode Desktop doesn't need special treatment.";
|
|
54244
|
-
sendIgnoredMessage2(input.client, sid, nudge).catch(() => {});
|
|
54245
|
-
}
|
|
54246
|
-
}
|
|
54247
54248
|
},
|
|
54248
54249
|
"command.execute.before": async (commandInput, _output) => {
|
|
54249
54250
|
if (isTuiMode2() || commandInput.command !== STATUS_COMMAND) {
|
|
@@ -19,6 +19,16 @@
|
|
|
19
19
|
* UI uses, so the active session's `SessionRunState` is the one that
|
|
20
20
|
* resolves `ensureRunning` and overlapping turns coalesce correctly.
|
|
21
21
|
*
|
|
22
|
+
* The workaround only works when the live HTTP listener is actually
|
|
23
|
+
* reachable. OpenCode Desktop (Electron+Node) and TUI launched with
|
|
24
|
+
* `opencode --port 0` bind a real API listener; plain TUI binds an
|
|
25
|
+
* internal-only listener that 404s for `/session/*`. We probe once at
|
|
26
|
+
* plugin init and cache the result. When the listener is unreachable
|
|
27
|
+
* the wake path silently uses the in-process `input.client.session.promptAsync`,
|
|
28
|
+
* which keeps wakes flowing (at the cost of the upstream duplicate-runner
|
|
29
|
+
* bug) instead of producing no notification at all or nagging the user
|
|
30
|
+
* to relaunch with a different flag.
|
|
31
|
+
*
|
|
22
32
|
* Tracked upstream as anomalyco/opencode#28202. When OpenCode fixes the
|
|
23
33
|
* runtime split, this helper and its single consumer in `bg-notifications.ts`
|
|
24
34
|
* can be deleted and the wake path can go back to `input.client`.
|
|
@@ -38,23 +48,32 @@ export type LiveServerClient = ReturnType<typeof createOpencodeClient>;
|
|
|
38
48
|
export declare function getLiveServerClient(serverUrl: string, directory: string): LiveServerClient;
|
|
39
49
|
/** Test helper — drop the cache between cases so each test starts clean. */
|
|
40
50
|
export declare function __resetLiveServerClientCacheForTests(): void;
|
|
41
|
-
/**
|
|
42
|
-
* True when the current runtime is Bun. OpenCode's TUI ships with Bun;
|
|
43
|
-
* the Electron Desktop app ships with Node. We use this to gate the
|
|
44
|
-
* `--port 0` nudge: Desktop is unaffected by anomalyco/opencode#28202
|
|
45
|
-
* because Node's webidl polyfill is complete, so undici v8 (and the live
|
|
46
|
-
* HTTP server) work without additional flags.
|
|
47
|
-
*/
|
|
48
|
-
export declare function isBunRuntime(): boolean;
|
|
49
51
|
/**
|
|
50
52
|
* Probe whether `serverUrl` accepts a connection within `timeoutMs`.
|
|
51
53
|
* Returns `true` for any HTTP response (including 4xx / 5xx) since the
|
|
52
54
|
* goal is to confirm the listener exists. Returns `false` on connection
|
|
53
55
|
* refused, DNS failure, timeout, or undefined URL.
|
|
54
56
|
*
|
|
55
|
-
* Used at plugin init
|
|
56
|
-
*
|
|
57
|
-
*
|
|
57
|
+
* Used at plugin init to decide whether bg-notifications should use the
|
|
58
|
+
* live-server wake transport (workaround for anomalyco/opencode#28202)
|
|
59
|
+
* or fall back to the in-process `input.client.session.promptAsync`
|
|
60
|
+
* path. Plain TUI (no `--port 0`) binds an internal-only listener that
|
|
61
|
+
* 404s for `/session/...`, so this returns false there; OpenCode
|
|
62
|
+
* Desktop, `opencode run`, and `opencode --port 0` TUI return true.
|
|
58
63
|
*/
|
|
59
64
|
export declare function probeServerReachable(serverUrl: string | undefined, timeoutMs?: number): Promise<boolean>;
|
|
65
|
+
/**
|
|
66
|
+
* Record the probe result. Idempotent; if you record twice, the latest
|
|
67
|
+
* value wins. The wake path reads through `useLiveServerWake()`.
|
|
68
|
+
*/
|
|
69
|
+
export declare function setLiveServerWakeAvailable(available: boolean): void;
|
|
70
|
+
/**
|
|
71
|
+
* Read the cached probe decision. `true` means the wake path should use
|
|
72
|
+
* `getLiveServerClient(serverUrl, directory)` and POST through the live
|
|
73
|
+
* HTTP listener. `false` means fall back to the in-process client passed
|
|
74
|
+
* via plugin context (`input.client`).
|
|
75
|
+
*/
|
|
76
|
+
export declare function useLiveServerWake(): boolean;
|
|
77
|
+
/** Test helper — reset the decision cache between cases. */
|
|
78
|
+
export declare function __resetLiveServerWakeForTests(): void;
|
|
60
79
|
//# sourceMappingURL=live-server-client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-server-client.d.ts","sourceRoot":"","sources":["../../src/shared/live-server-client.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"live-server-client.d.ts","sourceRoot":"","sources":["../../src/shared/live-server-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,MAAM,gBAAgB,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AA6BvE;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAY1F;AAED,4EAA4E;AAC5E,wBAAgB,oCAAoC,IAAI,IAAI,CAE3D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,SAAS,SAAO,GACf,OAAO,CAAC,OAAO,CAAC,CAqBlB;AAmBD;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAEnE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,4DAA4D;AAC5D,wBAAgB,6BAA6B,IAAI,IAAI,CAEpD"}
|
package/dist/tui.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createMemo as createMemo2, createSignal as createSignal2, onCleanup as
|
|
|
3
3
|
// package.json
|
|
4
4
|
var package_default = {
|
|
5
5
|
name: "@cortexkit/aft-opencode",
|
|
6
|
-
version: "0.29.
|
|
6
|
+
version: "0.29.1",
|
|
7
7
|
type: "module",
|
|
8
8
|
description: "OpenCode plugin for Agent File Tools (AFT) — tree-sitter and lsp powered code analysis",
|
|
9
9
|
main: "dist/index.js",
|
|
@@ -32,7 +32,7 @@ var package_default = {
|
|
|
32
32
|
},
|
|
33
33
|
dependencies: {
|
|
34
34
|
"@clack/prompts": "^1.2.0",
|
|
35
|
-
"@cortexkit/aft-bridge": "0.29.
|
|
35
|
+
"@cortexkit/aft-bridge": "0.29.1",
|
|
36
36
|
"@opencode-ai/plugin": "^1.15.5",
|
|
37
37
|
"@opencode-ai/sdk": "^1.15.5",
|
|
38
38
|
"comment-json": "^4.6.2",
|
|
@@ -40,12 +40,12 @@ var package_default = {
|
|
|
40
40
|
zod: "^4.1.8"
|
|
41
41
|
},
|
|
42
42
|
optionalDependencies: {
|
|
43
|
-
"@cortexkit/aft-darwin-arm64": "0.29.
|
|
44
|
-
"@cortexkit/aft-darwin-x64": "0.29.
|
|
45
|
-
"@cortexkit/aft-linux-arm64": "0.29.
|
|
46
|
-
"@cortexkit/aft-linux-x64": "0.29.
|
|
47
|
-
"@cortexkit/aft-win32-arm64": "0.29.
|
|
48
|
-
"@cortexkit/aft-win32-x64": "0.29.
|
|
43
|
+
"@cortexkit/aft-darwin-arm64": "0.29.1",
|
|
44
|
+
"@cortexkit/aft-darwin-x64": "0.29.1",
|
|
45
|
+
"@cortexkit/aft-linux-arm64": "0.29.1",
|
|
46
|
+
"@cortexkit/aft-linux-x64": "0.29.1",
|
|
47
|
+
"@cortexkit/aft-win32-arm64": "0.29.1",
|
|
48
|
+
"@cortexkit/aft-win32-x64": "0.29.1"
|
|
49
49
|
},
|
|
50
50
|
devDependencies: {
|
|
51
51
|
"@types/node": "^22.0.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/aft-opencode",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.1",
|
|
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",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@clack/prompts": "^1.2.0",
|
|
32
|
-
"@cortexkit/aft-bridge": "0.29.
|
|
32
|
+
"@cortexkit/aft-bridge": "0.29.1",
|
|
33
33
|
"@opencode-ai/plugin": "^1.15.5",
|
|
34
34
|
"@opencode-ai/sdk": "^1.15.5",
|
|
35
35
|
"comment-json": "^4.6.2",
|
|
@@ -37,12 +37,12 @@
|
|
|
37
37
|
"zod": "^4.1.8"
|
|
38
38
|
},
|
|
39
39
|
"optionalDependencies": {
|
|
40
|
-
"@cortexkit/aft-darwin-arm64": "0.29.
|
|
41
|
-
"@cortexkit/aft-darwin-x64": "0.29.
|
|
42
|
-
"@cortexkit/aft-linux-arm64": "0.29.
|
|
43
|
-
"@cortexkit/aft-linux-x64": "0.29.
|
|
44
|
-
"@cortexkit/aft-win32-arm64": "0.29.
|
|
45
|
-
"@cortexkit/aft-win32-x64": "0.29.
|
|
40
|
+
"@cortexkit/aft-darwin-arm64": "0.29.1",
|
|
41
|
+
"@cortexkit/aft-darwin-x64": "0.29.1",
|
|
42
|
+
"@cortexkit/aft-linux-arm64": "0.29.1",
|
|
43
|
+
"@cortexkit/aft-linux-x64": "0.29.1",
|
|
44
|
+
"@cortexkit/aft-win32-arm64": "0.29.1",
|
|
45
|
+
"@cortexkit/aft-win32-x64": "0.29.1"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/node": "^22.0.0",
|
|
@@ -19,6 +19,16 @@
|
|
|
19
19
|
* UI uses, so the active session's `SessionRunState` is the one that
|
|
20
20
|
* resolves `ensureRunning` and overlapping turns coalesce correctly.
|
|
21
21
|
*
|
|
22
|
+
* The workaround only works when the live HTTP listener is actually
|
|
23
|
+
* reachable. OpenCode Desktop (Electron+Node) and TUI launched with
|
|
24
|
+
* `opencode --port 0` bind a real API listener; plain TUI binds an
|
|
25
|
+
* internal-only listener that 404s for `/session/*`. We probe once at
|
|
26
|
+
* plugin init and cache the result. When the listener is unreachable
|
|
27
|
+
* the wake path silently uses the in-process `input.client.session.promptAsync`,
|
|
28
|
+
* which keeps wakes flowing (at the cost of the upstream duplicate-runner
|
|
29
|
+
* bug) instead of producing no notification at all or nagging the user
|
|
30
|
+
* to relaunch with a different flag.
|
|
31
|
+
*
|
|
22
32
|
* Tracked upstream as anomalyco/opencode#28202. When OpenCode fixes the
|
|
23
33
|
* runtime split, this helper and its single consumer in `bg-notifications.ts`
|
|
24
34
|
* can be deleted and the wake path can go back to `input.client`.
|
|
@@ -84,26 +94,18 @@ export function __resetLiveServerClientCacheForTests(): void {
|
|
|
84
94
|
clientCache.clear();
|
|
85
95
|
}
|
|
86
96
|
|
|
87
|
-
/**
|
|
88
|
-
* True when the current runtime is Bun. OpenCode's TUI ships with Bun;
|
|
89
|
-
* the Electron Desktop app ships with Node. We use this to gate the
|
|
90
|
-
* `--port 0` nudge: Desktop is unaffected by anomalyco/opencode#28202
|
|
91
|
-
* because Node's webidl polyfill is complete, so undici v8 (and the live
|
|
92
|
-
* HTTP server) work without additional flags.
|
|
93
|
-
*/
|
|
94
|
-
export function isBunRuntime(): boolean {
|
|
95
|
-
return typeof (globalThis as { Bun?: unknown }).Bun !== "undefined";
|
|
96
|
-
}
|
|
97
|
-
|
|
98
97
|
/**
|
|
99
98
|
* Probe whether `serverUrl` accepts a connection within `timeoutMs`.
|
|
100
99
|
* Returns `true` for any HTTP response (including 4xx / 5xx) since the
|
|
101
100
|
* goal is to confirm the listener exists. Returns `false` on connection
|
|
102
101
|
* refused, DNS failure, timeout, or undefined URL.
|
|
103
102
|
*
|
|
104
|
-
* Used at plugin init
|
|
105
|
-
*
|
|
106
|
-
*
|
|
103
|
+
* Used at plugin init to decide whether bg-notifications should use the
|
|
104
|
+
* live-server wake transport (workaround for anomalyco/opencode#28202)
|
|
105
|
+
* or fall back to the in-process `input.client.session.promptAsync`
|
|
106
|
+
* path. Plain TUI (no `--port 0`) binds an internal-only listener that
|
|
107
|
+
* 404s for `/session/...`, so this returns false there; OpenCode
|
|
108
|
+
* Desktop, `opencode run`, and `opencode --port 0` TUI return true.
|
|
107
109
|
*/
|
|
108
110
|
export async function probeServerReachable(
|
|
109
111
|
serverUrl: string | undefined,
|
|
@@ -130,3 +132,43 @@ export async function probeServerReachable(
|
|
|
130
132
|
clearTimeout(timer);
|
|
131
133
|
}
|
|
132
134
|
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Per-plugin-process decision: should bg-notifications use the live-server
|
|
138
|
+
* wake transport (workaround for anomalyco/opencode#28202), or fall back
|
|
139
|
+
* to the in-process `input.client.session.promptAsync` path?
|
|
140
|
+
*
|
|
141
|
+
* Set once at plugin init from the result of `probeServerReachable()`.
|
|
142
|
+
* Defaults to `false` if no decision has been recorded yet — that's the
|
|
143
|
+
* safe direction because `input.client.session.promptAsync` is always
|
|
144
|
+
* available (it's part of the plugin contract), whereas the live-server
|
|
145
|
+
* path needs both a probe-confirmed listener and the workaround code
|
|
146
|
+
* itself to be live.
|
|
147
|
+
*
|
|
148
|
+
* Read at wake time (not cached on a closure) so background probes that
|
|
149
|
+
* complete after plugin init still take effect on the next wake.
|
|
150
|
+
*/
|
|
151
|
+
let liveServerWakeAvailable = false;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Record the probe result. Idempotent; if you record twice, the latest
|
|
155
|
+
* value wins. The wake path reads through `useLiveServerWake()`.
|
|
156
|
+
*/
|
|
157
|
+
export function setLiveServerWakeAvailable(available: boolean): void {
|
|
158
|
+
liveServerWakeAvailable = available;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Read the cached probe decision. `true` means the wake path should use
|
|
163
|
+
* `getLiveServerClient(serverUrl, directory)` and POST through the live
|
|
164
|
+
* HTTP listener. `false` means fall back to the in-process client passed
|
|
165
|
+
* via plugin context (`input.client`).
|
|
166
|
+
*/
|
|
167
|
+
export function useLiveServerWake(): boolean {
|
|
168
|
+
return liveServerWakeAvailable;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Test helper — reset the decision cache between cases. */
|
|
172
|
+
export function __resetLiveServerWakeForTests(): void {
|
|
173
|
+
liveServerWakeAvailable = false;
|
|
174
|
+
}
|