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/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rivetplane contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Rivetplane CLI
|
|
2
|
+
|
|
3
|
+
Rivetplane connects local ACP-compatible and OpenCode agent sessions to a remote control plane. The client starts all remote connections. It does not open an inbound network port.
|
|
4
|
+
|
|
5
|
+
## Use the client
|
|
6
|
+
|
|
7
|
+
Node.js 22 or later is required.
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npx rivetplane login --server https://harness-control-plane-dimavedenyapin.fly.dev
|
|
11
|
+
npx rivetplane
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The login command opens the control plane in your browser and stores a machine-scoped token in your user configuration directory. The second command starts ACP discovery, the local API, and the outbound relay. Keep it running while you use the control plane.
|
|
15
|
+
|
|
16
|
+
Run `npx rivetplane --help` for all options.
|
|
17
|
+
|
|
18
|
+
Source and release instructions are in the [Rivetplane CLI repository](https://github.com/rivetplane/cli).
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import { SessionRegistry } from "./registry.js";
|
|
3
|
+
import { JsonRpcPeer } from "./rpc.js";
|
|
4
|
+
function object(value) { return typeof value === "object" && value !== null ? value : {}; }
|
|
5
|
+
function string(value, fallback = "") { return typeof value === "string" ? value : fallback; }
|
|
6
|
+
function json(value) {
|
|
7
|
+
if (value === undefined)
|
|
8
|
+
return undefined;
|
|
9
|
+
try {
|
|
10
|
+
return JSON.parse(JSON.stringify(value));
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return String(value);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function summary(value) {
|
|
17
|
+
if (typeof value === "string")
|
|
18
|
+
return value;
|
|
19
|
+
try {
|
|
20
|
+
const text = JSON.stringify(value);
|
|
21
|
+
return text.length > 500 ? `${text.slice(0, 497)}...` : text;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return String(value);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export class ACPAttach extends EventEmitter {
|
|
28
|
+
descriptor;
|
|
29
|
+
registry;
|
|
30
|
+
machineId;
|
|
31
|
+
#peer;
|
|
32
|
+
#pending;
|
|
33
|
+
#closed = false;
|
|
34
|
+
constructor(descriptor, registry, machineId = "local") {
|
|
35
|
+
super();
|
|
36
|
+
this.descriptor = descriptor;
|
|
37
|
+
this.registry = registry;
|
|
38
|
+
this.machineId = machineId;
|
|
39
|
+
}
|
|
40
|
+
get connected() { return this.#peer !== undefined; }
|
|
41
|
+
async connect() {
|
|
42
|
+
this.#closed = false;
|
|
43
|
+
const peer = await JsonRpcPeer.connect(this.descriptor.transport);
|
|
44
|
+
this.#peer = peer;
|
|
45
|
+
peer.on("warning", (error) => this.registry.emit("warning", error));
|
|
46
|
+
peer.on("close", (error) => this.#onClose(error));
|
|
47
|
+
peer.onNotification("session/update", (params) => this.#onUpdate(params));
|
|
48
|
+
peer.onRequest("session/request_permission", (params) => this.#onPermission(params));
|
|
49
|
+
peer.onRequest("session/requestPermission", (params) => this.#onPermission(params));
|
|
50
|
+
peer.onRequest("session/request_input", (params) => this.#onQuestion(params, "input"));
|
|
51
|
+
peer.onRequest("elicitation/create", (params) => this.#onQuestion(params, "elicitation"));
|
|
52
|
+
await peer.request("initialize", {
|
|
53
|
+
protocolVersion: 1,
|
|
54
|
+
clientCapabilities: { fs: { readTextFile: false, writeTextFile: false }, terminal: false },
|
|
55
|
+
clientInfo: { name: "harness-cp", title: "Harness Control Plane", version: "0.1.0" },
|
|
56
|
+
});
|
|
57
|
+
const now = new Date().toISOString();
|
|
58
|
+
const old = this.registry.get(this.descriptor.session_id);
|
|
59
|
+
const session = {
|
|
60
|
+
id: this.descriptor.session_id,
|
|
61
|
+
machine_id: old?.machine_id ?? this.machineId,
|
|
62
|
+
harness_type: this.descriptor.harness_type,
|
|
63
|
+
cwd: this.descriptor.cwd,
|
|
64
|
+
status: old?.status === "completed" ? "completed" : "running",
|
|
65
|
+
created_at: old?.created_at ?? this.descriptor.created_at ?? now,
|
|
66
|
+
last_activity_at: old?.last_activity_at ?? now,
|
|
67
|
+
pending: old?.pending ?? null,
|
|
68
|
+
};
|
|
69
|
+
this.registry.upsert(session);
|
|
70
|
+
await this.#loadSession(peer);
|
|
71
|
+
if (this.registry.get(this.descriptor.session_id)?.status === "running")
|
|
72
|
+
this.registry.setStatus(this.descriptor.session_id, "waiting_input", "attached");
|
|
73
|
+
}
|
|
74
|
+
async #loadSession(peer) {
|
|
75
|
+
const params = { sessionId: this.descriptor.session_id, cwd: this.descriptor.cwd, mcpServers: [] };
|
|
76
|
+
try {
|
|
77
|
+
await peer.request("session/load", params);
|
|
78
|
+
}
|
|
79
|
+
catch (loadError) {
|
|
80
|
+
try {
|
|
81
|
+
await peer.request("session/resume", params);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
throw loadError;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async sendMessage(text) {
|
|
89
|
+
const peer = this.#requirePeer();
|
|
90
|
+
this.registry.append(this.descriptor.session_id, "user_message", { text });
|
|
91
|
+
this.registry.setStatus(this.descriptor.session_id, "running");
|
|
92
|
+
try {
|
|
93
|
+
const response = object(await peer.request("session/prompt", {
|
|
94
|
+
sessionId: this.descriptor.session_id,
|
|
95
|
+
prompt: [{ type: "text", text }],
|
|
96
|
+
}));
|
|
97
|
+
const reason = string(response.stopReason, "end_turn");
|
|
98
|
+
this.registry.setStatus(this.descriptor.session_id, reason === "refusal" ? "error" : "waiting_input", reason);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
this.registry.setStatus(this.descriptor.session_id, "error", error instanceof Error ? error.message : String(error));
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
interrupt() {
|
|
106
|
+
this.#requirePeer().notify("session/cancel", { sessionId: this.descriptor.session_id });
|
|
107
|
+
this.registry.setStatus(this.descriptor.session_id, "waiting_input", "interrupted");
|
|
108
|
+
}
|
|
109
|
+
respondToPending(pendingId, response, scope) {
|
|
110
|
+
const pending = this.#pending;
|
|
111
|
+
if (!pending || pending.id !== pendingId)
|
|
112
|
+
throw new Error(`Pending interaction ${pendingId} is no longer active`);
|
|
113
|
+
if (pending.kind === "approval") {
|
|
114
|
+
const normalized = response.toLowerCase();
|
|
115
|
+
const deny = normalized === "deny" || normalized === "reject";
|
|
116
|
+
const option = pending.options?.find((item) => item.optionId === response)
|
|
117
|
+
?? pending.options?.find((item) => {
|
|
118
|
+
const kind = `${item.kind ?? ""} ${item.name ?? ""}`.toLowerCase();
|
|
119
|
+
if (deny)
|
|
120
|
+
return kind.includes("reject") || kind.includes("deny");
|
|
121
|
+
if (scope && scope !== "once")
|
|
122
|
+
return kind.includes("always");
|
|
123
|
+
return kind.includes("allow") || kind.includes("approve");
|
|
124
|
+
});
|
|
125
|
+
if (!option && !deny)
|
|
126
|
+
throw new Error("The harness did not provide a matching approval option");
|
|
127
|
+
this.#pending = undefined;
|
|
128
|
+
if (option)
|
|
129
|
+
pending.resolve({ outcome: { outcome: "selected", optionId: option.optionId } });
|
|
130
|
+
else
|
|
131
|
+
pending.resolve({ outcome: { outcome: "cancelled" } });
|
|
132
|
+
this.registry.append(this.descriptor.session_id, "permission_response", {
|
|
133
|
+
approval_id: pendingId,
|
|
134
|
+
resolution: deny ? "deny" : "approve",
|
|
135
|
+
...(scope ? { scope } : {}),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
this.#pending = undefined;
|
|
140
|
+
pending.resolve({ response, action: "accept", content: { response } });
|
|
141
|
+
}
|
|
142
|
+
this.registry.setPending(this.descriptor.session_id, null);
|
|
143
|
+
this.registry.setStatus(this.descriptor.session_id, "running");
|
|
144
|
+
}
|
|
145
|
+
close() { this.#closed = true; this.#peer?.close(); this.#peer = undefined; }
|
|
146
|
+
#onPermission(value) {
|
|
147
|
+
const params = object(value);
|
|
148
|
+
if (string(params.sessionId) !== this.descriptor.session_id)
|
|
149
|
+
throw new Error("Permission request has the wrong session ID");
|
|
150
|
+
const toolCall = object(params.toolCall);
|
|
151
|
+
const id = string(toolCall.toolCallId) || string(params.toolCallId) || `permission-${Date.now()}`;
|
|
152
|
+
const options = Array.isArray(params.options) ? params.options.map((value) => object(value)).map((item) => ({
|
|
153
|
+
optionId: string(item.optionId),
|
|
154
|
+
...(string(item.kind) ? { kind: string(item.kind) } : {}),
|
|
155
|
+
...(string(item.name) ? { name: string(item.name) } : {}),
|
|
156
|
+
})).filter((item) => item.optionId) : [];
|
|
157
|
+
if (this.#pending)
|
|
158
|
+
this.#pending.reject(new Error("A newer pending interaction replaced this request"));
|
|
159
|
+
this.registry.setPending(this.descriptor.session_id, {
|
|
160
|
+
type: "approval", id, session_id: this.descriptor.session_id,
|
|
161
|
+
tool_name: string(toolCall.title) || string(toolCall.kind, "tool"),
|
|
162
|
+
tool_input_summary: summary(toolCall.rawInput ?? toolCall.content ?? toolCall),
|
|
163
|
+
requested_at: new Date().toISOString(),
|
|
164
|
+
});
|
|
165
|
+
this.registry.append(this.descriptor.session_id, "permission_request", {
|
|
166
|
+
approval_id: id,
|
|
167
|
+
tool_name: string(toolCall.title) || string(toolCall.kind, "tool"),
|
|
168
|
+
tool_input_summary: summary(toolCall.rawInput ?? toolCall.content ?? toolCall),
|
|
169
|
+
});
|
|
170
|
+
this.registry.setStatus(this.descriptor.session_id, "waiting_approval");
|
|
171
|
+
return new Promise((resolve, reject) => { this.#pending = { id, kind: "approval", options, resolve, reject }; });
|
|
172
|
+
}
|
|
173
|
+
#onQuestion(value, method) {
|
|
174
|
+
const params = object(value);
|
|
175
|
+
const id = string(params.id) || `question-${Date.now()}`;
|
|
176
|
+
const prompt = string(params.prompt) || string(params.message, "Input required");
|
|
177
|
+
const options = Array.isArray(params.options) ? params.options.filter((item) => typeof item === "string") : undefined;
|
|
178
|
+
this.registry.setPending(this.descriptor.session_id, {
|
|
179
|
+
type: "question", id, session_id: this.descriptor.session_id, prompt,
|
|
180
|
+
...(options ? { options } : {}), requested_at: new Date().toISOString(),
|
|
181
|
+
});
|
|
182
|
+
this.registry.setStatus(this.descriptor.session_id, "waiting_input");
|
|
183
|
+
return new Promise((resolve, reject) => { this.#pending = { id, kind: "question", resolve: method === "elicitation" ? (answer) => resolve(answer) : resolve, reject }; });
|
|
184
|
+
}
|
|
185
|
+
#onUpdate(value) {
|
|
186
|
+
const params = object(value);
|
|
187
|
+
if (string(params.sessionId) !== this.descriptor.session_id)
|
|
188
|
+
return;
|
|
189
|
+
const update = object(params.update);
|
|
190
|
+
const kind = string(update.sessionUpdate) || string(update.type);
|
|
191
|
+
if (kind === "agent_message_chunk") {
|
|
192
|
+
const content = object(update.content);
|
|
193
|
+
if (content.type === "text")
|
|
194
|
+
this.registry.append(this.descriptor.session_id, "agent_message", { text: string(content.text) });
|
|
195
|
+
}
|
|
196
|
+
else if (kind === "user_message_chunk") {
|
|
197
|
+
const content = object(update.content);
|
|
198
|
+
if (content.type === "text")
|
|
199
|
+
this.registry.append(this.descriptor.session_id, "user_message", { text: string(content.text) });
|
|
200
|
+
}
|
|
201
|
+
else if (kind === "tool_call") {
|
|
202
|
+
const rawInput = update.rawInput;
|
|
203
|
+
this.registry.append(this.descriptor.session_id, "tool_call", {
|
|
204
|
+
tool_call_id: string(update.toolCallId), tool_name: string(update.title) || string(update.kind, "tool"),
|
|
205
|
+
input_summary: summary(rawInput ?? update.content ?? update), ...(json(rawInput) !== undefined ? { input: json(rawInput) } : {}),
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
else if (kind === "tool_call_update" && (update.status === "completed" || update.status === "failed")) {
|
|
209
|
+
const rawOutput = update.rawOutput;
|
|
210
|
+
this.registry.append(this.descriptor.session_id, "tool_result", {
|
|
211
|
+
tool_call_id: string(update.toolCallId), output_summary: summary(rawOutput ?? update.content ?? update),
|
|
212
|
+
...(json(rawOutput) !== undefined ? { output: json(rawOutput) } : {}), is_error: update.status === "failed",
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
#onClose(error) {
|
|
217
|
+
this.#peer = undefined;
|
|
218
|
+
this.#pending?.reject(error);
|
|
219
|
+
this.#pending = undefined;
|
|
220
|
+
if (!this.#closed && this.registry.get(this.descriptor.session_id))
|
|
221
|
+
this.registry.setStatus(this.descriptor.session_id, "error", "ACP connection closed");
|
|
222
|
+
if (!this.#closed)
|
|
223
|
+
this.emit("close", error);
|
|
224
|
+
}
|
|
225
|
+
#requirePeer() { if (!this.#peer)
|
|
226
|
+
throw new Error(`Session ${this.descriptor.session_id} is not attached`); return this.#peer; }
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=acp-attach.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acp-attach.js","sourceRoot":"","sources":["../src/acp-attach.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { hostname } from "node:os";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { HarnessControlClient } from "./client.js";
|
|
5
|
+
import { login, readCredentials, writeCredentials } from "./credentials.js";
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
const { version } = require("../package.json");
|
|
8
|
+
const HELP = `Rivetplane local client
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
rivetplane [--local-port PORT] [--discovery-dir PATH] [--opencode-url URL] [--opencode-directory PATH] [--no-opencode] [--no-relay]
|
|
12
|
+
rivetplane login --server URL [--machine-name NAME] [--machine ID --token TOKEN]
|
|
13
|
+
rivetplane --help
|
|
14
|
+
|
|
15
|
+
The client scans ~/.acp/sessions/*.json, attaches to ACP sessions, detects an
|
|
16
|
+
OpenCode server at http://localhost:4096, and exposes
|
|
17
|
+
the local API at http://127.0.0.1:PORT/v1.`;
|
|
18
|
+
function flag(name) { const offset = process.argv.indexOf(name); return offset >= 0 ? process.argv[offset + 1] : undefined; }
|
|
19
|
+
async function main() {
|
|
20
|
+
if (process.argv.includes("--help") || process.argv.includes("-h")) {
|
|
21
|
+
process.stdout.write(`${HELP}\n`);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (process.argv.includes("--version") || process.argv.includes("-v")) {
|
|
25
|
+
process.stdout.write(`${version}\n`);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (process.argv[2] === "login") {
|
|
29
|
+
const server_url = flag("--server") ?? process.env.HARNESS_CP_SERVER;
|
|
30
|
+
const machineName = flag("--machine-name");
|
|
31
|
+
if (!server_url)
|
|
32
|
+
throw new Error("Use --server URL or set HARNESS_CP_SERVER");
|
|
33
|
+
const token = flag("--token") ?? process.env.HCP_MACHINE_TOKEN;
|
|
34
|
+
if (token) {
|
|
35
|
+
const credentials = { server_url: server_url.replace(/\/$/, ""), machine_id: flag("--machine") ?? `local-${hostname()}`, machine_name: machineName ?? hostname(), device_id: flag("--machine") ?? `local-${hostname()}`, owner_account_id: "self-hosted", token };
|
|
36
|
+
await writeCredentials(credentials);
|
|
37
|
+
process.stdout.write(`Paired machine ${credentials.machine_name} (${credentials.machine_id}).\n`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
process.stdout.write(`Starting device pairing for ${machineName ?? hostname()}...\n`);
|
|
41
|
+
const credentials = await login({ server_url, ...(machineName ? { machine_name: machineName } : {}) });
|
|
42
|
+
process.stdout.write(`Paired machine ${credentials.machine_name} (${credentials.machine_id}).\n`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const credentials = await readCredentials();
|
|
46
|
+
const discoveryDirectory = flag("--discovery-dir");
|
|
47
|
+
const localPort = Number(flag("--local-port") ?? process.env.HARNESS_CP_LOCAL_PORT ?? 41737);
|
|
48
|
+
if (!Number.isInteger(localPort) || localPort < 0 || localPort > 65_535)
|
|
49
|
+
throw new Error("--local-port must be a valid port");
|
|
50
|
+
const client = new HarnessControlClient({
|
|
51
|
+
...(credentials ? { credentials } : {}),
|
|
52
|
+
...(discoveryDirectory ? { discovery_directory: discoveryDirectory } : {}),
|
|
53
|
+
local_port: localPort,
|
|
54
|
+
relay: !process.argv.includes("--no-relay"),
|
|
55
|
+
opencode_url: process.argv.includes("--no-opencode") ? false : (flag("--opencode-url") ?? process.env.HARNESS_CP_OPENCODE_URL),
|
|
56
|
+
opencode_directory: flag("--opencode-directory") ?? process.env.HARNESS_CP_OPENCODE_DIRECTORY ?? process.cwd(),
|
|
57
|
+
});
|
|
58
|
+
client.manager.registry.on("log", (message) => process.stderr.write(`${String(message)}\n`));
|
|
59
|
+
const started = await client.start();
|
|
60
|
+
process.stdout.write(`Local API: http://127.0.0.1:${started.local_port}/v1\n`);
|
|
61
|
+
process.stdout.write(credentials && !process.argv.includes("--no-relay") ? `Relay: ${credentials.server_url}\n` : "Relay: disabled (run rivetplane login to pair this machine)\n");
|
|
62
|
+
const harnesses = client.harnesses();
|
|
63
|
+
if (harnesses.length === 0)
|
|
64
|
+
process.stdout.write(`Harnesses: none found (ACP: ${client.manager.discovery.directory}; OpenCode: ${client.opencode ? `${client.opencode.url} for ${client.opencode.directory}` : "disabled"})\n`);
|
|
65
|
+
else
|
|
66
|
+
for (const harness of harnesses)
|
|
67
|
+
process.stdout.write(`Harness: ${harness.harness_type} (${harness.attached_sessions}/${harness.discovered_sessions} sessions attached)\n`);
|
|
68
|
+
let stopping = false;
|
|
69
|
+
const stop = () => { if (stopping)
|
|
70
|
+
return; stopping = true; void client.stop().finally(() => process.exit(0)); };
|
|
71
|
+
process.on("SIGINT", stop);
|
|
72
|
+
process.on("SIGTERM", stop);
|
|
73
|
+
}
|
|
74
|
+
void main().catch((error) => { process.stderr.write(`rivetplane: ${error instanceof Error ? error.message : String(error)}\n`); process.exitCode = 1; });
|
|
75
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { hostname } from "node:os";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { LocalApi } from "./local-api.js";
|
|
4
|
+
import { OutboundRelay } from "./relay.js";
|
|
5
|
+
import { SessionManager } from "./session-manager.js";
|
|
6
|
+
import { OpenCodeManager } from "./opencode-manager.js";
|
|
7
|
+
export class HarnessControlClient {
|
|
8
|
+
options;
|
|
9
|
+
manager;
|
|
10
|
+
local_api;
|
|
11
|
+
relay;
|
|
12
|
+
opencode;
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
this.options = options;
|
|
15
|
+
const machineId = options.credentials?.machine_id ?? `local-${randomUUID()}`;
|
|
16
|
+
this.manager = new SessionManager(machineId, { ...(options.discovery_directory ? { directory: options.discovery_directory } : {}), ...(options.discovery_interval_ms ? { interval_ms: options.discovery_interval_ms } : {}) });
|
|
17
|
+
if (options.opencode_url !== false)
|
|
18
|
+
this.opencode = new OpenCodeManager(machineId, this.manager.registry, { ...(typeof options.opencode_url === "string" ? { url: options.opencode_url } : {}), ...(options.opencode_directory ? { directory: options.opencode_directory } : {}), ...(options.discovery_interval_ms ? { interval_ms: options.discovery_interval_ms } : {}) });
|
|
19
|
+
const target = (id) => this.manager.target(id) ?? this.opencode?.target(id);
|
|
20
|
+
this.local_api = new LocalApi(this.manager.registry, { port: options.local_port ?? 41737, target,
|
|
21
|
+
harnesses: () => this.harnesses(), discovery_directory: this.manager.discovery.directory });
|
|
22
|
+
if (options.credentials && options.relay !== false)
|
|
23
|
+
this.relay = new OutboundRelay(options.credentials, this.manager.registry, target, {
|
|
24
|
+
createSession: async (command) => { if (command.harness_type !== "opencode" || !this.opencode)
|
|
25
|
+
throw new Error("Harness cannot create sessions"); return this.opencode.createSession(command); },
|
|
26
|
+
capabilities: () => { const value = this.opencode?.capabilities(); return value ? [value] : []; },
|
|
27
|
+
});
|
|
28
|
+
this.manager.registry.on("warning", (error) => this.manager.registry.emit("log", `Warning: ${error instanceof Error ? error.message : String(error)}`));
|
|
29
|
+
}
|
|
30
|
+
async start() { const local_port = await this.local_api.start(); await Promise.all([this.manager.start(), this.opencode?.start()]); this.relay?.start(); return { local_port }; }
|
|
31
|
+
async stop() { this.relay?.stop(); this.opencode?.stop(); this.manager.stop(); await this.local_api.stop(); }
|
|
32
|
+
harnesses() { return [...this.manager.harnesses(), ...(this.opencode?.harnesses() ?? [])]; }
|
|
33
|
+
}
|
|
34
|
+
export function localCredentials(server_url) {
|
|
35
|
+
const machine_id = `local-${randomUUID()}`;
|
|
36
|
+
return { server_url, machine_id, machine_name: hostname(), device_id: machine_id, owner_account_id: "local", token: "" };
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
|
+
import { homedir, hostname } from "node:os";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { createServer } from "node:http";
|
|
6
|
+
export function credentialsPath() { return join(homedir(), ".config", "harness-cp", "credentials"); }
|
|
7
|
+
export function deviceIdentityPath(credentials = credentialsPath()) { return join(dirname(credentials), "device-id"); }
|
|
8
|
+
export async function readOrCreateDeviceIdentity(path = deviceIdentityPath()) {
|
|
9
|
+
try {
|
|
10
|
+
const value = (await readFile(path, "utf8")).trim();
|
|
11
|
+
if (/^[a-f0-9-]{36}$/i.test(value))
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
if (error.code !== "ENOENT")
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
const value = randomUUID();
|
|
19
|
+
await mkdir(dirname(path), { recursive: true, mode: 0o700 });
|
|
20
|
+
await writeFile(path, `${value}\n`, { mode: 0o600 });
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
export async function readCredentials(path = credentialsPath()) {
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(await readFile(path, "utf8"));
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (error.code === "ENOENT")
|
|
29
|
+
return undefined;
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export async function writeCredentials(credentials, path = credentialsPath()) {
|
|
34
|
+
await mkdir(dirname(path), { recursive: true, mode: 0o700 });
|
|
35
|
+
const temporary = `${path}.${process.pid}.tmp`;
|
|
36
|
+
await writeFile(temporary, `${JSON.stringify(credentials, null, 2)}\n`, { mode: 0o600 });
|
|
37
|
+
await rename(temporary, path);
|
|
38
|
+
}
|
|
39
|
+
async function defaultOpenBrowser(url) {
|
|
40
|
+
const { spawn } = await import("node:child_process");
|
|
41
|
+
const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
42
|
+
const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
43
|
+
const child = spawn(command, args, { detached: true, stdio: "ignore" });
|
|
44
|
+
child.unref();
|
|
45
|
+
}
|
|
46
|
+
async function responseJson(response) {
|
|
47
|
+
const body = await response.json();
|
|
48
|
+
if (!response.ok)
|
|
49
|
+
throw new Error(typeof body.error === "string" ? body.error : `Pairing request failed (${response.status})`);
|
|
50
|
+
return body;
|
|
51
|
+
}
|
|
52
|
+
export async function login(options) {
|
|
53
|
+
const server = options.server_url.replace(/\/$/, "");
|
|
54
|
+
const machine_name = options.machine_name ?? hostname();
|
|
55
|
+
const credentialPath = options.credentials_path ?? credentialsPath();
|
|
56
|
+
const existing = await readCredentials(credentialPath);
|
|
57
|
+
const device_id = await readOrCreateDeviceIdentity(options.device_identity_path ?? deviceIdentityPath(credentialPath));
|
|
58
|
+
const state = randomBytes(24).toString("base64url");
|
|
59
|
+
const verifier = randomBytes(32).toString("base64url");
|
|
60
|
+
const challenge = createHash("sha256").update(verifier).digest("base64url");
|
|
61
|
+
let resolveCallback;
|
|
62
|
+
let rejectCallback;
|
|
63
|
+
const callback = new Promise((resolve, reject) => { resolveCallback = resolve; rejectCallback = reject; });
|
|
64
|
+
const callbackServer = createServer((request, response) => {
|
|
65
|
+
const url = new URL(request.url ?? "/", "http://127.0.0.1");
|
|
66
|
+
if (url.pathname !== "/callback") {
|
|
67
|
+
response.writeHead(404);
|
|
68
|
+
response.end();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (url.searchParams.get("state") !== state || !url.searchParams.get("code")) {
|
|
72
|
+
response.writeHead(400, { "content-type": "text/plain" });
|
|
73
|
+
response.end("Authorization failed. You can close this window.");
|
|
74
|
+
rejectCallback(new Error("The authorization callback is not valid"));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const address = callbackServer.address();
|
|
78
|
+
response.writeHead(200, { "content-type": "text/html; charset=utf-8", "content-security-policy": "default-src 'none'; style-src 'unsafe-inline'" });
|
|
79
|
+
response.end("<!doctype html><meta charset=utf-8><title>Connected</title><style>body{font:18px system-ui;padding:48px;background:#0b111b;color:#edf3ff}h1{color:#70e1b2}</style><h1>Client connected</h1><p>You can close this window and return to the terminal.</p>");
|
|
80
|
+
resolveCallback({ code: url.searchParams.get("code"), redirect_uri: `http://127.0.0.1:${address.port}/callback` });
|
|
81
|
+
});
|
|
82
|
+
await new Promise((resolve, reject) => { callbackServer.once("error", reject); callbackServer.listen(0, "127.0.0.1", resolve); });
|
|
83
|
+
const redirect_uri = `http://127.0.0.1:${callbackServer.address().port}/callback`;
|
|
84
|
+
const authorize = new URL(`${server}/authorize`);
|
|
85
|
+
authorize.searchParams.set("redirect_uri", redirect_uri);
|
|
86
|
+
authorize.searchParams.set("state", state);
|
|
87
|
+
authorize.searchParams.set("code_challenge", challenge);
|
|
88
|
+
authorize.searchParams.set("code_challenge_method", "S256");
|
|
89
|
+
authorize.searchParams.set("machine_name", machine_name);
|
|
90
|
+
authorize.searchParams.set("device_id", device_id);
|
|
91
|
+
if (existing?.server_url === server)
|
|
92
|
+
authorize.searchParams.set("previous_machine_id", existing.machine_id);
|
|
93
|
+
const timeout = setTimeout(() => rejectCallback(new Error("Browser authorization timed out")), options.timeout_ms ?? 10 * 60_000);
|
|
94
|
+
timeout.unref();
|
|
95
|
+
try {
|
|
96
|
+
await (options.open_browser ?? defaultOpenBrowser)(authorize.toString());
|
|
97
|
+
const result = await callback;
|
|
98
|
+
const issued = await responseJson(await fetch(`${server}/v1/auth/token`, { method: "POST", headers: { "content-type": "application/json" },
|
|
99
|
+
body: JSON.stringify({ grant_type: "authorization_code", code: result.code, redirect_uri: result.redirect_uri, code_verifier: verifier }) }));
|
|
100
|
+
const credentials = { server_url: server, machine_id: String(issued.machine_id ?? randomUUID()), machine_name, device_id,
|
|
101
|
+
owner_account_id: String(issued.owner_account_id ?? "paired"), token: String(issued.access_token ?? "") };
|
|
102
|
+
if (!credentials.token)
|
|
103
|
+
throw new Error("The authorization server did not return a token");
|
|
104
|
+
await writeCredentials(credentials, credentialPath);
|
|
105
|
+
return credentials;
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
clearTimeout(timeout);
|
|
109
|
+
await new Promise((resolve) => callbackServer.close(() => resolve()));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"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"}
|