cngkit 1.1.5 → 1.1.7

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 (57) hide show
  1. package/README.md +7 -4
  2. package/dist/{chunk-TZRXQ6GR.js → chunk-EQEIX7N5.js} +3 -3
  3. package/dist/chunk-EQEIX7N5.js.map +1 -0
  4. package/dist/chunk-HUZZPV5E.js +411 -0
  5. package/dist/chunk-HUZZPV5E.js.map +1 -0
  6. package/dist/{chunk-YY2VGJ5N.js → chunk-MLKBG5YJ.js} +2 -2
  7. package/dist/{chunk-YY2VGJ5N.js.map → chunk-MLKBG5YJ.js.map} +1 -1
  8. package/dist/{chunk-UXMP5Z5P.js → chunk-QEZQGKFX.js} +13 -1364
  9. package/dist/{chunk-UXMP5Z5P.js.map → chunk-QEZQGKFX.js.map} +1 -1
  10. package/dist/chunk-QZEB4VMX.js +32 -0
  11. package/dist/chunk-QZEB4VMX.js.map +1 -0
  12. package/dist/chunk-TZKXST4G.js +291 -0
  13. package/dist/chunk-TZKXST4G.js.map +1 -0
  14. package/dist/{chunk-SSRUN6G5.js → chunk-VI5XQH3U.js} +3 -18
  15. package/dist/chunk-VI5XQH3U.js.map +1 -0
  16. package/dist/chunk-XDXRVTPK.js +18 -0
  17. package/dist/chunk-XDXRVTPK.js.map +1 -0
  18. package/dist/{chunk-SNTLRTQ2.js → chunk-Z4DDLEWR.js} +3 -3
  19. package/dist/chunk-Z4DDLEWR.js.map +1 -0
  20. package/dist/cli.js +8 -6
  21. package/dist/cli.js.map +1 -1
  22. package/dist/commands/coderoom/index.js +6 -5
  23. package/dist/commands/coderoom/index.js.map +1 -1
  24. package/dist/commands/coderoom/join.js +6 -5
  25. package/dist/commands/coderoom/join.js.map +1 -1
  26. package/dist/commands/coderoom/share.js +6 -5
  27. package/dist/commands/coderoom/share.js.map +1 -1
  28. package/dist/commands/index.js +5 -4
  29. package/dist/commands/index.js.map +1 -1
  30. package/dist/commands/knowledges/audiences.js +8 -5
  31. package/dist/commands/knowledges/audiences.js.map +1 -1
  32. package/dist/commands/knowledges/files.js +8 -5
  33. package/dist/commands/knowledges/files.js.map +1 -1
  34. package/dist/commands/knowledges/glob.js +8 -5
  35. package/dist/commands/knowledges/glob.js.map +1 -1
  36. package/dist/commands/knowledges/grep.js +8 -5
  37. package/dist/commands/knowledges/grep.js.map +1 -1
  38. package/dist/commands/knowledges/index.js +6 -5
  39. package/dist/commands/knowledges/index.js.map +1 -1
  40. package/dist/commands/knowledges/list.js +8 -5
  41. package/dist/commands/knowledges/list.js.map +1 -1
  42. package/dist/commands/knowledges/read.js +8 -5
  43. package/dist/commands/knowledges/read.js.map +1 -1
  44. package/dist/commands/knowledges/search.js +8 -5
  45. package/dist/commands/knowledges/search.js.map +1 -1
  46. package/dist/commands/knowledges/status.js +8 -5
  47. package/dist/commands/knowledges/status.js.map +1 -1
  48. package/dist/commands/login.js +49 -6
  49. package/dist/commands/login.js.map +1 -1
  50. package/dist/commands/scrub.js +256 -7
  51. package/dist/commands/scrub.js.map +1 -1
  52. package/dist/commands/transcripts.js +377 -6
  53. package/dist/commands/transcripts.js.map +1 -1
  54. package/package.json +15 -14
  55. package/dist/chunk-SNTLRTQ2.js.map +0 -1
  56. package/dist/chunk-SSRUN6G5.js.map +0 -1
  57. package/dist/chunk-TZRXQ6GR.js.map +0 -1
package/README.md CHANGED
@@ -47,13 +47,16 @@ Global options accepted by every command:
47
47
  - `--help` / `-h` prints the progressive help for the current command.
48
48
 
49
49
  The canonical CLI spec lives at `docs/superpowers/specs/2026-06-25-cngkit-cli-spec.md`
50
- in the repository. The baked help source lives in `src/help-specs.ts`; keep both
50
+ in the repository. The baked help source lives in `src/cli/help-specs.ts`; keep both
51
51
  aligned when changing command behavior.
52
52
 
53
53
  Command routing is implemented with Pastel route files under `src/commands/`, rendered
54
- through Ink. `tsup` emits a file-preserving ESM build so the published package contains
55
- `dist/cli.js` plus `dist/commands/**`; the private workspace client stays bundled while
56
- public runtime packages remain normal package dependencies.
54
+ through the Ink runner in `src/cli/command-runner.tsx`. The route files are interface
55
+ adapters only. Command behavior lives under `src/features/<feature>/`, and shared
56
+ runtime concerns such as config, output, browser opening, and API client construction
57
+ live under `src/shared/`. `tsup` emits a file-preserving ESM build so the published
58
+ package contains `dist/cli.js` plus `dist/commands/**`; the private workspace client
59
+ stays bundled while public runtime packages remain normal package dependencies.
57
60
 
58
61
  `scrub` requires the `trufflehog` binary on `PATH`. On macOS, install it with:
59
62
 
@@ -1,7 +1,7 @@
1
- // src/config.ts
1
+ // src/shared/config.ts
2
2
  import { randomBytes, randomUUID } from "crypto";
3
3
  import process from "process";
4
- var packageVersion = "1.1.5";
4
+ var packageVersion = "1.1.7";
5
5
  var defaultApiBaseUrl = "https://curly.ng";
