@tpsdev-ai/cli 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.
Files changed (206) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +79 -0
  3. package/dist/bin/tps.d.ts +3 -0
  4. package/dist/bin/tps.d.ts.map +1 -0
  5. package/dist/bin/tps.js +267 -0
  6. package/dist/bin/tps.js.map +1 -0
  7. package/dist/src/cli/hire.d.ts +16 -0
  8. package/dist/src/cli/hire.d.ts.map +1 -0
  9. package/dist/src/cli/hire.js +176 -0
  10. package/dist/src/cli/hire.js.map +1 -0
  11. package/dist/src/cli/office.d.ts +7 -0
  12. package/dist/src/cli/office.d.ts.map +1 -0
  13. package/dist/src/cli/office.js +51 -0
  14. package/dist/src/cli/office.js.map +1 -0
  15. package/dist/src/cli/review.d.ts +9 -0
  16. package/dist/src/cli/review.d.ts.map +1 -0
  17. package/dist/src/cli/review.js +109 -0
  18. package/dist/src/cli/review.js.map +1 -0
  19. package/dist/src/cli/roster.d.ts +6 -0
  20. package/dist/src/cli/roster.d.ts.map +1 -0
  21. package/dist/src/cli/roster.js +60 -0
  22. package/dist/src/cli/roster.js.map +1 -0
  23. package/dist/src/commands/branch.d.ts +14 -0
  24. package/dist/src/commands/branch.d.ts.map +1 -0
  25. package/dist/src/commands/branch.js +395 -0
  26. package/dist/src/commands/branch.js.map +1 -0
  27. package/dist/src/commands/context.d.ts +9 -0
  28. package/dist/src/commands/context.d.ts.map +1 -0
  29. package/dist/src/commands/context.js +57 -0
  30. package/dist/src/commands/context.js.map +1 -0
  31. package/dist/src/commands/identity.d.ts +13 -0
  32. package/dist/src/commands/identity.d.ts.map +1 -0
  33. package/dist/src/commands/identity.js +231 -0
  34. package/dist/src/commands/identity.js.map +1 -0
  35. package/dist/src/commands/mail.d.ts +12 -0
  36. package/dist/src/commands/mail.d.ts.map +1 -0
  37. package/dist/src/commands/mail.js +225 -0
  38. package/dist/src/commands/mail.js.map +1 -0
  39. package/dist/src/commands/office.d.ts +19 -0
  40. package/dist/src/commands/office.d.ts.map +1 -0
  41. package/dist/src/commands/office.js +598 -0
  42. package/dist/src/commands/office.js.map +1 -0
  43. package/dist/src/commands/roster.d.ts +10 -0
  44. package/dist/src/commands/roster.d.ts.map +1 -0
  45. package/dist/src/commands/roster.js +143 -0
  46. package/dist/src/commands/roster.js.map +1 -0
  47. package/dist/src/generators/claude-code.d.ts +17 -0
  48. package/dist/src/generators/claude-code.d.ts.map +1 -0
  49. package/dist/src/generators/claude-code.js +80 -0
  50. package/dist/src/generators/claude-code.js.map +1 -0
  51. package/dist/src/generators/codex.d.ts +22 -0
  52. package/dist/src/generators/codex.d.ts.map +1 -0
  53. package/dist/src/generators/codex.js +78 -0
  54. package/dist/src/generators/codex.js.map +1 -0
  55. package/dist/src/generators/ollama.d.ts +18 -0
  56. package/dist/src/generators/ollama.d.ts.map +1 -0
  57. package/dist/src/generators/ollama.js +97 -0
  58. package/dist/src/generators/ollama.js.map +1 -0
  59. package/dist/src/generators/openclaw.d.ts +15 -0
  60. package/dist/src/generators/openclaw.d.ts.map +1 -0
  61. package/dist/src/generators/openclaw.js +103 -0
  62. package/dist/src/generators/openclaw.js.map +1 -0
  63. package/dist/src/generators/registry.d.ts +36 -0
  64. package/dist/src/generators/registry.d.ts.map +1 -0
  65. package/dist/src/generators/registry.js +99 -0
  66. package/dist/src/generators/registry.js.map +1 -0
  67. package/dist/src/schema/manifest.d.ts +140 -0
  68. package/dist/src/schema/manifest.d.ts.map +1 -0
  69. package/dist/src/schema/manifest.js +62 -0
  70. package/dist/src/schema/manifest.js.map +1 -0
  71. package/dist/src/schema/report.d.ts +166 -0
  72. package/dist/src/schema/report.d.ts.map +1 -0
  73. package/dist/src/schema/report.js +90 -0
  74. package/dist/src/schema/report.js.map +1 -0
  75. package/dist/src/schema/sanitizer.d.ts +30 -0
  76. package/dist/src/schema/sanitizer.d.ts.map +1 -0
  77. package/dist/src/schema/sanitizer.js +97 -0
  78. package/dist/src/schema/sanitizer.js.map +1 -0
  79. package/dist/src/soundstage/mock-llm.d.ts +3 -0
  80. package/dist/src/soundstage/mock-llm.d.ts.map +1 -0
  81. package/dist/src/soundstage/mock-llm.js +68 -0
  82. package/dist/src/soundstage/mock-llm.js.map +1 -0
  83. package/dist/src/utils/agent-info.d.ts +28 -0
  84. package/dist/src/utils/agent-info.d.ts.map +1 -0
  85. package/dist/src/utils/agent-info.js +102 -0
  86. package/dist/src/utils/agent-info.js.map +1 -0
  87. package/dist/src/utils/archive.d.ts +27 -0
  88. package/dist/src/utils/archive.d.ts.map +1 -0
  89. package/dist/src/utils/archive.js +80 -0
  90. package/dist/src/utils/archive.js.map +1 -0
  91. package/dist/src/utils/config-inject.d.ts +27 -0
  92. package/dist/src/utils/config-inject.d.ts.map +1 -0
  93. package/dist/src/utils/config-inject.js +83 -0
  94. package/dist/src/utils/config-inject.js.map +1 -0
  95. package/dist/src/utils/config.d.ts +30 -0
  96. package/dist/src/utils/config.d.ts.map +1 -0
  97. package/dist/src/utils/config.js +55 -0
  98. package/dist/src/utils/config.js.map +1 -0
  99. package/dist/src/utils/connection-state.d.ts +27 -0
  100. package/dist/src/utils/connection-state.d.ts.map +1 -0
  101. package/dist/src/utils/connection-state.js +81 -0
  102. package/dist/src/utils/connection-state.js.map +1 -0
  103. package/dist/src/utils/context.d.ts +14 -0
  104. package/dist/src/utils/context.d.ts.map +1 -0
  105. package/dist/src/utils/context.js +68 -0
  106. package/dist/src/utils/context.js.map +1 -0
  107. package/dist/src/utils/github-webhook.d.ts +3 -0
  108. package/dist/src/utils/github-webhook.d.ts.map +1 -0
  109. package/dist/src/utils/github-webhook.js +105 -0
  110. package/dist/src/utils/github-webhook.js.map +1 -0
  111. package/dist/src/utils/identity.d.ts +114 -0
  112. package/dist/src/utils/identity.d.ts.map +1 -0
  113. package/dist/src/utils/identity.js +341 -0
  114. package/dist/src/utils/identity.js.map +1 -0
  115. package/dist/src/utils/internal-mail.d.ts +18 -0
  116. package/dist/src/utils/internal-mail.d.ts.map +1 -0
  117. package/dist/src/utils/internal-mail.js +75 -0
  118. package/dist/src/utils/internal-mail.js.map +1 -0
  119. package/dist/src/utils/loop-detector.d.ts +27 -0
  120. package/dist/src/utils/loop-detector.d.ts.map +1 -0
  121. package/dist/src/utils/loop-detector.js +42 -0
  122. package/dist/src/utils/loop-detector.js.map +1 -0
  123. package/dist/src/utils/mail-handler.d.ts +19 -0
  124. package/dist/src/utils/mail-handler.d.ts.map +1 -0
  125. package/dist/src/utils/mail-handler.js +94 -0
  126. package/dist/src/utils/mail-handler.js.map +1 -0
  127. package/dist/src/utils/mail.d.ts +22 -0
  128. package/dist/src/utils/mail.d.ts.map +1 -0
  129. package/dist/src/utils/mail.js +111 -0
  130. package/dist/src/utils/mail.js.map +1 -0
  131. package/dist/src/utils/manifest.d.ts +36 -0
  132. package/dist/src/utils/manifest.d.ts.map +1 -0
  133. package/dist/src/utils/manifest.js +91 -0
  134. package/dist/src/utils/manifest.js.map +1 -0
  135. package/dist/src/utils/noise-ik-transport.d.ts +18 -0
  136. package/dist/src/utils/noise-ik-transport.d.ts.map +1 -0
  137. package/dist/src/utils/noise-ik-transport.js +357 -0
  138. package/dist/src/utils/noise-ik-transport.js.map +1 -0
  139. package/dist/src/utils/nono.d.ts +72 -0
  140. package/dist/src/utils/nono.d.ts.map +1 -0
  141. package/dist/src/utils/nono.js +166 -0
  142. package/dist/src/utils/nono.js.map +1 -0
  143. package/dist/src/utils/outbox.d.ts +10 -0
  144. package/dist/src/utils/outbox.d.ts.map +1 -0
  145. package/dist/src/utils/outbox.js +29 -0
  146. package/dist/src/utils/outbox.js.map +1 -0
  147. package/dist/src/utils/output.d.ts +17 -0
  148. package/dist/src/utils/output.d.ts.map +1 -0
  149. package/dist/src/utils/output.js +83 -0
  150. package/dist/src/utils/output.js.map +1 -0
  151. package/dist/src/utils/plain-tcp-transport.d.ts +10 -0
  152. package/dist/src/utils/plain-tcp-transport.d.ts.map +1 -0
  153. package/dist/src/utils/plain-tcp-transport.js +209 -0
  154. package/dist/src/utils/plain-tcp-transport.js.map +1 -0
  155. package/dist/src/utils/provision.d.ts +2 -0
  156. package/dist/src/utils/provision.d.ts.map +1 -0
  157. package/dist/src/utils/provision.js +186 -0
  158. package/dist/src/utils/provision.js.map +1 -0
  159. package/dist/src/utils/relay.d.ts +30 -0
  160. package/dist/src/utils/relay.d.ts.map +1 -0
  161. package/dist/src/utils/relay.js +539 -0
  162. package/dist/src/utils/relay.js.map +1 -0
  163. package/dist/src/utils/sandbox.d.ts +37 -0
  164. package/dist/src/utils/sandbox.d.ts.map +1 -0
  165. package/dist/src/utils/sandbox.js +126 -0
  166. package/dist/src/utils/sandbox.js.map +1 -0
  167. package/dist/src/utils/transport.d.ts +62 -0
  168. package/dist/src/utils/transport.d.ts.map +1 -0
  169. package/dist/src/utils/transport.js +75 -0
  170. package/dist/src/utils/transport.js.map +1 -0
  171. package/dist/src/utils/wall.d.ts +5 -0
  172. package/dist/src/utils/wall.d.ts.map +1 -0
  173. package/dist/src/utils/wall.js +51 -0
  174. package/dist/src/utils/wall.js.map +1 -0
  175. package/dist/src/utils/wire-delivery.d.ts +10 -0
  176. package/dist/src/utils/wire-delivery.d.ts.map +1 -0
  177. package/dist/src/utils/wire-delivery.js +57 -0
  178. package/dist/src/utils/wire-delivery.js.map +1 -0
  179. package/dist/src/utils/wire-frame.d.ts +10 -0
  180. package/dist/src/utils/wire-frame.d.ts.map +1 -0
  181. package/dist/src/utils/wire-frame.js +66 -0
  182. package/dist/src/utils/wire-frame.js.map +1 -0
  183. package/dist/src/utils/wire-mail.d.ts +54 -0
  184. package/dist/src/utils/wire-mail.d.ts.map +1 -0
  185. package/dist/src/utils/wire-mail.js +24 -0
  186. package/dist/src/utils/wire-mail.js.map +1 -0
  187. package/dist/src/utils/ws-noise-transport.d.ts +18 -0
  188. package/dist/src/utils/ws-noise-transport.d.ts.map +1 -0
  189. package/dist/src/utils/ws-noise-transport.js +356 -0
  190. package/dist/src/utils/ws-noise-transport.js.map +1 -0
  191. package/nono-profiles/tps-hire.toml +17 -0
  192. package/nono-profiles/tps-review-deep.toml +18 -0
  193. package/nono-profiles/tps-review-local.toml +21 -0
  194. package/nono-profiles/tps-roster.toml +16 -0
  195. package/package.json +68 -0
  196. package/personas/designer.tps +58 -0
  197. package/personas/developer.tps +59 -0
  198. package/personas/ea.tps +59 -0
  199. package/personas/ops.tps +60 -0
  200. package/personas/security.tps +59 -0
  201. package/personas/strategy.tps +60 -0
  202. package/personas/support.tps +57 -0
  203. package/reports/anvil.tps +68 -0
  204. package/reports/flint.tps +71 -0
  205. package/reports/kern.tps +65 -0
  206. package/reports/pulse.tps +64 -0
