rivetplane 0.1.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/LICENSE +21 -0
- package/README.md +18 -0
- package/dist/acp-attach.js +228 -0
- package/dist/acp-attach.js.map +1 -0
- package/dist/cli.js +75 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.js +38 -0
- package/dist/client.js.map +1 -0
- package/dist/credentials.js +112 -0
- package/dist/credentials.js.map +1 -0
- package/dist/discovery.js +113 -0
- package/dist/discovery.js.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/local-api.js +133 -0
- package/dist/local-api.js.map +1 -0
- package/dist/opencode-manager.js +237 -0
- package/dist/opencode-manager.js.map +1 -0
- package/dist/registry.js +42 -0
- package/dist/registry.js.map +1 -0
- package/dist/relay.js +153 -0
- package/dist/relay.js.map +1 -0
- package/dist/rpc.js +119 -0
- package/dist/rpc.js.map +1 -0
- package/dist/session-manager.js +73 -0
- package/dist/session-manager.js.map +1 -0
- package/package.json +56 -0
package/dist/relay.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import WebSocket from "ws";
|
|
3
|
+
import { SessionRegistry } from "./registry.js";
|
|
4
|
+
function relayUrl(server) {
|
|
5
|
+
const url = new URL(server);
|
|
6
|
+
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
7
|
+
url.pathname = `${url.pathname.replace(/\/$/, "")}/v1/relay`;
|
|
8
|
+
return url.toString();
|
|
9
|
+
}
|
|
10
|
+
export class OutboundRelay extends EventEmitter {
|
|
11
|
+
credentials;
|
|
12
|
+
registry;
|
|
13
|
+
target;
|
|
14
|
+
options;
|
|
15
|
+
#socket;
|
|
16
|
+
#retry;
|
|
17
|
+
#heartbeat;
|
|
18
|
+
#stopped = true;
|
|
19
|
+
#attempt = 0;
|
|
20
|
+
#queue = [];
|
|
21
|
+
#externalToLocal = new Map();
|
|
22
|
+
constructor(credentials, registry, target, options = {}) {
|
|
23
|
+
super();
|
|
24
|
+
this.credentials = credentials;
|
|
25
|
+
this.registry = registry;
|
|
26
|
+
this.target = target;
|
|
27
|
+
this.options = options;
|
|
28
|
+
registry.on("session", (session) => this.send({ type: "session.upsert", session: this.#namespace(session) }));
|
|
29
|
+
registry.on("transcript", (event) => {
|
|
30
|
+
const session = registry.get(event.session_id);
|
|
31
|
+
if (!session)
|
|
32
|
+
return;
|
|
33
|
+
this.send({ type: "transcript.append", event: { ...event, session_id: this.#externalId(session) } });
|
|
34
|
+
});
|
|
35
|
+
registry.on("removed", (session_id) => {
|
|
36
|
+
const external = [...this.#externalToLocal].find(([, local]) => local === session_id)?.[0] ?? session_id;
|
|
37
|
+
this.send({ type: "session.removed", session_id: external, removed_at: new Date().toISOString() });
|
|
38
|
+
this.#externalToLocal.delete(external);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
start() { if (!this.#stopped)
|
|
42
|
+
return; this.#stopped = false; this.#connect(); }
|
|
43
|
+
stop() { this.#stopped = true; if (this.#retry)
|
|
44
|
+
clearTimeout(this.#retry); if (this.#heartbeat)
|
|
45
|
+
clearInterval(this.#heartbeat); this.#socket?.close(); }
|
|
46
|
+
send(message) {
|
|
47
|
+
if (this.#socket?.readyState === WebSocket.OPEN)
|
|
48
|
+
this.#socket.send(JSON.stringify(message));
|
|
49
|
+
else {
|
|
50
|
+
this.#queue.push(message);
|
|
51
|
+
if (this.#queue.length > 10_000)
|
|
52
|
+
this.#queue.shift();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
#connect() {
|
|
56
|
+
if (this.#stopped)
|
|
57
|
+
return;
|
|
58
|
+
const socket = new WebSocket(relayUrl(this.credentials.server_url), { headers: { authorization: `Bearer ${this.credentials.token}` } });
|
|
59
|
+
this.#socket = socket;
|
|
60
|
+
socket.on("open", () => {
|
|
61
|
+
this.#attempt = 0;
|
|
62
|
+
const now = new Date().toISOString();
|
|
63
|
+
const machine = { id: this.credentials.machine_id, name: this.credentials.machine_name, owner_account_id: this.credentials.owner_account_id, last_seen_at: now, status: "online" };
|
|
64
|
+
socket.send(JSON.stringify({ type: "machine.hello", protocol_version: 1, machine }));
|
|
65
|
+
for (const session of this.registry.list()) {
|
|
66
|
+
socket.send(JSON.stringify({ type: "session.upsert", session: this.#namespace(session) }));
|
|
67
|
+
// Replay the local transcript after reconnect. The server deduplicates
|
|
68
|
+
// by event id and sequence, so this also repairs an interrupted sync.
|
|
69
|
+
for (const event of this.registry.transcript(session.id, 0, Number.MAX_SAFE_INTEGER)) {
|
|
70
|
+
socket.send(JSON.stringify({ type: "transcript.append", event: { ...event, session_id: this.#externalId(session) } }));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
for (const capabilities of this.options.capabilities?.() ?? [])
|
|
74
|
+
socket.send(JSON.stringify({ type: "harness.capabilities", capabilities }));
|
|
75
|
+
for (const message of this.#queue.splice(0))
|
|
76
|
+
socket.send(JSON.stringify(message));
|
|
77
|
+
this.#heartbeat = setInterval(() => {
|
|
78
|
+
this.send({ type: "machine.heartbeat", machine_id: machine.id, sent_at: new Date().toISOString() });
|
|
79
|
+
for (const capabilities of this.options.capabilities?.() ?? [])
|
|
80
|
+
this.send({ type: "harness.capabilities", capabilities });
|
|
81
|
+
}, 15_000);
|
|
82
|
+
this.#heartbeat.unref();
|
|
83
|
+
this.emit("online");
|
|
84
|
+
});
|
|
85
|
+
socket.on("message", (data) => void this.#command(data.toString()));
|
|
86
|
+
socket.on("error", (error) => this.emit("warning", error));
|
|
87
|
+
socket.on("close", () => {
|
|
88
|
+
if (this.#heartbeat)
|
|
89
|
+
clearInterval(this.#heartbeat);
|
|
90
|
+
this.#heartbeat = undefined;
|
|
91
|
+
this.#socket = undefined;
|
|
92
|
+
this.emit("offline");
|
|
93
|
+
if (!this.#stopped) {
|
|
94
|
+
const delay = Math.min(30_000, 500 * 2 ** this.#attempt++);
|
|
95
|
+
this.#retry = setTimeout(() => this.#connect(), delay);
|
|
96
|
+
this.#retry.unref();
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
async #command(raw) {
|
|
101
|
+
let command;
|
|
102
|
+
try {
|
|
103
|
+
command = JSON.parse(raw);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
this.emit("warning", new Error("Relay sent invalid JSON"));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (command.type !== "command.send_message" && command.type !== "command.respond_to_pending" && command.type !== "command.interrupt_session" && command.type !== "command.create_session")
|
|
110
|
+
return;
|
|
111
|
+
if (command.type === "command.create_session") {
|
|
112
|
+
try {
|
|
113
|
+
const session_id = await this.options.createSession?.(command);
|
|
114
|
+
if (!session_id)
|
|
115
|
+
throw new Error("Harness cannot create sessions");
|
|
116
|
+
this.send({ type: "command.result", command_id: command.command_id, ok: true, result: { session_id } });
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
this.send({ type: "command.result", command_id: command.command_id, ok: false, error: error instanceof Error ? error.message : String(error) });
|
|
120
|
+
}
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const session = this.target(this.#externalToLocal.get(command.session_id) ?? command.session_id);
|
|
124
|
+
if (!session) {
|
|
125
|
+
this.send({ type: "command.result", command_id: command.command_id, ok: false, error: "Session is not attached" });
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
if (command.type === "command.send_message")
|
|
130
|
+
await session.sendMessage(command.text);
|
|
131
|
+
else if (command.type === "command.respond_to_pending")
|
|
132
|
+
await session.respondToPending(command.pending_id, command.response, command.scope);
|
|
133
|
+
else if (command.type === "command.interrupt_session")
|
|
134
|
+
await session.interrupt();
|
|
135
|
+
else
|
|
136
|
+
throw new Error("Unknown command type");
|
|
137
|
+
this.send({ type: "command.result", command_id: command.command_id, ok: true });
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
this.send({ type: "command.result", command_id: command.command_id, ok: false, error: error instanceof Error ? error.message : String(error) });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
#externalId(session) {
|
|
144
|
+
const value = `${this.credentials.machine_id}/${session.harness_type}/${session.id}`;
|
|
145
|
+
this.#externalToLocal.set(value, session.id);
|
|
146
|
+
return value;
|
|
147
|
+
}
|
|
148
|
+
#namespace(session) {
|
|
149
|
+
const id = this.#externalId(session);
|
|
150
|
+
return { ...session, id, pending: session.pending ? { ...session.pending, session_id: id } : null };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=relay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relay.js","sourceRoot":"","sources":["../src/relay.ts"],"names":[],"mappings":"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"}
|
package/dist/rpc.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import { createConnection } from "node:net";
|
|
3
|
+
import WebSocket from "ws";
|
|
4
|
+
class WebSocketChannel {
|
|
5
|
+
socket;
|
|
6
|
+
constructor(socket) {
|
|
7
|
+
this.socket = socket;
|
|
8
|
+
}
|
|
9
|
+
send(value) { this.socket.send(value); }
|
|
10
|
+
close() { this.socket.close(); }
|
|
11
|
+
onMessage(handler) { this.socket.on("message", (data) => handler(data.toString())); }
|
|
12
|
+
onClose(handler) { this.socket.on("close", () => handler()); this.socket.on("error", handler); }
|
|
13
|
+
}
|
|
14
|
+
class LineChannel {
|
|
15
|
+
socket;
|
|
16
|
+
#buffer = "";
|
|
17
|
+
constructor(socket) {
|
|
18
|
+
this.socket = socket;
|
|
19
|
+
}
|
|
20
|
+
send(value) { this.socket.write(`${value}\n`); }
|
|
21
|
+
close() { this.socket.destroy(); }
|
|
22
|
+
onMessage(handler) {
|
|
23
|
+
this.socket.setEncoding("utf8");
|
|
24
|
+
this.socket.on("data", (chunk) => {
|
|
25
|
+
this.#buffer += chunk;
|
|
26
|
+
for (;;) {
|
|
27
|
+
const offset = this.#buffer.indexOf("\n");
|
|
28
|
+
if (offset < 0)
|
|
29
|
+
break;
|
|
30
|
+
const line = this.#buffer.slice(0, offset).trim();
|
|
31
|
+
this.#buffer = this.#buffer.slice(offset + 1);
|
|
32
|
+
if (line)
|
|
33
|
+
handler(line);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
onClose(handler) { this.socket.on("close", () => handler()); this.socket.on("error", handler); }
|
|
38
|
+
}
|
|
39
|
+
async function connectChannel(transport) {
|
|
40
|
+
if (transport.kind === "websocket") {
|
|
41
|
+
const socket = new WebSocket(transport.url, { headers: transport.headers });
|
|
42
|
+
await new Promise((resolve, reject) => { socket.once("open", resolve); socket.once("error", reject); });
|
|
43
|
+
return new WebSocketChannel(socket);
|
|
44
|
+
}
|
|
45
|
+
const socket = transport.kind === "unix" ? createConnection(transport.path) : createConnection(transport.port, transport.host);
|
|
46
|
+
await new Promise((resolve, reject) => { socket.once("connect", resolve); socket.once("error", reject); });
|
|
47
|
+
return new LineChannel(socket);
|
|
48
|
+
}
|
|
49
|
+
export class JsonRpcPeer extends EventEmitter {
|
|
50
|
+
channel;
|
|
51
|
+
#nextId = 1;
|
|
52
|
+
#pending = new Map();
|
|
53
|
+
#requests = new Map();
|
|
54
|
+
#notifications = new Map();
|
|
55
|
+
constructor(channel) {
|
|
56
|
+
super();
|
|
57
|
+
this.channel = channel;
|
|
58
|
+
channel.onMessage((value) => void this.#receive(value));
|
|
59
|
+
channel.onClose((error) => this.#closed(error));
|
|
60
|
+
}
|
|
61
|
+
static async connect(transport) { return new JsonRpcPeer(await connectChannel(transport)); }
|
|
62
|
+
onRequest(method, handler) { this.#requests.set(method, handler); }
|
|
63
|
+
onNotification(method, handler) { this.#notifications.set(method, handler); }
|
|
64
|
+
request(method, params) {
|
|
65
|
+
const id = this.#nextId++;
|
|
66
|
+
this.channel.send(JSON.stringify({ jsonrpc: "2.0", id, method, params }));
|
|
67
|
+
return new Promise((resolve, reject) => this.#pending.set(id, { resolve: (value) => resolve(value), reject }));
|
|
68
|
+
}
|
|
69
|
+
notify(method, params) { this.channel.send(JSON.stringify({ jsonrpc: "2.0", method, params })); }
|
|
70
|
+
close() { this.channel.close(); }
|
|
71
|
+
async #receive(raw) {
|
|
72
|
+
let message;
|
|
73
|
+
try {
|
|
74
|
+
message = JSON.parse(raw);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
this.emit("warning", new Error("ACP sent invalid JSON"));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (message.method && message.id !== undefined) {
|
|
81
|
+
const handler = this.#requests.get(message.method);
|
|
82
|
+
if (!handler) {
|
|
83
|
+
this.#sendError(message.id, -32601, `Method not found: ${message.method}`);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
const result = await handler(message.params, message.id);
|
|
88
|
+
this.channel.send(JSON.stringify({ jsonrpc: "2.0", id: message.id, result }));
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
this.#sendError(message.id, -32000, error instanceof Error ? error.message : String(error));
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (message.method) {
|
|
96
|
+
try {
|
|
97
|
+
await this.#notifications.get(message.method)?.(message.params);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
this.emit("warning", error);
|
|
101
|
+
}
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (message.id !== undefined) {
|
|
105
|
+
const pending = this.#pending.get(message.id);
|
|
106
|
+
if (!pending)
|
|
107
|
+
return;
|
|
108
|
+
this.#pending.delete(message.id);
|
|
109
|
+
if (message.error)
|
|
110
|
+
pending.reject(new Error(message.error.message));
|
|
111
|
+
else
|
|
112
|
+
pending.resolve(message.result);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
#sendError(id, code, message) { this.channel.send(JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } })); }
|
|
116
|
+
#closed(error) { const reason = error ?? new Error("ACP connection closed"); for (const item of this.#pending.values())
|
|
117
|
+
item.reject(reason); this.#pending.clear(); this.emit("close", reason); }
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=rpc.js.map
|
package/dist/rpc.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../src/rpc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { SessionDiscovery } from "./discovery.js";
|
|
2
|
+
import { ACPAttach } from "./acp-attach.js";
|
|
3
|
+
import { SessionRegistry } from "./registry.js";
|
|
4
|
+
export class SessionManager {
|
|
5
|
+
machine_id;
|
|
6
|
+
registry;
|
|
7
|
+
discovery;
|
|
8
|
+
#sessions = new Map();
|
|
9
|
+
#connecting = new Set();
|
|
10
|
+
#descriptors = new Map();
|
|
11
|
+
#reconcile = Promise.resolve();
|
|
12
|
+
constructor(machine_id, options = {}) {
|
|
13
|
+
this.machine_id = machine_id;
|
|
14
|
+
this.registry = new SessionRegistry();
|
|
15
|
+
this.discovery = new SessionDiscovery(options);
|
|
16
|
+
this.discovery.on("sessions", (descriptors) => {
|
|
17
|
+
this.#descriptors = new Map(descriptors.map((descriptor) => [descriptor.session_id, descriptor]));
|
|
18
|
+
this.#reconcile = this.#reconcileSessions(descriptors);
|
|
19
|
+
});
|
|
20
|
+
this.discovery.on("session", (descriptor) => this.registry.emit("log", `ACP endpoint found: ${descriptor.harness_type} (${descriptor.session_id})`));
|
|
21
|
+
this.discovery.on("warning", (error) => this.registry.emit("warning", error));
|
|
22
|
+
}
|
|
23
|
+
async start() { await this.discovery.poll(); await this.#reconcile; this.discovery.start(); }
|
|
24
|
+
stop() { this.discovery.stop(); for (const item of this.#sessions.values())
|
|
25
|
+
item.attach.close(); this.#sessions.clear(); }
|
|
26
|
+
target(id) { return this.#sessions.get(id)?.attach; }
|
|
27
|
+
harnesses() {
|
|
28
|
+
const types = new Set([...this.#descriptors.values()].map((item) => item.harness_type));
|
|
29
|
+
return [...types].sort().map((harness_type) => ({
|
|
30
|
+
harness_type,
|
|
31
|
+
discovered_sessions: [...this.#descriptors.values()].filter((item) => item.harness_type === harness_type).length,
|
|
32
|
+
attached_sessions: this.registry.list().filter((item) => item.harness_type === harness_type && this.#sessions.get(item.id)?.attach.connected).length,
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
async #reconcileSessions(descriptors) {
|
|
36
|
+
const found = new Set(descriptors.map((item) => item.session_id));
|
|
37
|
+
for (const [id, managed] of this.#sessions) {
|
|
38
|
+
if (!found.has(id)) {
|
|
39
|
+
managed.attach.close();
|
|
40
|
+
this.#sessions.delete(id);
|
|
41
|
+
if (this.registry.get(id))
|
|
42
|
+
this.registry.setStatus(id, "error", "ACP discovery record is missing");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
await Promise.all(descriptors.map((descriptor) => this.#ensure(descriptor)));
|
|
46
|
+
}
|
|
47
|
+
async #ensure(descriptor) {
|
|
48
|
+
const signature = JSON.stringify(descriptor);
|
|
49
|
+
const current = this.#sessions.get(descriptor.session_id);
|
|
50
|
+
if (current?.signature === signature && current.attach.connected)
|
|
51
|
+
return;
|
|
52
|
+
if (this.#connecting.has(descriptor.session_id))
|
|
53
|
+
return;
|
|
54
|
+
current?.attach.close();
|
|
55
|
+
this.#sessions.delete(descriptor.session_id);
|
|
56
|
+
this.#connecting.add(descriptor.session_id);
|
|
57
|
+
const attach = new ACPAttach(descriptor, this.registry, this.machine_id);
|
|
58
|
+
try {
|
|
59
|
+
await attach.connect();
|
|
60
|
+
this.#sessions.set(descriptor.session_id, { signature, attach });
|
|
61
|
+
this.registry.emit("log", `Harness attached: ${descriptor.harness_type} (${descriptor.session_id})`);
|
|
62
|
+
attach.once("close", () => this.#sessions.delete(descriptor.session_id));
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
attach.close();
|
|
66
|
+
this.registry.emit("warning", new Error(`Cannot attach ${descriptor.session_id}: ${error instanceof Error ? error.message : String(error)}`));
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
this.#connecting.delete(descriptor.session_id);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=session-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../src/session-manager.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rivetplane",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Connect local agent harnesses to the Rivetplane control plane",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"acp",
|
|
7
|
+
"agent",
|
|
8
|
+
"cli",
|
|
9
|
+
"control-plane",
|
|
10
|
+
"opencode"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"homepage": "https://github.com/rivetplane/cli#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/rivetplane/cli/issues"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/rivetplane/cli.git",
|
|
20
|
+
"directory": "packages/client"
|
|
21
|
+
},
|
|
22
|
+
"type": "module",
|
|
23
|
+
"bin": {
|
|
24
|
+
"rivetplane": "dist/cli.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist/*.js",
|
|
28
|
+
"dist/*.js.map",
|
|
29
|
+
"!dist/*.test.js",
|
|
30
|
+
"!dist/*.test.js.map",
|
|
31
|
+
"LICENSE",
|
|
32
|
+
"README.md"
|
|
33
|
+
],
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=22.0.0"
|
|
36
|
+
},
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public",
|
|
39
|
+
"provenance": true
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsc -b",
|
|
43
|
+
"clean": "tsc -b --clean && rm -rf dist",
|
|
44
|
+
"start": "node dist/cli.js",
|
|
45
|
+
"test": "node --test dist/*.test.js",
|
|
46
|
+
"typecheck": "tsc --noEmit --composite false",
|
|
47
|
+
"prepack": "npm run clean && npm run build"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@opencode-ai/sdk": "^1.18.21",
|
|
51
|
+
"ws": "^8.21.0"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@types/ws": "^8.18.1"
|
|
55
|
+
}
|
|
56
|
+
}
|