tono 0.2.1 → 0.3.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/README.md +95 -3
- package/dist/cli/checks.js +504 -0
- package/dist/cli/checks.js.map +1 -0
- package/dist/cli/commands/config.js +20 -3
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/configure.js +1 -1
- package/dist/cli/commands/configure.js.map +1 -1
- package/dist/cli/commands/doctor.js +22 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/gateway.js +23 -10
- package/dist/cli/commands/gateway.js.map +1 -1
- package/dist/cli/commands/init.js +22 -3
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/start.js +72 -18
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/worker.js +458 -0
- package/dist/cli/commands/worker.js.map +1 -0
- package/dist/cli/index.js +28 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/launchd.js +5 -5
- package/dist/cli/launchd.js.map +1 -1
- package/dist/server/app.js +88 -13
- package/dist/server/app.js.map +1 -1
- package/dist/server/config/load.js +19 -1
- package/dist/server/config/load.js.map +1 -1
- package/dist/server/config/schema.json +19 -0
- package/dist/server/db/client.js +50 -1
- package/dist/server/db/client.js.map +1 -1
- package/dist/server/db/queries.js +126 -3
- package/dist/server/db/queries.js.map +1 -1
- package/dist/server/db/schema.sql +36 -21
- package/dist/server/events.js.map +1 -1
- package/dist/server/server.js +28 -11
- package/dist/server/server.js.map +1 -1
- package/dist/server/worker/agent.js +396 -0
- package/dist/server/worker/agent.js.map +1 -0
- package/dist/server/worker/pty-bridge.js +27 -0
- package/dist/server/worker/pty-bridge.js.map +1 -0
- package/dist/server/workers/github-poller.js +26 -8
- package/dist/server/workers/github-poller.js.map +1 -1
- package/dist/server/workers/reaper.js +44 -0
- package/dist/server/workers/reaper.js.map +1 -0
- package/dist/server/workers/registry.js +166 -0
- package/dist/server/workers/registry.js.map +1 -0
- package/dist/server/workers/scheduler.js +79 -130
- package/dist/server/workers/scheduler.js.map +1 -1
- package/dist/server/ws/pty.js +66 -54
- package/dist/server/ws/pty.js.map +1 -1
- package/dist/server/ws/workers.js +206 -0
- package/dist/server/ws/workers.js.map +1 -0
- package/dist/shared/types.js +4 -1
- package/dist/shared/types.js.map +1 -1
- package/dist/shared/worker-protocol.js +28 -0
- package/dist/shared/worker-protocol.js.map +1 -0
- package/dist/web/assets/{index-5VFn-lxF.js → index-DPB0x7SX.js} +21 -21
- package/dist/web/index.html +1 -1
- package/package.json +18 -26
package/dist/server/ws/pty.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
const PATH_RE = /^\/api\/sessions\/([^/]+)\/pty\/?$/;
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Browser PTY proxy. The session's owning worker is looked up from the DB; we
|
|
4
|
+
* stream frames out of the gateway-side scrollback ring + live fan-out from
|
|
5
|
+
* the registry, and forward inbound input/resize back to the worker over the
|
|
6
|
+
* worker's control WS.
|
|
7
|
+
*/
|
|
8
|
+
export function attachPtyWs(deps) {
|
|
9
|
+
const { wss, registry, q } = deps;
|
|
4
10
|
wss.on("connection", (ws, req) => {
|
|
5
11
|
const url = req.url ?? "";
|
|
6
12
|
const m = url.match(PATH_RE);
|
|
@@ -9,64 +15,70 @@ export function attachPtyWs(args) {
|
|
|
9
15
|
return;
|
|
10
16
|
}
|
|
11
17
|
const sessionId = decodeURIComponent(m[1]);
|
|
12
|
-
const
|
|
13
|
-
if (!
|
|
18
|
+
const dbRow = q.getSession(sessionId);
|
|
19
|
+
if (!dbRow) {
|
|
14
20
|
ws.close(1008, "unknown session");
|
|
15
21
|
return;
|
|
16
22
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
ws.send(scrollback, { binary: true });
|
|
33
|
-
}
|
|
34
|
-
// 3. Stream live data.
|
|
35
|
-
const onData = (chunk) => {
|
|
36
|
-
if (ws.readyState === ws.OPEN)
|
|
37
|
-
ws.send(chunk, { binary: true });
|
|
38
|
-
};
|
|
39
|
-
const onExit = (info) => {
|
|
40
|
-
if (ws.readyState === ws.OPEN) {
|
|
41
|
-
ws.send(JSON.stringify({ type: "exit", ...info }));
|
|
42
|
-
ws.close(1000, "session ended");
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
session.on("data", onData);
|
|
46
|
-
session.once("exit", onExit);
|
|
47
|
-
// 4. Inputs from the browser.
|
|
48
|
-
ws.on("message", (raw, isBinary) => {
|
|
49
|
-
if (isBinary) {
|
|
50
|
-
session.write(raw.toString("utf8"));
|
|
51
|
-
return;
|
|
23
|
+
const sessionState = registry.getSession(sessionId);
|
|
24
|
+
const workerId = dbRow.workerId ?? sessionState?.workerId ?? null;
|
|
25
|
+
// Header so the client knows session metadata up front.
|
|
26
|
+
ws.send(JSON.stringify({
|
|
27
|
+
type: "hello",
|
|
28
|
+
sessionId,
|
|
29
|
+
taskId: dbRow.taskId,
|
|
30
|
+
status: dbRow.endedAt ? "exited" : "running",
|
|
31
|
+
size: { cols: sessionState?.cols ?? 120, rows: sessionState?.rows ?? 32 },
|
|
32
|
+
workerId,
|
|
33
|
+
}));
|
|
34
|
+
// Replay scrollback as a binary frame.
|
|
35
|
+
const scrollback = registry.scrollbackFor(sessionId);
|
|
36
|
+
if (scrollback.length > 0) {
|
|
37
|
+
ws.send(scrollback, { binary: true });
|
|
52
38
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
catch {
|
|
39
|
+
if (dbRow.endedAt) {
|
|
40
|
+
// Session already ended: replay buffer and close cleanly.
|
|
41
|
+
ws.send(JSON.stringify({ type: "exit", exitCode: 0, signal: 0 }));
|
|
42
|
+
ws.close(1000, "session already ended");
|
|
58
43
|
return;
|
|
59
44
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
45
|
+
// Live data fan-out from the registry.
|
|
46
|
+
const unsubscribe = registry.subscribe(sessionId, (chunk) => {
|
|
47
|
+
if (ws.readyState === ws.OPEN)
|
|
48
|
+
ws.send(chunk, { binary: true });
|
|
49
|
+
});
|
|
50
|
+
// Inputs from the browser → forward to the worker.
|
|
51
|
+
ws.on("message", (raw, isBinary) => {
|
|
52
|
+
if (!workerId)
|
|
53
|
+
return;
|
|
54
|
+
if (isBinary) {
|
|
55
|
+
const buf = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
|
|
56
|
+
registry.sendInput(workerId, sessionId, buf);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
let msg;
|
|
60
|
+
try {
|
|
61
|
+
msg = JSON.parse(raw.toString("utf8"));
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (msg.type === "input" && typeof msg.data === "string") {
|
|
67
|
+
registry.sendInput(workerId, sessionId, Buffer.from(msg.data, "utf8"));
|
|
68
|
+
}
|
|
69
|
+
else if (msg.type === "resize" && Number.isFinite(msg.cols) && Number.isFinite(msg.rows)) {
|
|
70
|
+
registry.sendControl(workerId, {
|
|
71
|
+
type: "session.resize",
|
|
72
|
+
sessionId,
|
|
73
|
+
cols: msg.cols,
|
|
74
|
+
rows: msg.rows,
|
|
75
|
+
});
|
|
76
|
+
registry.setSessionSize(sessionId, msg.cols, msg.rows);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
ws.on("close", () => {
|
|
80
|
+
unsubscribe();
|
|
81
|
+
});
|
|
70
82
|
});
|
|
71
83
|
}
|
|
72
84
|
//# sourceMappingURL=pty.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pty.js","sourceRoot":"","sources":["../../../src/server/ws/pty.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pty.js","sourceRoot":"","sources":["../../../src/server/ws/pty.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { decodePtyFrame, } from "../../shared/worker-protocol.js";
|
|
2
|
+
import { parsePrUrl } from "../github/gh.js";
|
|
3
|
+
export function attachWorkersWs(deps) {
|
|
4
|
+
const { wss, registry, q, bus, log } = deps;
|
|
5
|
+
wss.on("connection", (ws, req) => {
|
|
6
|
+
const url = req.url ?? "";
|
|
7
|
+
if (!url.startsWith("/api/workers/connect"))
|
|
8
|
+
return;
|
|
9
|
+
let workerId = null;
|
|
10
|
+
let hostname = "(unknown)";
|
|
11
|
+
const helloDeadline = setTimeout(() => {
|
|
12
|
+
if (!workerId) {
|
|
13
|
+
try {
|
|
14
|
+
ws.close(4001, "hello timeout");
|
|
15
|
+
}
|
|
16
|
+
catch { /* ignore */ }
|
|
17
|
+
}
|
|
18
|
+
}, 10_000);
|
|
19
|
+
ws.on("message", (raw, isBinary) => {
|
|
20
|
+
if (isBinary) {
|
|
21
|
+
if (!workerId)
|
|
22
|
+
return;
|
|
23
|
+
const buf = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
|
|
24
|
+
const decoded = decodePtyFrame(buf);
|
|
25
|
+
if (!decoded)
|
|
26
|
+
return;
|
|
27
|
+
registry.appendSessionData(decoded.sessionId, decoded.payload);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
let msg;
|
|
31
|
+
try {
|
|
32
|
+
msg = JSON.parse(raw.toString("utf8"));
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
log(`[workers-ws] bad JSON from ${workerId ?? "(pre-hello)"}; closing`);
|
|
36
|
+
try {
|
|
37
|
+
ws.close(1003, "bad json");
|
|
38
|
+
}
|
|
39
|
+
catch { /* ignore */ }
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (!workerId) {
|
|
43
|
+
if (msg.type !== "worker.hello") {
|
|
44
|
+
log(`[workers-ws] expected worker.hello, got ${msg.type}; closing`);
|
|
45
|
+
try {
|
|
46
|
+
ws.close(4002, "hello required first");
|
|
47
|
+
}
|
|
48
|
+
catch { /* ignore */ }
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
clearTimeout(helloDeadline);
|
|
52
|
+
workerId = msg.workerId;
|
|
53
|
+
hostname = msg.hostname;
|
|
54
|
+
q.upsertWorker({
|
|
55
|
+
id: msg.workerId,
|
|
56
|
+
hostname: msg.hostname,
|
|
57
|
+
os: msg.os,
|
|
58
|
+
arch: msg.arch,
|
|
59
|
+
capabilities: msg.capabilities,
|
|
60
|
+
});
|
|
61
|
+
const running = new Map(msg.runningSessions.map((r) => [r.sessionId, r]));
|
|
62
|
+
registry.register({
|
|
63
|
+
workerId: msg.workerId,
|
|
64
|
+
hostname: msg.hostname,
|
|
65
|
+
os: msg.os,
|
|
66
|
+
arch: msg.arch,
|
|
67
|
+
capabilities: msg.capabilities,
|
|
68
|
+
capacity: msg.capacity,
|
|
69
|
+
runningSessions: running,
|
|
70
|
+
ws,
|
|
71
|
+
connectedAt: new Date(),
|
|
72
|
+
lastHeartbeatAt: new Date(),
|
|
73
|
+
});
|
|
74
|
+
// Reconcile sessions: for ones we still know about, clear the
|
|
75
|
+
// disconnect flag. For ones the worker reports that we don't claim
|
|
76
|
+
// anymore (terminal / cleaned), tell the worker to kill them.
|
|
77
|
+
for (const ref of msg.runningSessions) {
|
|
78
|
+
const dbSession = q.getSession(ref.sessionId);
|
|
79
|
+
if (dbSession && !dbSession.endedAt) {
|
|
80
|
+
q.clearSessionDisconnected(ref.sessionId);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
log(`[workers-ws] worker ${workerId} reports orphaned session ${ref.sessionId}; killing`);
|
|
84
|
+
try {
|
|
85
|
+
ws.send(JSON.stringify({ type: "session.kill", sessionId: ref.sessionId }));
|
|
86
|
+
}
|
|
87
|
+
catch { /* ignore */ }
|
|
88
|
+
deps.onOrphanSession?.(msg.workerId, ref.sessionId);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
log(`[workers-ws] worker connected: ${msg.workerId} (${msg.hostname}) — ${msg.runningSessions.length} live session(s)`);
|
|
92
|
+
bus.emit("worker:connected", { workerId: msg.workerId, hostname: msg.hostname });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
switch (msg.type) {
|
|
96
|
+
case "worker.heartbeat": {
|
|
97
|
+
q.touchWorker(workerId);
|
|
98
|
+
registry.updateHeartbeat(workerId, msg.capacity, msg.runningSessions);
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
case "task.accepted": {
|
|
102
|
+
// Worker is committing to start the task. Status flip to 'running'
|
|
103
|
+
// happens once session.started arrives.
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
case "task.nacked": {
|
|
107
|
+
log(`[workers-ws] worker ${workerId} nacked task #${msg.taskId}: ${msg.reason}`);
|
|
108
|
+
q.clearTaskAssignment(msg.taskId);
|
|
109
|
+
// Reset to queued so the scheduler picks it up again.
|
|
110
|
+
const t = q.getTask(msg.taskId);
|
|
111
|
+
if (t && t.status === "assigning") {
|
|
112
|
+
q.resetForRetry(msg.taskId);
|
|
113
|
+
const updated = q.getTask(msg.taskId);
|
|
114
|
+
if (updated)
|
|
115
|
+
bus.emit("task:queued", { task: updated });
|
|
116
|
+
}
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
case "session.started": {
|
|
120
|
+
q.insertSession({
|
|
121
|
+
id: msg.sessionId,
|
|
122
|
+
taskId: msg.taskId,
|
|
123
|
+
workerId,
|
|
124
|
+
pid: msg.pid,
|
|
125
|
+
worktreePath: msg.worktreePath,
|
|
126
|
+
});
|
|
127
|
+
q.setTaskStatus(msg.taskId, "running");
|
|
128
|
+
registry.ensureSession(msg.sessionId, workerId, msg.taskId);
|
|
129
|
+
const updated = q.getTask(msg.taskId);
|
|
130
|
+
if (updated)
|
|
131
|
+
bus.emit("task:updated", { task: updated });
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
case "session.exit": {
|
|
135
|
+
q.endSession(msg.sessionId);
|
|
136
|
+
const cur = q.getTask(msg.taskId);
|
|
137
|
+
const preserveStatuses = new Set(["completed", "pr_open", "pr_closed", "merged", "cleaned"]);
|
|
138
|
+
if (cur && preserveStatuses.has(cur.status)) {
|
|
139
|
+
log(`[workers-ws] task #${msg.taskId} session ended (exit ${msg.exitCode}); status ${cur.status} preserved`);
|
|
140
|
+
q.clearTaskAssignment(msg.taskId);
|
|
141
|
+
registry.forgetSession(msg.sessionId);
|
|
142
|
+
bus.emit("task:updated", { task: cur });
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
// Last-chance PR URL detection from the gateway-side scrollback ring,
|
|
146
|
+
// mirroring the old scheduler behavior. (The worker also reports its
|
|
147
|
+
// own detected URL via task.update; this is the fallback.)
|
|
148
|
+
const prUrl = msg.prUrl ?? parsePrUrl(registry.scrollbackFor(msg.sessionId).toString("utf8"));
|
|
149
|
+
const status = msg.exitCode === 0 ? "completed" : "failed";
|
|
150
|
+
q.setTaskStatus(msg.taskId, status, { exitCode: msg.exitCode, prUrl });
|
|
151
|
+
q.clearTaskAssignment(msg.taskId);
|
|
152
|
+
registry.forgetSession(msg.sessionId);
|
|
153
|
+
const post = q.getTask(msg.taskId);
|
|
154
|
+
if (post)
|
|
155
|
+
bus.emit("task:updated", { task: post });
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
case "task.update": {
|
|
159
|
+
if (msg.agentSessionId)
|
|
160
|
+
q.setAgentSessionId(msg.taskId, msg.agentSessionId);
|
|
161
|
+
if (msg.prUrl) {
|
|
162
|
+
const t = q.getTask(msg.taskId);
|
|
163
|
+
if (t && t.kind === "implement" && (t.status === "running" || t.status === "assigning")) {
|
|
164
|
+
q.setTaskStatus(msg.taskId, "pr_open", { prUrl: msg.prUrl, exitCode: 0 });
|
|
165
|
+
log(`[workers-ws] task #${msg.taskId} -> pr_open (${msg.prUrl})`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const post = q.getTask(msg.taskId);
|
|
169
|
+
if (post)
|
|
170
|
+
bus.emit("task:updated", { task: post });
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
case "session.scrollback": {
|
|
174
|
+
// We rebuild scrollback from incoming PTY frames already; this is
|
|
175
|
+
// only used when the worker proactively flushes a buffer (e.g. on
|
|
176
|
+
// re-attach). Append directly into the gateway ring.
|
|
177
|
+
const payload = Buffer.from(msg.data, "base64");
|
|
178
|
+
registry.appendSessionData(msg.sessionId, payload);
|
|
179
|
+
registry.setSessionSize(msg.sessionId, msg.cols, msg.rows);
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
default: {
|
|
183
|
+
// Unknown control type — ignore.
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
ws.on("close", () => {
|
|
189
|
+
clearTimeout(helloDeadline);
|
|
190
|
+
if (!workerId)
|
|
191
|
+
return;
|
|
192
|
+
log(`[workers-ws] worker disconnected: ${workerId} (${hostname})`);
|
|
193
|
+
// Mark all sessions this worker owned as disconnected. The reaper will
|
|
194
|
+
// fail them if the worker doesn't reconnect within graceMs.
|
|
195
|
+
const owned = q.listSessionsForWorker(workerId);
|
|
196
|
+
for (const s of owned)
|
|
197
|
+
q.markSessionDisconnected(s.id);
|
|
198
|
+
registry.unregister(workerId);
|
|
199
|
+
bus.emit("worker:disconnected", { workerId, hostname });
|
|
200
|
+
});
|
|
201
|
+
ws.on("error", (err) => {
|
|
202
|
+
log(`[workers-ws] ws error from ${workerId ?? "(pre-hello)"}: ${err.message}`);
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=workers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workers.js","sourceRoot":"","sources":["../../../src/server/ws/workers.ts"],"names":[],"mappings":"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"}
|
package/dist/shared/types.js
CHANGED
|
@@ -18,6 +18,9 @@ export function labelForAgentKind(agent, kind) {
|
|
|
18
18
|
const short = agentShortName(agent);
|
|
19
19
|
return kind === "implement" ? `tono-${short}` : `tono-${short}-review`;
|
|
20
20
|
}
|
|
21
|
+
/** The bare default-agent labels (no agent suffix). */
|
|
22
|
+
export const DEFAULT_IMPLEMENT_LABEL = "tono";
|
|
23
|
+
export const DEFAULT_REVIEW_LABEL = "tono-review";
|
|
21
24
|
export const TERMINAL_STATUSES = ["merged", "pr_closed", "cleaned"];
|
|
22
|
-
export const ACTIVE_STATUSES = ["queued", "running", "pr_open"];
|
|
25
|
+
export const ACTIVE_STATUSES = ["queued", "assigning", "running", "pr_open"];
|
|
23
26
|
//# sourceMappingURL=types.js.map
|
package/dist/shared/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,WAAW,GAAgB,CAAC,aAAa,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;AAQ7E,MAAM,CAAC,MAAM,UAAU,GAAe,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;AAE9D;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,KAAgB;IAC7C,OAAO,KAAK,KAAK,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAgB,EAAE,IAAc;IAChE,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACpC,OAAO,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC;AACzE,CAAC;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,WAAW,GAAgB,CAAC,aAAa,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;AAQ7E,MAAM,CAAC,MAAM,UAAU,GAAe,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;AAE9D;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,KAAgB;IAC7C,OAAO,KAAK,KAAK,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAgB,EAAE,IAAc;IAChE,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACpC,OAAO,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC;AACzE,CAAC;AA4CD,uDAAuD;AACvD,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAC9C,MAAM,CAAC,MAAM,oBAAoB,GAAG,aAAa,CAAC;AA+DlD,MAAM,CAAC,MAAM,iBAAiB,GAAiB,CAAC,QAAQ,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;AAClF,MAAM,CAAC,MAAM,eAAe,GAAiB,CAAC,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Wire protocol between tono workers and the gateway. Both sides import this.
|
|
2
|
+
//
|
|
3
|
+
// Transport: a single multiplexed WebSocket from worker → gateway. Gateway is
|
|
4
|
+
// the WS server, worker is the client. Both directions exchange:
|
|
5
|
+
//
|
|
6
|
+
// - JSON text frames for the control plane (assignment, lifecycle, status).
|
|
7
|
+
// - Binary frames for PTY data, formatted as <36 bytes UTF-8 sessionId><payload>.
|
|
8
|
+
// Direction is implicit: worker→gateway = pty output; gateway→worker = pty input.
|
|
9
|
+
// ---- binary frame helpers ----
|
|
10
|
+
//
|
|
11
|
+
// Binary frame layout: <36 bytes UTF-8 sessionId><payload bytes...>
|
|
12
|
+
// Both worker and gateway use the same encoder/decoder.
|
|
13
|
+
export const SESSION_ID_BYTES = 36;
|
|
14
|
+
export function encodePtyFrame(sessionId, payload) {
|
|
15
|
+
if (sessionId.length !== SESSION_ID_BYTES) {
|
|
16
|
+
throw new Error(`encodePtyFrame: sessionId must be ${SESSION_ID_BYTES} chars, got ${sessionId.length}`);
|
|
17
|
+
}
|
|
18
|
+
const head = Buffer.from(sessionId, "utf8");
|
|
19
|
+
return Buffer.concat([head, payload]);
|
|
20
|
+
}
|
|
21
|
+
export function decodePtyFrame(frame) {
|
|
22
|
+
if (frame.length < SESSION_ID_BYTES)
|
|
23
|
+
return null;
|
|
24
|
+
const sessionId = frame.subarray(0, SESSION_ID_BYTES).toString("utf8");
|
|
25
|
+
const payload = frame.subarray(SESSION_ID_BYTES);
|
|
26
|
+
return { sessionId, payload };
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=worker-protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-protocol.js","sourceRoot":"","sources":["../../src/shared/worker-protocol.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,EAAE;AACF,8EAA8E;AAC9E,iEAAiE;AACjE,EAAE;AACF,8EAA8E;AAC9E,oFAAoF;AACpF,sFAAsF;AA8KtF,iCAAiC;AACjC,EAAE;AACF,oEAAoE;AACpE,wDAAwD;AAExD,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAEnC,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,OAAe;IAC/D,IAAI,SAAS,CAAC,MAAM,KAAK,gBAAgB,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,qCAAqC,gBAAgB,eAAe,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1G,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC5C,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,IAAI,KAAK,CAAC,MAAM,GAAG,gBAAgB;QAAE,OAAO,IAAI,CAAC;IACjD,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvE,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACjD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AAChC,CAAC"}
|