-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcode-buddy-opencode-plugin.js
More file actions
153 lines (138 loc) · 3.82 KB
/
Copy pathcode-buddy-opencode-plugin.js
File metadata and controls
153 lines (138 loc) · 3.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/**
* Code Buddy Plugin for OpenCode
*
* Sends tool execution events to Code Buddy via HTTP POST.
*
* Installation:
* cp code-buddy-opencode-plugin.js ~/.config/opencode/plugins/
*
* Debug: set CODE_BUDDY_DEBUG=1 to see logs
*/
const HTTP_URL = "http://127.0.0.1:8765";
const IDLE_TIMEOUT_MS = 120000;
const sessionTimers = new Map();
function debug(msg) {
if (process.env.CODE_BUDDY_DEBUG === "1") {
console.error(`[code-buddy] ${msg}`);
}
}
async function sendEvent(eventType, payload) {
const body = JSON.stringify({
type: eventType,
payload: {
source: "opencode",
session_id: payload.sessionId,
cwd: payload.cwd || process.cwd(),
tool_name: normalizeToolName(payload.toolName),
},
});
debug(`Sending ${eventType}: ${body}`);
try {
if (typeof fetch === "function") {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 1000);
await fetch(HTTP_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body,
signal: controller.signal,
});
clearTimeout(timeout);
debug(`Sent ${eventType} via fetch`);
} else {
const http = require("http");
const url = new URL(HTTP_URL);
const req = http.request(
{
hostname: url.hostname,
port: url.port,
path: "/",
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(body),
},
timeout: 1000,
},
() => debug(`Sent ${eventType} via http`)
);
req.on("error", () => {});
req.write(body);
req.end();
}
} catch (e) {
debug(`Error sending ${eventType}: ${e.message}`);
}
}
function normalizeToolName(name) {
const map = {
run_shell_command: "Bash",
shell: "Bash",
bash: "Bash",
read_file: "Read",
read: "Read",
write_file: "Write",
write: "Write",
edit_file: "Edit",
edit: "Edit",
search_files: "Grep",
grep: "Grep",
list_files: "Glob",
glob: "Glob",
};
const lower = (name || "").toLowerCase();
return map[lower] || name || "Unknown";
}
function generateSessionId(cwd) {
const crypto = require("crypto");
return crypto
.createHash("sha256")
.update(`opencode:${cwd || process.cwd()}`)
.digest("hex")
.slice(0, 12);
}
function ensureSessionStarted(sessionId, cwd) {
if (sessionTimers.has(sessionId)) return;
debug(`Session start: ${sessionId}`);
sendEvent("SessionStart", { sessionId, cwd });
}
function scheduleSessionEnd(sessionId, cwd) {
const existing = sessionTimers.get(sessionId);
if (existing) clearTimeout(existing);
const timer = setTimeout(() => {
debug(`Session end: ${sessionId}`);
sendEvent("SessionEnd", { sessionId, cwd });
sessionTimers.delete(sessionId);
}, IDLE_TIMEOUT_MS);
sessionTimers.set(sessionId, timer);
}
/**
* OpenCode Plugin (original format)
*/
export default async function CodeBuddyPlugin(pluginInput) {
const cwd = pluginInput?.directory || process.cwd();
const sessionId = generateSessionId(cwd);
debug(`Plugin loaded: cwd=${cwd}, sessionId=${sessionId}`);
return {
"tool.execute.before": async function (input, output) {
debug(`tool.execute.before: ${input.tool}`);
ensureSessionStarted(sessionId, cwd);
scheduleSessionEnd(sessionId, cwd);
await sendEvent("PreToolUse", {
toolName: input.tool,
sessionId,
cwd,
});
},
"tool.execute.after": async function (input, output) {
debug(`tool.execute.after: ${input.tool}`);
ensureSessionStarted(sessionId, cwd);
scheduleSessionEnd(sessionId, cwd);
await sendEvent("PostToolUse", {
toolName: input.tool,
sessionId,
cwd,
});
},
};
}