tono 0.2.0 → 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.
Files changed (59) hide show
  1. package/README.md +95 -3
  2. package/dist/cli/checks.js +504 -0
  3. package/dist/cli/checks.js.map +1 -0
  4. package/dist/cli/commands/config.js +20 -3
  5. package/dist/cli/commands/config.js.map +1 -1
  6. package/dist/cli/commands/configure.js +1 -1
  7. package/dist/cli/commands/configure.js.map +1 -1
  8. package/dist/cli/commands/doctor.js +22 -0
  9. package/dist/cli/commands/doctor.js.map +1 -0
  10. package/dist/cli/commands/gateway.js +23 -10
  11. package/dist/cli/commands/gateway.js.map +1 -1
  12. package/dist/cli/commands/init.js +22 -3
  13. package/dist/cli/commands/init.js.map +1 -1
  14. package/dist/cli/commands/start.js +72 -18
  15. package/dist/cli/commands/start.js.map +1 -1
  16. package/dist/cli/commands/worker.js +458 -0
  17. package/dist/cli/commands/worker.js.map +1 -0
  18. package/dist/cli/index.js +28 -9
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/cli/launchd.js +5 -5
  21. package/dist/cli/launchd.js.map +1 -1
  22. package/dist/server/app.js +90 -14
  23. package/dist/server/app.js.map +1 -1
  24. package/dist/server/config/load.js +19 -1
  25. package/dist/server/config/load.js.map +1 -1
  26. package/dist/server/config/schema.json +19 -0
  27. package/dist/server/db/client.js +50 -1
  28. package/dist/server/db/client.js.map +1 -1
  29. package/dist/server/db/queries.js +126 -3
  30. package/dist/server/db/queries.js.map +1 -1
  31. package/dist/server/db/schema.sql +36 -21
  32. package/dist/server/events.js.map +1 -1
  33. package/dist/server/server.js +28 -11
  34. package/dist/server/server.js.map +1 -1
  35. package/dist/server/worker/agent.js +396 -0
  36. package/dist/server/worker/agent.js.map +1 -0
  37. package/dist/server/worker/pty-bridge.js +27 -0
  38. package/dist/server/worker/pty-bridge.js.map +1 -0
  39. package/dist/server/workers/github-poller.js +26 -8
  40. package/dist/server/workers/github-poller.js.map +1 -1
  41. package/dist/server/workers/reaper.js +44 -0
  42. package/dist/server/workers/reaper.js.map +1 -0
  43. package/dist/server/workers/registry.js +166 -0
  44. package/dist/server/workers/registry.js.map +1 -0
  45. package/dist/server/workers/scheduler.js +79 -130
  46. package/dist/server/workers/scheduler.js.map +1 -1
  47. package/dist/server/ws/pty.js +66 -54
  48. package/dist/server/ws/pty.js.map +1 -1
  49. package/dist/server/ws/workers.js +206 -0
  50. package/dist/server/ws/workers.js.map +1 -0
  51. package/dist/shared/types.js +4 -1
  52. package/dist/shared/types.js.map +1 -1
  53. package/dist/shared/version.js +18 -0
  54. package/dist/shared/version.js.map +1 -0
  55. package/dist/shared/worker-protocol.js +28 -0
  56. package/dist/shared/worker-protocol.js.map +1 -0
  57. package/dist/web/assets/{index-5VFn-lxF.js → index-DPB0x7SX.js} +21 -21
  58. package/dist/web/index.html +1 -1
  59. package/package.json +18 -26
@@ -1,6 +1,12 @@
1
1
  const PATH_RE = /^\/api\/sessions\/([^/]+)\/pty\/?$/;
2
- export function attachPtyWs(args) {
3
- const { wss, pty } = args;
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 session = pty.get(sessionId);
13
- if (!session) {
18
+ const dbRow = q.getSession(sessionId);
19
+ if (!dbRow) {
14
20
  ws.close(1008, "unknown session");
15
21
  return;
16
22
  }
17
- bind(ws, session);
18
- });
19
- }
20
- function bind(ws, session) {
21
- // 1. Send a small JSON header so the client knows session metadata up front.
22
- ws.send(JSON.stringify({
23
- type: "hello",
24
- sessionId: session.id,
25
- taskId: session.taskId,
26
- status: session.status,
27
- size: session.size(),
28
- }));
29
- // 2. Replay scrollback as one binary frame.
30
- const scrollback = session.scrollback();
31
- if (scrollback.length > 0) {
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
- let msg;
54
- try {
55
- msg = JSON.parse(raw.toString("utf8"));
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
- if (msg.type === "input" && typeof msg.data === "string") {
61
- session.write(msg.data);
62
- }
63
- else if (msg.type === "resize" && Number.isFinite(msg.cols) && Number.isFinite(msg.rows)) {
64
- session.resize(msg.cols, msg.rows);
65
- }
66
- });
67
- ws.on("close", () => {
68
- session.off("data", onData);
69
- session.off("exit", onExit);
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":"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"}
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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"}
@@ -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
@@ -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;AAyFD,MAAM,CAAC,MAAM,iBAAiB,GAAiB,CAAC,QAAQ,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;AAClF,MAAM,CAAC,MAAM,eAAe,GAAiB,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,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,18 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const HERE = dirname(fileURLToPath(import.meta.url));
5
+ // dist/shared/version.js → package root (../..) → package.json.
6
+ // Same depth in both the local dev tree and an installed node_modules/tono.
7
+ const PKG_PATH = join(HERE, "..", "..", "package.json");
8
+ function readVersion() {
9
+ try {
10
+ const pkg = JSON.parse(readFileSync(PKG_PATH, "utf8"));
11
+ return typeof pkg.version === "string" ? pkg.version : "0.0.0-unknown";
12
+ }
13
+ catch {
14
+ return "0.0.0-unknown";
15
+ }
16
+ }
17
+ export const VERSION = readVersion();
18
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/shared/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,gEAAgE;AAChE,4EAA4E;AAC5E,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;AAExD,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAA0B,CAAC;QAChF,OAAO,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,eAAe,CAAC;IACzB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,WAAW,EAAE,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"}