cngkit 1.1.21 → 1.1.23
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 +198 -4
- package/README.md +22 -12
- package/dist/{chunk-NGEWD4BW.js → chunk-25Q463MH.js} +1 -2
- package/dist/{chunk-SMTQ3W3F.js → chunk-3BATDTKU.js} +131 -112
- package/dist/chunk-3BATDTKU.js.map +1 -0
- package/dist/{chunk-DIJEVOVN.js → chunk-67FUBMNB.js} +71 -240
- package/dist/chunk-67FUBMNB.js.map +1 -0
- package/dist/chunk-AS7FIJWP.js +88 -0
- package/dist/chunk-AS7FIJWP.js.map +1 -0
- package/dist/chunk-BRFWVQI4.js +18 -0
- package/dist/chunk-BRFWVQI4.js.map +1 -0
- package/dist/{chunk-CVF2ODLP.js → chunk-BXS4IKUA.js} +300 -143
- package/dist/chunk-BXS4IKUA.js.map +1 -0
- package/dist/{chunk-YJXAH7D5.js → chunk-GYRLVNJX.js} +2 -2
- package/dist/chunk-GYRLVNJX.js.map +1 -0
- package/dist/{chunk-SKK2XLRZ.js → chunk-JNHW72SU.js} +21 -15
- package/dist/chunk-JNHW72SU.js.map +1 -0
- package/dist/chunk-U725ZHCI.js +67 -0
- package/dist/chunk-U725ZHCI.js.map +1 -0
- package/dist/chunk-VMTXY4KQ.js +111 -0
- package/dist/chunk-VMTXY4KQ.js.map +1 -0
- package/dist/chunk-WIEYHKQA.js +268 -0
- package/dist/chunk-WIEYHKQA.js.map +1 -0
- package/dist/chunk-YALWTRIP.js +102 -0
- package/dist/chunk-YALWTRIP.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/coderoom/index.js +4 -4
- package/dist/commands/coderoom/join.js +5 -5
- package/dist/commands/coderoom/share.js +8 -11
- package/dist/commands/coderoom/share.js.map +1 -1
- package/dist/commands/hookify/index.js +4 -4
- package/dist/commands/hookify/ingest.js +4 -4
- package/dist/commands/hooks/index.js +4 -4
- package/dist/commands/hooks/install.js +4 -4
- package/dist/commands/hooks/uninstall.js +4 -4
- package/dist/commands/index.js +3 -3
- package/dist/commands/knowledges/audiences.js +26 -8
- package/dist/commands/knowledges/audiences.js.map +1 -1
- package/dist/commands/knowledges/cat.js +26 -7
- package/dist/commands/knowledges/cat.js.map +1 -1
- package/dist/commands/knowledges/files.js +39 -8
- package/dist/commands/knowledges/files.js.map +1 -1
- package/dist/commands/knowledges/find.js +48 -8
- package/dist/commands/knowledges/find.js.map +1 -1
- package/dist/commands/knowledges/glob.js +41 -8
- package/dist/commands/knowledges/glob.js.map +1 -1
- package/dist/commands/knowledges/grep.js +73 -8
- package/dist/commands/knowledges/grep.js.map +1 -1
- package/dist/commands/knowledges/head.js +31 -8
- package/dist/commands/knowledges/head.js.map +1 -1
- package/dist/commands/knowledges/index.js +4 -4
- package/dist/commands/knowledges/list.js +39 -8
- package/dist/commands/knowledges/list.js.map +1 -1
- package/dist/commands/knowledges/ls.js +47 -8
- package/dist/commands/knowledges/ls.js.map +1 -1
- package/dist/commands/knowledges/read.js +46 -8
- package/dist/commands/knowledges/read.js.map +1 -1
- package/dist/commands/knowledges/realpath.js +23 -8
- package/dist/commands/knowledges/realpath.js.map +1 -1
- package/dist/commands/knowledges/search.js +34 -8
- package/dist/commands/knowledges/search.js.map +1 -1
- package/dist/commands/knowledges/stat.js +32 -8
- package/dist/commands/knowledges/stat.js.map +1 -1
- package/dist/commands/knowledges/status.js +26 -8
- package/dist/commands/knowledges/status.js.map +1 -1
- package/dist/commands/knowledges/tail.js +30 -8
- package/dist/commands/knowledges/tail.js.map +1 -1
- package/dist/commands/knowledges/tree.js +38 -8
- package/dist/commands/knowledges/tree.js.map +1 -1
- package/dist/commands/login.js +3 -3
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/scrub.js +3 -3
- package/dist/commands/scrub.js.map +1 -1
- package/dist/commands/transcripts.js +137 -119
- package/dist/commands/transcripts.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-52PGDSFU.js +0 -42
- package/dist/chunk-52PGDSFU.js.map +0 -1
- package/dist/chunk-5WTRGYAO.js +0 -658
- package/dist/chunk-5WTRGYAO.js.map +0 -1
- package/dist/chunk-CVF2ODLP.js.map +0 -1
- package/dist/chunk-DIJEVOVN.js.map +0 -1
- package/dist/chunk-SKK2XLRZ.js.map +0 -1
- package/dist/chunk-SMTQ3W3F.js.map +0 -1
- package/dist/chunk-YJXAH7D5.js.map +0 -1
- /package/dist/{chunk-NGEWD4BW.js.map → chunk-25Q463MH.js.map} +0 -0
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
+
createCngApiClient,
|
|
2
3
|
readBackendHealth
|
|
3
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-GYRLVNJX.js";
|
|
4
5
|
import {
|
|
5
|
-
createPeerId,
|
|
6
|
-
createRoomCode,
|
|
7
6
|
resolveApiBaseUrl
|
|
8
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-67FUBMNB.js";
|
|
9
8
|
|
|
10
9
|
// src/features/coderoom/run-coderoom-command.ts
|
|
11
|
-
import
|
|
10
|
+
import process3 from "process";
|
|
12
11
|
|
|
13
12
|
// src/features/coderoom/sync/client.ts
|
|
14
|
-
import
|
|
15
|
-
import fs2 from "fs";
|
|
16
|
-
import chokidar from "chokidar";
|
|
17
|
-
import WebSocket from "ws";
|
|
13
|
+
import WebSocket2 from "ws";
|
|
18
14
|
|
|
19
15
|
// src/features/coderoom/sync/files.ts
|
|
20
16
|
import fs from "fs/promises";
|
|
@@ -98,10 +94,10 @@ function createSuppressionTracker(windowMs = 1500) {
|
|
|
98
94
|
}
|
|
99
95
|
};
|
|
100
96
|
}
|
|
101
|
-
async function* collectSnapshotMessages(context
|
|
102
|
-
yield* collectDirectorySnapshot(context, context.rootDir
|
|
97
|
+
async function* collectSnapshotMessages(context) {
|
|
98
|
+
yield* collectDirectorySnapshot(context, context.rootDir);
|
|
103
99
|
}
|
|
104
|
-
async function* collectDirectorySnapshot(context, directoryPath
|
|
100
|
+
async function* collectDirectorySnapshot(context, directoryPath) {
|
|
105
101
|
const entries = await fs.opendir(directoryPath);
|
|
106
102
|
for await (const entry of entries) {
|
|
107
103
|
const absolutePath = path2.join(directoryPath, entry.name);
|
|
@@ -110,7 +106,7 @@ async function* collectDirectorySnapshot(context, directoryPath, peerId) {
|
|
|
110
106
|
continue;
|
|
111
107
|
}
|
|
112
108
|
if (entry.isDirectory()) {
|
|
113
|
-
yield* collectDirectorySnapshot(context, absolutePath
|
|
109
|
+
yield* collectDirectorySnapshot(context, absolutePath);
|
|
114
110
|
continue;
|
|
115
111
|
}
|
|
116
112
|
if (!entry.isFile()) {
|
|
@@ -119,15 +115,13 @@ async function* collectDirectorySnapshot(context, directoryPath, peerId) {
|
|
|
119
115
|
const [content, stat] = await Promise.all([fs.readFile(absolutePath), fs.stat(absolutePath)]);
|
|
120
116
|
yield {
|
|
121
117
|
type: "file",
|
|
122
|
-
peerId,
|
|
123
118
|
path: relativePath,
|
|
124
119
|
contentBase64: content.toString("base64"),
|
|
125
|
-
mtimeMs: stat.mtimeMs
|
|
126
|
-
sentAt: Date.now()
|
|
120
|
+
mtimeMs: stat.mtimeMs
|
|
127
121
|
};
|
|
128
122
|
}
|
|
129
123
|
}
|
|
130
|
-
async function buildFileMessage(context,
|
|
124
|
+
async function buildFileMessage(context, relativePath) {
|
|
131
125
|
if (!await shouldSyncRelativePath(context, relativePath)) {
|
|
132
126
|
return void 0;
|
|
133
127
|
}
|
|
@@ -142,11 +136,9 @@ async function buildFileMessage(context, peerId, relativePath) {
|
|
|
142
136
|
const content = await fs.readFile(absolutePath);
|
|
143
137
|
return {
|
|
144
138
|
type: "file",
|
|
145
|
-
peerId,
|
|
146
139
|
path: relativePath,
|
|
147
140
|
contentBase64: content.toString("base64"),
|
|
148
|
-
mtimeMs: stat.mtimeMs
|
|
149
|
-
sentAt: Date.now()
|
|
141
|
+
mtimeMs: stat.mtimeMs
|
|
150
142
|
};
|
|
151
143
|
}
|
|
152
144
|
async function applyRemoteMessage(context, message, suppressionTracker) {
|
|
@@ -163,102 +155,195 @@ async function applyRemoteMessage(context, message, suppressionTracker) {
|
|
|
163
155
|
await fs.writeFile(absolutePath, Buffer.from(message.contentBase64, "base64"));
|
|
164
156
|
}
|
|
165
157
|
|
|
158
|
+
// src/features/coderoom/sync/local-events.ts
|
|
159
|
+
import fs2 from "fs";
|
|
160
|
+
import chokidar from "chokidar";
|
|
161
|
+
|
|
162
|
+
// src/features/coderoom/sync/session.ts
|
|
163
|
+
import os from "os";
|
|
164
|
+
import process from "process";
|
|
165
|
+
import WebSocket from "ws";
|
|
166
|
+
|
|
166
167
|
// src/features/coderoom/sync/protocol.ts
|
|
167
168
|
import { z } from "zod";
|
|
168
|
-
var
|
|
169
|
-
peerId: z.string().min(1),
|
|
170
|
-
sentAt: z.number().finite()
|
|
171
|
-
});
|
|
172
|
-
var SyncHelloMessageSchema = SyncBaseMessageSchema.extend({
|
|
173
|
-
type: z.literal("hello"),
|
|
174
|
-
role: z.union([z.literal("share"), z.literal("join")])
|
|
175
|
-
});
|
|
176
|
-
var SyncFileMessageSchema = SyncBaseMessageSchema.extend({
|
|
169
|
+
var ClientFileMessageSchema = z.object({
|
|
177
170
|
type: z.literal("file"),
|
|
178
171
|
path: z.string().min(1),
|
|
179
172
|
contentBase64: z.string(),
|
|
180
173
|
mtimeMs: z.number().finite()
|
|
181
174
|
});
|
|
182
|
-
var
|
|
175
|
+
var ClientDeleteMessageSchema = z.object({
|
|
183
176
|
type: z.literal("delete"),
|
|
184
177
|
path: z.string().min(1),
|
|
185
178
|
mtimeMs: z.number().finite()
|
|
186
179
|
});
|
|
187
|
-
var
|
|
188
|
-
type: z.literal("
|
|
180
|
+
var ClientJoinApprovalMessageSchema = z.object({
|
|
181
|
+
type: z.literal("join-approval"),
|
|
182
|
+
joinRequestId: z.string().min(1),
|
|
183
|
+
approved: z.boolean()
|
|
184
|
+
});
|
|
185
|
+
var ClientMessageSchema = z.discriminatedUnion("type", [
|
|
186
|
+
ClientFileMessageSchema,
|
|
187
|
+
ClientDeleteMessageSchema,
|
|
188
|
+
ClientJoinApprovalMessageSchema
|
|
189
|
+
]);
|
|
190
|
+
var ServerConnectedMessageSchema = z.object({
|
|
191
|
+
type: z.literal("connected"),
|
|
192
|
+
roomCode: z.string(),
|
|
193
|
+
participantId: z.string(),
|
|
194
|
+
role: z.union([z.literal("host"), z.literal("guest")]),
|
|
195
|
+
status: z.union([z.literal("approved"), z.literal("pending"), z.literal("denied")])
|
|
196
|
+
});
|
|
197
|
+
var ServerJoinPendingMessageSchema = z.object({
|
|
198
|
+
type: z.literal("join-pending"),
|
|
199
|
+
participantId: z.string(),
|
|
200
|
+
joinRequestId: z.string(),
|
|
201
|
+
roomCode: z.string()
|
|
202
|
+
});
|
|
203
|
+
var ServerJoinRequestMessageSchema = z.object({
|
|
204
|
+
type: z.literal("join-request"),
|
|
205
|
+
joinRequestId: z.string(),
|
|
206
|
+
participantId: z.string(),
|
|
207
|
+
displayName: z.string(),
|
|
208
|
+
requestedAt: z.number().finite()
|
|
209
|
+
});
|
|
210
|
+
var ServerJoinApprovedMessageSchema = z.object({
|
|
211
|
+
type: z.literal("join-approved"),
|
|
212
|
+
participantId: z.string()
|
|
213
|
+
});
|
|
214
|
+
var ServerJoinDeniedMessageSchema = z.object({
|
|
215
|
+
type: z.literal("join-denied"),
|
|
216
|
+
participantId: z.string(),
|
|
217
|
+
reason: z.string()
|
|
218
|
+
});
|
|
219
|
+
var ServerFileMessageSchema = z.object({
|
|
220
|
+
type: z.literal("file"),
|
|
221
|
+
fileId: z.string(),
|
|
222
|
+
path: z.string().min(1),
|
|
223
|
+
sha256: z.string(),
|
|
224
|
+
size: z.number().int().nonnegative(),
|
|
225
|
+
contentBase64: z.string(),
|
|
226
|
+
mtimeMs: z.number().finite(),
|
|
227
|
+
updatedByParticipantId: z.string()
|
|
228
|
+
});
|
|
229
|
+
var ServerDeleteMessageSchema = z.object({
|
|
230
|
+
type: z.literal("delete"),
|
|
231
|
+
fileId: z.string().optional(),
|
|
232
|
+
path: z.string().min(1),
|
|
233
|
+
mtimeMs: z.number().finite(),
|
|
234
|
+
updatedByParticipantId: z.string()
|
|
235
|
+
});
|
|
236
|
+
var ServerFileAckMessageSchema = z.object({
|
|
237
|
+
type: z.literal("file-ack"),
|
|
238
|
+
fileId: z.string(),
|
|
239
|
+
path: z.string().min(1),
|
|
240
|
+
sha256: z.string(),
|
|
241
|
+
size: z.number().int().nonnegative(),
|
|
242
|
+
storage: z.union([z.literal("durable-object"), z.literal("r2")])
|
|
243
|
+
});
|
|
244
|
+
var ServerTreeStartMessageSchema = z.object({
|
|
245
|
+
type: z.literal("tree-start"),
|
|
189
246
|
fileCount: z.number().int().nonnegative()
|
|
190
247
|
});
|
|
191
|
-
var
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
248
|
+
var ServerTreeCompleteMessageSchema = z.object({
|
|
249
|
+
type: z.literal("tree-complete"),
|
|
250
|
+
fileCount: z.number().int().nonnegative()
|
|
251
|
+
});
|
|
252
|
+
var ServerErrorMessageSchema = z.object({
|
|
253
|
+
type: z.literal("error"),
|
|
254
|
+
error: z.string()
|
|
255
|
+
});
|
|
256
|
+
var ServerMessageSchema = z.discriminatedUnion("type", [
|
|
257
|
+
ServerConnectedMessageSchema,
|
|
258
|
+
ServerJoinPendingMessageSchema,
|
|
259
|
+
ServerJoinRequestMessageSchema,
|
|
260
|
+
ServerJoinApprovedMessageSchema,
|
|
261
|
+
ServerJoinDeniedMessageSchema,
|
|
262
|
+
ServerFileMessageSchema,
|
|
263
|
+
ServerDeleteMessageSchema,
|
|
264
|
+
ServerFileAckMessageSchema,
|
|
265
|
+
ServerTreeStartMessageSchema,
|
|
266
|
+
ServerTreeCompleteMessageSchema,
|
|
267
|
+
ServerErrorMessageSchema
|
|
196
268
|
]);
|
|
197
|
-
function
|
|
198
|
-
return JSON.stringify(
|
|
269
|
+
function encodeClientMessage(message) {
|
|
270
|
+
return JSON.stringify(ClientMessageSchema.parse(message));
|
|
199
271
|
}
|
|
200
|
-
function
|
|
272
|
+
function decodeServerMessage(value) {
|
|
201
273
|
if (typeof value !== "string") {
|
|
202
274
|
return void 0;
|
|
203
275
|
}
|
|
204
276
|
try {
|
|
205
|
-
return
|
|
277
|
+
return ServerMessageSchema.parse(JSON.parse(value));
|
|
206
278
|
} catch {
|
|
207
279
|
return void 0;
|
|
208
280
|
}
|
|
209
281
|
}
|
|
210
282
|
|
|
211
|
-
// src/features/coderoom/sync/
|
|
212
|
-
function createSyncWebSocketUrl(
|
|
213
|
-
const url = new URL(apiBaseUrl);
|
|
283
|
+
// src/features/coderoom/sync/session.ts
|
|
284
|
+
function createSyncWebSocketUrl(options) {
|
|
285
|
+
const url = new URL(options.apiBaseUrl);
|
|
214
286
|
url.protocol = url.protocol === "http:" ? "ws:" : "wss:";
|
|
215
|
-
url.pathname = `/api/cng/
|
|
287
|
+
url.pathname = `/api/cng/coderoom/rooms/${encodeURIComponent(options.roomCode)}/ws`;
|
|
216
288
|
url.search = "";
|
|
217
289
|
url.hash = "";
|
|
290
|
+
url.searchParams.set("role", options.role);
|
|
291
|
+
url.searchParams.set("displayName", createDisplayName());
|
|
292
|
+
if (options.creatorToken) {
|
|
293
|
+
url.searchParams.set("creatorToken", options.creatorToken);
|
|
294
|
+
}
|
|
218
295
|
return url.toString();
|
|
219
296
|
}
|
|
220
297
|
function sendMessage(socket, message) {
|
|
221
298
|
if (socket.readyState === WebSocket.OPEN) {
|
|
222
|
-
socket.send(
|
|
299
|
+
socket.send(encodeClientMessage(message));
|
|
223
300
|
}
|
|
224
301
|
}
|
|
225
|
-
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
302
|
+
function createDisplayName() {
|
|
303
|
+
const username = os.userInfo().username || "user";
|
|
304
|
+
return `${username}@${os.hostname()}`;
|
|
305
|
+
}
|
|
306
|
+
async function waitForSessionClose(socket, watcher) {
|
|
307
|
+
await new Promise((resolve, reject) => {
|
|
308
|
+
let settled = false;
|
|
309
|
+
const closeSession = async () => {
|
|
310
|
+
await watcher.close();
|
|
311
|
+
if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
|
|
312
|
+
socket.close();
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
const finish = async () => {
|
|
316
|
+
if (settled) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
settled = true;
|
|
320
|
+
process.off("SIGINT", onSignal);
|
|
321
|
+
process.off("SIGTERM", onSignal);
|
|
322
|
+
await closeSession();
|
|
323
|
+
resolve();
|
|
324
|
+
};
|
|
325
|
+
const onSignal = () => {
|
|
326
|
+
void finish();
|
|
327
|
+
};
|
|
328
|
+
socket.on("error", async (error) => {
|
|
329
|
+
if (settled) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
settled = true;
|
|
333
|
+
process.off("SIGINT", onSignal);
|
|
334
|
+
process.off("SIGTERM", onSignal);
|
|
335
|
+
await closeSession();
|
|
336
|
+
reject(error);
|
|
248
337
|
});
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
socket.on("message", (data) => {
|
|
252
|
-
void handleRemoteMessage({
|
|
253
|
-
data,
|
|
254
|
-
repoContext,
|
|
255
|
-
peerId,
|
|
256
|
-
suppressionTracker,
|
|
257
|
-
output: options.output
|
|
338
|
+
socket.on("close", () => {
|
|
339
|
+
void finish();
|
|
258
340
|
});
|
|
341
|
+
process.on("SIGINT", onSignal);
|
|
342
|
+
process.on("SIGTERM", onSignal);
|
|
259
343
|
});
|
|
260
|
-
await waitForSessionClose(socket, watcher);
|
|
261
344
|
}
|
|
345
|
+
|
|
346
|
+
// src/features/coderoom/sync/local-events.ts
|
|
262
347
|
function createRepoWatcher(context) {
|
|
263
348
|
const watcher = chokidar.watch(context.repoContext.rootDir, {
|
|
264
349
|
ignoreInitial: true,
|
|
@@ -285,30 +370,29 @@ function createRepoWatcher(context) {
|
|
|
285
370
|
void sendLocalDelete(context, absolutePath);
|
|
286
371
|
});
|
|
287
372
|
watcher.on("error", (watcherError) => {
|
|
288
|
-
context.output.warning(
|
|
373
|
+
context.output.warning(
|
|
374
|
+
`watcher error: ${watcherError instanceof Error ? watcherError.message : String(watcherError)}`
|
|
375
|
+
);
|
|
289
376
|
});
|
|
290
377
|
return watcher;
|
|
291
378
|
}
|
|
292
|
-
async function sendInitialSnapshot(socket, repoContext,
|
|
379
|
+
async function sendInitialSnapshot(socket, repoContext, output) {
|
|
293
380
|
let fileCount = 0;
|
|
294
|
-
for await (const message of collectSnapshotMessages(repoContext
|
|
381
|
+
for await (const message of collectSnapshotMessages(repoContext)) {
|
|
295
382
|
sendMessage(socket, message);
|
|
296
383
|
fileCount += 1;
|
|
297
384
|
}
|
|
298
|
-
sendMessage(socket, {
|
|
299
|
-
type: "snapshot-complete",
|
|
300
|
-
peerId,
|
|
301
|
-
sentAt: Date.now(),
|
|
302
|
-
fileCount
|
|
303
|
-
});
|
|
304
385
|
output.success(`sent snapshot ${fileCount} files`);
|
|
305
386
|
}
|
|
306
387
|
async function sendLocalFileChange(context, absolutePath) {
|
|
388
|
+
if (!context.state.approved) {
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
307
391
|
const relativePath = toRepoRelativePath(context.repoContext.rootDir, absolutePath);
|
|
308
392
|
if (!relativePath || context.suppressionTracker.isSuppressed(relativePath)) {
|
|
309
393
|
return;
|
|
310
394
|
}
|
|
311
|
-
const message = await buildFileMessage(context.repoContext,
|
|
395
|
+
const message = await buildFileMessage(context.repoContext, relativePath);
|
|
312
396
|
if (!message) {
|
|
313
397
|
return;
|
|
314
398
|
}
|
|
@@ -316,6 +400,9 @@ async function sendLocalFileChange(context, absolutePath) {
|
|
|
316
400
|
context.output.muted(`sent file ${relativePath}`);
|
|
317
401
|
}
|
|
318
402
|
async function sendLocalDelete(context, absolutePath) {
|
|
403
|
+
if (!context.state.approved) {
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
319
406
|
const relativePath = toRepoRelativePath(context.repoContext.rootDir, absolutePath);
|
|
320
407
|
if (!relativePath || context.suppressionTracker.isSuppressed(relativePath)) {
|
|
321
408
|
return;
|
|
@@ -325,82 +412,147 @@ async function sendLocalDelete(context, absolutePath) {
|
|
|
325
412
|
}
|
|
326
413
|
sendMessage(context.socket, {
|
|
327
414
|
type: "delete",
|
|
328
|
-
peerId: context.peerId,
|
|
329
415
|
path: relativePath,
|
|
330
|
-
mtimeMs: Date.now()
|
|
331
|
-
sentAt: Date.now()
|
|
416
|
+
mtimeMs: Date.now()
|
|
332
417
|
});
|
|
333
418
|
context.output.warning(`sent delete ${relativePath}`);
|
|
334
419
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
420
|
+
|
|
421
|
+
// src/features/coderoom/sync/remote-handler.ts
|
|
422
|
+
import process2 from "process";
|
|
423
|
+
import readline from "readline/promises";
|
|
424
|
+
async function handleServerMessage(options) {
|
|
425
|
+
const decodedMessage = decodeServerMessage(options.data.toString());
|
|
426
|
+
if (!decodedMessage) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
if (decodedMessage.type === "connected") {
|
|
430
|
+
options.state.participantId = decodedMessage.participantId;
|
|
431
|
+
options.state.approved = decodedMessage.status === "approved";
|
|
432
|
+
options.output.muted(`Participant: ${decodedMessage.participantId}`);
|
|
338
433
|
return;
|
|
339
434
|
}
|
|
340
|
-
if (decodedMessage.type === "
|
|
341
|
-
options.output.info(`
|
|
435
|
+
if (decodedMessage.type === "join-pending") {
|
|
436
|
+
options.output.info(`Join request sent: ${decodedMessage.joinRequestId}`);
|
|
342
437
|
return;
|
|
343
438
|
}
|
|
344
|
-
if (decodedMessage.type === "
|
|
345
|
-
options.
|
|
439
|
+
if (decodedMessage.type === "join-request") {
|
|
440
|
+
await approveJoinRequest(options.socket, decodedMessage, options.output);
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
if (decodedMessage.type === "join-approved") {
|
|
444
|
+
options.state.approved = true;
|
|
445
|
+
options.output.success("Join approved. Applying room file tree...");
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
if (decodedMessage.type === "join-denied") {
|
|
449
|
+
options.output.warning(`Join denied: ${decodedMessage.reason}`);
|
|
450
|
+
options.socket.close();
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
if (decodedMessage.type === "tree-start") {
|
|
454
|
+
options.output.info(`receiving room tree ${decodedMessage.fileCount} files`);
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
if (decodedMessage.type === "tree-complete") {
|
|
458
|
+
options.output.success(`room tree complete ${decodedMessage.fileCount} files`);
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
if (decodedMessage.type === "file-ack") {
|
|
462
|
+
options.output.muted(
|
|
463
|
+
`stored ${decodedMessage.storage} ${decodedMessage.path} ${decodedMessage.sha256}`
|
|
464
|
+
);
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
if (decodedMessage.type === "error") {
|
|
468
|
+
options.output.warning(`server error: ${decodedMessage.error}`);
|
|
346
469
|
return;
|
|
347
470
|
}
|
|
348
471
|
await applyRemoteMessage(options.repoContext, decodedMessage, options.suppressionTracker);
|
|
349
472
|
options.output.success(`applied ${decodedMessage.type} ${decodedMessage.path}`);
|
|
350
473
|
}
|
|
351
|
-
async function
|
|
352
|
-
await
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
474
|
+
async function approveJoinRequest(socket, message, output) {
|
|
475
|
+
const approved = await askForApproval(message, output);
|
|
476
|
+
sendMessage(socket, {
|
|
477
|
+
type: "join-approval",
|
|
478
|
+
joinRequestId: message.joinRequestId,
|
|
479
|
+
approved
|
|
480
|
+
});
|
|
481
|
+
output[approved ? "success" : "warning"](
|
|
482
|
+
`${approved ? "approved" : "denied"} ${message.displayName}`
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
async function askForApproval(message, output) {
|
|
486
|
+
output.info(`Join request: ${message.displayName} (${message.joinRequestId})`);
|
|
487
|
+
if (!process2.stdin.isTTY) {
|
|
488
|
+
output.warning("No interactive terminal available. Denying join request.");
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
const interfaceReader = readline.createInterface({
|
|
492
|
+
input: process2.stdin,
|
|
493
|
+
output: process2.stdout
|
|
494
|
+
});
|
|
495
|
+
try {
|
|
496
|
+
const answer = await interfaceReader.question("Approve join request? [y/N] ");
|
|
497
|
+
return answer.trim().toLowerCase() === "y" || answer.trim().toLowerCase() === "yes";
|
|
498
|
+
} finally {
|
|
499
|
+
interfaceReader.close();
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// src/features/coderoom/sync/client.ts
|
|
504
|
+
async function startSyncSession(options) {
|
|
505
|
+
const repoContext = await resolveRepoContext(options.cwd);
|
|
506
|
+
const suppressionTracker = createSuppressionTracker();
|
|
507
|
+
const webSocketUrl = createSyncWebSocketUrl(options);
|
|
508
|
+
const socket = new WebSocket2(webSocketUrl);
|
|
509
|
+
const state = {
|
|
510
|
+
approved: options.role === "host",
|
|
511
|
+
participantId: void 0
|
|
512
|
+
};
|
|
513
|
+
options.output.success(`Room: ${options.roomCode}`);
|
|
514
|
+
options.output.info(`Repo: ${repoContext.rootDir}`);
|
|
515
|
+
const watcherContext = {
|
|
516
|
+
repoContext,
|
|
517
|
+
socket,
|
|
518
|
+
state,
|
|
519
|
+
suppressionTracker,
|
|
520
|
+
output: options.output
|
|
521
|
+
};
|
|
522
|
+
const watcher = createRepoWatcher(watcherContext);
|
|
523
|
+
socket.on("open", () => {
|
|
524
|
+
if (options.role === "host") {
|
|
525
|
+
void sendInitialSnapshot(socket, repoContext, options.output);
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
options.output.info("Waiting for host approval...");
|
|
529
|
+
});
|
|
530
|
+
socket.on("message", (data) => {
|
|
531
|
+
void handleServerMessage({
|
|
532
|
+
data,
|
|
533
|
+
socket,
|
|
534
|
+
repoContext,
|
|
535
|
+
state,
|
|
536
|
+
suppressionTracker,
|
|
537
|
+
output: options.output
|
|
385
538
|
});
|
|
386
|
-
process.on("SIGINT", onSignal);
|
|
387
|
-
process.on("SIGTERM", onSignal);
|
|
388
539
|
});
|
|
540
|
+
await waitForSessionClose(socket, watcher);
|
|
389
541
|
}
|
|
390
542
|
|
|
391
543
|
// src/features/coderoom/run-coderoom-command.ts
|
|
392
|
-
async function runShareCommand(
|
|
393
|
-
const
|
|
394
|
-
output.success(`Share code: ${
|
|
544
|
+
async function runShareCommand(options, output) {
|
|
545
|
+
const room = await createCoderoomRoom(options);
|
|
546
|
+
output.success(`Share code: ${room.roomCode}`);
|
|
395
547
|
await printBackendStatus(options, output);
|
|
396
|
-
await runSyncSession("
|
|
548
|
+
await runSyncSession("host", room.roomCode, room.creatorToken, options, output);
|
|
397
549
|
}
|
|
398
550
|
async function runJoinCommand(roomCode, options, output) {
|
|
399
551
|
if (!roomCode) {
|
|
400
552
|
throw new Error("Missing room code. Usage: cngkit coderoom join <room-code>");
|
|
401
553
|
}
|
|
402
554
|
await printBackendStatus(options, output);
|
|
403
|
-
await runSyncSession("
|
|
555
|
+
await runSyncSession("guest", roomCode, void 0, options, output);
|
|
404
556
|
}
|
|
405
557
|
async function printBackendStatus(options, output) {
|
|
406
558
|
const health = await readBackendHealth(options);
|
|
@@ -410,18 +562,23 @@ async function printBackendStatus(options, output) {
|
|
|
410
562
|
}
|
|
411
563
|
output.warning(`API: unavailable (${health.message})`);
|
|
412
564
|
}
|
|
413
|
-
async function runSyncSession(role, roomCode, options, output) {
|
|
565
|
+
async function runSyncSession(role, roomCode, creatorToken, options, output) {
|
|
414
566
|
await startSyncSession({
|
|
415
567
|
apiBaseUrl: resolveApiBaseUrl(options),
|
|
416
568
|
roomCode,
|
|
569
|
+
creatorToken,
|
|
417
570
|
role,
|
|
418
|
-
cwd:
|
|
571
|
+
cwd: process3.cwd(),
|
|
419
572
|
output
|
|
420
573
|
});
|
|
421
574
|
}
|
|
575
|
+
async function createCoderoomRoom(options) {
|
|
576
|
+
const client = createCngApiClient(options);
|
|
577
|
+
return client.coderoom.createCoderoomRoom();
|
|
578
|
+
}
|
|
422
579
|
|
|
423
580
|
export {
|
|
424
581
|
runShareCommand,
|
|
425
582
|
runJoinCommand
|
|
426
583
|
};
|
|
427
|
-
//# sourceMappingURL=chunk-
|
|
584
|
+
//# sourceMappingURL=chunk-BXS4IKUA.js.map
|