cngkit 1.1.7 → 1.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +261 -82
- package/dist/{chunk-EQEIX7N5.js → chunk-575IBOIA.js} +2 -2
- package/dist/{chunk-EQEIX7N5.js.map → chunk-575IBOIA.js.map} +1 -1
- package/dist/{chunk-QEZQGKFX.js → chunk-CHSTTMTO.js} +2 -2
- package/dist/{chunk-TZKXST4G.js → chunk-LWZPSJVC.js} +48 -20
- package/dist/chunk-LWZPSJVC.js.map +1 -0
- package/dist/{chunk-Z4DDLEWR.js → chunk-NTF45QBC.js} +4 -12
- package/dist/chunk-NTF45QBC.js.map +1 -0
- package/dist/{chunk-HUZZPV5E.js → chunk-OKKJBRUU.js} +16 -12
- package/dist/chunk-OKKJBRUU.js.map +1 -0
- package/dist/chunk-OTQRKCFP.js +139 -0
- package/dist/chunk-OTQRKCFP.js.map +1 -0
- package/dist/{chunk-VI5XQH3U.js → chunk-WPBMAXXM.js} +3 -3
- package/dist/{chunk-VI5XQH3U.js.map → chunk-WPBMAXXM.js.map} +1 -1
- package/dist/cli.js +8 -8
- package/dist/cli.js.map +1 -1
- package/dist/commands/coderoom/index.js +4 -4
- package/dist/commands/coderoom/index.js.map +1 -1
- package/dist/commands/coderoom/join.js +5 -5
- package/dist/commands/coderoom/share.js +5 -5
- package/dist/commands/index.js +4 -4
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/knowledges/audiences.js +6 -6
- package/dist/commands/knowledges/files.js +6 -6
- package/dist/commands/knowledges/glob.js +6 -6
- package/dist/commands/knowledges/grep.js +6 -6
- package/dist/commands/knowledges/index.js +4 -4
- package/dist/commands/knowledges/index.js.map +1 -1
- package/dist/commands/knowledges/list.js +6 -6
- package/dist/commands/knowledges/read.js +6 -6
- package/dist/commands/knowledges/search.js +6 -6
- package/dist/commands/knowledges/status.js +6 -6
- package/dist/commands/login.js +5 -5
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/scrub.js +7 -7
- package/dist/commands/scrub.js.map +1 -1
- package/dist/commands/transcripts.js +9 -9
- package/dist/commands/transcripts.js.map +1 -1
- package/package.json +6 -1
- package/dist/chunk-HUZZPV5E.js.map +0 -1
- package/dist/chunk-TZKXST4G.js.map +0 -1
- package/dist/chunk-XDXRVTPK.js +0 -18
- package/dist/chunk-XDXRVTPK.js.map +0 -1
- package/dist/chunk-Z4DDLEWR.js.map +0 -1
- /package/dist/{chunk-QEZQGKFX.js.map → chunk-CHSTTMTO.js.map} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
createCommandOutput,
|
|
2
3
|
formatError
|
|
3
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-OTQRKCFP.js";
|
|
4
5
|
|
|
5
6
|
// src/cli/command-runner.tsx
|
|
6
7
|
import { useEffect } from "react";
|
|
@@ -8,16 +9,7 @@ import { useApp } from "ink";
|
|
|
8
9
|
function CommandRunner({ run }) {
|
|
9
10
|
const { exit } = useApp();
|
|
10
11
|
useEffect(() => {
|
|
11
|
-
const output =
|
|
12
|
-
info(message) {
|
|
13
|
-
process.stdout.write(`${message}
|
|
14
|
-
`);
|
|
15
|
-
},
|
|
16
|
-
error(message) {
|
|
17
|
-
process.stderr.write(`${message}
|
|
18
|
-
`);
|
|
19
|
-
}
|
|
20
|
-
};
|
|
12
|
+
const output = createCommandOutput(process.stdout, process.stderr);
|
|
21
13
|
void run(output).catch((error) => {
|
|
22
14
|
process.exitCode = 1;
|
|
23
15
|
output.error(formatError(error));
|
|
@@ -31,4 +23,4 @@ function CommandRunner({ run }) {
|
|
|
31
23
|
export {
|
|
32
24
|
CommandRunner
|
|
33
25
|
};
|
|
34
|
-
//# sourceMappingURL=chunk-
|
|
26
|
+
//# sourceMappingURL=chunk-NTF45QBC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/command-runner.tsx"],"sourcesContent":["import { useEffect } from \"react\";\nimport { useApp } from \"ink\";\n\nimport { createCommandOutput, formatError, type CommandOutput } from \"../shared/output.js\";\n\ntype CommandRunnerProps = {\n readonly run: (output: CommandOutput) => Promise<void>;\n};\n\nexport function CommandRunner({ run }: CommandRunnerProps) {\n const { exit } = useApp();\n\n useEffect(() => {\n const output = createCommandOutput(process.stdout, process.stderr);\n\n void run(output)\n .catch((error: unknown) => {\n process.exitCode = 1;\n output.error(formatError(error));\n })\n .finally(() => {\n exit();\n });\n }, [exit, run]);\n\n return null;\n}\n"],"mappings":";;;;;;AAAA,SAAS,iBAAiB;AAC1B,SAAS,cAAc;AAQhB,SAAS,cAAc,EAAE,IAAI,GAAuB;AACzD,QAAM,EAAE,KAAK,IAAI,OAAO;AAExB,YAAU,MAAM;AACd,UAAM,SAAS,oBAAoB,QAAQ,QAAQ,QAAQ,MAAM;AAEjE,SAAK,IAAI,MAAM,EACZ,MAAM,CAAC,UAAmB;AACzB,cAAQ,WAAW;AACnB,aAAO,MAAM,YAAY,KAAK,CAAC;AAAA,IACjC,CAAC,EACA,QAAQ,MAAM;AACb,WAAK;AAAA,IACP,CAAC;AAAA,EACL,GAAG,CAAC,MAAM,GAAG,CAAC;AAEd,SAAO;AACT;","names":[]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
readBackendHealth
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-CHSTTMTO.js";
|
|
4
4
|
import {
|
|
5
5
|
createPeerId,
|
|
6
6
|
createRoomCode,
|
|
7
7
|
resolveApiBaseUrl
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-575IBOIA.js";
|
|
9
9
|
|
|
10
10
|
// src/features/coderoom/run-coderoom-command.ts
|
|
11
11
|
import process2 from "process";
|
|
@@ -227,9 +227,9 @@ async function startSyncSession(options) {
|
|
|
227
227
|
const suppressionTracker = createSuppressionTracker();
|
|
228
228
|
const webSocketUrl = createSyncWebSocketUrl(options.apiBaseUrl, options.roomCode);
|
|
229
229
|
const socket = new WebSocket(webSocketUrl);
|
|
230
|
-
options.output.
|
|
230
|
+
options.output.success(`Room: ${options.roomCode}`);
|
|
231
231
|
options.output.info(`Repo: ${repoContext.rootDir}`);
|
|
232
|
-
options.output.
|
|
232
|
+
options.output.muted(`Peer: ${peerId}`);
|
|
233
233
|
const watcherContext = {
|
|
234
234
|
repoContext,
|
|
235
235
|
socket,
|
|
@@ -289,7 +289,7 @@ async function sendInitialSnapshot(socket, repoContext, peerId, output) {
|
|
|
289
289
|
sentAt: Date.now(),
|
|
290
290
|
fileCount
|
|
291
291
|
});
|
|
292
|
-
output.
|
|
292
|
+
output.success(`sent snapshot ${fileCount} files`);
|
|
293
293
|
}
|
|
294
294
|
async function sendLocalFileChange(context, absolutePath) {
|
|
295
295
|
const relativePath = toRepoRelativePath(context.repoContext.rootDir, absolutePath);
|
|
@@ -301,7 +301,7 @@ async function sendLocalFileChange(context, absolutePath) {
|
|
|
301
301
|
return;
|
|
302
302
|
}
|
|
303
303
|
sendMessage(context.socket, message);
|
|
304
|
-
context.output.
|
|
304
|
+
context.output.muted(`sent file ${relativePath}`);
|
|
305
305
|
}
|
|
306
306
|
async function sendLocalDelete(context, absolutePath) {
|
|
307
307
|
const relativePath = toRepoRelativePath(context.repoContext.rootDir, absolutePath);
|
|
@@ -318,7 +318,7 @@ async function sendLocalDelete(context, absolutePath) {
|
|
|
318
318
|
mtimeMs: Date.now(),
|
|
319
319
|
sentAt: Date.now()
|
|
320
320
|
});
|
|
321
|
-
context.output.
|
|
321
|
+
context.output.warning(`sent delete ${relativePath}`);
|
|
322
322
|
}
|
|
323
323
|
async function handleRemoteMessage(options) {
|
|
324
324
|
const decodedMessage = decodeSyncMessage(options.data.toString());
|
|
@@ -330,11 +330,11 @@ async function handleRemoteMessage(options) {
|
|
|
330
330
|
return;
|
|
331
331
|
}
|
|
332
332
|
if (decodedMessage.type === "snapshot-complete") {
|
|
333
|
-
options.output.
|
|
333
|
+
options.output.success(`peer snapshot complete ${decodedMessage.fileCount} files`);
|
|
334
334
|
return;
|
|
335
335
|
}
|
|
336
336
|
await applyRemoteMessage(options.repoContext, decodedMessage, options.suppressionTracker);
|
|
337
|
-
options.output.
|
|
337
|
+
options.output.success(`applied ${decodedMessage.type} ${decodedMessage.path}`);
|
|
338
338
|
}
|
|
339
339
|
async function waitForSessionClose(socket, watcher) {
|
|
340
340
|
await new Promise((resolve, reject) => {
|
|
@@ -379,7 +379,7 @@ async function waitForSessionClose(socket, watcher) {
|
|
|
379
379
|
// src/features/coderoom/run-coderoom-command.ts
|
|
380
380
|
async function runShareCommand(roomCode, options, output) {
|
|
381
381
|
const syncRoomCode = roomCode ?? createRoomCode();
|
|
382
|
-
output.
|
|
382
|
+
output.success(`Share code: ${syncRoomCode}`);
|
|
383
383
|
await printBackendStatus(options, output);
|
|
384
384
|
await runSyncSession("share", syncRoomCode, options, output);
|
|
385
385
|
}
|
|
@@ -392,7 +392,11 @@ async function runJoinCommand(roomCode, options, output) {
|
|
|
392
392
|
}
|
|
393
393
|
async function printBackendStatus(options, output) {
|
|
394
394
|
const health = await readBackendHealth(options);
|
|
395
|
-
|
|
395
|
+
if (health.ok) {
|
|
396
|
+
output.success(`API: ${health.service} ready`);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
output.warning(`API: unavailable (${health.message})`);
|
|
396
400
|
}
|
|
397
401
|
async function runSyncSession(role, roomCode, options, output) {
|
|
398
402
|
await startSyncSession({
|
|
@@ -408,4 +412,4 @@ export {
|
|
|
408
412
|
runShareCommand,
|
|
409
413
|
runJoinCommand
|
|
410
414
|
};
|
|
411
|
-
//# sourceMappingURL=chunk-
|
|
415
|
+
//# sourceMappingURL=chunk-OKKJBRUU.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.success(`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 if (health.ok) {\n output.success(`API: ${health.service} ready`);\n return;\n }\n\n output.warning(`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.success(`Room: ${options.roomCode}`);\n options.output.info(`Repo: ${repoContext.rootDir}`);\n options.output.muted(`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.success(`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.muted(`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.warning(`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.success(`peer snapshot complete ${decodedMessage.fileCount} files`);\n return;\n }\n\n await applyRemoteMessage(options.repoContext, decodedMessage, options.suppressionTracker);\n options.output.success(`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"]}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// src/shared/output.ts
|
|
2
|
+
import process from "process";
|
|
3
|
+
import { Marked } from "marked";
|
|
4
|
+
import { markedTerminal } from "marked-terminal";
|
|
5
|
+
import { createElement } from "react";
|
|
6
|
+
import { renderToString, Text } from "ink";
|
|
7
|
+
|
|
8
|
+
// src/shared/theme.ts
|
|
9
|
+
import { Chalk } from "chalk";
|
|
10
|
+
var statusStylePropsByOutputStyle = {
|
|
11
|
+
info: {
|
|
12
|
+
color: "cyan"
|
|
13
|
+
},
|
|
14
|
+
success: {
|
|
15
|
+
color: "green",
|
|
16
|
+
bold: true
|
|
17
|
+
},
|
|
18
|
+
warning: {
|
|
19
|
+
color: "yellow",
|
|
20
|
+
bold: true
|
|
21
|
+
},
|
|
22
|
+
muted: {
|
|
23
|
+
dimColor: true
|
|
24
|
+
},
|
|
25
|
+
error: {
|
|
26
|
+
color: "red",
|
|
27
|
+
bold: true
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
function createMarkdownTheme(useColor) {
|
|
31
|
+
const chalk = new Chalk({ level: useColor ? 1 : 0 });
|
|
32
|
+
return {
|
|
33
|
+
code: chalk.yellow,
|
|
34
|
+
blockquote: chalk.gray.italic,
|
|
35
|
+
html: chalk.gray,
|
|
36
|
+
heading: chalk.cyan.bold,
|
|
37
|
+
firstHeading: chalk.green.bold,
|
|
38
|
+
hr: chalk.dim,
|
|
39
|
+
listitem: chalk.reset,
|
|
40
|
+
table: chalk.reset,
|
|
41
|
+
paragraph: chalk.reset,
|
|
42
|
+
strong: chalk.bold,
|
|
43
|
+
em: chalk.italic,
|
|
44
|
+
codespan: chalk.yellow,
|
|
45
|
+
del: chalk.dim.strikethrough,
|
|
46
|
+
link: chalk.cyan,
|
|
47
|
+
href: chalk.blue.underline,
|
|
48
|
+
text: chalk.reset,
|
|
49
|
+
showSectionPrefix: true,
|
|
50
|
+
reflowText: true,
|
|
51
|
+
unescape: true,
|
|
52
|
+
emoji: false,
|
|
53
|
+
tab: 2
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/shared/output.ts
|
|
58
|
+
var consoleOutput = createCommandOutput(process.stdout, process.stderr);
|
|
59
|
+
function createCommandOutput(stdout, stderr) {
|
|
60
|
+
return {
|
|
61
|
+
info(message) {
|
|
62
|
+
writeStyledMessage(stdout, "info", message);
|
|
63
|
+
},
|
|
64
|
+
success(message) {
|
|
65
|
+
writeStyledMessage(stdout, "success", message);
|
|
66
|
+
},
|
|
67
|
+
warning(message) {
|
|
68
|
+
writeStyledMessage(stdout, "warning", message);
|
|
69
|
+
},
|
|
70
|
+
muted(message) {
|
|
71
|
+
writeStyledMessage(stdout, "muted", message);
|
|
72
|
+
},
|
|
73
|
+
markdown(message) {
|
|
74
|
+
stdout.write(`${formatMarkdownMessage(stdout, message)}
|
|
75
|
+
`);
|
|
76
|
+
},
|
|
77
|
+
raw(message) {
|
|
78
|
+
stdout.write(`${message}
|
|
79
|
+
`);
|
|
80
|
+
},
|
|
81
|
+
error(message) {
|
|
82
|
+
writeStyledMessage(stderr, "error", message);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function formatError(error) {
|
|
87
|
+
return error instanceof Error ? error.message : String(error);
|
|
88
|
+
}
|
|
89
|
+
function writeStyledMessage(stream, style, message) {
|
|
90
|
+
stream.write(`${formatStyledMessage(stream, style, message)}
|
|
91
|
+
`);
|
|
92
|
+
}
|
|
93
|
+
function formatStyledMessage(stream, style, message) {
|
|
94
|
+
if (!shouldRenderColor(stream)) {
|
|
95
|
+
return message;
|
|
96
|
+
}
|
|
97
|
+
return renderToString(
|
|
98
|
+
createElement(
|
|
99
|
+
Text,
|
|
100
|
+
{
|
|
101
|
+
...statusStylePropsByOutputStyle[style],
|
|
102
|
+
wrap: "wrap"
|
|
103
|
+
},
|
|
104
|
+
message
|
|
105
|
+
),
|
|
106
|
+
{
|
|
107
|
+
columns: 1e4
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
function formatMarkdownMessage(stream, markdown) {
|
|
112
|
+
if (stream.isTTY !== true) {
|
|
113
|
+
return markdown;
|
|
114
|
+
}
|
|
115
|
+
const parser = new Marked();
|
|
116
|
+
parser.use(
|
|
117
|
+
markedTerminal({
|
|
118
|
+
...createMarkdownTheme(shouldRenderColor(stream)),
|
|
119
|
+
width: clampMarkdownWidth(stream.columns)
|
|
120
|
+
})
|
|
121
|
+
);
|
|
122
|
+
return String(parser.parse(markdown)).trimEnd();
|
|
123
|
+
}
|
|
124
|
+
function shouldRenderColor(stream) {
|
|
125
|
+
return stream.isTTY === true && process.env.NO_COLOR === void 0;
|
|
126
|
+
}
|
|
127
|
+
function clampMarkdownWidth(columns) {
|
|
128
|
+
if (columns === void 0) {
|
|
129
|
+
return 100;
|
|
130
|
+
}
|
|
131
|
+
return Math.max(72, Math.min(columns, 120));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export {
|
|
135
|
+
consoleOutput,
|
|
136
|
+
createCommandOutput,
|
|
137
|
+
formatError
|
|
138
|
+
};
|
|
139
|
+
//# sourceMappingURL=chunk-OTQRKCFP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/output.ts","../src/shared/theme.ts"],"sourcesContent":["import process from \"node:process\";\nimport { Marked, type MarkedExtension } from \"marked\";\nimport { markedTerminal } from \"marked-terminal\";\nimport { createElement } from \"react\";\nimport { renderToString, Text } from \"ink\";\nimport {\n createMarkdownTheme,\n statusStylePropsByOutputStyle,\n type OutputStyle,\n} from \"./theme.js\";\n\ntype OutputStream = NodeJS.WriteStream & {\n isTTY?: boolean;\n columns?: number;\n};\n\nexport type CommandOutput = {\n info(message: string): void;\n success(message: string): void;\n warning(message: string): void;\n muted(message: string): void;\n markdown(message: string): void;\n raw(message: string): void;\n error(message: string): void;\n};\n\nexport const consoleOutput = createCommandOutput(process.stdout, process.stderr);\n\nexport function createCommandOutput(stdout: OutputStream, stderr: OutputStream): CommandOutput {\n return {\n info(message) {\n writeStyledMessage(stdout, \"info\", message);\n },\n success(message) {\n writeStyledMessage(stdout, \"success\", message);\n },\n warning(message) {\n writeStyledMessage(stdout, \"warning\", message);\n },\n muted(message) {\n writeStyledMessage(stdout, \"muted\", message);\n },\n markdown(message) {\n stdout.write(`${formatMarkdownMessage(stdout, message)}\\n`);\n },\n raw(message) {\n stdout.write(`${message}\\n`);\n },\n error(message) {\n writeStyledMessage(stderr, \"error\", message);\n },\n };\n}\n\nexport function formatError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction writeStyledMessage(stream: OutputStream, style: OutputStyle, message: string): void {\n stream.write(`${formatStyledMessage(stream, style, message)}\\n`);\n}\n\nfunction formatStyledMessage(stream: OutputStream, style: OutputStyle, message: string): string {\n if (!shouldRenderColor(stream)) {\n return message;\n }\n\n return renderToString(\n createElement(\n Text,\n {\n ...statusStylePropsByOutputStyle[style],\n wrap: \"wrap\",\n },\n message\n ),\n {\n columns: 10_000,\n }\n );\n}\n\nfunction formatMarkdownMessage(stream: OutputStream, markdown: string): string {\n if (stream.isTTY !== true) {\n return markdown;\n }\n\n const parser = new Marked();\n parser.use(\n markedTerminal({\n ...createMarkdownTheme(shouldRenderColor(stream)),\n width: clampMarkdownWidth(stream.columns),\n }) as unknown as MarkedExtension\n );\n\n return String(parser.parse(markdown)).trimEnd();\n}\n\nfunction shouldRenderColor(stream: OutputStream): boolean {\n return stream.isTTY === true && process.env.NO_COLOR === undefined;\n}\n\nfunction clampMarkdownWidth(columns: number | undefined): number {\n if (columns === undefined) {\n return 100;\n }\n\n return Math.max(72, Math.min(columns, 120));\n}\n","import { Chalk } from \"chalk\";\nimport type { TextProps } from \"ink\";\n\nexport type OutputStyle = \"info\" | \"success\" | \"warning\" | \"muted\" | \"error\";\n\nexport const statusStylePropsByOutputStyle = {\n info: {\n color: \"cyan\",\n },\n success: {\n color: \"green\",\n bold: true,\n },\n warning: {\n color: \"yellow\",\n bold: true,\n },\n muted: {\n dimColor: true,\n },\n error: {\n color: \"red\",\n bold: true,\n },\n} satisfies Record<OutputStyle, TextProps>;\n\nexport function createMarkdownTheme(useColor: boolean) {\n const chalk = new Chalk({ level: useColor ? 1 : 0 });\n\n return {\n code: chalk.yellow,\n blockquote: chalk.gray.italic,\n html: chalk.gray,\n heading: chalk.cyan.bold,\n firstHeading: chalk.green.bold,\n hr: chalk.dim,\n listitem: chalk.reset,\n table: chalk.reset,\n paragraph: chalk.reset,\n strong: chalk.bold,\n em: chalk.italic,\n codespan: chalk.yellow,\n del: chalk.dim.strikethrough,\n link: chalk.cyan,\n href: chalk.blue.underline,\n text: chalk.reset,\n showSectionPrefix: true,\n reflowText: true,\n unescape: true,\n emoji: false,\n tab: 2,\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -420,7 +420,7 @@ cngkit knowledges grep <pattern> [--path <path>] [--include <glob>] [--output-mo
|
|
|
420
420
|
## Inputs
|
|
421
421
|
|
|
422
422
|
- \`pattern\`: JavaScript regular expression source.
|
|
423
|
-
- \`--path\`: catalog path prefix. Default:
|
|
423
|
+
- \`--path\`: catalog path prefix. Default: \`skills\`.
|
|
424
424
|
- \`--include\`: filename include filter. Default: \`*\`.
|
|
425
425
|
- Modes: content, files_with_matches, or count.
|
|
426
426
|
- \`--output-mode\`: \`content\`, \`files_with_matches\`, or \`count\`. Default: \`content\`.
|
|
@@ -458,7 +458,7 @@ cngkit knowledges glob [pattern] [--path <path>] [--json]
|
|
|
458
458
|
## Inputs
|
|
459
459
|
|
|
460
460
|
- \`pattern\`: supported glob pattern. CLI default: \`**/*.md\`.
|
|
461
|
-
- \`--path\`: catalog path prefix. Default:
|
|
461
|
+
- \`--path\`: catalog path prefix. Default: \`skills\`.
|
|
462
462
|
|
|
463
463
|
## Supported Patterns
|
|
464
464
|
|
|
@@ -506,4 +506,4 @@ export {
|
|
|
506
506
|
formatCngkitHelp,
|
|
507
507
|
formatKnowledgesHelp
|
|
508
508
|
};
|
|
509
|
-
//# sourceMappingURL=chunk-
|
|
509
|
+
//# sourceMappingURL=chunk-WPBMAXXM.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/help-specs.ts"],"sourcesContent":["type HelpTopic = {\n title: string;\n aliases: string[];\n body: string;\n};\n\nconst commandList = [\n \"`cngkit login` - open Curly.ng login.\",\n \"`cngkit coderoom ...` - unite developers in a live shared code room.\",\n \"`cngkit scrub [path]` - scan for secrets and optionally mask them inline.\",\n \"`cngkit transcripts ...` - list, read, and grep local Claude/Codex transcripts.\",\n \"`cngkit knowledges ...` - read the hosted Harness catalog.\",\n].join(\"\\n\");\n\nconst coderoomCommandList = [\n \"`share [room-code]` - start a live room from the current directory.\",\n \"`join <room-code>` - join another developer's live room from the current directory.\",\n].join(\"\\n\");\n\nconst knowledgesCommandList = [\n \"`status` - print remote catalog state.\",\n \"`audiences` - list valid audience filters.\",\n \"`search <query>` - semantic search over Cloudflare Vectorize-backed records.\",\n \"`list [query]` - list known subskills.\",\n \"`files [query]` - list uploaded catalog files.\",\n \"`read <file-path>` - Claude-style file read.\",\n \"`grep <pattern>` - Claude-style content search.\",\n \"`glob [pattern]` - Claude-style file discovery.\",\n].join(\"\\n\");\n\nconst helpTopics: HelpTopic[] = [\n {\n title: \"cngkit\",\n aliases: [\"\", \"overview\", \"help\"],\n body: `# cngkit\n\nCurly.ng operator CLI for backend-connected repo sync, secret scrubbing, and Harness knowledges access.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit <command> [options]\n\\`\\`\\`\n\n## Commands\n\n${commandList}\n\n## Progressive Help\n\n\\`\\`\\`bash\ncngkit <command> --help\ncngkit coderoom --help\ncngkit coderoom <subcommand> --help\ncngkit transcripts --help\ncngkit knowledges --help\ncngkit knowledges <subcommand> --help\n\\`\\`\\`\n\nThe CLI intentionally prints plain Markdown or line-oriented text with no color-only state, tables that require terminal width, or hidden interactive prompts. Add \\`--json\\` to read-only knowledges commands when another agent or tool needs structured backend data.\n\n## Backend\n\nDefault API: \\`https://curly.ng\\`\n\nOverride with:\n\n\\`\\`\\`bash\ncngkit --api-base-url <url> ...\nCNGKIT_API_BASE_URL=<url> cngkit ...\n\\`\\`\\`\n`,\n },\n {\n title: \"login\",\n aliases: [\"login\"],\n body: `# cngkit login\n\nOpen Curly.ng login in a browser. In headless environments, print the URL so an agent can surface it to the operator.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit login\n\\`\\`\\`\n\n## Output Contract\n\n- First line names the login URL being opened.\n- If no local browser opener exists, the CLI prints a direct URL.\n- No credentials are printed or persisted by this command.\n`,\n },\n {\n title: \"transcripts\",\n aliases: [\"transcripts\", \"transcript\"],\n body: `# cngkit transcripts\n\nRead local agent transcript JSONL files from \\`~/.codex/sessions\\`, \\`~/.codex/archived_sessions\\`, \\`~/.claude/projects\\`, and \\`~/.claude/history.jsonl\\`.\n\nThis is local operator tooling. It does not call the Curly backend and it does not upload transcript content.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit transcripts list [--source all|codex|claude] [--limit <n>] [--json]\ncngkit transcripts read <path-or-session-id> [--source all|codex|claude] [--limit <n>] [--include-internal] [--json]\ncngkit transcripts grep <query> [--source all|codex|claude] [--limit <n>] [--file-limit <n>] [--include-internal] [--json]\n\\`\\`\\`\n\n## Defaults\n\n- \\`list\\`: newest 12 transcript files.\n- \\`read\\`: newest 80 user/assistant entries from the selected file.\n- \\`grep\\`: first 80 matching user/assistant entries from the newest 60 files.\n- \\`--source\\`: \\`all\\`.\n\n## Output Contract\n\n- Text mode prints source, role, timestamp when available, and extracted message text.\n- Internal developer/system payloads and hook/tool noise are skipped unless \\`--include-internal\\` is passed.\n- Direct file paths, home-relative paths, and partial session ids are accepted by \\`read\\`.\n`,\n },\n {\n title: \"coderoom\",\n aliases: [\"coderoom\", \"code-room\", \"repo-sync\"],\n body: `# cngkit coderoom\n\nCoderoom is the fast way to unite developers around one working tree. It gives a pair or team a temporary shared room over the Curly backend so one developer can share local file changes and another can join from their own machine.\n\nIt is intentionally closer to a Drive-like project room than a raw socket command: the room code is the shared folder link, each connected machine is a collaborator, and the file stream is the activity feed. The browser experience at \\`/coderoom\\` provides the helper surface for copying commands and explaining the room model.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit coderoom <subcommand> [options]\n\\`\\`\\`\n\n## Subcommands\n\n${coderoomCommandList}\n\n## Common Flow\n\n\\`\\`\\`bash\ncngkit coderoom share\ncngkit coderoom join <room-code>\n\\`\\`\\`\n\n## Backend Contract\n\n- Connects to \\`/api/cng/sync/:roomCode\\` on the configured Curly backend.\n- Uses WebSocket transport backed by the \\`CngSyncRoom\\` Durable Object.\n- Sends an initial snapshot, then file and delete events.\n- Last received change wins.\n- Current rooms are live relays, not durable cloud storage. The Drive-like frontend is the collaboration shell around that live primitive.\n`,\n },\n {\n title: \"coderoom share\",\n aliases: [\"coderoom-share\"],\n body: `# cngkit coderoom share\n\nStart a real-time repository sync room from the current directory.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit coderoom share [room-code]\n\\`\\`\\`\n\n## Backend Contract\n\n- Connects to \\`/api/cng/sync/:roomCode\\` on the configured Curly backend.\n- Uses WebSocket transport backed by the \\`CngSyncRoom\\` Durable Object.\n- Sends an initial snapshot, then file and delete events.\n- Last received change wins.\n\n## Filesystem Contract\n\n- Preserves \\`.git/\\`.\n- Preserves files ignored by the repo's \\`.gitignore\\`.\n- Sends regular files as base64 payloads in the sync protocol.\n\n## Output Contract\n\n- Prints room code, repo root, peer id, backend health, and concise sync events.\n- Keeps running until the socket closes or the process receives a termination signal.\n`,\n },\n {\n title: \"coderoom join\",\n aliases: [\"coderoom-join\"],\n body: `# cngkit coderoom join\n\nJoin an existing real-time repository sync room in the current directory.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit coderoom join <room-code>\n\\`\\`\\`\n\n## Backend Contract\n\nSame transport and filesystem contract as \\`cngkit coderoom share\\`. The supplied room code selects the Durable Object room.\n\n## Output Contract\n\n- Prints backend health, room code, repo root, peer id, and concise sync events.\n- Missing room code exits with a usage error.\n`,\n },\n {\n title: \"scrub\",\n aliases: [\"scrub\"],\n body: `# cngkit scrub\n\nScan a file or directory for secrets with TruffleHog. Report-only is the default. Inline masking requires \\`--yes\\`.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit scrub [path]\ncngkit scrub [path] --yes\n\\`\\`\\`\n\n## Requirements\n\n- \\`trufflehog\\` must be available on \\`PATH\\`.\n\n## Safety Contract\n\n- Default mode does not rewrite files.\n- \\`--yes\\` rewrites detected secret values inline with \\`[CNGKIT_SECRET:<detector>:<verified|unverified>]\\` placeholders.\n- \\`--mask\\` is accepted as a compatibility alias, but still requires \\`--yes\\`.\n- Raw and redacted secret values are never printed in the report.\n`,\n },\n {\n title: \"knowledges\",\n aliases: [\"knowledges\", \"knowledge\"],\n body: `# cngkit knowledges\n\nRead the hosted Harness knowledges catalog from the Curly backend. These commands are read-only and use the generated \\`@cng/client\\` SDK against public backend routes.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges <subcommand> [options]\n\\`\\`\\`\n\n## Subcommands\n\n${knowledgesCommandList}\n\n## Progressive Help\n\n\\`\\`\\`bash\ncngkit knowledges <subcommand> --help\ncngkit knowledges read --help\ncngkit knowledges grep --help\ncngkit knowledges glob --help\n\\`\\`\\`\n\n## Common Examples\n\n\\`\\`\\`bash\ncngkit knowledges search \"cloudflare backend\" --limit 3\ncngkit knowledges read /libraries/lib-cloudflare/SUBSKILL.md --limit 80\ncngkit knowledges grep Cloudflare --path /libraries/lib-cloudflare --output-mode files_with_matches\ncngkit knowledges glob \"**/*.md\" --path /libraries/lib-cloudflare\n\\`\\`\\`\n\n## AI-Friendly Output\n\n- Default output is line-oriented and intended to be directly usable by agents.\n- \\`read\\` prints file content with no wrapper before any truncation note.\n- \\`grep --output-mode content\\` prints \\`path:line\\` blocks.\n- \\`grep --output-mode files_with_matches\\` and \\`glob\\` print one path per line.\n- \\`--json\\` prints the typed backend data payload for machine consumption.\n`,\n },\n {\n title: \"knowledges status\",\n aliases: [\"knowledges-status\", \"status\"],\n body: `# cngkit knowledges status\n\nPrint remote Harness catalog state from \\`GET /api/harness/knowledges/catalog\\`.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges status [--json]\n\\`\\`\\`\n\n## Output Contract\n\n- Text mode prints catalog name, file count, blob count, Vectorize binding, and latest run when present.\n- \\`--json\\` prints the backend data payload.\n`,\n },\n {\n title: \"knowledges audiences\",\n aliases: [\"knowledges-audiences\", \"audiences\"],\n body: `# cngkit knowledges audiences\n\nList valid audience filters from \\`GET /api/harness/knowledges/audiences\\`.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges audiences [--json]\n\\`\\`\\`\n\nUse this before \\`cngkit knowledges files --audience <id>\\`.\n`,\n },\n {\n title: \"knowledges search\",\n aliases: [\"knowledges-search\", \"search\"],\n body: `# cngkit knowledges search\n\nRun semantic search against the Cloudflare Vectorize-backed Harness index.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges search <query> [--limit <n>] [--json]\n\\`\\`\\`\n\n## Defaults\n\n- \\`--limit\\`: \\`5\\`\n\n## Example\n\n\\`\\`\\`bash\ncngkit knowledges search \"cloudflare backend\" --limit 3\n\\`\\`\\`\n`,\n },\n {\n title: \"knowledges list\",\n aliases: [\"knowledges-list\", \"list\"],\n body: `# cngkit knowledges list\n\nList known subskills from \\`GET /api/harness/knowledges/subskills\\`, optionally filtered locally by query.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges list [query] [--limit <n>] [--json]\n\\`\\`\\`\n\n## Defaults\n\n- \\`--limit\\`: \\`25\\`\n`,\n },\n {\n title: \"knowledges files\",\n aliases: [\"knowledges-files\", \"files\"],\n body: `# cngkit knowledges files\n\nList uploaded catalog files from \\`GET /api/harness/knowledges/files\\`.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges files [query] [--audience <id>] [--limit <n>] [--json]\n\\`\\`\\`\n\n## Defaults\n\n- \\`--limit\\`: \\`25\\`\n- \\`--audience\\`: omitted\n\nRun \\`cngkit knowledges audiences\\` to discover supported audience ids.\n`,\n },\n {\n title: \"knowledges read\",\n aliases: [\"knowledges-read\", \"read\"],\n body: `# cngkit knowledges read\n\nClaude-style read tool for hosted Harness catalog files. Backed by \\`GET /api/harness/filesystem/read\\` and \\`HarnessReadQuerySchema\\`.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges read <file-path> [--offset <n>] [--limit <n>] [--json]\n\\`\\`\\`\n\n## Inputs\n\n- \\`file-path\\`: normalized catalog path. Shorthand paths such as \\`/libraries/lib-cloudflare/SUBSKILL.md\\` are expanded to \\`skills/knowledges/subskills/libraries/lib-cloudflare/SUBSKILL.md\\`.\n- \\`--offset\\`: zero-based starting line. Default: \\`0\\`.\n- \\`--limit\\`: maximum lines. Default in CLI: \\`200\\`. Backend max: \\`2000\\`.\n\n## Output Contract\n\n- Text mode prints only the returned file content first.\n- If truncated, a final bracketed truncation note is printed after the content.\n- \\`--json\\` prints \\`{ file_path, content, total_lines, offset, limit, truncated }\\`.\n\n## Example\n\n\\`\\`\\`bash\ncngkit knowledges read /libraries/lib-cloudflare/SUBSKILL.md --limit 80\n\\`\\`\\`\n`,\n },\n {\n title: \"knowledges grep\",\n aliases: [\"knowledges-grep\", \"grep\"],\n body: `# cngkit knowledges grep\n\nClaude-style grep tool for hosted Harness catalog files. Backed by \\`GET /api/harness/filesystem/grep\\` and \\`HarnessGrepQuerySchema\\`.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges grep <pattern> [--path <path>] [--include <glob>] [--output-mode <mode>] [--context <n>] [--case-insensitive] [--json]\n\\`\\`\\`\n\n## Inputs\n\n- \\`pattern\\`: JavaScript regular expression source.\n- \\`--path\\`: catalog path prefix. Default: \\`/\\`.\n- \\`--include\\`: filename include filter. Default: \\`*\\`.\n- Modes: content, files_with_matches, or count.\n- \\`--output-mode\\`: \\`content\\`, \\`files_with_matches\\`, or \\`count\\`. Default: \\`content\\`.\n- \\`--context\\`: context lines around content matches. Default: \\`0\\`. Backend max: \\`20\\`.\n- \\`--case-insensitive\\`: maps to backend \\`case_insensitive=true\\`.\n\n## Output Contract\n\n- \\`content\\`: prints blocks as \\`file_path:line_number\\`, optional context lines, then \\`> matching line\\`.\n- \\`files_with_matches\\`: prints one matching file path per line.\n- \\`count\\`: prints \\`file_path: match_count\\` lines.\n- \\`--json\\` prints the typed backend response union.\n\n## Examples\n\n\\`\\`\\`bash\ncngkit knowledges grep Cloudflare --path /libraries/lib-cloudflare --output-mode files_with_matches\ncngkit knowledges grep \"Vectorize|D1\" --path /libraries/lib-cloudflare --context 2\n\\`\\`\\`\n`,\n },\n {\n title: \"knowledges glob\",\n aliases: [\"knowledges-glob\", \"glob\"],\n body: `# cngkit knowledges glob\n\nClaude-style glob tool for hosted Harness catalog files. Backed by \\`GET /api/harness/filesystem/glob\\` and \\`HarnessGlobQuerySchema\\`.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges glob [pattern] [--path <path>] [--json]\n\\`\\`\\`\n\n## Inputs\n\n- \\`pattern\\`: supported glob pattern. CLI default: \\`**/*.md\\`.\n- \\`--path\\`: catalog path prefix. Default: \\`/\\`.\n\n## Supported Patterns\n\n- \\`**/*.md\\`\n- \\`**/*.SUBSKILL.md\\`\n- \\`**/SKILL.md\\`\n- \\`*.md\\`\n- \\`*.SUBSKILL.md\\`\n- \\`SKILL.md\\`\n\n## Output Contract\n\n- Text mode prints one file path per line.\n- If truncated, a final bracketed truncation note is printed.\n- \\`--json\\` prints \\`{ files, total_files, truncated }\\`.\n\n## Example\n\n\\`\\`\\`bash\ncngkit knowledges glob \"**/*.md\" --path /libraries/lib-cloudflare\n\\`\\`\\`\n`,\n },\n];\n\nconst helpTopicByAlias = new Map<string, HelpTopic>();\n\nfor (const topic of helpTopics) {\n for (const alias of topic.aliases) {\n helpTopicByAlias.set(alias, topic);\n }\n}\n\nexport function formatCngkitHelp(topicName?: string): string {\n const normalizedTopicName = normalizeHelpTopicName(topicName);\n return (helpTopicByAlias.get(normalizedTopicName) ?? helpTopicByAlias.get(\"\"))?.body.trim() ?? \"\";\n}\n\nexport function formatKnowledgesHelp(topicName?: string): string {\n const normalizedTopicName = normalizeHelpTopicName(topicName);\n const topicKey = normalizedTopicName ? `knowledges-${normalizedTopicName}` : \"knowledges\";\n return formatCngkitHelp(topicKey);\n}\n\nfunction normalizeHelpTopicName(value: string | undefined): string {\n return value?.trim().toLowerCase().replace(/\\s+/g, \"-\") ?? \"\";\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/help-specs.ts"],"sourcesContent":["type HelpTopic = {\n title: string;\n aliases: string[];\n body: string;\n};\n\nconst commandList = [\n \"`cngkit login` - open Curly.ng login.\",\n \"`cngkit coderoom ...` - unite developers in a live shared code room.\",\n \"`cngkit scrub [path]` - scan for secrets and optionally mask them inline.\",\n \"`cngkit transcripts ...` - list, read, and grep local Claude/Codex transcripts.\",\n \"`cngkit knowledges ...` - read the hosted Harness catalog.\",\n].join(\"\\n\");\n\nconst coderoomCommandList = [\n \"`share [room-code]` - start a live room from the current directory.\",\n \"`join <room-code>` - join another developer's live room from the current directory.\",\n].join(\"\\n\");\n\nconst knowledgesCommandList = [\n \"`status` - print remote catalog state.\",\n \"`audiences` - list valid audience filters.\",\n \"`search <query>` - semantic search over Cloudflare Vectorize-backed records.\",\n \"`list [query]` - list known subskills.\",\n \"`files [query]` - list uploaded catalog files.\",\n \"`read <file-path>` - Claude-style file read.\",\n \"`grep <pattern>` - Claude-style content search.\",\n \"`glob [pattern]` - Claude-style file discovery.\",\n].join(\"\\n\");\n\nconst helpTopics: HelpTopic[] = [\n {\n title: \"cngkit\",\n aliases: [\"\", \"overview\", \"help\"],\n body: `# cngkit\n\nCurly.ng operator CLI for backend-connected repo sync, secret scrubbing, and Harness knowledges access.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit <command> [options]\n\\`\\`\\`\n\n## Commands\n\n${commandList}\n\n## Progressive Help\n\n\\`\\`\\`bash\ncngkit <command> --help\ncngkit coderoom --help\ncngkit coderoom <subcommand> --help\ncngkit transcripts --help\ncngkit knowledges --help\ncngkit knowledges <subcommand> --help\n\\`\\`\\`\n\nThe CLI intentionally prints plain Markdown or line-oriented text with no color-only state, tables that require terminal width, or hidden interactive prompts. Add \\`--json\\` to read-only knowledges commands when another agent or tool needs structured backend data.\n\n## Backend\n\nDefault API: \\`https://curly.ng\\`\n\nOverride with:\n\n\\`\\`\\`bash\ncngkit --api-base-url <url> ...\nCNGKIT_API_BASE_URL=<url> cngkit ...\n\\`\\`\\`\n`,\n },\n {\n title: \"login\",\n aliases: [\"login\"],\n body: `# cngkit login\n\nOpen Curly.ng login in a browser. In headless environments, print the URL so an agent can surface it to the operator.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit login\n\\`\\`\\`\n\n## Output Contract\n\n- First line names the login URL being opened.\n- If no local browser opener exists, the CLI prints a direct URL.\n- No credentials are printed or persisted by this command.\n`,\n },\n {\n title: \"transcripts\",\n aliases: [\"transcripts\", \"transcript\"],\n body: `# cngkit transcripts\n\nRead local agent transcript JSONL files from \\`~/.codex/sessions\\`, \\`~/.codex/archived_sessions\\`, \\`~/.claude/projects\\`, and \\`~/.claude/history.jsonl\\`.\n\nThis is local operator tooling. It does not call the Curly backend and it does not upload transcript content.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit transcripts list [--source all|codex|claude] [--limit <n>] [--json]\ncngkit transcripts read <path-or-session-id> [--source all|codex|claude] [--limit <n>] [--include-internal] [--json]\ncngkit transcripts grep <query> [--source all|codex|claude] [--limit <n>] [--file-limit <n>] [--include-internal] [--json]\n\\`\\`\\`\n\n## Defaults\n\n- \\`list\\`: newest 12 transcript files.\n- \\`read\\`: newest 80 user/assistant entries from the selected file.\n- \\`grep\\`: first 80 matching user/assistant entries from the newest 60 files.\n- \\`--source\\`: \\`all\\`.\n\n## Output Contract\n\n- Text mode prints source, role, timestamp when available, and extracted message text.\n- Internal developer/system payloads and hook/tool noise are skipped unless \\`--include-internal\\` is passed.\n- Direct file paths, home-relative paths, and partial session ids are accepted by \\`read\\`.\n`,\n },\n {\n title: \"coderoom\",\n aliases: [\"coderoom\", \"code-room\", \"repo-sync\"],\n body: `# cngkit coderoom\n\nCoderoom is the fast way to unite developers around one working tree. It gives a pair or team a temporary shared room over the Curly backend so one developer can share local file changes and another can join from their own machine.\n\nIt is intentionally closer to a Drive-like project room than a raw socket command: the room code is the shared folder link, each connected machine is a collaborator, and the file stream is the activity feed. The browser experience at \\`/coderoom\\` provides the helper surface for copying commands and explaining the room model.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit coderoom <subcommand> [options]\n\\`\\`\\`\n\n## Subcommands\n\n${coderoomCommandList}\n\n## Common Flow\n\n\\`\\`\\`bash\ncngkit coderoom share\ncngkit coderoom join <room-code>\n\\`\\`\\`\n\n## Backend Contract\n\n- Connects to \\`/api/cng/sync/:roomCode\\` on the configured Curly backend.\n- Uses WebSocket transport backed by the \\`CngSyncRoom\\` Durable Object.\n- Sends an initial snapshot, then file and delete events.\n- Last received change wins.\n- Current rooms are live relays, not durable cloud storage. The Drive-like frontend is the collaboration shell around that live primitive.\n`,\n },\n {\n title: \"coderoom share\",\n aliases: [\"coderoom-share\"],\n body: `# cngkit coderoom share\n\nStart a real-time repository sync room from the current directory.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit coderoom share [room-code]\n\\`\\`\\`\n\n## Backend Contract\n\n- Connects to \\`/api/cng/sync/:roomCode\\` on the configured Curly backend.\n- Uses WebSocket transport backed by the \\`CngSyncRoom\\` Durable Object.\n- Sends an initial snapshot, then file and delete events.\n- Last received change wins.\n\n## Filesystem Contract\n\n- Preserves \\`.git/\\`.\n- Preserves files ignored by the repo's \\`.gitignore\\`.\n- Sends regular files as base64 payloads in the sync protocol.\n\n## Output Contract\n\n- Prints room code, repo root, peer id, backend health, and concise sync events.\n- Keeps running until the socket closes or the process receives a termination signal.\n`,\n },\n {\n title: \"coderoom join\",\n aliases: [\"coderoom-join\"],\n body: `# cngkit coderoom join\n\nJoin an existing real-time repository sync room in the current directory.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit coderoom join <room-code>\n\\`\\`\\`\n\n## Backend Contract\n\nSame transport and filesystem contract as \\`cngkit coderoom share\\`. The supplied room code selects the Durable Object room.\n\n## Output Contract\n\n- Prints backend health, room code, repo root, peer id, and concise sync events.\n- Missing room code exits with a usage error.\n`,\n },\n {\n title: \"scrub\",\n aliases: [\"scrub\"],\n body: `# cngkit scrub\n\nScan a file or directory for secrets with TruffleHog. Report-only is the default. Inline masking requires \\`--yes\\`.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit scrub [path]\ncngkit scrub [path] --yes\n\\`\\`\\`\n\n## Requirements\n\n- \\`trufflehog\\` must be available on \\`PATH\\`.\n\n## Safety Contract\n\n- Default mode does not rewrite files.\n- \\`--yes\\` rewrites detected secret values inline with \\`[CNGKIT_SECRET:<detector>:<verified|unverified>]\\` placeholders.\n- \\`--mask\\` is accepted as a compatibility alias, but still requires \\`--yes\\`.\n- Raw and redacted secret values are never printed in the report.\n`,\n },\n {\n title: \"knowledges\",\n aliases: [\"knowledges\", \"knowledge\"],\n body: `# cngkit knowledges\n\nRead the hosted Harness knowledges catalog from the Curly backend. These commands are read-only and use the generated \\`@cng/client\\` SDK against public backend routes.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges <subcommand> [options]\n\\`\\`\\`\n\n## Subcommands\n\n${knowledgesCommandList}\n\n## Progressive Help\n\n\\`\\`\\`bash\ncngkit knowledges <subcommand> --help\ncngkit knowledges read --help\ncngkit knowledges grep --help\ncngkit knowledges glob --help\n\\`\\`\\`\n\n## Common Examples\n\n\\`\\`\\`bash\ncngkit knowledges search \"cloudflare backend\" --limit 3\ncngkit knowledges read /libraries/lib-cloudflare/SUBSKILL.md --limit 80\ncngkit knowledges grep Cloudflare --path /libraries/lib-cloudflare --output-mode files_with_matches\ncngkit knowledges glob \"**/*.md\" --path /libraries/lib-cloudflare\n\\`\\`\\`\n\n## AI-Friendly Output\n\n- Default output is line-oriented and intended to be directly usable by agents.\n- \\`read\\` prints file content with no wrapper before any truncation note.\n- \\`grep --output-mode content\\` prints \\`path:line\\` blocks.\n- \\`grep --output-mode files_with_matches\\` and \\`glob\\` print one path per line.\n- \\`--json\\` prints the typed backend data payload for machine consumption.\n`,\n },\n {\n title: \"knowledges status\",\n aliases: [\"knowledges-status\", \"status\"],\n body: `# cngkit knowledges status\n\nPrint remote Harness catalog state from \\`GET /api/harness/knowledges/catalog\\`.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges status [--json]\n\\`\\`\\`\n\n## Output Contract\n\n- Text mode prints catalog name, file count, blob count, Vectorize binding, and latest run when present.\n- \\`--json\\` prints the backend data payload.\n`,\n },\n {\n title: \"knowledges audiences\",\n aliases: [\"knowledges-audiences\", \"audiences\"],\n body: `# cngkit knowledges audiences\n\nList valid audience filters from \\`GET /api/harness/knowledges/audiences\\`.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges audiences [--json]\n\\`\\`\\`\n\nUse this before \\`cngkit knowledges files --audience <id>\\`.\n`,\n },\n {\n title: \"knowledges search\",\n aliases: [\"knowledges-search\", \"search\"],\n body: `# cngkit knowledges search\n\nRun semantic search against the Cloudflare Vectorize-backed Harness index.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges search <query> [--limit <n>] [--json]\n\\`\\`\\`\n\n## Defaults\n\n- \\`--limit\\`: \\`5\\`\n\n## Example\n\n\\`\\`\\`bash\ncngkit knowledges search \"cloudflare backend\" --limit 3\n\\`\\`\\`\n`,\n },\n {\n title: \"knowledges list\",\n aliases: [\"knowledges-list\", \"list\"],\n body: `# cngkit knowledges list\n\nList known subskills from \\`GET /api/harness/knowledges/subskills\\`, optionally filtered locally by query.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges list [query] [--limit <n>] [--json]\n\\`\\`\\`\n\n## Defaults\n\n- \\`--limit\\`: \\`25\\`\n`,\n },\n {\n title: \"knowledges files\",\n aliases: [\"knowledges-files\", \"files\"],\n body: `# cngkit knowledges files\n\nList uploaded catalog files from \\`GET /api/harness/knowledges/files\\`.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges files [query] [--audience <id>] [--limit <n>] [--json]\n\\`\\`\\`\n\n## Defaults\n\n- \\`--limit\\`: \\`25\\`\n- \\`--audience\\`: omitted\n\nRun \\`cngkit knowledges audiences\\` to discover supported audience ids.\n`,\n },\n {\n title: \"knowledges read\",\n aliases: [\"knowledges-read\", \"read\"],\n body: `# cngkit knowledges read\n\nClaude-style read tool for hosted Harness catalog files. Backed by \\`GET /api/harness/filesystem/read\\` and \\`HarnessReadQuerySchema\\`.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges read <file-path> [--offset <n>] [--limit <n>] [--json]\n\\`\\`\\`\n\n## Inputs\n\n- \\`file-path\\`: normalized catalog path. Shorthand paths such as \\`/libraries/lib-cloudflare/SUBSKILL.md\\` are expanded to \\`skills/knowledges/subskills/libraries/lib-cloudflare/SUBSKILL.md\\`.\n- \\`--offset\\`: zero-based starting line. Default: \\`0\\`.\n- \\`--limit\\`: maximum lines. Default in CLI: \\`200\\`. Backend max: \\`2000\\`.\n\n## Output Contract\n\n- Text mode prints only the returned file content first.\n- If truncated, a final bracketed truncation note is printed after the content.\n- \\`--json\\` prints \\`{ file_path, content, total_lines, offset, limit, truncated }\\`.\n\n## Example\n\n\\`\\`\\`bash\ncngkit knowledges read /libraries/lib-cloudflare/SUBSKILL.md --limit 80\n\\`\\`\\`\n`,\n },\n {\n title: \"knowledges grep\",\n aliases: [\"knowledges-grep\", \"grep\"],\n body: `# cngkit knowledges grep\n\nClaude-style grep tool for hosted Harness catalog files. Backed by \\`GET /api/harness/filesystem/grep\\` and \\`HarnessGrepQuerySchema\\`.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges grep <pattern> [--path <path>] [--include <glob>] [--output-mode <mode>] [--context <n>] [--case-insensitive] [--json]\n\\`\\`\\`\n\n## Inputs\n\n- \\`pattern\\`: JavaScript regular expression source.\n- \\`--path\\`: catalog path prefix. Default: \\`skills\\`.\n- \\`--include\\`: filename include filter. Default: \\`*\\`.\n- Modes: content, files_with_matches, or count.\n- \\`--output-mode\\`: \\`content\\`, \\`files_with_matches\\`, or \\`count\\`. Default: \\`content\\`.\n- \\`--context\\`: context lines around content matches. Default: \\`0\\`. Backend max: \\`20\\`.\n- \\`--case-insensitive\\`: maps to backend \\`case_insensitive=true\\`.\n\n## Output Contract\n\n- \\`content\\`: prints blocks as \\`file_path:line_number\\`, optional context lines, then \\`> matching line\\`.\n- \\`files_with_matches\\`: prints one matching file path per line.\n- \\`count\\`: prints \\`file_path: match_count\\` lines.\n- \\`--json\\` prints the typed backend response union.\n\n## Examples\n\n\\`\\`\\`bash\ncngkit knowledges grep Cloudflare --path /libraries/lib-cloudflare --output-mode files_with_matches\ncngkit knowledges grep \"Vectorize|D1\" --path /libraries/lib-cloudflare --context 2\n\\`\\`\\`\n`,\n },\n {\n title: \"knowledges glob\",\n aliases: [\"knowledges-glob\", \"glob\"],\n body: `# cngkit knowledges glob\n\nClaude-style glob tool for hosted Harness catalog files. Backed by \\`GET /api/harness/filesystem/glob\\` and \\`HarnessGlobQuerySchema\\`.\n\n## Usage\n\n\\`\\`\\`bash\ncngkit knowledges glob [pattern] [--path <path>] [--json]\n\\`\\`\\`\n\n## Inputs\n\n- \\`pattern\\`: supported glob pattern. CLI default: \\`**/*.md\\`.\n- \\`--path\\`: catalog path prefix. Default: \\`skills\\`.\n\n## Supported Patterns\n\n- \\`**/*.md\\`\n- \\`**/*.SUBSKILL.md\\`\n- \\`**/SKILL.md\\`\n- \\`*.md\\`\n- \\`*.SUBSKILL.md\\`\n- \\`SKILL.md\\`\n\n## Output Contract\n\n- Text mode prints one file path per line.\n- If truncated, a final bracketed truncation note is printed.\n- \\`--json\\` prints \\`{ files, total_files, truncated }\\`.\n\n## Example\n\n\\`\\`\\`bash\ncngkit knowledges glob \"**/*.md\" --path /libraries/lib-cloudflare\n\\`\\`\\`\n`,\n },\n];\n\nconst helpTopicByAlias = new Map<string, HelpTopic>();\n\nfor (const topic of helpTopics) {\n for (const alias of topic.aliases) {\n helpTopicByAlias.set(alias, topic);\n }\n}\n\nexport function formatCngkitHelp(topicName?: string): string {\n const normalizedTopicName = normalizeHelpTopicName(topicName);\n return (helpTopicByAlias.get(normalizedTopicName) ?? helpTopicByAlias.get(\"\"))?.body.trim() ?? \"\";\n}\n\nexport function formatKnowledgesHelp(topicName?: string): string {\n const normalizedTopicName = normalizeHelpTopicName(topicName);\n const topicKey = normalizedTopicName ? `knowledges-${normalizedTopicName}` : \"knowledges\";\n return formatCngkitHelp(topicKey);\n}\n\nfunction normalizeHelpTopicName(value: string | undefined): string {\n return value?.trim().toLowerCase().replace(/\\s+/g, \"-\") ?? \"\";\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli.js
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import {
|
|
3
3
|
formatCngkitHelp,
|
|
4
4
|
formatKnowledgesHelp
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-WPBMAXXM.js";
|
|
6
6
|
import {
|
|
7
7
|
packageVersion
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-575IBOIA.js";
|
|
9
9
|
import {
|
|
10
10
|
consoleOutput,
|
|
11
11
|
formatError
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-OTQRKCFP.js";
|
|
13
13
|
import "./chunk-PZ5AY32C.js";
|
|
14
14
|
|
|
15
15
|
// src/cli.ts
|
|
@@ -20,13 +20,13 @@ import Pastel from "pastel";
|
|
|
20
20
|
function printMarkdownHelpIfRequested(argv, output = consoleOutput) {
|
|
21
21
|
const commandName = argv[2];
|
|
22
22
|
if (commandName === void 0 || commandName === "--help" || commandName === "-h") {
|
|
23
|
-
output.
|
|
23
|
+
output.markdown(formatCngkitHelp());
|
|
24
24
|
return true;
|
|
25
25
|
}
|
|
26
26
|
if (commandName === "help") {
|
|
27
27
|
const [topicName, subtopicName] = argv.slice(3);
|
|
28
28
|
const topic = (topicName === "knowledges" || topicName === "coderoom") && subtopicName ? `${topicName}-${subtopicName}` : topicName;
|
|
29
|
-
output.
|
|
29
|
+
output.markdown(formatCngkitHelp(topic));
|
|
30
30
|
return true;
|
|
31
31
|
}
|
|
32
32
|
const commandArgs = argv.slice(3);
|
|
@@ -36,15 +36,15 @@ function printMarkdownHelpIfRequested(argv, output = consoleOutput) {
|
|
|
36
36
|
}
|
|
37
37
|
if (commandName === "knowledges") {
|
|
38
38
|
const topic = commandArgs.find((argument, index) => index !== helpIndex && !argument.startsWith("-"));
|
|
39
|
-
output.
|
|
39
|
+
output.markdown(formatKnowledgesHelp(topic));
|
|
40
40
|
return true;
|
|
41
41
|
}
|
|
42
42
|
if (commandName === "coderoom") {
|
|
43
43
|
const topic = commandArgs.find((argument, index) => index !== helpIndex && !argument.startsWith("-"));
|
|
44
|
-
output.
|
|
44
|
+
output.markdown(formatCngkitHelp(topic ? `coderoom-${topic}` : "coderoom"));
|
|
45
45
|
return true;
|
|
46
46
|
}
|
|
47
|
-
output.
|
|
47
|
+
output.markdown(formatCngkitHelp(commandName));
|
|
48
48
|
return true;
|
|
49
49
|
}
|
|
50
50
|
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/cli/help.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport process from \"node:process\";\n\nimport Pastel from \"pastel\";\n\nimport { printMarkdownHelpIfRequested } from \"./cli/help.js\";\nimport { packageVersion } from \"./shared/config.js\";\nimport { formatError } from \"./shared/output.js\";\n\nconst normalizedArgv = normalizeGlobalOptions(process.argv);\n\nif (printMarkdownHelpIfRequested(normalizedArgv)) {\n process.exit(0);\n}\n\nconst app = new Pastel({\n importMeta: import.meta,\n name: \"cngkit\",\n version: packageVersion,\n description: \"Opinionated Curly.ng CLI kit for Coderoom collaboration and website tooling.\",\n});\n\ntry {\n await app.run(normalizedArgv);\n} catch (error) {\n console.error(formatError(error));\n process.exitCode = 1;\n}\n\nfunction normalizeGlobalOptions(argv: string[]): string[] {\n const normalizedArgv = [...argv];\n\n for (let index = 2; index < normalizedArgv.length; index += 1) {\n const argument = normalizedArgv[index];\n\n if (argument === \"--api-base-url\") {\n const value = normalizedArgv[index + 1];\n if (!value || value.startsWith(\"-\")) {\n throw new Error(\"Missing value for --api-base-url\");\n }\n\n process.env.CNGKIT_API_BASE_URL = value;\n normalizedArgv.splice(index, 2);\n index -= 1;\n continue;\n }\n\n if (argument.startsWith(\"--api-base-url=\")) {\n process.env.CNGKIT_API_BASE_URL = argument.slice(\"--api-base-url=\".length);\n normalizedArgv.splice(index, 1);\n index -= 1;\n }\n }\n\n return normalizedArgv;\n}\n","import { formatCngkitHelp, formatKnowledgesHelp } from \"./help-specs.js\";\nimport { consoleOutput, type CommandOutput } from \"../shared/output.js\";\n\nexport function printMarkdownHelpIfRequested(\n argv: string[],\n output: CommandOutput = consoleOutput\n): boolean {\n const commandName = argv[2];\n\n if (commandName === undefined || commandName === \"--help\" || commandName === \"-h\") {\n output.
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/cli/help.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport process from \"node:process\";\n\nimport Pastel from \"pastel\";\n\nimport { printMarkdownHelpIfRequested } from \"./cli/help.js\";\nimport { packageVersion } from \"./shared/config.js\";\nimport { formatError } from \"./shared/output.js\";\n\nconst normalizedArgv = normalizeGlobalOptions(process.argv);\n\nif (printMarkdownHelpIfRequested(normalizedArgv)) {\n process.exit(0);\n}\n\nconst app = new Pastel({\n importMeta: import.meta,\n name: \"cngkit\",\n version: packageVersion,\n description: \"Opinionated Curly.ng CLI kit for Coderoom collaboration and website tooling.\",\n});\n\ntry {\n await app.run(normalizedArgv);\n} catch (error) {\n console.error(formatError(error));\n process.exitCode = 1;\n}\n\nfunction normalizeGlobalOptions(argv: string[]): string[] {\n const normalizedArgv = [...argv];\n\n for (let index = 2; index < normalizedArgv.length; index += 1) {\n const argument = normalizedArgv[index];\n\n if (argument === \"--api-base-url\") {\n const value = normalizedArgv[index + 1];\n if (!value || value.startsWith(\"-\")) {\n throw new Error(\"Missing value for --api-base-url\");\n }\n\n process.env.CNGKIT_API_BASE_URL = value;\n normalizedArgv.splice(index, 2);\n index -= 1;\n continue;\n }\n\n if (argument.startsWith(\"--api-base-url=\")) {\n process.env.CNGKIT_API_BASE_URL = argument.slice(\"--api-base-url=\".length);\n normalizedArgv.splice(index, 1);\n index -= 1;\n }\n }\n\n return normalizedArgv;\n}\n","import { formatCngkitHelp, formatKnowledgesHelp } from \"./help-specs.js\";\nimport { consoleOutput, type CommandOutput } from \"../shared/output.js\";\n\nexport function printMarkdownHelpIfRequested(\n argv: string[],\n output: CommandOutput = consoleOutput\n): boolean {\n const commandName = argv[2];\n\n if (commandName === undefined || commandName === \"--help\" || commandName === \"-h\") {\n output.markdown(formatCngkitHelp());\n return true;\n }\n\n if (commandName === \"help\") {\n const [topicName, subtopicName] = argv.slice(3);\n const topic =\n (topicName === \"knowledges\" || topicName === \"coderoom\") && subtopicName\n ? `${topicName}-${subtopicName}`\n : topicName;\n output.markdown(formatCngkitHelp(topic));\n return true;\n }\n\n const commandArgs = argv.slice(3);\n const helpIndex = commandArgs.findIndex((argument) => argument === \"--help\" || argument === \"-h\");\n\n if (helpIndex < 0) {\n return false;\n }\n\n if (commandName === \"knowledges\") {\n const topic = commandArgs.find((argument, index) => index !== helpIndex && !argument.startsWith(\"-\"));\n output.markdown(formatKnowledgesHelp(topic));\n return true;\n }\n\n if (commandName === \"coderoom\") {\n const topic = commandArgs.find((argument, index) => index !== helpIndex && !argument.startsWith(\"-\"));\n output.markdown(formatCngkitHelp(topic ? `coderoom-${topic}` : \"coderoom\"));\n return true;\n }\n\n output.markdown(formatCngkitHelp(commandName));\n return true;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAEA,OAAO,aAAa;AAEpB,OAAO,YAAY;;;ACDZ,SAAS,6BACd,MACA,SAAwB,eACf;AACT,QAAM,cAAc,KAAK,CAAC;AAE1B,MAAI,gBAAgB,UAAa,gBAAgB,YAAY,gBAAgB,MAAM;AACjF,WAAO,SAAS,iBAAiB,CAAC;AAClC,WAAO;AAAA,EACT;AAEA,MAAI,gBAAgB,QAAQ;AAC1B,UAAM,CAAC,WAAW,YAAY,IAAI,KAAK,MAAM,CAAC;AAC9C,UAAM,SACH,cAAc,gBAAgB,cAAc,eAAe,eACxD,GAAG,SAAS,IAAI,YAAY,KAC5B;AACN,WAAO,SAAS,iBAAiB,KAAK,CAAC;AACvC,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,KAAK,MAAM,CAAC;AAChC,QAAM,YAAY,YAAY,UAAU,CAAC,aAAa,aAAa,YAAY,aAAa,IAAI;AAEhG,MAAI,YAAY,GAAG;AACjB,WAAO;AAAA,EACT;AAEA,MAAI,gBAAgB,cAAc;AAChC,UAAM,QAAQ,YAAY,KAAK,CAAC,UAAU,UAAU,UAAU,aAAa,CAAC,SAAS,WAAW,GAAG,CAAC;AACpG,WAAO,SAAS,qBAAqB,KAAK,CAAC;AAC3C,WAAO;AAAA,EACT;AAEA,MAAI,gBAAgB,YAAY;AAC9B,UAAM,QAAQ,YAAY,KAAK,CAAC,UAAU,UAAU,UAAU,aAAa,CAAC,SAAS,WAAW,GAAG,CAAC;AACpG,WAAO,SAAS,iBAAiB,QAAQ,YAAY,KAAK,KAAK,UAAU,CAAC;AAC1E,WAAO;AAAA,EACT;AAEA,SAAO,SAAS,iBAAiB,WAAW,CAAC;AAC7C,SAAO;AACT;;;ADnCA,IAAM,iBAAiB,uBAAuB,QAAQ,IAAI;AAE1D,IAAI,6BAA6B,cAAc,GAAG;AAChD,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,MAAM,IAAI,OAAO;AAAA,EACrB,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AACf,CAAC;AAED,IAAI;AACF,QAAM,IAAI,IAAI,cAAc;AAC9B,SAAS,OAAO;AACd,UAAQ,MAAM,YAAY,KAAK,CAAC;AAChC,UAAQ,WAAW;AACrB;AAEA,SAAS,uBAAuB,MAA0B;AACxD,QAAMA,kBAAiB,CAAC,GAAG,IAAI;AAE/B,WAAS,QAAQ,GAAG,QAAQA,gBAAe,QAAQ,SAAS,GAAG;AAC7D,UAAM,WAAWA,gBAAe,KAAK;AAErC,QAAI,aAAa,kBAAkB;AACjC,YAAM,QAAQA,gBAAe,QAAQ,CAAC;AACtC,UAAI,CAAC,SAAS,MAAM,WAAW,GAAG,GAAG;AACnC,cAAM,IAAI,MAAM,kCAAkC;AAAA,MACpD;AAEA,cAAQ,IAAI,sBAAsB;AAClC,MAAAA,gBAAe,OAAO,OAAO,CAAC;AAC9B,eAAS;AACT;AAAA,IACF;AAEA,QAAI,SAAS,WAAW,iBAAiB,GAAG;AAC1C,cAAQ,IAAI,sBAAsB,SAAS,MAAM,kBAAkB,MAAM;AACzE,MAAAA,gBAAe,OAAO,OAAO,CAAC;AAC9B,eAAS;AAAA,IACX;AAAA,EACF;AAEA,SAAOA;AACT;","names":["normalizedArgv"]}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
formatCngkitHelp
|
|
3
|
-
} from "../../chunk-
|
|
3
|
+
} from "../../chunk-WPBMAXXM.js";
|
|
4
4
|
import {
|
|
5
5
|
GlobalOptionsSchema
|
|
6
6
|
} from "../../chunk-MLKBG5YJ.js";
|
|
7
7
|
import {
|
|
8
8
|
CommandRunner
|
|
9
|
-
} from "../../chunk-
|
|
10
|
-
import "../../chunk-
|
|
9
|
+
} from "../../chunk-NTF45QBC.js";
|
|
10
|
+
import "../../chunk-OTQRKCFP.js";
|
|
11
11
|
import "../../chunk-PZ5AY32C.js";
|
|
12
12
|
|
|
13
13
|
// src/commands/coderoom/index.tsx
|
|
@@ -15,7 +15,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
15
15
|
var description = "Start or join a real-time repo sync room";
|
|
16
16
|
var options = GlobalOptionsSchema;
|
|
17
17
|
function CoderoomCommand() {
|
|
18
|
-
return /* @__PURE__ */ jsx(CommandRunner, { run: async (output) => output.
|
|
18
|
+
return /* @__PURE__ */ jsx(CommandRunner, { run: async (output) => output.markdown(formatCngkitHelp("coderoom")) });
|
|
19
19
|
}
|
|
20
20
|
export {
|
|
21
21
|
CoderoomCommand as default,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/coderoom/index.tsx"],"sourcesContent":["import { GlobalOptionsSchema } from \"../../cli/options.js\";\nimport { formatCngkitHelp } from \"../../cli/help-specs.js\";\nimport { CommandRunner } from \"../../cli/command-runner.js\";\n\nexport const description = \"Start or join a real-time repo sync room\";\nexport const options = GlobalOptionsSchema;\n\nexport default function CoderoomCommand() {\n return <CommandRunner run={async (output) => output.
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/coderoom/index.tsx"],"sourcesContent":["import { GlobalOptionsSchema } from \"../../cli/options.js\";\nimport { formatCngkitHelp } from \"../../cli/help-specs.js\";\nimport { CommandRunner } from \"../../cli/command-runner.js\";\n\nexport const description = \"Start or join a real-time repo sync room\";\nexport const options = GlobalOptionsSchema;\n\nexport default function CoderoomCommand() {\n return <CommandRunner run={async (output) => output.markdown(formatCngkitHelp(\"coderoom\"))} />;\n}\n"],"mappings":";;;;;;;;;;;;;AAQS;AAJF,IAAM,cAAc;AACpB,IAAM,UAAU;AAER,SAAR,kBAAmC;AACxC,SAAO,oBAAC,iBAAc,KAAK,OAAO,WAAW,OAAO,SAAS,iBAAiB,UAAU,CAAC,GAAG;AAC9F;","names":[]}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runJoinCommand
|
|
3
|
-
} from "../../chunk-
|
|
4
|
-
import "../../chunk-
|
|
5
|
-
import "../../chunk-
|
|
3
|
+
} from "../../chunk-OKKJBRUU.js";
|
|
4
|
+
import "../../chunk-CHSTTMTO.js";
|
|
5
|
+
import "../../chunk-575IBOIA.js";
|
|
6
6
|
import {
|
|
7
7
|
GlobalOptionsSchema,
|
|
8
8
|
RequiredRoomCodeArgsSchema
|
|
9
9
|
} from "../../chunk-MLKBG5YJ.js";
|
|
10
10
|
import {
|
|
11
11
|
CommandRunner
|
|
12
|
-
} from "../../chunk-
|
|
13
|
-
import "../../chunk-
|
|
12
|
+
} from "../../chunk-NTF45QBC.js";
|
|
13
|
+
import "../../chunk-OTQRKCFP.js";
|
|
14
14
|
import "../../chunk-PZ5AY32C.js";
|
|
15
15
|
|
|
16
16
|
// src/commands/coderoom/join.tsx
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runShareCommand
|
|
3
|
-
} from "../../chunk-
|
|
4
|
-
import "../../chunk-
|
|
5
|
-
import "../../chunk-
|
|
3
|
+
} from "../../chunk-OKKJBRUU.js";
|
|
4
|
+
import "../../chunk-CHSTTMTO.js";
|
|
5
|
+
import "../../chunk-575IBOIA.js";
|
|
6
6
|
import {
|
|
7
7
|
GlobalOptionsSchema,
|
|
8
8
|
OptionalRoomCodeArgsSchema
|
|
9
9
|
} from "../../chunk-MLKBG5YJ.js";
|
|
10
10
|
import {
|
|
11
11
|
CommandRunner
|
|
12
|
-
} from "../../chunk-
|
|
13
|
-
import "../../chunk-
|
|
12
|
+
} from "../../chunk-NTF45QBC.js";
|
|
13
|
+
import "../../chunk-OTQRKCFP.js";
|
|
14
14
|
import "../../chunk-PZ5AY32C.js";
|
|
15
15
|
|
|
16
16
|
// src/commands/coderoom/share.tsx
|