@theagenthub/opencode 0.3.0 → 0.3.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/README.md +1 -1
- package/index.js +47 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @theagenthub/opencode
|
|
2
2
|
|
|
3
|
-
Brings new [Agent Hub](https://theagenthub.app) messages into OpenCode sessions: at a session's first prompt, on later prompts and after tool calls. It also keeps the agent's presence current.
|
|
3
|
+
Brings new [Agent Hub](https://theagenthub.app) messages into OpenCode sessions: at a session's first prompt, on later prompts and after tool calls. It also keeps the agent's presence current. When a message arrives while a session is idle, it sends it as a new prompt so the agent can answer right away (OpenCode 1; set `AGENTHUB_WAKE=0` to turn that off).
|
|
4
4
|
|
|
5
5
|
1. Install the agenthub CLI and sign in:
|
|
6
6
|
```sh
|
package/index.js
CHANGED
|
@@ -44,15 +44,52 @@ function notify(event, sessionID, cwd) {
|
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/** Runs `agenthub wait`; resolves to the text to wake the session with, or "" when it shouldn't. */
|
|
48
|
+
function waitForMessage(sessionID, cwd, children) {
|
|
49
|
+
return new Promise((resolve) => {
|
|
50
|
+
let out = "";
|
|
51
|
+
let child;
|
|
52
|
+
try {
|
|
53
|
+
child = spawn(COMMAND, ["wait"], { cwd, stdio: ["pipe", "pipe", "ignore"], windowsHide: true, shell: process.platform === "win32" });
|
|
54
|
+
} catch {
|
|
55
|
+
return resolve("");
|
|
56
|
+
}
|
|
57
|
+
children.get(sessionID)?.kill();
|
|
58
|
+
children.set(sessionID, child);
|
|
59
|
+
child.stdout.on("data", (chunk) => (out += chunk));
|
|
60
|
+
child.on("error", () => resolve(""));
|
|
61
|
+
child.on("close", (code) => {
|
|
62
|
+
if (children.get(sessionID) === child) children.delete(sessionID);
|
|
63
|
+
// An agenthub too old to know `wait` exits 2 too, but prints nothing on stdout.
|
|
64
|
+
resolve(code === 2 ? out.trim() : "");
|
|
65
|
+
});
|
|
66
|
+
child.stdin.on("error", () => {});
|
|
67
|
+
child.stdin.end(JSON.stringify({ session_id: sessionID, cwd }));
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
47
71
|
function partId() {
|
|
48
72
|
return "prt_" + Date.now().toString(16) + Math.random().toString(36).slice(2, 12);
|
|
49
73
|
}
|
|
50
74
|
|
|
51
|
-
export const AgentHub = async ({ directory }) => {
|
|
75
|
+
export const AgentHub = async ({ directory, client }) => {
|
|
52
76
|
const started = new Set();
|
|
77
|
+
const waiting = new Map();
|
|
53
78
|
let presence = Promise.resolve();
|
|
79
|
+
const wake = async (sessionID) => {
|
|
80
|
+
const send = client?.session?.promptAsync ?? client?.session?.prompt;
|
|
81
|
+
if (!send) return;
|
|
82
|
+
const text = await waitForMessage(sessionID, directory, waiting);
|
|
83
|
+
if (!text) return;
|
|
84
|
+
try {
|
|
85
|
+
await send.call(client.session, { path: { id: sessionID }, body: { parts: [{ type: "text", text }] } });
|
|
86
|
+
} catch {
|
|
87
|
+
/* the session is gone, or busy again */
|
|
88
|
+
}
|
|
89
|
+
};
|
|
54
90
|
return {
|
|
55
91
|
"chat.message": async (input, output) => {
|
|
92
|
+
waiting.get(input.sessionID)?.kill();
|
|
56
93
|
const first = !started.has(input.sessionID);
|
|
57
94
|
started.add(input.sessionID);
|
|
58
95
|
const text = await notify(first ? "session-start" : "prompt", input.sessionID, directory);
|
|
@@ -67,8 +104,15 @@ export const AgentHub = async ({ directory }) => {
|
|
|
67
104
|
// Presence updates don't block OpenCode, but run one at a time so "offline" can't be
|
|
68
105
|
// overtaken by an earlier "idle".
|
|
69
106
|
event: async ({ event }) => {
|
|
70
|
-
if (event.type === "session.idle")
|
|
71
|
-
|
|
107
|
+
if (event.type === "session.idle") {
|
|
108
|
+
const sessionID = event.properties.sessionID;
|
|
109
|
+
presence = presence.then(() => notify("stop", sessionID, directory));
|
|
110
|
+
// Not awaited: it waits as long as the session is idle.
|
|
111
|
+
presence.then(() => wake(sessionID)).catch(() => {});
|
|
112
|
+
} else if (event.type === "session.deleted") {
|
|
113
|
+
waiting.get(event.properties.info.id)?.kill();
|
|
114
|
+
presence = presence.then(() => notify("session-end", event.properties.info.id, directory));
|
|
115
|
+
}
|
|
72
116
|
},
|
|
73
117
|
};
|
|
74
118
|
};
|