aboutsummaryrefslogtreecommitdiff
path: root/src/integration/assets/opencode/herdr-tui-session.js
diff options
context:
space:
mode:
authorakbash <akbash@herdr.dev>2026-08-10 14:57:44 +0300
committerGitHub <noreply@github.com>2026-08-10 14:57:44 +0300
commitccccda54c21f6ef1649a44bb098d7c498724404d (patch)
tree86f28b85086ef36fd7ebc0f1d928b7606d76c487 /src/integration/assets/opencode/herdr-tui-session.js
parent2e8cc9060d723a5ac32a2325e695fd8750ff60fe (diff)
fix: track opencode tui session selection (#2455)
refs #2450 Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
Diffstat (limited to 'src/integration/assets/opencode/herdr-tui-session.js')
-rw-r--r--src/integration/assets/opencode/herdr-tui-session.js113
1 files changed, 113 insertions, 0 deletions
diff --git a/src/integration/assets/opencode/herdr-tui-session.js b/src/integration/assets/opencode/herdr-tui-session.js
new file mode 100644
index 00000000..b5be5bbc
--- /dev/null
+++ b/src/integration/assets/opencode/herdr-tui-session.js
@@ -0,0 +1,113 @@
+// installed by herdr
+// managed by herdr; reinstalling or updating the integration overwrites this file.
+// HERDR_INTEGRATION_ID=opencode-tui
+// HERDR_INTEGRATION_VERSION=10
+
+import net from "node:net";
+
+const SOURCE = "herdr:opencode";
+const AGENT = "opencode";
+const ROUTE_POLL_INTERVAL_MS = 100;
+const SELECTION_RETRY_DELAYS_MS = [100, 400, 1_000];
+
+function requestOnce(sessionID) {
+ const paneId = process.env.HERDR_PANE_ID;
+ const socketPath = process.env.HERDR_SOCKET_PATH;
+ if (!paneId || !socketPath) {
+ return Promise.resolve();
+ }
+
+ const socketEndpoint =
+ process.platform === "win32" ? `\\\\.\\pipe\\${socketPath}` : socketPath;
+ const request = {
+ id: `${SOURCE}:tui:${Date.now()}:${Math.floor(Math.random() * 1_000_000)
+ .toString()
+ .padStart(6, "0")}`,
+ method: "pane.report_agent_session",
+ params: {
+ pane_id: paneId,
+ source: SOURCE,
+ agent: AGENT,
+ agent_session_id: sessionID,
+ session_start_source: "select",
+ },
+ };
+
+ return new Promise((resolve) => {
+ const client = net.createConnection(socketEndpoint, () => {
+ client.write(`${JSON.stringify(request)}\n`);
+ });
+ const finish = () => {
+ client.destroy();
+ resolve();
+ };
+
+ client.setTimeout(500, finish);
+ client.on("data", finish);
+ client.on("error", finish);
+ client.on("end", finish);
+ client.on("close", resolve);
+ });
+}
+
+export default {
+ id: "herdr.opencode.session-selection",
+ tui: async (api) => {
+ if (
+ process.env.HERDR_ENV !== "1" ||
+ !process.env.HERDR_SOCKET_PATH ||
+ !process.env.HERDR_PANE_ID
+ ) {
+ return;
+ }
+
+ let selectedSessionID;
+ let retryIndex = 0;
+ let nextReportAt = 0;
+ let reportPending = false;
+ const syncSelectedSession = async () => {
+ const route = api.route.current;
+ const sessionID = route?.name === "session" ? route.params?.sessionID : undefined;
+ const session =
+ typeof sessionID === "string" && sessionID
+ ? api.state.session.get(sessionID)
+ : undefined;
+ if (!session || session.parentID) {
+ selectedSessionID = undefined;
+ retryIndex = 0;
+ nextReportAt = 0;
+ return;
+ }
+ if (sessionID !== selectedSessionID) {
+ selectedSessionID = sessionID;
+ retryIndex = 0;
+ nextReportAt = 0;
+ }
+ if (reportPending || Date.now() < nextReportAt) {
+ return;
+ }
+
+ const reportingSessionID = sessionID;
+ reportPending = true;
+ try {
+ await requestOnce(reportingSessionID);
+ } catch {
+ // Best-effort reporting retries below while the selected route remains active.
+ } finally {
+ reportPending = false;
+ }
+ if (selectedSessionID !== reportingSessionID) {
+ retryIndex = 0;
+ nextReportAt = 0;
+ return;
+ }
+ const retryDelay = SELECTION_RETRY_DELAYS_MS[retryIndex];
+ retryIndex += 1;
+ nextReportAt = retryDelay === undefined ? Number.POSITIVE_INFINITY : Date.now() + retryDelay;
+ };
+
+ await syncSelectedSession();
+ const routePoll = setInterval(() => void syncSelectedSession(), ROUTE_POLL_INTERVAL_MS);
+ api.lifecycle.onDispose(() => clearInterval(routePoll));
+ },
+};