@@ -0,0 +1,356 @@
1
+ import { createServer } from "node:http";
2
+ import { EventEmitter } from "node:events";
3
+ import { WebSocketServer, WebSocket } from "ws";
4
+ import Noise from "noise-handshake/noise.js";
5
+ import Cipher from "noise-handshake/cipher.js";
6
+ import { decodeWireMessage, encodeWireMessage } from "./wire-frame.js";
7
+ import { fingerprint, lookupBranch } from "./identity.js";
8
+ import { JoinCompleteBodySchema, MSG_JOIN_COMPLETE } from "./wire-mail.js";
9
+ import { handleGithubWebhook } from "./github-webhook.js";
10
+ const PROLOGUE = Buffer.from("tps-v1");
11
+ const HANDSHAKE_TIMEOUT_MS = 10_000;
12
+ const MAX_MESSAGE_BYTES = 1024 * 1024 + 64;
13
+ const WS_PATH = "/tps/wire";
14
+ function toBuffer(data) {
15
+ if (Buffer.isBuffer(data))
16
+ return data;
17
+ if (Array.isArray(data))
18
+ return Buffer.concat(data.map((d) => Buffer.from(d)));
19
+ if (data instanceof ArrayBuffer)
20
+ return Buffer.from(data);
21
+ return Buffer.from(data);
22
+ }
23
+ function waitForMessage(ws, timeoutMs) {
24
+ return new Promise((resolve, reject) => {
25
+ const cleanup = () => {
26
+ ws.off("close", onClose);
27
+ ws.off("error", onErr);
28
+ };
29
+ const timer = setTimeout(() => {
30
+ cleanup();
31
+ reject(new Error(`WebSocket message timeout after ${timeoutMs}ms`));
32
+ }, timeoutMs);
33
+ const onClose = () => {
34
+ clearTimeout(timer);
35
+ cleanup();
36
+ reject(new Error("WebSocket closed before message received"));
37
+ };
38
+ const onErr = (err) => {
39
+ clearTimeout(timer);
40
+ cleanup();
41
+ reject(err);
42
+ };
43
+ ws.once("message", (data) => {
44
+ clearTimeout(timer);
45
+ cleanup();
46
+ resolve(toBuffer(data));
47
+ });
48
+ ws.once("close", onClose);
49
+ ws.once("error", onErr);
50
+ });
51
+ }
52
+ class WsNoiseChannel {
53
+ ws;
54
+ sendCipher;
55
+ recvCipher;
56
+ peerFp;
57
+ alive = true;
58
+ emitter = new EventEmitter();
59
+ constructor(ws, sendCipher, recvCipher, peerFp) {
60
+ this.ws = ws;
61
+ this.sendCipher = sendCipher;
62
+ this.recvCipher = recvCipher;
63
+ this.peerFp = peerFp;
64
+ ws.on("close", () => {
65
+ this.alive = false;
66
+ });
67
+ ws.on("message", (data) => {
68
+ try {
69
+ const raw = toBuffer(data);
70
+ if (raw.length > MAX_MESSAGE_BYTES) {
71
+ ws.close(1008, "rejected");
72
+ return;
73
+ }
74
+ const decrypted = Buffer.from(this.recvCipher.decrypt(raw));
75
+ const msg = decodeWireMessage(decrypted);
76
+ this.emitter.emit("message", msg);
77
+ }
78
+ catch {
79
+ ws.close(1008, "rejected");
80
+ }
81
+ });
82
+ }
83
+ async send(msg) {
84
+ const wire = encodeWireMessage(msg);
85
+ const encrypted = Buffer.from(this.sendCipher.encrypt(wire));
86
+ await new Promise((resolve, reject) => {
87
+ this.ws.send(encrypted, (err) => (err ? reject(err) : resolve()));
88
+ });
89
+ }
90
+ onMessage(handler) {
91
+ this.emitter.on("message", handler);
92
+ }
93
+ offMessage(handler) {
94
+ this.emitter.off("message", handler);
95
+ }
96
+ async close() {
97
+ this.ws.close();
98
+ this.alive = false;
99
+ }
100
+ isAlive() {
101
+ return this.alive && this.ws.readyState === WebSocket.OPEN;
102
+ }
103
+ peerFingerprint() {
104
+ return this.peerFp;
105
+ }
106
+ }
107
+ class WsNoiseServer {
108
+ httpServer;
109
+ wss;
110
+ onConn = null;
111
+ constructor(httpServer, wss) {
112
+ this.httpServer = httpServer;
113
+ this.wss = wss;
114
+ }
115
+ port() {
116
+ const addr = this.httpServer.address();
117
+ if (!addr || typeof addr === "string")
118
+ return 0;
119
+ return addr.port;
120
+ }
121
+ onConnection(handler) {
122
+ this.onConn = handler;
123
+ }
124
+ dispatch(channel) {
125
+ this.onConn?.(channel);
126
+ }
127
+ async close() {
128
+ await new Promise((resolve) => this.wss.close(() => resolve()));
129
+ await new Promise((resolve, reject) => {
130
+ this.httpServer.close((err) => (err ? reject(err) : resolve()));
131
+ });
132
+ }
133
+ }
134
+ export class WsNoiseTransport {
135
+ localKeyPair;
136
+ hostKeyPair;
137
+ constructor(localKeyPair, hostKeyPair) {
138
+ this.localKeyPair = localKeyPair;
139
+ this.hostKeyPair = hostKeyPair;
140
+ }
141
+ async listen(port) {
142
+ const host = this.hostKeyPair ?? this.localKeyPair;
143
+ const httpServer = createServer((_req, res) => {
144
+ res.statusCode = 404;
145
+ res.end();
146
+ });
147
+ const wss = new WebSocketServer({ server: httpServer, path: WS_PATH });
148
+ const wrapper = new WsNoiseServer(httpServer, wss);
149
+ const hostStatic = {
150
+ publicKey: Buffer.from(host.encryption.publicKey),
151
+ secretKey: Buffer.from(host.encryption.privateKey),
152
+ };
153
+ wss.on("connection", async (ws) => {
154
+ try {
155
+ const responder = new Noise("IK", false, hostStatic);
156
+ responder.initialise(PROLOGUE);
157
+ const msg1 = await waitForMessage(ws, HANDSHAKE_TIMEOUT_MS);
158
+ const payload = Buffer.from(responder.recv(msg1));
159
+ const branchId = payload.toString("utf-8");
160
+ const known = lookupBranch(branchId);
161
+ const expected = known?.encryptionKey ? Buffer.from(known.encryptionKey) : null;
162
+ const got = Buffer.from(responder.rs);
163
+ if (!expected || !got.equals(expected)) {
164
+ ws.close(1008, "rejected");
165
+ return;
166
+ }
167
+ const msg2 = Buffer.from(responder.send());
168
+ ws.send(msg2);
169
+ const channel = new WsNoiseChannel(ws, new Cipher(responder.tx), new Cipher(responder.rx), fingerprint(got));
170
+ wrapper.dispatch(channel);
171
+ }
172
+ catch {
173
+ ws.close(1008, "rejected");
174
+ }
175
+ });
176
+ await new Promise((resolve, reject) => {
177
+ httpServer.listen(port, "0.0.0.0", () => resolve());
178
+ httpServer.once("error", reject);
179
+ });
180
+ return wrapper;
181
+ }
182
+ async connect(target) {
183
+ const isLocal = target.host === "localhost" || target.host === "127.0.0.1" || target.host === "::1";
184
+ const scheme = isLocal ? "ws" : "wss";
185
+ const url = `${scheme}://${target.host}:${target.port}${WS_PATH}`;
186
+ const ws = new WebSocket(url);
187
+ // Track early close from server (rejection before handshake completes)
188
+ let earlyClose = false;
189
+ let earlyCloseReject = null;
190
+ await new Promise((resolve, reject) => {
191
+ ws.once("open", () => resolve());
192
+ ws.once("error", reject);
193
+ });
194
+ // Attach close handler IMMEDIATELY after open, before any handshake
195
+ ws.on("close", () => {
196
+ earlyClose = true;
197
+ earlyCloseReject?.(new Error("Connection rejected by server"));
198
+ });
199
+ const localStatic = {
200
+ publicKey: Buffer.from(this.localKeyPair.encryption.publicKey),
201
+ secretKey: Buffer.from(this.localKeyPair.encryption.privateKey),
202
+ };
203
+ const initiator = new Noise("IK", true, localStatic);
204
+ initiator.initialise(PROLOGUE, Buffer.from(target.hostPublicKey));
205
+ const msg1 = Buffer.from(initiator.send(Buffer.from(target.branchId)));
206
+ ws.send(msg1);
207
+ // Wait for msg2 OR early close
208
+ let msg2;
209
+ try {
210
+ msg2 = await new Promise((resolve, reject) => {
211
+ if (earlyClose) {
212
+ reject(new Error("Connection rejected by server"));
213
+ return;
214
+ }
215
+ earlyCloseReject = reject;
216
+ const timer = setTimeout(() => {
217
+ reject(new Error(`Handshake timeout after ${HANDSHAKE_TIMEOUT_MS}ms`));
218
+ }, HANDSHAKE_TIMEOUT_MS);
219
+ ws.once("message", (data) => {
220
+ clearTimeout(timer);
221
+ earlyCloseReject = null;
222
+ resolve(toBuffer(data));
223
+ });
224
+ });
225
+ }
226
+ catch (e) {
227
+ ws.close(1008, "rejected");
228
+ throw e;
229
+ }
230
+ initiator.recv(msg2);
231
+ const gotHost = Buffer.from(initiator.rs);
232
+ const expectedHost = Buffer.from(target.hostPublicKey);
233
+ if (!gotHost.equals(expectedHost)) {
234
+ ws.close(1008, "rejected");
235
+ throw new Error("Host key mismatch after Noise_IK handshake");
236
+ }
237
+ return new WsNoiseChannel(ws, new Cipher(initiator.tx), new Cipher(initiator.rx), fingerprint(gotHost));
238
+ }
239
+ }
240
+ export async function listenForJoinWs(branchKeyPair, port, timeoutMs = 120_000) {
241
+ // Join-mode WS server: raw Noise_IK handshake without registry lookup.
242
+ // Analogous to listenForJoin() in noise-ik-transport.ts.
243
+ const httpServer = createServer((_req, res) => { res.statusCode = 404; res.end(); });
244
+ const wss = new WebSocketServer({ server: httpServer, path: WS_PATH });
245
+ const branchStatic = {
246
+ publicKey: Buffer.from(branchKeyPair.encryption.publicKey),
247
+ secretKey: Buffer.from(branchKeyPair.encryption.privateKey),
248
+ };
249
+ await new Promise((resolve, reject) => {
250
+ httpServer.once("error", reject);
251
+ httpServer.listen(port, "0.0.0.0", () => resolve());
252
+ });
253
+ // Wrap as a TransportServer (for close(); onConnection not used in join mode)
254
+ const serverWrapper = {
255
+ onConnection: () => { },
256
+ close: () => new Promise((resolve, reject) => {
257
+ wss.close();
258
+ httpServer.close((err) => (err ? reject(err) : resolve()));
259
+ }),
260
+ };
261
+ const joined = new Promise((resolve, reject) => {
262
+ const timeout = timeoutMs > 0
263
+ ? setTimeout(() => reject(new Error("JOIN_COMPLETE timeout")), timeoutMs)
264
+ : null;
265
+ wss.once("connection", async (ws) => {
266
+ try {
267
+ const responder = new Noise("IK", false, branchStatic);
268
+ responder.initialise(PROLOGUE);
269
+ const msg1 = await waitForMessage(ws, HANDSHAKE_TIMEOUT_MS);
270
+ responder.recv(msg1);
271
+ const msg2 = Buffer.from(responder.send());
272
+ ws.send(msg2);
273
+ const channel = new WsNoiseChannel(ws, new Cipher(responder.tx), new Cipher(responder.rx), fingerprint(Buffer.from(responder.rs)));
274
+ const handler = (msg) => {
275
+ if (msg.type !== MSG_JOIN_COMPLETE)
276
+ return;
277
+ const parsed = JoinCompleteBodySchema.safeParse(msg.body);
278
+ if (!parsed.success)
279
+ return;
280
+ const hostPub = new Uint8Array(Buffer.from(parsed.data.hostPubkey, "base64url"));
281
+ const fp = fingerprint(hostPub);
282
+ const claimed = parsed.data.hostFingerprint.replace(/^sha256:/, "");
283
+ if (fp !== claimed) {
284
+ channel.offMessage(handler);
285
+ reject(new Error("Host fingerprint mismatch in JOIN_COMPLETE"));
286
+ return;
287
+ }
288
+ if (timeout)
289
+ clearTimeout(timeout);
290
+ channel.offMessage(handler);
291
+ resolve({ channel, hostPubkey: hostPub, hostFingerprint: fp, hostId: parsed.data.hostId });
292
+ };
293
+ channel.onMessage(handler);
294
+ }
295
+ catch (e) {
296
+ ws.close(1011, "handshake failed");
297
+ reject(e);
298
+ }
299
+ });
300
+ });
301
+ const result = await joined;
302
+ return { ...result, server: serverWrapper };
303
+ }
304
+ export async function listenForHostWs(branchKeyPair, expectedHostPubkey, port, onMessage) {
305
+ // Branch-side persistent listener: raw Noise_IK handshake without registry lookup.
306
+ // After handshake, verify peer is the pinned host key.
307
+ const httpServer = createServer((req, res) => {
308
+ if (req.method === "POST" && req.url === "/github/webhook") {
309
+ handleGithubWebhook(req, res).catch((e) => {
310
+ res.statusCode = 500;
311
+ res.end("Internal error");
312
+ console.error("[webhook] error:", e.message);
313
+ });
314
+ return;
315
+ }
316
+ res.statusCode = 404;
317
+ res.end();
318
+ });
319
+ const wss = new WebSocketServer({ server: httpServer, path: WS_PATH });
320
+ const branchStatic = {
321
+ publicKey: Buffer.from(branchKeyPair.encryption.publicKey),
322
+ secretKey: Buffer.from(branchKeyPair.encryption.privateKey),
323
+ };
324
+ wss.on("connection", async (ws) => {
325
+ try {
326
+ const responder = new Noise("IK", false, branchStatic);
327
+ responder.initialise(PROLOGUE);
328
+ const msg1 = await waitForMessage(ws, HANDSHAKE_TIMEOUT_MS);
329
+ responder.recv(msg1); // payload = branchId sent by host (ignored here)
330
+ const peerKey = Buffer.from(responder.rs);
331
+ if (!peerKey.equals(Buffer.from(expectedHostPubkey))) {
332
+ ws.close(1008, "rejected");
333
+ return;
334
+ }
335
+ const msg2 = Buffer.from(responder.send());
336
+ ws.send(msg2);
337
+ const channel = new WsNoiseChannel(ws, new Cipher(responder.tx), new Cipher(responder.rx), fingerprint(Buffer.from(responder.rs)));
338
+ channel.onMessage((msg) => onMessage(msg, channel));
339
+ }
340
+ catch {
341
+ ws.close(1011, "handshake failed");
342
+ }
343
+ });
344
+ await new Promise((resolve, reject) => {
345
+ httpServer.once("error", reject);
346
+ httpServer.listen(port, "0.0.0.0", () => resolve());
347
+ });
348
+ return {
349
+ onConnection: () => { },
350
+ close: () => new Promise((resolve, reject) => {
351
+ wss.close();
352
+ httpServer.close((err) => (err ? reject(err) : resolve()));
353
+ }),
354
+ };
355
+ }
356
+ //# sourceMappingURL=ws-noise-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws-noise-transport.js","sourceRoot":"","sources":["../../../src/utils/ws-noise-transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA6B,MAAM,WAAW,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAChD,OAAO,KAAK,MAAM,0BAA0B,CAAC;AAC7C,OAAO,MAAM,MAAM,2BAA2B,CAAC;AAQ/C,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,WAAW,EAAoB,YAAY,EAAmB,MAAM,eAAe,CAAC;AAC7F,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACvC,MAAM,oBAAoB,GAAG,MAAM,CAAC;AACpC,MAAM,iBAAiB,GAAG,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;AAC3C,MAAM,OAAO,GAAG,WAAW,CAAC;AAE5B,SAAS,QAAQ,CAAC,IAAuB;IACvC,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/E,IAAI,IAAI,YAAY,WAAW;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1D,OAAO,MAAM,CAAC,IAAI,CAAC,IAAW,CAAC,CAAC;AAClC,CAAC;AAED,SAAS,cAAc,CAAC,EAAa,EAAE,SAAiB;IACtD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACzB,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACzB,CAAC,CAAC;QAEF,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,IAAI,KAAK,CAAC,mCAAmC,SAAS,IAAI,CAAC,CAAC,CAAC;QACtE,CAAC,EAAE,SAAS,CAAC,CAAC;QAEd,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC,CAAC;QAChE,CAAC,CAAC;QACF,MAAM,KAAK,GAAG,CAAC,GAAU,EAAE,EAAE;YAC3B,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC;QAEF,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;YAC1B,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC1B,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,cAAc;IAKC;IACA;IACA;IACA;IAPX,KAAK,GAAG,IAAI,CAAC;IACb,OAAO,GAAG,IAAI,YAAY,EAAE,CAAC;IAErC,YACmB,EAAa,EACb,UAAkB,EAClB,UAAkB,EAClB,MAAc;QAHd,OAAE,GAAF,EAAE,CAAW;QACb,eAAU,GAAV,UAAU,CAAQ;QAClB,eAAU,GAAV,UAAU,CAAQ;QAClB,WAAM,GAAN,MAAM,CAAQ;QAE/B,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YAClB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACrB,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;gBAC3B,IAAI,GAAG,CAAC,MAAM,GAAG,iBAAiB,EAAE,CAAC;oBACnC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;oBAC3B,OAAO;gBACT,CAAC;gBACD,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC5D,MAAM,GAAG,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;gBACzC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YACpC,CAAC;YAAC,MAAM,CAAC;gBACP,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,GAAe;QACxB,MAAM,IAAI,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAC7D,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC;IACL,CAAC;IAED,SAAS,CAAC,OAAkC;QAC1C,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC;IAED,UAAU,CAAC,OAAkC;QAC3C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;QAChB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,CAAC;IAC7D,CAAC;IAED,eAAe;QACb,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CACF;AAED,MAAM,aAAa;IAGY;IAAyC;IAF9D,MAAM,GAAiD,IAAI,CAAC;IAEpE,YAA6B,UAAsB,EAAmB,GAAoB;QAA7D,eAAU,GAAV,UAAU,CAAY;QAAmB,QAAG,GAAH,GAAG,CAAiB;IAAG,CAAC;IAE9F,IAAI;QACF,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;QACvC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,OAAO,CAAC,CAAC;QAChD,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,YAAY,CAAC,OAA4C;QACvD,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;IACxB,CAAC;IAED,QAAQ,CAAC,OAAyB;QAChC,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACtE,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAED,MAAM,OAAO,gBAAgB;IAER;IACA;IAFnB,YACmB,YAAwB,EACxB,WAAwB;QADxB,iBAAY,GAAZ,YAAY,CAAY;QACxB,gBAAW,GAAX,WAAW,CAAa;IACxC,CAAC;IAEJ,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,YAAY,CAAC;QACnD,MAAM,UAAU,GAAG,YAAY,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;YAC5C,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;YACrB,GAAG,CAAC,GAAG,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACvE,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QAEnD,MAAM,UAAU,GAAG;YACjB,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;YACjD,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;SACnD,CAAC;QAEF,GAAG,CAAC,EAAE,CAAC,YAAY,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YAChC,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;gBACrD,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;gBAE/B,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,EAAE,EAAE,oBAAoB,CAAC,CAAC;gBAC5D,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;gBAClD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;gBAE3C,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;gBACrC,MAAM,QAAQ,GAAG,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;gBAChF,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;gBACtC,IAAI,CAAC,QAAQ,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;oBACvC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;oBAC3B,OAAO;gBACT,CAAC;gBAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC3C,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAEd,MAAM,OAAO,GAAG,IAAI,cAAc,CAChC,EAAE,EACF,IAAI,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,EACxB,IAAI,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,EACxB,WAAW,CAAC,GAAG,CAAC,CACjB,CAAC;gBACF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACP,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YACpD,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAoB;QAChC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,KAAK,WAAW,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC;QACpG,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;QACtC,MAAM,GAAG,GAAG,GAAG,MAAM,MAAM,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,GAAG,OAAO,EAAE,CAAC;QAClE,MAAM,EAAE,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC;QAE9B,uEAAuE;QACvE,IAAI,UAAU,GAAG,KAAK,CAAC;QACvB,IAAI,gBAAgB,GAAkC,IAAI,CAAC;QAE3D,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YACjC,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC3B,CAAC,CAAC,CAAC;QAEH,oEAAoE;QACpE,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YAClB,UAAU,GAAG,IAAI,CAAC;YAClB,gBAAgB,EAAE,CAAC,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC,CAAC;QACjE,CAAC,CAAC,CAAC;QAEH,MAAM,WAAW,GAAG;YAClB,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,SAAS,CAAC;YAC9D,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,UAAU,CAAC;SAChE,CAAC;QAEF,MAAM,SAAS,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;QACrD,SAAS,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;QAElE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QACvE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,+BAA+B;QAC/B,IAAI,IAAY,CAAC;QACjB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACnD,IAAI,UAAU,EAAE,CAAC;oBAAC,MAAM,CAAC,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC,CAAC;oBAAC,OAAO;gBAAC,CAAC;gBAC/E,gBAAgB,GAAG,MAAM,CAAC;gBAE1B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;oBAC5B,MAAM,CAAC,IAAI,KAAK,CAAC,2BAA2B,oBAAoB,IAAI,CAAC,CAAC,CAAC;gBACzE,CAAC,EAAE,oBAAoB,CAAC,CAAC;gBAEzB,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;oBAC1B,YAAY,CAAC,KAAK,CAAC,CAAC;oBACpB,gBAAgB,GAAG,IAAI,CAAC;oBACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC1B,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YAC3B,MAAM,CAAC,CAAC;QACV,CAAC;QACD,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAErB,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAC1C,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QACvD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;YAClC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QAED,OAAO,IAAI,cAAc,CACvB,EAAE,EACF,IAAI,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,EACxB,IAAI,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,EACxB,WAAW,CAAC,OAAO,CAAC,CACrB,CAAC;IACJ,CAAC;CACF;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,aAAyB,EACzB,IAAY,EACZ,YAAoB,OAAO;IAQ3B,uEAAuE;IACvE,yDAAyD;IACzD,MAAM,UAAU,GAAG,YAAY,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,GAAG,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,MAAM,GAAG,GAAG,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAEvE,MAAM,YAAY,GAAG;QACnB,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,SAAS,CAAC;QAC1D,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,UAAU,CAAC;KAC5D,CAAC;IAEF,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACjC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,8EAA8E;IAC9E,MAAM,aAAa,GAAoB;QACrC,YAAY,EAAE,GAAG,EAAE,GAAE,CAAC;QACtB,KAAK,EAAE,GAAG,EAAE,CACV,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACpC,GAAG,CAAC,KAAK,EAAE,CAAC;YACZ,UAAU,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC7D,CAAC,CAAC;KACL,CAAC;IAEF,MAAM,MAAM,GAAG,IAAI,OAAO,CAKvB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrB,MAAM,OAAO,GACX,SAAS,GAAG,CAAC;YACX,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC,EAAE,SAAS,CAAC;YACzE,CAAC,CAAC,IAAI,CAAC;QAEX,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YAClC,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;gBACvD,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;gBAE/B,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,EAAE,EAAE,oBAAoB,CAAC,CAAC;gBAC5D,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAErB,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC3C,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAEd,MAAM,OAAO,GAAG,IAAI,cAAc,CAChC,EAAE,EACF,IAAI,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,EACxB,IAAI,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,EACxB,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CACvC,CAAC;gBAEF,MAAM,OAAO,GAAG,CAAC,GAAe,EAAE,EAAE;oBAClC,IAAI,GAAG,CAAC,IAAI,KAAK,iBAAiB;wBAAE,OAAO;oBAC3C,MAAM,MAAM,GAAG,sBAAsB,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBAC1D,IAAI,CAAC,MAAM,CAAC,OAAO;wBAAE,OAAO;oBAE5B,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC;oBACjF,MAAM,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;oBAChC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;oBACpE,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;wBACnB,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;wBAC5B,MAAM,CAAC,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC,CAAC;wBAChE,OAAO;oBACT,CAAC;oBACD,IAAI,OAAO;wBAAE,YAAY,CAAC,OAAO,CAAC,CAAC;oBACnC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;oBAC5B,OAAO,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;gBAC7F,CAAC,CAAC;gBAEF,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAC7B,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;gBACnC,MAAM,CAAC,CAAC,CAAC,CAAC;YACZ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC;IAC5B,OAAO,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;AAC9C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,aAAyB,EACzB,kBAA8B,EAC9B,IAAY,EACZ,SAA+E;IAE/E,mFAAmF;IACnF,uDAAuD;IACvD,MAAM,UAAU,GAAG,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC3C,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,GAAG,KAAK,iBAAiB,EAAE,CAAC;YAC3D,mBAAmB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAQ,EAAE,EAAE;gBAC/C,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;gBACrB,GAAG,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;gBAC1B,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;YAC/C,CAAC,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;QACrB,GAAG,CAAC,GAAG,EAAE,CAAC;IACZ,CAAC,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAEvE,MAAM,YAAY,GAAG;QACnB,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,SAAS,CAAC;QAC1D,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,UAAU,CAAC;KAC5D,CAAC;IAEF,GAAG,CAAC,EAAE,CAAC,YAAY,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;QAChC,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;YACvD,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAE/B,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,EAAE,EAAE,oBAAoB,CAAC,CAAC;YAC5D,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,iDAAiD;YAEvE,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YAC1C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC;gBACrD,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBAC3B,OAAO;YACT,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;YAC3C,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEd,MAAM,OAAO,GAAG,IAAI,cAAc,CAChC,EAAE,EACF,IAAI,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,EACxB,IAAI,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,EACxB,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CACvC,CAAC;YACF,OAAO,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACP,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;QACrC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACjC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,YAAY,EAAE,GAAG,EAAE,GAAE,CAAC;QACtB,KAAK,EAAE,GAAG,EAAE,CACV,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACpC,GAAG,CAAC,KAAK,EAAE,CAAC;YACZ,UAAU,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC7D,CAAC,CAAC;KACL,CAAC;AACJ,CAAC"}
@@ -0,0 +1,17 @@
1
+ [meta]
2
+ name = "tps-hire"
3
+ version = "1.0.0"
4
+ description = "tps hire — agent workspace scaffolding. Least privilege: writes only to target workspace."
5
+
6
+ # CWD = the target workspace directory passed via --workdir
7
+ [workdir]
8
+ access = "readwrite"
9
+
10
+ [filesystem]
11
+ # No openclaw.json access — hire doesn't need to read existing config (S1.4)
12
+ # No $HOME/.tps/templates — templates are bundled in the npm package
13
+ # No $TMPDIR — no build artifacts in Phase 1.5
14
+ # Nothing. Workdir only.
15
+
16
+ [network]
17
+ block = true # No network during hire. Templates are bundled.
@@ -0,0 +1,18 @@
1
+ [meta]
2
+ name = "tps-review-deep"
3
+ version = "1.0.0"
4
+ description = "tps review --deep — LLM-assisted review. Same filesystem access as local, adds network."
5
+
6
+ [workdir]
7
+ access = "none"
8
+
9
+ [filesystem]
10
+ read_file = [
11
+ "$HOME/.openclaw/openclaw.json"
12
+ ]
13
+ read = [
14
+ "$WORKDIR" # Named agent workspace only. No siblings.
15
+ ]
16
+
17
+ [network]
18
+ block = false # LLM API access required. Allowlist TBD when nono network allowlist support ships.
@@ -0,0 +1,21 @@
1
+ [meta]
2
+ name = "tps-review-local"
3
+ version = "1.0.0"
4
+ description = "tps review (default) — reads named agent workspace, no LLM, no network."
5
+
6
+ # workdir = the specific named agent workspace (set via --workdir by tps CLI)
7
+ # This naturally enforces S3.2: sibling workspaces are inaccessible because
8
+ # only $WORKDIR is in the read allowlist.
9
+ [workdir]
10
+ access = "none"
11
+
12
+ [filesystem]
13
+ read_file = [
14
+ "$HOME/.openclaw/openclaw.json" # Agent metadata lookup
15
+ ]
16
+ read = [
17
+ "$WORKDIR" # Named agent workspace only. No siblings.
18
+ ]
19
+
20
+ [network]
21
+ block = true
@@ -0,0 +1,16 @@
1
+ [meta]
2
+ name = "tps-roster"
3
+ version = "1.0.0"
4
+ description = "tps roster — read-only org chart. Single file, no writes, no network."
5
+
6
+ [workdir]
7
+ access = "none"
8
+
9
+ [filesystem]
10
+ # read_file = single file access (non-recursive) — more precise than read = [dir]
11
+ read_file = [
12
+ "$HOME/.openclaw/openclaw.json"
13
+ ]
14
+
15
+ [network]
16
+ block = true
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@tpsdev-ai/cli",
3
+ "version": "0.1.0",
4
+ "description": "TPS Report CLI — because every agent needs the proper paperwork.",
5
+ "type": "module",
6
+ "bin": {
7
+ "tps": "./dist/bin/tps.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "dev": "tsc --watch",
12
+ "start": "node dist/bin/tps.js",
13
+ "tps": "node dist/bin/tps.js",
14
+ "lint": "biome lint ./src ./bin",
15
+ "lint:ci": "biome lint ./src ./bin --max-diagnostics=200",
16
+ "pretest": "tsc",
17
+ "test": "bun test",
18
+ "test:unit": "bun test --filter unit",
19
+ "test:integration": "docker compose run --rm test"
20
+ },
21
+ "keywords": [
22
+ "cli",
23
+ "agents",
24
+ "openclaw",
25
+ "tps"
26
+ ],
27
+ "license": "Apache-2.0",
28
+ "dependencies": {
29
+ "@noble/curves": "^2.0.1",
30
+ "@noble/ed25519": "^3.0.0",
31
+ "@noble/hashes": "^2.0.1",
32
+ "@types/ws": "^8.18.1",
33
+ "handlebars": "^4.7.8",
34
+ "ink": "^5.2.0",
35
+ "js-yaml": "^4.1.0",
36
+ "meow": "^13.2.0",
37
+ "msgpackr": "^1.11.8",
38
+ "noise-handshake": "^4.2.0",
39
+ "react": "^18.3.1",
40
+ "ws": "^8.19.0",
41
+ "zod": "^3.24.0"
42
+ },
43
+ "devDependencies": {
44
+ "@biomejs/biome": "^2.4.4",
45
+ "@types/js-yaml": "^4.0.9",
46
+ "@types/node": "^22.0.0",
47
+ "@types/react": "^18.3.0",
48
+ "typescript": "^5.7.0"
49
+ },
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "git+https://github.com/tpsdev-ai/cli.git"
53
+ },
54
+ "homepage": "https://github.com/tpsdev-ai/cli#readme",
55
+ "bugs": {
56
+ "url": "https://github.com/tpsdev-ai/cli/issues"
57
+ },
58
+ "files": [
59
+ "dist",
60
+ "nono-profiles",
61
+ "personas",
62
+ "reports"
63
+ ],
64
+ "author": "tpsdev-ai",
65
+ "publishConfig": {
66
+ "access": "public"
67
+ }
68
+ }
@@ -0,0 +1,58 @@
1
+ version: "1"
2
+
3
+ name: Designer
4
+ description: >
5
+ UI/UX design, user research, visual design, and design systems.
6
+ Advocates for the user experience and ensures the product looks
7
+ and feels right.
8
+
9
+ identity:
10
+ default_name: Pixel
11
+ emoji: "🎨"
12
+ personality: >
13
+ Creative, user-focused, detail-obsessed about visual consistency.
14
+ Balances aesthetics with usability. Pushes back when something
15
+ feels wrong even if it's technically correct.
16
+ communication_style: >
17
+ Visual thinker — prefers showing over telling. Uses references
18
+ and examples. Explains design decisions in terms of user impact.
19
+
20
+ flair:
21
+ - ui-design
22
+ - ux-research
23
+ - design-systems
24
+ - prototyping
25
+ - accessibility
26
+
27
+ model:
28
+ default: reasoning
29
+
30
+ tools:
31
+ required:
32
+ - file-ops
33
+ - web-search
34
+ - browser
35
+ optional:
36
+ - git
37
+
38
+ communication:
39
+ channels: [team-chat, direct]
40
+ handoff_targets: [developer]
41
+
42
+ boundaries:
43
+ can_commit: false
44
+ can_send_external: false
45
+ can_spend: false
46
+
47
+ memory:
48
+ private: true
49
+ shared_read:
50
+ - project-state
51
+ - decisions
52
+ shared_write:
53
+ - design-specs
54
+
55
+ openclaw:
56
+ model: "anthropic/claude-sonnet-4-20250514"
57
+ thinking: "off"
58
+ channel: "discord"
@@ -0,0 +1,59 @@
1
+ version: "1"
2
+
3
+ name: Developer
4
+ description: >
5
+ Software development, code review, architecture decisions,
6
+ debugging, and technical implementation. The hands-on builder
7
+ who turns ideas into working software.
8
+
9
+ identity:
10
+ default_name: Dev
11
+ emoji: "💻"
12
+ personality: >
13
+ Pragmatic, detail-oriented, opinionated about code quality.
14
+ Prefers working solutions over theoretical perfection. Knows
15
+ when to refactor and when to ship.
16
+ communication_style: >
17
+ Technical but accessible. Uses code examples when helpful.
18
+ Direct about tradeoffs and complexity estimates.
19
+
20
+ flair:
21
+ - code-review
22
+ - architecture
23
+ - debugging
24
+ - implementation
25
+ - testing
26
+
27
+ model:
28
+ default: reasoning
29
+
30
+ tools:
31
+ required:
32
+ - file-ops
33
+ - git
34
+ - exec
35
+ optional:
36
+ - web-search
37
+ - browser
38
+
39
+ communication:
40
+ channels: [team-chat, direct]
41
+ handoff_targets: []
42
+
43
+ boundaries:
44
+ can_commit: true
45
+ can_send_external: false
46
+ can_spend: false
47
+
48
+ memory:
49
+ private: true
50
+ shared_read:
51
+ - project-state
52
+ - decisions
53
+ shared_write:
54
+ - project-state
55
+
56
+ openclaw:
57
+ model: "anthropic/claude-sonnet-4-20250514"
58
+ thinking: "off"
59
+ channel: "discord"