6
6
  function resolveApiBaseUrl(options) {
7
7
  return options.apiBaseUrl ?? process.env.CNGKIT_API_BASE_URL ?? defaultApiBaseUrl;
@@ -19,4 +19,4 @@ export {
19
19
  createRoomCode,
20
20
  createPeerId
21
21
  };
22
- //# sourceMappingURL=chunk-TZRXQ6GR.js.map
22
+ //# sourceMappingURL=chunk-EQEIX7N5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared/config.ts"],"sourcesContent":["import { randomBytes, randomUUID } from \"node:crypto\";\nimport process from \"node:process\";\n\nexport const packageVersion = \"1.1.7\";\nexport const defaultApiBaseUrl = \"https://curly.ng\";\n\nexport type GlobalCommandOptions = {\n apiBaseUrl?: string;\n};\n\nexport function resolveApiBaseUrl(options: GlobalCommandOptions): string {\n return options.apiBaseUrl ?? process.env.CNGKIT_API_BASE_URL ?? defaultApiBaseUrl;\n}\n\nexport function createRoomCode(): string {\n return randomBytes(4).toString(\"hex\").toUpperCase();\n}\n\nexport function createPeerId(): string {\n return randomUUID();\n}\n"],"mappings":";AAAA,SAAS,aAAa,kBAAkB;AACxC,OAAO,aAAa;AAEb,IAAM,iBAAiB;AACvB,IAAM,oBAAoB;AAM1B,SAAS,kBAAkB,SAAuC;AACvE,SAAO,QAAQ,cAAc,QAAQ,IAAI,uBAAuB;AAClE;AAEO,SAAS,iBAAyB;AACvC,SAAO,YAAY,CAAC,EAAE,SAAS,KAAK,EAAE,YAAY;AACpD;AAEO,SAAS,eAAuB;AACrC,SAAO,WAAW;AACpB;","names":[]}
@@ -0,0 +1,411 @@
1
+ import {
2
+ readBackendHealth
3
+ } from "./chunk-QEZQGKFX.js";
4
+ import {
5
+ createPeerId,
6
+ createRoomCode,
7
+ resolveApiBaseUrl
8
+ } from "./chunk-EQEIX7N5.js";
9
+
10
+ // src/features/coderoom/run-coderoom-command.ts
11
+ import process2 from "process";
12
+
13
+ // src/features/coderoom/sync/client.ts
14
+ import process from "process";
15
+ import chokidar from "chokidar";
16
+ import WebSocket from "ws";
17
+
18
+ // src/features/coderoom/sync/files.ts
19
+ import fs from "fs/promises";
20
+ import path2 from "path";
21
+
22
+ // src/features/coderoom/sync/paths.ts
23
+ import { execFile } from "child_process";
24
+ import path from "path";
25
+ import { promisify } from "util";
26
+ var execFileAsync = promisify(execFile);
27
+ async function resolveRepoContext(cwd) {
28
+ try {
29
+ const { stdout } = await execFileAsync("git", ["rev-parse", "--show-toplevel"], {
30
+ cwd
31
+ });
32
+ return { rootDir: path.resolve(stdout.trim()) };
33
+ } catch {
34
+ return { rootDir: path.resolve(cwd) };
35
+ }
36
+ }
37
+ function toRepoRelativePath(rootDir, absolutePath) {
38
+ const relativePath = path.relative(rootDir, absolutePath);
39
+ if (!relativePath || relativePath.startsWith("..") || path.isAbsolute(relativePath)) {
40
+ return void 0;
41
+ }
42
+ return relativePath.split(path.sep).join("/");
43
+ }
44
+ function resolveRepoPath(rootDir, relativePath) {
45
+ if (!isSafeRelativePath(relativePath)) {
46
+ return void 0;
47
+ }
48
+ const absolutePath = path.resolve(rootDir, relativePath);
49
+ const normalizedRoot = `${path.resolve(rootDir)}${path.sep}`;
50
+ if (absolutePath !== path.resolve(rootDir) && !absolutePath.startsWith(normalizedRoot)) {
51
+ return void 0;
52
+ }
53
+ return absolutePath;
54
+ }
55
+ function isSafeRelativePath(relativePath) {
56
+ if (!relativePath || relativePath.startsWith("/") || relativePath.includes("\0")) {
57
+ return false;
58
+ }
59
+ const normalizedParts = relativePath.split(/[\\/]+/).filter(Boolean);
60
+ if (normalizedParts.includes("..")) {
61
+ return false;
62
+ }
63
+ return normalizedParts[0] !== ".git";
64
+ }
65
+ async function shouldSyncRelativePath(context, relativePath) {
66
+ if (!isSafeRelativePath(relativePath)) {
67
+ return false;
68
+ }
69
+ try {
70
+ await execFileAsync("git", ["check-ignore", "--quiet", "--", relativePath], {
71
+ cwd: context.rootDir
72
+ });
73
+ return false;
74
+ } catch (error) {
75
+ const exitCode = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
76
+ return exitCode === 1;
77
+ }
78
+ }
79
+
80
+ // src/features/coderoom/sync/files.ts
81
+ function createSuppressionTracker(windowMs = 1500) {
82
+ const suppressedUntilByPath = /* @__PURE__ */ new Map();
83
+ return {
84
+ suppress(relativePath) {
85
+ suppressedUntilByPath.set(relativePath, Date.now() + windowMs);
86
+ },
87
+ isSuppressed(relativePath) {
88
+ const suppressedUntil = suppressedUntilByPath.get(relativePath);
89
+ if (!suppressedUntil) {
90
+ return false;
91
+ }
92
+ if (suppressedUntil < Date.now()) {
93
+ suppressedUntilByPath.delete(relativePath);
94
+ return false;
95
+ }
96
+ return true;
97
+ }
98
+ };
99
+ }
100
+ async function* collectSnapshotMessages(context, peerId) {
101
+ yield* collectDirectorySnapshot(context, context.rootDir, peerId);
102
+ }
103
+ async function* collectDirectorySnapshot(context, directoryPath, peerId) {
104
+ const entries = await fs.opendir(directoryPath);
105
+ for await (const entry of entries) {
106
+ const absolutePath = path2.join(directoryPath, entry.name);
107
+ const relativePath = toRepoRelativePath(context.rootDir, absolutePath);
108
+ if (!relativePath || !await shouldSyncRelativePath(context, relativePath)) {
109
+ continue;
110
+ }
111
+ if (entry.isDirectory()) {
112
+ yield* collectDirectorySnapshot(context, absolutePath, peerId);
113
+ continue;
114
+ }
115
+ if (!entry.isFile()) {
116
+ continue;
117
+ }
118
+ const [content, stat] = await Promise.all([fs.readFile(absolutePath), fs.stat(absolutePath)]);
119
+ yield {
120
+ type: "file",
121
+ peerId,
122
+ path: relativePath,
123
+ contentBase64: content.toString("base64"),
124
+ mtimeMs: stat.mtimeMs,
125
+ sentAt: Date.now()
126
+ };
127
+ }
128
+ }
129
+ async function buildFileMessage(context, peerId, relativePath) {
130
+ if (!await shouldSyncRelativePath(context, relativePath)) {
131
+ return void 0;
132
+ }
133
+ const absolutePath = resolveRepoPath(context.rootDir, relativePath);
134
+ if (!absolutePath) {
135
+ return void 0;
136
+ }
137
+ const stat = await fs.stat(absolutePath);
138
+ if (!stat.isFile()) {
139
+ return void 0;
140
+ }
141
+ const content = await fs.readFile(absolutePath);
142
+ return {
143
+ type: "file",
144
+ peerId,
145
+ path: relativePath,
146
+ contentBase64: content.toString("base64"),
147
+ mtimeMs: stat.mtimeMs,
148
+ sentAt: Date.now()
149
+ };
150
+ }
151
+ async function applyRemoteMessage(context, message, suppressionTracker) {
152
+ const absolutePath = resolveRepoPath(context.rootDir, message.path);
153
+ if (!absolutePath || !await shouldSyncRelativePath(context, message.path)) {
154
+ return;
155
+ }
156
+ suppressionTracker.suppress(message.path);
157
+ if (message.type === "delete") {
158
+ await fs.rm(absolutePath, { force: true });
159
+ return;
160
+ }
161
+ await fs.mkdir(path2.dirname(absolutePath), { recursive: true });
162
+ await fs.writeFile(absolutePath, Buffer.from(message.contentBase64, "base64"));
163
+ }
164
+
165
+ // src/features/coderoom/sync/protocol.ts
166
+ import { z } from "zod";
167
+ var SyncBaseMessageSchema = z.object({
168
+ peerId: z.string().min(1),
169
+ sentAt: z.number().finite()
170
+ });
171
+ var SyncHelloMessageSchema = SyncBaseMessageSchema.extend({
172
+ type: z.literal("hello"),
173
+ role: z.union([z.literal("share"), z.literal("join")])
174
+ });
175
+ var SyncFileMessageSchema = SyncBaseMessageSchema.extend({
176
+ type: z.literal("file"),
177
+ path: z.string().min(1),
178
+ contentBase64: z.string(),
179
+ mtimeMs: z.number().finite()
180
+ });
181
+ var SyncDeleteMessageSchema = SyncBaseMessageSchema.extend({
182
+ type: z.literal("delete"),
183
+ path: z.string().min(1),
184
+ mtimeMs: z.number().finite()
185
+ });
186
+ var SyncSnapshotCompleteMessageSchema = SyncBaseMessageSchema.extend({
187
+ type: z.literal("snapshot-complete"),
188
+ fileCount: z.number().int().nonnegative()
189
+ });
190
+ var SyncMessageSchema = z.discriminatedUnion("type", [
191
+ SyncHelloMessageSchema,
192
+ SyncFileMessageSchema,
193
+ SyncDeleteMessageSchema,
194
+ SyncSnapshotCompleteMessageSchema
195
+ ]);
196
+ function encodeSyncMessage(message) {
197
+ return JSON.stringify(SyncMessageSchema.parse(message));
198
+ }
199
+ function decodeSyncMessage(value) {
200
+ if (typeof value !== "string") {
201
+ return void 0;
202
+ }
203
+ try {
204
+ return SyncMessageSchema.parse(JSON.parse(value));
205
+ } catch {
206
+ return void 0;
207
+ }
208
+ }
209
+
210
+ // src/features/coderoom/sync/client.ts
211
+ function createSyncWebSocketUrl(apiBaseUrl, roomCode) {
212
+ const url = new URL(apiBaseUrl);
213
+ url.protocol = url.protocol === "http:" ? "ws:" : "wss:";
214
+ url.pathname = `/api/cng/sync/${encodeURIComponent(roomCode)}`;
215
+ url.search = "";
216
+ url.hash = "";
217
+ return url.toString();
218
+ }
219
+ function sendMessage(socket, message) {
220
+ if (socket.readyState === WebSocket.OPEN) {
221
+ socket.send(encodeSyncMessage(message));
222
+ }
223
+ }
224
+ async function startSyncSession(options) {
225
+ const repoContext = await resolveRepoContext(options.cwd);
226
+ const peerId = createPeerId();
227
+ const suppressionTracker = createSuppressionTracker();
228
+ const webSocketUrl = createSyncWebSocketUrl(options.apiBaseUrl, options.roomCode);
229
+ const socket = new WebSocket(webSocketUrl);
230
+ options.output.info(`Room: ${options.roomCode}`);
231
+ options.output.info(`Repo: ${repoContext.rootDir}`);
232
+ options.output.info(`Peer: ${peerId}`);
233
+ const watcherContext = {
234
+ repoContext,
235
+ socket,
236
+ peerId,
237
+ suppressionTracker,
238
+ output: options.output
239
+ };
240
+ const watcher = createRepoWatcher(watcherContext);
241
+ socket.on("open", () => {
242
+ sendMessage(socket, {
243
+ type: "hello",
244
+ peerId,
245
+ role: options.role,
246
+ sentAt: Date.now()
247
+ });
248
+ void sendInitialSnapshot(socket, repoContext, peerId, options.output);
249
+ });
250
+ socket.on("message", (data) => {
251
+ void handleRemoteMessage({
252
+ data,
253
+ repoContext,
254
+ peerId,
255
+ suppressionTracker,
256
+ output: options.output
257
+ });
258
+ });
259
+ await waitForSessionClose(socket, watcher);
260
+ }
261
+ function createRepoWatcher(context) {
262
+ const watcher = chokidar.watch(context.repoContext.rootDir, {
263
+ ignoreInitial: true,
264
+ ignored: (candidatePath) => {
265
+ const relativePath = toRepoRelativePath(context.repoContext.rootDir, candidatePath);
266
+ return relativePath?.split("/").includes(".git") ?? false;
267
+ }
268
+ });
269
+ watcher.on("add", (absolutePath) => {
270
+ void sendLocalFileChange(context, absolutePath);
271
+ });
272
+ watcher.on("change", (absolutePath) => {
273
+ void sendLocalFileChange(context, absolutePath);
274
+ });
275
+ watcher.on("unlink", (absolutePath) => {
276
+ void sendLocalDelete(context, absolutePath);
277
+ });
278
+ return watcher;
279
+ }
280
+ async function sendInitialSnapshot(socket, repoContext, peerId, output) {
281
+ let fileCount = 0;
282
+ for await (const message of collectSnapshotMessages(repoContext, peerId)) {
283
+ sendMessage(socket, message);
284
+ fileCount += 1;
285
+ }
286
+ sendMessage(socket, {
287
+ type: "snapshot-complete",
288
+ peerId,
289
+ sentAt: Date.now(),
290
+ fileCount
291
+ });
292
+ output.info(`sent snapshot ${fileCount} files`);
293
+ }
294
+ async function sendLocalFileChange(context, absolutePath) {
295
+ const relativePath = toRepoRelativePath(context.repoContext.rootDir, absolutePath);
296
+ if (!relativePath || context.suppressionTracker.isSuppressed(relativePath)) {
297
+ return;
298
+ }
299
+ const message = await buildFileMessage(context.repoContext, context.peerId, relativePath);
300
+ if (!message) {
301
+ return;
302
+ }
303
+ sendMessage(context.socket, message);
304
+ context.output.info(`sent file ${relativePath}`);
305
+ }
306
+ async function sendLocalDelete(context, absolutePath) {
307
+ const relativePath = toRepoRelativePath(context.repoContext.rootDir, absolutePath);
308
+ if (!relativePath || context.suppressionTracker.isSuppressed(relativePath)) {
309
+ return;
310
+ }
311
+ if (!await shouldSyncRelativePath(context.repoContext, relativePath)) {
312
+ return;
313
+ }
314
+ sendMessage(context.socket, {
315
+ type: "delete",
316
+ peerId: context.peerId,
317
+ path: relativePath,
318
+ mtimeMs: Date.now(),
319
+ sentAt: Date.now()
320
+ });
321
+ context.output.info(`sent delete ${relativePath}`);
322
+ }
323
+ async function handleRemoteMessage(options) {
324
+ const decodedMessage = decodeSyncMessage(options.data.toString());
325
+ if (!decodedMessage || decodedMessage.peerId === options.peerId) {
326
+ return;
327
+ }
328
+ if (decodedMessage.type === "hello") {
329
+ options.output.info(`peer joined ${decodedMessage.peerId}`);
330
+ return;
331
+ }
332
+ if (decodedMessage.type === "snapshot-complete") {
333
+ options.output.info(`peer snapshot complete ${decodedMessage.fileCount} files`);
334
+ return;
335
+ }
336
+ await applyRemoteMessage(options.repoContext, decodedMessage, options.suppressionTracker);
337
+ options.output.info(`applied ${decodedMessage.type} ${decodedMessage.path}`);
338
+ }
339
+ async function waitForSessionClose(socket, watcher) {
340
+ await new Promise((resolve, reject) => {
341
+ let settled = false;
342
+ const closeSession = async () => {
343
+ await watcher.close();
344
+ if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
345
+ socket.close();
346
+ }
347
+ };
348
+ const finish = async () => {
349
+ if (settled) {
350
+ return;
351
+ }
352
+ settled = true;
353
+ process.off("SIGINT", onSignal);
354
+ process.off("SIGTERM", onSignal);
355
+ await closeSession();
356
+ resolve();
357
+ };
358
+ const onSignal = () => {
359
+ void finish();
360
+ };
361
+ socket.on("error", async (error) => {
362
+ if (settled) {
363
+ return;
364
+ }
365
+ settled = true;
366
+ process.off("SIGINT", onSignal);
367
+ process.off("SIGTERM", onSignal);
368
+ await closeSession();
369
+ reject(error);
370
+ });
371
+ socket.on("close", () => {
372
+ void finish();
373
+ });
374
+ process.on("SIGINT", onSignal);
375
+ process.on("SIGTERM", onSignal);
376
+ });
377
+ }
378
+
379
+ // src/features/coderoom/run-coderoom-command.ts
380
+ async function runShareCommand(roomCode, options, output) {
381
+ const syncRoomCode = roomCode ?? createRoomCode();
382
+ output.info(`Share code: ${syncRoomCode}`);
383
+ await printBackendStatus(options, output);
384
+ await runSyncSession("share", syncRoomCode, options, output);
385
+ }
386
+ async function runJoinCommand(roomCode, options, output) {
387
+ if (!roomCode) {
388
+ throw new Error("Missing room code. Usage: cngkit coderoom join <room-code>");
389
+ }
390
+ await printBackendStatus(options, output);
391
+ await runSyncSession("join", roomCode, options, output);
392
+ }
393
+ async function printBackendStatus(options, output) {
394
+ const health = await readBackendHealth(options);
395
+ output.info(health.ok ? `API: ${health.service} ready` : `API: unavailable (${health.message})`);
396
+ }
397
+ async function runSyncSession(role, roomCode, options, output) {
398
+ await startSyncSession({
399
+ apiBaseUrl: resolveApiBaseUrl(options),
400
+ roomCode,
401
+ role,
402
+ cwd: process2.cwd(),
403
+ output
404
+ });
405
+ }
406
+
407
+ export {
408
+ runShareCommand,
409
+ runJoinCommand
410
+ };
411
+ //# sourceMappingURL=chunk-HUZZPV5E.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/features/coderoom/run-coderoom-command.ts","../src/features/coderoom/sync/client.ts","../src/features/coderoom/sync/files.ts","../src/features/coderoom/sync/paths.ts","../src/features/coderoom/sync/protocol.ts"],"sourcesContent":["import process from \"node:process\";\n\nimport { readBackendHealth } from \"../../shared/api-client.js\";\nimport { createRoomCode, resolveApiBaseUrl, type GlobalCommandOptions } from \"../../shared/config.js\";\nimport type { CommandOutput } from \"../../shared/output.js\";\nimport { startSyncSession, type SyncSessionRole } from \"./sync/client.js\";\n\nexport type CoderoomCommandOptions = GlobalCommandOptions;\n\nexport type ShareCommandOptions = GlobalCommandOptions;\n\nexport async function runCoderoomCommand(\n args: string[] | undefined,\n options: CoderoomCommandOptions,\n output: CommandOutput\n): Promise<void> {\n const [subcommand, ...subcommandArgs] = args ?? [];\n\n switch (subcommand) {\n case \"share\":\n return runShareCommand(subcommandArgs[0], options, output);\n case \"join\":\n return runJoinCommand(subcommandArgs[0], options, output);\n default:\n throw new Error(\"Missing coderoom command. Usage: cngkit coderoom <share|join>\");\n }\n}\n\nexport async function runShareCommand(\n roomCode: string | undefined,\n options: ShareCommandOptions,\n output: CommandOutput\n): Promise<void> {\n const syncRoomCode = roomCode ?? createRoomCode();\n\n output.info(`Share code: ${syncRoomCode}`);\n await printBackendStatus(options, output);\n await runSyncSession(\"share\", syncRoomCode, options, output);\n}\n\nexport async function runJoinCommand(\n roomCode: string | undefined,\n options: GlobalCommandOptions,\n output: CommandOutput\n): Promise<void> {\n if (!roomCode) {\n throw new Error(\"Missing room code. Usage: cngkit coderoom join <room-code>\");\n }\n\n await printBackendStatus(options, output);\n await runSyncSession(\"join\", roomCode, options, output);\n}\n\nasync function printBackendStatus(\n options: GlobalCommandOptions,\n output: CommandOutput\n): Promise<void> {\n const health = await readBackendHealth(options);\n output.info(health.ok ? `API: ${health.service} ready` : `API: unavailable (${health.message})`);\n}\n\nasync function runSyncSession(\n role: SyncSessionRole,\n roomCode: string,\n options: GlobalCommandOptions,\n output: CommandOutput\n): Promise<void> {\n await startSyncSession({\n apiBaseUrl: resolveApiBaseUrl(options),\n roomCode,\n role,\n cwd: process.cwd(),\n output,\n });\n}\n","import process from \"node:process\";\n\nimport chokidar, { type FSWatcher } from \"chokidar\";\nimport WebSocket, { type RawData } from \"ws\";\n\nimport { createPeerId } from \"../../../shared/config.js\";\nimport type { CommandOutput } from \"../../../shared/output.js\";\nimport {\n applyRemoteMessage,\n buildFileMessage,\n collectSnapshotMessages,\n createSuppressionTracker,\n type SuppressionTracker,\n} from \"./files.js\";\nimport {\n resolveRepoContext,\n shouldSyncRelativePath,\n toRepoRelativePath,\n type RepoContext,\n} from \"./paths.js\";\nimport { decodeSyncMessage, encodeSyncMessage, type SyncMessage } from \"./protocol.js\";\n\nexport type SyncSessionRole = \"share\" | \"join\";\n\nexport type StartSyncSessionOptions = {\n apiBaseUrl: string;\n roomCode: string;\n role: SyncSessionRole;\n cwd: string;\n output: CommandOutput;\n};\n\ntype WatcherContext = {\n repoContext: RepoContext;\n socket: WebSocket;\n peerId: string;\n suppressionTracker: SuppressionTracker;\n output: CommandOutput;\n};\n\nfunction createSyncWebSocketUrl(apiBaseUrl: string, roomCode: string): string {\n const url = new URL(apiBaseUrl);\n url.protocol = url.protocol === \"http:\" ? \"ws:\" : \"wss:\";\n url.pathname = `/api/cng/sync/${encodeURIComponent(roomCode)}`;\n url.search = \"\";\n url.hash = \"\";\n return url.toString();\n}\n\nfunction sendMessage(socket: WebSocket, message: SyncMessage): void {\n if (socket.readyState === WebSocket.OPEN) {\n socket.send(encodeSyncMessage(message));\n }\n}\n\nexport async function startSyncSession(options: StartSyncSessionOptions): Promise<void> {\n const repoContext = await resolveRepoContext(options.cwd);\n const peerId = createPeerId();\n const suppressionTracker = createSuppressionTracker();\n const webSocketUrl = createSyncWebSocketUrl(options.apiBaseUrl, options.roomCode);\n const socket = new WebSocket(webSocketUrl);\n\n options.output.info(`Room: ${options.roomCode}`);\n options.output.info(`Repo: ${repoContext.rootDir}`);\n options.output.info(`Peer: ${peerId}`);\n\n const watcherContext: WatcherContext = {\n repoContext,\n socket,\n peerId,\n suppressionTracker,\n output: options.output,\n };\n const watcher = createRepoWatcher(watcherContext);\n\n socket.on(\"open\", () => {\n sendMessage(socket, {\n type: \"hello\",\n peerId,\n role: options.role,\n sentAt: Date.now(),\n });\n void sendInitialSnapshot(socket, repoContext, peerId, options.output);\n });\n\n socket.on(\"message\", (data) => {\n void handleRemoteMessage({\n data,\n repoContext,\n peerId,\n suppressionTracker,\n output: options.output,\n });\n });\n\n await waitForSessionClose(socket, watcher);\n}\n\nfunction createRepoWatcher(context: WatcherContext): FSWatcher {\n const watcher = chokidar.watch(context.repoContext.rootDir, {\n ignoreInitial: true,\n ignored: (candidatePath) => {\n const relativePath = toRepoRelativePath(context.repoContext.rootDir, candidatePath);\n return relativePath?.split(\"/\").includes(\".git\") ?? false;\n },\n });\n\n watcher.on(\"add\", (absolutePath) => {\n void sendLocalFileChange(context, absolutePath);\n });\n watcher.on(\"change\", (absolutePath) => {\n void sendLocalFileChange(context, absolutePath);\n });\n watcher.on(\"unlink\", (absolutePath) => {\n void sendLocalDelete(context, absolutePath);\n });\n\n return watcher;\n}\n\nasync function sendInitialSnapshot(\n socket: WebSocket,\n repoContext: RepoContext,\n peerId: string,\n output: CommandOutput\n): Promise<void> {\n let fileCount = 0;\n\n for await (const message of collectSnapshotMessages(repoContext, peerId)) {\n sendMessage(socket, message);\n fileCount += 1;\n }\n\n sendMessage(socket, {\n type: \"snapshot-complete\",\n peerId,\n sentAt: Date.now(),\n fileCount,\n });\n output.info(`sent snapshot ${fileCount} files`);\n}\n\nasync function sendLocalFileChange(context: WatcherContext, absolutePath: string): Promise<void> {\n const relativePath = toRepoRelativePath(context.repoContext.rootDir, absolutePath);\n if (!relativePath || context.suppressionTracker.isSuppressed(relativePath)) {\n return;\n }\n\n const message = await buildFileMessage(context.repoContext, context.peerId, relativePath);\n if (!message) {\n return;\n }\n\n sendMessage(context.socket, message);\n context.output.info(`sent file ${relativePath}`);\n}\n\nasync function sendLocalDelete(context: WatcherContext, absolutePath: string): Promise<void> {\n const relativePath = toRepoRelativePath(context.repoContext.rootDir, absolutePath);\n if (!relativePath || context.suppressionTracker.isSuppressed(relativePath)) {\n return;\n }\n\n if (!(await shouldSyncRelativePath(context.repoContext, relativePath))) {\n return;\n }\n\n sendMessage(context.socket, {\n type: \"delete\",\n peerId: context.peerId,\n path: relativePath,\n mtimeMs: Date.now(),\n sentAt: Date.now(),\n });\n context.output.info(`sent delete ${relativePath}`);\n}\n\nasync function handleRemoteMessage(options: {\n data: RawData;\n repoContext: RepoContext;\n peerId: string;\n suppressionTracker: SuppressionTracker;\n output: CommandOutput;\n}): Promise<void> {\n const decodedMessage = decodeSyncMessage(options.data.toString());\n if (!decodedMessage || decodedMessage.peerId === options.peerId) {\n return;\n }\n\n if (decodedMessage.type === \"hello\") {\n options.output.info(`peer joined ${decodedMessage.peerId}`);\n return;\n }\n\n if (decodedMessage.type === \"snapshot-complete\") {\n options.output.info(`peer snapshot complete ${decodedMessage.fileCount} files`);\n return;\n }\n\n await applyRemoteMessage(options.repoContext, decodedMessage, options.suppressionTracker);\n options.output.info(`applied ${decodedMessage.type} ${decodedMessage.path}`);\n}\n\nasync function waitForSessionClose(socket: WebSocket, watcher: FSWatcher): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n let settled = false;\n\n const closeSession = async (): Promise<void> => {\n await watcher.close();\n if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {\n socket.close();\n }\n };\n\n const finish = async (): Promise<void> => {\n if (settled) {\n return;\n }\n settled = true;\n process.off(\"SIGINT\", onSignal);\n process.off(\"SIGTERM\", onSignal);\n await closeSession();\n resolve();\n };\n\n const onSignal = (): void => {\n void finish();\n };\n\n socket.on(\"error\", async (error) => {\n if (settled) {\n return;\n }\n settled = true;\n process.off(\"SIGINT\", onSignal);\n process.off(\"SIGTERM\", onSignal);\n await closeSession();\n reject(error);\n });\n\n socket.on(\"close\", () => {\n void finish();\n });\n\n process.on(\"SIGINT\", onSignal);\n process.on(\"SIGTERM\", onSignal);\n });\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { SyncFileMutationMessage, SyncMessage } from \"./protocol.js\";\nimport {\n resolveRepoPath,\n shouldSyncRelativePath,\n toRepoRelativePath,\n type RepoContext,\n} from \"./paths.js\";\n\nexport type SuppressionTracker = {\n suppress(relativePath: string): void;\n isSuppressed(relativePath: string): boolean;\n};\n\nexport function createSuppressionTracker(windowMs = 1500): SuppressionTracker {\n const suppressedUntilByPath = new Map<string, number>();\n\n return {\n suppress(relativePath: string) {\n suppressedUntilByPath.set(relativePath, Date.now() + windowMs);\n },\n isSuppressed(relativePath: string) {\n const suppressedUntil = suppressedUntilByPath.get(relativePath);\n if (!suppressedUntil) {\n return false;\n }\n if (suppressedUntil < Date.now()) {\n suppressedUntilByPath.delete(relativePath);\n return false;\n }\n return true;\n },\n };\n}\n\nexport async function* collectSnapshotMessages(\n context: RepoContext,\n peerId: string\n): AsyncGenerator<SyncMessage> {\n yield* collectDirectorySnapshot(context, context.rootDir, peerId);\n}\n\nasync function* collectDirectorySnapshot(\n context: RepoContext,\n directoryPath: string,\n peerId: string\n): AsyncGenerator<SyncMessage> {\n const entries = await fs.opendir(directoryPath);\n\n for await (const entry of entries) {\n const absolutePath = path.join(directoryPath, entry.name);\n const relativePath = toRepoRelativePath(context.rootDir, absolutePath);\n\n if (!relativePath || !(await shouldSyncRelativePath(context, relativePath))) {\n continue;\n }\n\n if (entry.isDirectory()) {\n yield* collectDirectorySnapshot(context, absolutePath, peerId);\n continue;\n }\n\n if (!entry.isFile()) {\n continue;\n }\n\n const [content, stat] = await Promise.all([fs.readFile(absolutePath), fs.stat(absolutePath)]);\n yield {\n type: \"file\",\n peerId,\n path: relativePath,\n contentBase64: content.toString(\"base64\"),\n mtimeMs: stat.mtimeMs,\n sentAt: Date.now(),\n };\n }\n}\n\nexport async function buildFileMessage(\n context: RepoContext,\n peerId: string,\n relativePath: string\n): Promise<SyncMessage | undefined> {\n if (!(await shouldSyncRelativePath(context, relativePath))) {\n return undefined;\n }\n\n const absolutePath = resolveRepoPath(context.rootDir, relativePath);\n if (!absolutePath) {\n return undefined;\n }\n\n const stat = await fs.stat(absolutePath);\n if (!stat.isFile()) {\n return undefined;\n }\n\n const content = await fs.readFile(absolutePath);\n return {\n type: \"file\",\n peerId,\n path: relativePath,\n contentBase64: content.toString(\"base64\"),\n mtimeMs: stat.mtimeMs,\n sentAt: Date.now(),\n };\n}\n\nexport async function applyRemoteMessage(\n context: RepoContext,\n message: SyncFileMutationMessage,\n suppressionTracker: SuppressionTracker\n): Promise<void> {\n const absolutePath = resolveRepoPath(context.rootDir, message.path);\n if (!absolutePath || !(await shouldSyncRelativePath(context, message.path))) {\n return;\n }\n\n suppressionTracker.suppress(message.path);\n\n if (message.type === \"delete\") {\n await fs.rm(absolutePath, { force: true });\n return;\n }\n\n await fs.mkdir(path.dirname(absolutePath), { recursive: true });\n await fs.writeFile(absolutePath, Buffer.from(message.contentBase64, \"base64\"));\n}\n","import { execFile } from \"node:child_process\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\nexport type RepoContext = {\n rootDir: string;\n};\n\nexport async function resolveRepoContext(cwd: string): Promise<RepoContext> {\n try {\n const { stdout } = await execFileAsync(\"git\", [\"rev-parse\", \"--show-toplevel\"], {\n cwd,\n });\n return { rootDir: path.resolve(stdout.trim()) };\n } catch {\n return { rootDir: path.resolve(cwd) };\n }\n}\n\nexport function toRepoRelativePath(rootDir: string, absolutePath: string): string | undefined {\n const relativePath = path.relative(rootDir, absolutePath);\n\n if (!relativePath || relativePath.startsWith(\"..\") || path.isAbsolute(relativePath)) {\n return undefined;\n }\n\n return relativePath.split(path.sep).join(\"/\");\n}\n\nexport function resolveRepoPath(rootDir: string, relativePath: string): string | undefined {\n if (!isSafeRelativePath(relativePath)) {\n return undefined;\n }\n\n const absolutePath = path.resolve(rootDir, relativePath);\n const normalizedRoot = `${path.resolve(rootDir)}${path.sep}`;\n\n if (absolutePath !== path.resolve(rootDir) && !absolutePath.startsWith(normalizedRoot)) {\n return undefined;\n }\n\n return absolutePath;\n}\n\nexport function isSafeRelativePath(relativePath: string): boolean {\n if (!relativePath || relativePath.startsWith(\"/\") || relativePath.includes(\"\\0\")) {\n return false;\n }\n\n const normalizedParts = relativePath.split(/[\\\\/]+/).filter(Boolean);\n if (normalizedParts.includes(\"..\")) {\n return false;\n }\n\n return normalizedParts[0] !== \".git\";\n}\n\nexport async function shouldSyncRelativePath(\n context: RepoContext,\n relativePath: string\n): Promise<boolean> {\n if (!isSafeRelativePath(relativePath)) {\n return false;\n }\n\n try {\n await execFileAsync(\"git\", [\"check-ignore\", \"--quiet\", \"--\", relativePath], {\n cwd: context.rootDir,\n });\n return false;\n } catch (error) {\n const exitCode =\n typeof error === \"object\" && error !== null && \"code\" in error ? error.code : undefined;\n return exitCode === 1;\n }\n}\n","import { z } from \"zod\";\n\nconst SyncBaseMessageSchema = z.object({\n peerId: z.string().min(1),\n sentAt: z.number().finite(),\n});\n\nexport const SyncHelloMessageSchema = SyncBaseMessageSchema.extend({\n type: z.literal(\"hello\"),\n role: z.union([z.literal(\"share\"), z.literal(\"join\")]),\n});\n\nexport const SyncFileMessageSchema = SyncBaseMessageSchema.extend({\n type: z.literal(\"file\"),\n path: z.string().min(1),\n contentBase64: z.string(),\n mtimeMs: z.number().finite(),\n});\n\nexport const SyncDeleteMessageSchema = SyncBaseMessageSchema.extend({\n type: z.literal(\"delete\"),\n path: z.string().min(1),\n mtimeMs: z.number().finite(),\n});\n\nexport const SyncSnapshotCompleteMessageSchema = SyncBaseMessageSchema.extend({\n type: z.literal(\"snapshot-complete\"),\n fileCount: z.number().int().nonnegative(),\n});\n\nexport const SyncMessageSchema = z.discriminatedUnion(\"type\", [\n SyncHelloMessageSchema,\n SyncFileMessageSchema,\n SyncDeleteMessageSchema,\n SyncSnapshotCompleteMessageSchema,\n]);\n\nexport type SyncMessage = z.infer<typeof SyncMessageSchema>;\nexport type SyncFileMutationMessage = Extract<SyncMessage, { type: \"file\" | \"delete\" }>;\n\nexport function encodeSyncMessage(message: SyncMessage): string {\n return JSON.stringify(SyncMessageSchema.parse(message));\n}\n\nexport function decodeSyncMessage(value: unknown): SyncMessage | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n\n try {\n return SyncMessageSchema.parse(JSON.parse(value));\n } catch {\n return undefined;\n }\n}\n"],"mappings":"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","names":["process","path","path","process"]}
@@ -1,4 +1,4 @@
1
- // src/cli-options.ts
1
+ // src/cli/options.ts
2
2
  import { argument, option } from "pastel";
3
3
  import { z } from "zod";
4
4
  var GlobalOptionsSchema = z.object({
@@ -111,4 +111,4 @@ export {
111
111
  LimitOptionsSchema,
112
112
  TranscriptArgsSchema
113
113
  };
114
- //# sourceMappingURL=chunk-YY2VGJ5N.js.map
114
+ //# sourceMappingURL=chunk-MLKBG5YJ.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli-options.ts"],"sourcesContent":["import { argument, option } from \"pastel\";\nimport { z } from \"zod\";\n\nexport const GlobalOptionsSchema = z.object({\n apiBaseUrl: z\n .string()\n .optional()\n .describe(\n option({\n description: \"Curly API base URL. Default: CNGKIT_API_BASE_URL or https://curly.ng\",\n valueDescription: \"url\",\n })\n ),\n});\n\nexport const JsonOutputOptionsSchema = GlobalOptionsSchema.extend({\n json: z\n .boolean()\n .optional()\n .describe(\n option({\n description: \"Print raw JSON\",\n })\n ),\n});\n\nexport const OptionalPathArgsSchema = z.tuple([\n z\n .string()\n .optional()\n .describe(\n argument({\n name: \"path\",\n description: \"Path to scan\",\n })\n ),\n]);\n\nexport const OptionalRoomCodeArgsSchema = z.tuple([\n z\n .string()\n .optional()\n .describe(\n argument({\n name: \"room-code\",\n description: \"Room code\",\n })\n ),\n]);\n\nexport const RequiredRoomCodeArgsSchema = z.tuple([\n z.string().describe(\n argument({\n name: \"room-code\",\n description: \"Room code\",\n })\n ),\n]);\n\nexport const OptionalQueryArgsSchema = z.tuple([\n z\n .string()\n .optional()\n .describe(\n argument({\n name: \"query\",\n description: \"Optional query\",\n })\n ),\n]);\n\nexport const RequiredQueryArgsSchema = z.array(\n z.string().describe(\n argument({\n name: \"query\",\n description: \"Search query\",\n })\n )\n);\n\nexport const RequiredFilePathArgsSchema = z.tuple([\n z.string().describe(\n argument({\n name: \"file-path\",\n description: \"Catalog file path\",\n })\n ),\n]);\n\nexport const RequiredPatternArgsSchema = z.array(\n z.string().describe(\n argument({\n name: \"pattern\",\n description: \"Search pattern\",\n })\n )\n);\n\nexport const OptionalGlobPatternArgsSchema = z.array(\n z.string().describe(\n argument({\n name: \"pattern\",\n description: \"Glob pattern\",\n })\n )\n);\n\nexport const LimitOptionsSchema = JsonOutputOptionsSchema.extend({\n limit: z\n .number()\n .optional()\n .describe(\n option({\n description: \"Maximum results\",\n valueDescription: \"n\",\n })\n ),\n});\n\nexport const TranscriptArgsSchema = z.array(\n z.string().describe(\n argument({\n name: \"transcript-args\",\n description: \"Transcript action and arguments\",\n })\n )\n);\n"],"mappings":";AAAA,SAAS,UAAU,cAAc;AACjC,SAAS,SAAS;AAEX,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,YAAY,EACT,OAAO,EACP,SAAS,EACT;AAAA,IACC,OAAO;AAAA,MACL,aAAa;AAAA,MACb,kBAAkB;AAAA,IACpB,CAAC;AAAA,EACH;AACJ,CAAC;AAEM,IAAM,0BAA0B,oBAAoB,OAAO;AAAA,EAChE,MAAM,EACH,QAAQ,EACR,SAAS,EACT;AAAA,IACC,OAAO;AAAA,MACL,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACJ,CAAC;AAEM,IAAM,yBAAyB,EAAE,MAAM;AAAA,EAC5C,EACG,OAAO,EACP,SAAS,EACT;AAAA,IACC,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACJ,CAAC;AAEM,IAAM,6BAA6B,EAAE,MAAM;AAAA,EAChD,EACG,OAAO,EACP,SAAS,EACT;AAAA,IACC,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACJ,CAAC;AAEM,IAAM,6BAA6B,EAAE,MAAM;AAAA,EAChD,EAAE,OAAO,EAAE;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACF,CAAC;AAEM,IAAM,0BAA0B,EAAE,MAAM;AAAA,EAC7C,EACG,OAAO,EACP,SAAS,EACT;AAAA,IACC,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACJ,CAAC;AAEM,IAAM,0BAA0B,EAAE;AAAA,EACvC,EAAE,OAAO,EAAE;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACF;AAEO,IAAM,6BAA6B,EAAE,MAAM;AAAA,EAChD,EAAE,OAAO,EAAE;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACF,CAAC;AAEM,IAAM,4BAA4B,EAAE;AAAA,EACzC,EAAE,OAAO,EAAE;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACF;AAEO,IAAM,gCAAgC,EAAE;AAAA,EAC7C,EAAE,OAAO,EAAE;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACF;AAEO,IAAM,qBAAqB,wBAAwB,OAAO;AAAA,EAC/D,OAAO,EACJ,OAAO,EACP,SAAS,EACT;AAAA,IACC,OAAO;AAAA,MACL,aAAa;AAAA,MACb,kBAAkB;AAAA,IACpB,CAAC;AAAA,EACH;AACJ,CAAC;AAEM,IAAM,uBAAuB,EAAE;AAAA,EACpC,EAAE,OAAO,EAAE;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/cli/options.ts"],"sourcesContent":["import { argument, option } from \"pastel\";\nimport { z } from \"zod\";\n\nexport const GlobalOptionsSchema = z.object({\n apiBaseUrl: z\n .string()\n .optional()\n .describe(\n option({\n description: \"Curly API base URL. Default: CNGKIT_API_BASE_URL or https://curly.ng\",\n valueDescription: \"url\",\n })\n ),\n});\n\nexport const JsonOutputOptionsSchema = GlobalOptionsSchema.extend({\n json: z\n .boolean()\n .optional()\n .describe(\n option({\n description: \"Print raw JSON\",\n })\n ),\n});\n\nexport const OptionalPathArgsSchema = z.tuple([\n z\n .string()\n .optional()\n .describe(\n argument({\n name: \"path\",\n description: \"Path to scan\",\n })\n ),\n]);\n\nexport const OptionalRoomCodeArgsSchema = z.tuple([\n z\n .string()\n .optional()\n .describe(\n argument({\n name: \"room-code\",\n description: \"Room code\",\n })\n ),\n]);\n\nexport const RequiredRoomCodeArgsSchema = z.tuple([\n z.string().describe(\n argument({\n name: \"room-code\",\n description: \"Room code\",\n })\n ),\n]);\n\nexport const OptionalQueryArgsSchema = z.tuple([\n z\n .string()\n .optional()\n .describe(\n argument({\n name: \"query\",\n description: \"Optional query\",\n })\n ),\n]);\n\nexport const RequiredQueryArgsSchema = z.array(\n z.string().describe(\n argument({\n name: \"query\",\n description: \"Search query\",\n })\n )\n);\n\nexport const RequiredFilePathArgsSchema = z.tuple([\n z.string().describe(\n argument({\n name: \"file-path\",\n description: \"Catalog file path\",\n })\n ),\n]);\n\nexport const RequiredPatternArgsSchema = z.array(\n z.string().describe(\n argument({\n name: \"pattern\",\n description: \"Search pattern\",\n })\n )\n);\n\nexport const OptionalGlobPatternArgsSchema = z.array(\n z.string().describe(\n argument({\n name: \"pattern\",\n description: \"Glob pattern\",\n })\n )\n);\n\nexport const LimitOptionsSchema = JsonOutputOptionsSchema.extend({\n limit: z\n .number()\n .optional()\n .describe(\n option({\n description: \"Maximum results\",\n valueDescription: \"n\",\n })\n ),\n});\n\nexport const TranscriptArgsSchema = z.array(\n z.string().describe(\n argument({\n name: \"transcript-args\",\n description: \"Transcript action and arguments\",\n })\n )\n);\n"],"mappings":";AAAA,SAAS,UAAU,cAAc;AACjC,SAAS,SAAS;AAEX,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,YAAY,EACT,OAAO,EACP,SAAS,EACT;AAAA,IACC,OAAO;AAAA,MACL,aAAa;AAAA,MACb,kBAAkB;AAAA,IACpB,CAAC;AAAA,EACH;AACJ,CAAC;AAEM,IAAM,0BAA0B,oBAAoB,OAAO;AAAA,EAChE,MAAM,EACH,QAAQ,EACR,SAAS,EACT;AAAA,IACC,OAAO;AAAA,MACL,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACJ,CAAC;AAEM,IAAM,yBAAyB,EAAE,MAAM;AAAA,EAC5C,EACG,OAAO,EACP,SAAS,EACT;AAAA,IACC,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACJ,CAAC;AAEM,IAAM,6BAA6B,EAAE,MAAM;AAAA,EAChD,EACG,OAAO,EACP,SAAS,EACT;AAAA,IACC,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACJ,CAAC;AAEM,IAAM,6BAA6B,EAAE,MAAM;AAAA,EAChD,EAAE,OAAO,EAAE;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACF,CAAC;AAEM,IAAM,0BAA0B,EAAE,MAAM;AAAA,EAC7C,EACG,OAAO,EACP,SAAS,EACT;AAAA,IACC,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACJ,CAAC;AAEM,IAAM,0BAA0B,EAAE;AAAA,EACvC,EAAE,OAAO,EAAE;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACF;AAEO,IAAM,6BAA6B,EAAE,MAAM;AAAA,EAChD,EAAE,OAAO,EAAE;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACF,CAAC;AAEM,IAAM,4BAA4B,EAAE;AAAA,EACzC,EAAE,OAAO,EAAE;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACF;AAEO,IAAM,gCAAgC,EAAE;AAAA,EAC7C,EAAE,OAAO,EAAE;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACF;AAEO,IAAM,qBAAqB,wBAAwB,OAAO;AAAA,EAC/D,OAAO,EACJ,OAAO,EACP,SAAS,EACT;AAAA,IACC,OAAO;AAAA,MACL,aAAa;AAAA,MACb,kBAAkB;AAAA,IACpB,CAAC;AAAA,EACH;AACJ,CAAC;AAEM,IAAM,uBAAuB,EAAE;AAAA,EACpC,EAAE,OAAO,EAAE;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACF;","names":[]}