cngkit 1.1.23 → 1.1.25
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 +9 -7
- package/dist/{chunk-AS7FIJWP.js → chunk-2Y5FMKFS.js} +3 -4
- package/dist/chunk-2Y5FMKFS.js.map +1 -0
- package/dist/{chunk-VMTXY4KQ.js → chunk-3VDQDFHG.js} +14 -6
- package/dist/chunk-3VDQDFHG.js.map +1 -0
- package/dist/{chunk-U725ZHCI.js → chunk-55IPOJ3R.js} +2 -2
- package/dist/{chunk-BXS4IKUA.js → chunk-DDQ5TITN.js} +91 -15
- package/dist/chunk-DDQ5TITN.js.map +1 -0
- package/dist/{chunk-BRFWVQI4.js → chunk-LC4CYVCT.js} +1 -1
- package/dist/chunk-LC4CYVCT.js.map +1 -0
- package/dist/{chunk-YALWTRIP.js → chunk-LNFZT3R3.js} +2 -2
- package/dist/{chunk-JNHW72SU.js → chunk-QCAHQE7Q.js} +14 -9
- package/dist/chunk-QCAHQE7Q.js.map +1 -0
- package/dist/{chunk-WIEYHKQA.js → chunk-TC6YIS5Z.js} +12 -15
- package/dist/chunk-TC6YIS5Z.js.map +1 -0
- package/dist/{chunk-67FUBMNB.js → chunk-X3UQB2CC.js} +2 -2
- package/dist/{chunk-67FUBMNB.js.map → chunk-X3UQB2CC.js.map} +1 -1
- package/dist/{chunk-GYRLVNJX.js → chunk-YIU6G2D3.js} +2 -2
- package/dist/{chunk-3BATDTKU.js → chunk-YPGDQ6P2.js} +2 -4
- package/dist/chunk-YPGDQ6P2.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/coderoom/index.js +3 -3
- package/dist/commands/coderoom/join.js +14 -5
- package/dist/commands/coderoom/join.js.map +1 -1
- package/dist/commands/coderoom/share.js +4 -4
- package/dist/commands/hookify/index.js +3 -3
- package/dist/commands/hookify/ingest.js +3 -3
- package/dist/commands/hooks/index.js +3 -3
- package/dist/commands/hooks/install.js +3 -3
- package/dist/commands/hooks/uninstall.js +3 -3
- package/dist/commands/index.js +3 -3
- package/dist/commands/knowledges/audiences.js +6 -6
- package/dist/commands/knowledges/cat.js +6 -6
- package/dist/commands/knowledges/files.js +6 -6
- package/dist/commands/knowledges/find.js +6 -6
- package/dist/commands/knowledges/find.js.map +1 -1
- package/dist/commands/knowledges/glob.js +5 -5
- package/dist/commands/knowledges/grep.js +5 -5
- package/dist/commands/knowledges/grep.js.map +1 -1
- package/dist/commands/knowledges/head.js +6 -6
- package/dist/commands/knowledges/index.js +3 -3
- package/dist/commands/knowledges/list.js +6 -6
- package/dist/commands/knowledges/ls.js +6 -6
- package/dist/commands/knowledges/ls.js.map +1 -1
- package/dist/commands/knowledges/read.js +5 -5
- package/dist/commands/knowledges/read.js.map +1 -1
- package/dist/commands/knowledges/realpath.js +3 -3
- package/dist/commands/knowledges/realpath.js.map +1 -1
- package/dist/commands/knowledges/search.js +6 -6
- package/dist/commands/knowledges/stat.js +6 -6
- package/dist/commands/knowledges/status.js +6 -6
- package/dist/commands/knowledges/tail.js +6 -6
- package/dist/commands/knowledges/tree.js +6 -6
- package/dist/commands/login.js +2 -2
- package/dist/commands/scrub.js +17 -14
- package/dist/commands/scrub.js.map +1 -1
- package/dist/commands/transcripts.js +37 -27
- package/dist/commands/transcripts.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-3BATDTKU.js.map +0 -1
- package/dist/chunk-AS7FIJWP.js.map +0 -1
- package/dist/chunk-BRFWVQI4.js.map +0 -1
- package/dist/chunk-BXS4IKUA.js.map +0 -1
- package/dist/chunk-JNHW72SU.js.map +0 -1
- package/dist/chunk-VMTXY4KQ.js.map +0 -1
- package/dist/chunk-WIEYHKQA.js.map +0 -1
- /package/dist/{chunk-U725ZHCI.js.map → chunk-55IPOJ3R.js.map} +0 -0
- /package/dist/{chunk-YALWTRIP.js.map → chunk-LNFZT3R3.js.map} +0 -0
- /package/dist/{chunk-GYRLVNJX.js.map → chunk-YIU6G2D3.js.map} +0 -0
|
@@ -7,15 +7,15 @@ import {
|
|
|
7
7
|
} from "../chunk-XQGLUQFM.js";
|
|
8
8
|
import {
|
|
9
9
|
renderCngkitHelp
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-QCAHQE7Q.js";
|
|
11
11
|
import {
|
|
12
12
|
GlobalOptionsSchema,
|
|
13
13
|
TranscriptArgsSchema
|
|
14
14
|
} from "../chunk-25Q463MH.js";
|
|
15
15
|
import {
|
|
16
16
|
CommandRunner
|
|
17
|
-
} from "../chunk-
|
|
18
|
-
import "../chunk-
|
|
17
|
+
} from "../chunk-TC6YIS5Z.js";
|
|
18
|
+
import "../chunk-X3UQB2CC.js";
|
|
19
19
|
import "../chunk-PZ5AY32C.js";
|
|
20
20
|
|
|
21
21
|
// src/commands/transcripts.tsx
|
|
@@ -311,33 +311,43 @@ function parseClaudeEntry(record, parsed, includeInternal) {
|
|
|
311
311
|
// src/features/transcripts/transcript-output.tsx
|
|
312
312
|
import { Box, Text } from "ink";
|
|
313
313
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
314
|
-
function TranscriptRecordList({
|
|
314
|
+
function TranscriptRecordList({
|
|
315
|
+
records
|
|
316
|
+
}) {
|
|
315
317
|
if (records.length === 0) {
|
|
316
318
|
return /* @__PURE__ */ jsx(Text, { color: "yellow", children: "No transcript files found." });
|
|
317
319
|
}
|
|
318
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: records.map((record, index) => /* @__PURE__ */ jsxs(
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
320
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: records.map((record, index) => /* @__PURE__ */ jsxs(
|
|
321
|
+
Box,
|
|
322
|
+
{
|
|
323
|
+
flexDirection: "column",
|
|
324
|
+
marginBottom: 1,
|
|
325
|
+
children: [
|
|
326
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
327
|
+
/* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
|
|
328
|
+
index + 1,
|
|
329
|
+
". "
|
|
330
|
+
] }),
|
|
331
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: record.source }),
|
|
332
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
333
|
+
" ",
|
|
334
|
+
record.updatedAt
|
|
335
|
+
] })
|
|
336
|
+
] }),
|
|
337
|
+
/* @__PURE__ */ jsx(Text, { children: record.filePath }),
|
|
338
|
+
record.sessionId ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
339
|
+
"session ",
|
|
340
|
+
record.sessionId
|
|
341
|
+
] }) : null,
|
|
342
|
+
record.cwd ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
343
|
+
"cwd ",
|
|
344
|
+
record.cwd
|
|
345
|
+
] }) : null,
|
|
346
|
+
record.title ? /* @__PURE__ */ jsx(Text, { children: singleLine(record.title) }) : null
|
|
347
|
+
]
|
|
348
|
+
},
|
|
349
|
+
`${record.source}-${record.filePath}-${index}`
|
|
350
|
+
)) });
|
|
341
351
|
}
|
|
342
352
|
|
|
343
353
|
// src/features/transcripts/run-transcript-command.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/transcripts.tsx","../../src/features/transcripts/run-transcript-command.ts","../../src/features/transcripts/reader.ts","../../src/features/transcripts/jsonl.ts","../../src/features/transcripts/paths.ts","../../src/features/transcripts/discovery.ts","../../src/features/transcripts/types.ts","../../src/features/transcripts/transcript-output.tsx"],"sourcesContent":["import { option } from \"pastel\";\nimport { z } from \"zod\";\n\nimport { GlobalOptionsSchema, TranscriptArgsSchema } from \"../cli/options.js\";\nimport { runTranscriptCommand, type TranscriptCommandOptions } from \"../features/transcripts/run-transcript-command.js\";\nimport { CommandRunner } from \"../cli/command-runner.js\";\n\nexport const description = \"List, read, and grep local Claude/Codex transcript JSONL files\";\nexport const args = TranscriptArgsSchema;\nexport const options = GlobalOptionsSchema.extend({\n source: z\n .enum([\"all\", \"codex\", \"claude\"])\n .optional()\n .describe(\n option({\n description: \"Transcript source. Default: all\",\n valueDescription: \"all|codex|claude\",\n })\n ),\n limit: z\n .number()\n .optional()\n .describe(\n option({\n description: \"Maximum records or entries\",\n valueDescription: \"n\",\n })\n ),\n fileLimit: z\n .number()\n .optional()\n .describe(\n option({\n description: \"Maximum recent files to scan for grep\",\n valueDescription: \"n\",\n })\n ),\n includeInternal: z\n .boolean()\n .optional()\n .describe(\n option({\n description: \"Include developer/system/internal transcript entries\",\n })\n ),\n json: z\n .boolean()\n .optional()\n .describe(\n option({\n description: \"Print raw JSON\",\n })\n ),\n});\n\ntype TranscriptsCommandProps = {\n readonly args: string[];\n readonly options: TranscriptCommandOptions;\n};\n\nexport default function TranscriptsCommand({ args, options }: TranscriptsCommandProps) {\n return <CommandRunner run={(output) => runTranscriptCommand(args, options, output)} />;\n}\n","import { createElement } from \"react\";\n\nimport { renderCngkitHelp } from \"../../cli/help-specs.js\";\nimport {\n coerceLimit,\n formatJson,\n optionalJoinedArgument,\n shouldPrintJson,\n type JsonOutputOptions,\n type NumberOption,\n} from \"../../shared/command-utils.js\";\nimport type { GlobalCommandOptions } from \"../../shared/config.js\";\nimport type { CommandOutput } from \"../../shared/output/types.js\";\nimport {\n grepTranscriptEntries,\n listTranscriptRecords,\n readTranscriptEntries,\n type TranscriptEntry,\n type TranscriptScopeName,\n} from \"./reader.js\";\nimport { TranscriptRecordList } from \"./transcript-output.js\";\n\nexport type TranscriptCommandOptions = GlobalCommandOptions &\n JsonOutputOptions & {\n source?: string;\n limit?: NumberOption;\n fileLimit?: NumberOption;\n includeInternal?: boolean;\n };\n\nexport async function runTranscriptCommand(\n args: string[] | undefined,\n options: TranscriptCommandOptions,\n output: CommandOutput\n): Promise<void> {\n const [action = \"list\", ...actionArgs] = args ?? [];\n const source = normalizeTranscriptSource(options.source);\n const limit = coerceLimit(options.limit, action === \"list\" ? 12 : 80, 500);\n const includeInternal = options.includeInternal === true;\n\n switch (action) {\n case \"help\":\n output.component(renderCngkitHelp(\"transcripts\"));\n return;\n case \"list\": {\n const records = await listTranscriptRecords({ source, limit });\n if (shouldPrintJson(options)) {\n output.raw(formatJson({ records }));\n return;\n }\n\n output.component(createElement(TranscriptRecordList, { records }));\n return;\n }\n case \"read\": {\n const target = actionArgs[0];\n if (!target) {\n throw new Error(\"Missing transcript target. Usage: cngkit transcripts read <path-or-id>\");\n }\n\n const entries = await readTranscriptEntries({\n source,\n target,\n limit,\n includeInternal,\n });\n\n if (shouldPrintJson(options)) {\n output.raw(formatJson({ entries }));\n return;\n }\n\n output.raw(formatTranscriptEntries(entries));\n return;\n }\n case \"grep\": {\n const query = optionalJoinedArgument(actionArgs);\n if (!query) {\n throw new Error(\"Missing query. Usage: cngkit transcripts grep <query>\");\n }\n\n const entries = await grepTranscriptEntries({\n source,\n query,\n limit,\n fileLimit: coerceLimit(options.fileLimit, 60, 5000),\n includeInternal,\n });\n\n if (shouldPrintJson(options)) {\n output.raw(formatJson({ entries }));\n return;\n }\n\n output.raw(formatTranscriptEntries(entries));\n return;\n }\n default:\n throw new Error(\"Unknown transcripts command. Usage: cngkit transcripts <list|read|grep>\");\n }\n}\n\nfunction formatTranscriptEntries(entries: TranscriptEntry[]): string {\n if (entries.length === 0) {\n return \"No transcript entries found.\";\n }\n\n return entries\n .map((entry) => {\n const when = entry.timestamp ? ` ${entry.timestamp}` : \"\";\n return `[${entry.source}] ${entry.role}${when}\\n${entry.text.trim()}`;\n })\n .join(\"\\n\\n\");\n}\n\nfunction normalizeTranscriptSource(value: string | undefined): TranscriptScopeName {\n if (value === undefined) {\n return \"all\";\n }\n\n switch (value) {\n case \"all\":\n case \"codex\":\n case \"claude\":\n return value;\n default:\n throw new Error(\"Unknown transcript source. Use one of: all, codex, claude.\");\n }\n}\n","// Public API entrypoint for transcript reading. Internal helpers live in\n// `./types.ts`, `./paths.ts`, `./jsonl.ts`, and `./discovery.ts`; only the\n// consumer-facing functions are exported here.\n\nimport { promises as fs } from \"node:fs\";\n\nimport {\n asObject,\n extractContentText,\n parseJsonObject,\n readString,\n} from \"./jsonl.js\";\nimport {\n discoverTranscriptFiles,\n readTranscriptRecord,\n resolveTranscriptFile,\n} from \"./discovery.js\";\nimport type {\n TranscriptEntry,\n TranscriptGrepOptions,\n TranscriptListOptions,\n TranscriptRecord,\n TranscriptReadOptions,\n} from \"./types.js\";\n\nexport {\n TranscriptSourceNames,\n type TranscriptEntry,\n type TranscriptGrepOptions,\n type TranscriptListOptions,\n type TranscriptReadOptions,\n type TranscriptRecord,\n type TranscriptScopeName,\n type TranscriptSourceName,\n} from \"./types.js\";\n\nexport async function listTranscriptRecords(\n options: TranscriptListOptions\n): Promise<TranscriptRecord[]> {\n const files = await discoverTranscriptFiles(options.source);\n const records = await Promise.all(files.slice(0, options.limit).map(readTranscriptRecord));\n return records;\n}\n\nexport async function readTranscriptEntries(\n options: TranscriptReadOptions\n): Promise<TranscriptEntry[]> {\n const file = await resolveTranscriptFile(options.source, options.target);\n const entries = await readEntriesFromFile(file, options.includeInternal);\n return entries.slice(Math.max(0, entries.length - options.limit));\n}\n\nexport async function grepTranscriptEntries(\n options: TranscriptGrepOptions\n): Promise<TranscriptEntry[]> {\n const files = await discoverTranscriptFiles(options.source);\n const normalizedQuery = options.query.toLowerCase();\n const matches: TranscriptEntry[] = [];\n\n for (const file of files.slice(0, options.fileLimit)) {\n const entries = await readEntriesFromFile(file, options.includeInternal);\n\n for (const entry of entries) {\n if (entry.text.toLowerCase().includes(normalizedQuery)) {\n matches.push(entry);\n }\n\n if (matches.length >= options.limit) {\n return matches;\n }\n }\n }\n\n return matches;\n}\n\nasync function readEntriesFromFile(\n record: TranscriptRecord,\n includeInternal: boolean\n): Promise<TranscriptEntry[]> {\n const content = await fs.readFile(record.filePath, \"utf8\");\n const entries: TranscriptEntry[] = [];\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) {\n continue;\n }\n\n const parsed = parseJsonObject(line);\n if (!parsed) {\n continue;\n }\n\n const entry =\n record.source === \"codex\"\n ? parseCodexEntry(record, parsed, includeInternal)\n : parseClaudeEntry(record, parsed, includeInternal);\n\n if (entry) {\n entries.push(entry);\n }\n }\n\n return entries;\n}\n\nfunction parseCodexEntry(\n record: TranscriptRecord,\n parsed: Record<string, unknown>,\n includeInternal: boolean\n): TranscriptEntry | undefined {\n const payload = asObject(parsed.payload);\n if (!payload || parsed.type !== \"response_item\") {\n return undefined;\n }\n\n const role = readString(payload.role);\n if (!role || (!includeInternal && role !== \"user\" && role !== \"assistant\")) {\n return undefined;\n }\n\n const text = extractContentText(payload.content);\n if (!text) {\n return undefined;\n }\n\n return {\n source: record.source,\n filePath: record.filePath,\n timestamp: readString(parsed.timestamp),\n role,\n text,\n };\n}\n\nfunction parseClaudeEntry(\n record: TranscriptRecord,\n parsed: Record<string, unknown>,\n includeInternal: boolean\n): TranscriptEntry | undefined {\n const message = asObject(parsed.message);\n const role = readString(message?.role) ?? readString(parsed.type);\n\n if (!role || (!includeInternal && role !== \"user\" && role !== \"assistant\")) {\n return undefined;\n }\n\n const text = message ? extractContentText(message.content) : readString(parsed.content);\n if (!text) {\n return undefined;\n }\n\n return {\n source: record.source,\n filePath: record.filePath,\n timestamp: readString(parsed.timestamp),\n role,\n text,\n };\n}\n","import { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\n\nimport type { TranscriptRecord } from \"./types.js\";\nimport { statIfExists } from \"./paths.js\";\n\nexport async function readJsonlLines(filePath: string, limit: number): Promise<string[]> {\n const content = await fs.readFile(filePath, \"utf8\");\n return content.split(\"\\n\").filter(Boolean).slice(0, limit);\n}\n\nexport function parseJsonObject(line: string): Record<string, unknown> | undefined {\n try {\n const parsed: unknown = JSON.parse(line);\n return asObject(parsed);\n } catch {\n return undefined;\n }\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function asObject(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nexport function readString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value : undefined;\n}\n\nexport function extractContentText(value: unknown): string | undefined {\n if (typeof value === \"string\") {\n return value;\n }\n\n if (!Array.isArray(value)) {\n return undefined;\n }\n\n const parts = value.flatMap((item) => {\n if (typeof item === \"string\") {\n return [item];\n }\n\n const objectItem = asObject(item);\n if (!objectItem) {\n return [];\n }\n\n return [readString(objectItem.text), readString(objectItem.content)].filter(\n (part): part is string => Boolean(part)\n );\n });\n\n return parts.length > 0 ? parts.join(\"\\n\") : undefined;\n}\n\nexport async function discoverJsonlFiles(\n source: TranscriptRecord[\"source\"],\n rootPath: string\n): Promise<TranscriptRecord[]> {\n const stat = await statIfExists(rootPath);\n if (!stat) {\n return [];\n }\n\n if (stat.isFile()) {\n return [await recordFromPath(source, rootPath, stat.mtime)];\n }\n\n const records: TranscriptRecord[] = [];\n const entries = await fs.readdir(rootPath, { withFileTypes: true });\n\n for (const entry of entries) {\n const entryPath = path.join(rootPath, entry.name);\n if (entry.isDirectory()) {\n records.push(...(await discoverJsonlFiles(source, entryPath)));\n continue;\n }\n\n if (entry.isFile() && entry.name.endsWith(\".jsonl\")) {\n const entryStat = await fs.stat(entryPath);\n records.push(await recordFromPath(source, entryPath, entryStat.mtime));\n }\n }\n\n return records;\n}\n\nexport async function recordFromPath(\n source: TranscriptRecord[\"source\"],\n filePath: string,\n mtime: Date\n): Promise<TranscriptRecord> {\n return {\n source,\n filePath,\n updatedAt: mtime.toISOString(),\n };\n}\n","import os from \"node:os\";\nimport { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\n\nimport type { TranscriptSourceName } from \"./types.js\";\n\nexport async function statIfExists(filePath: string) {\n try {\n return await fs.stat(filePath);\n } catch (error) {\n if (isNodeError(error) && error.code === \"ENOENT\") {\n return undefined;\n }\n throw error;\n }\n}\n\nexport function isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error;\n}\n\nexport function expandHome(value: string): string {\n if (value === \"~\") {\n return os.homedir();\n }\n if (value.startsWith(\"~/\")) {\n return path.join(os.homedir(), value.slice(2));\n }\n return value;\n}\n\nexport function detectSourceFromPath(filePath: string): TranscriptSourceName {\n return filePath.includes(`${path.sep}.claude${path.sep}`) ? \"claude\" : \"codex\";\n}\n\nexport function truncateSingleLine(value: string, maxLength: number): string {\n const line = value.replace(/\\s+/g, \" \").trim();\n return line.length > maxLength ? `${line.slice(0, maxLength - 1)}...` : line;\n}\n","import path from \"node:path\";\n\nimport {\n asObject,\n discoverJsonlFiles,\n extractContentText,\n parseJsonObject,\n readJsonlLines,\n readString,\n recordFromPath,\n} from \"./jsonl.js\";\nimport {\n detectSourceFromPath,\n expandHome,\n statIfExists,\n truncateSingleLine,\n} from \"./paths.js\";\nimport {\n TranscriptSourceNames,\n type TranscriptRecord,\n type TranscriptScopeName,\n type TranscriptSourceName,\n} from \"./types.js\";\n\nexport async function discoverTranscriptFiles(\n source: TranscriptScopeName\n): Promise<TranscriptRecord[]> {\n const sources = source === \"all\" ? TranscriptSourceNames : [source];\n const records = await Promise.all(sources.flatMap((sourceName) => sourceRoots(sourceName)));\n return records\n .flat()\n .sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));\n}\n\nfunction sourceRoots(source: TranscriptSourceName): Promise<TranscriptRecord[]>[] {\n if (source === \"codex\") {\n return [\n discoverJsonlFiles(\"codex\", expandHome(\"~/.codex/sessions\")),\n discoverJsonlFiles(\"codex\", expandHome(\"~/.codex/archived_sessions\")),\n ];\n }\n\n return [\n discoverJsonlFiles(\"claude\", expandHome(\"~/.claude/projects\")),\n discoverJsonlFiles(\"claude\", expandHome(\"~/.claude/history.jsonl\")),\n ];\n}\n\nexport async function readTranscriptRecord(record: TranscriptRecord): Promise<TranscriptRecord> {\n const metadata = await readMetadataFromFile(record.source, record.filePath);\n return {\n ...record,\n ...metadata,\n };\n}\n\nexport async function readMetadataFromFile(\n source: TranscriptSourceName,\n filePath: string\n): Promise<Pick<TranscriptRecord, \"cwd\" | \"sessionId\" | \"title\">> {\n const lines = await readJsonlLines(filePath, 80);\n\n for (const line of lines) {\n const parsed = parseJsonObject(line);\n if (!parsed) {\n continue;\n }\n\n if (source === \"codex\") {\n const payload = asObject(parsed.payload);\n if (parsed.type === \"session_meta\" && payload) {\n return {\n cwd: readString(payload.cwd),\n sessionId: readString(payload.session_id) ?? readString(payload.id),\n title: readString(payload.cwd),\n };\n }\n }\n\n if (source === \"claude\") {\n const message = asObject(parsed.message);\n const role = readString(message?.role) ?? readString(parsed.type);\n const content = message ? extractContentText(message.content) : readString(parsed.content);\n if (content && (role === \"user\" || role === \"assistant\")) {\n return {\n cwd: readString(parsed.cwd) ?? readString(parsed.project),\n sessionId: readString(parsed.sessionId),\n title: truncateSingleLine(content, 120),\n };\n }\n }\n }\n\n return {\n sessionId: path.basename(filePath, \".jsonl\"),\n };\n}\n\nexport async function resolveTranscriptFile(\n source: TranscriptScopeName,\n target: string\n): Promise<TranscriptRecord> {\n const expandedTarget = expandHome(target);\n const directStat = await statIfExists(expandedTarget);\n if (directStat?.isFile()) {\n return recordFromPath(detectSourceFromPath(expandedTarget), expandedTarget, directStat.mtime);\n }\n\n const files = await discoverTranscriptFiles(source);\n const normalizedTarget = target.toLowerCase();\n const match = files.find((file) => {\n return (\n file.filePath.toLowerCase().includes(normalizedTarget) ||\n file.sessionId?.toLowerCase().includes(normalizedTarget)\n );\n });\n\n if (!match) {\n throw new Error(`No transcript matched \"${target}\". Run cngkit transcripts list first.`);\n }\n\n return match;\n}\n","export const TranscriptSourceNames = [\"codex\", \"claude\"] as const;\n\nexport type TranscriptSourceName = (typeof TranscriptSourceNames)[number];\nexport type TranscriptScopeName = TranscriptSourceName | \"all\";\n\nexport type TranscriptRecord = {\n readonly source: TranscriptSourceName;\n readonly filePath: string;\n readonly updatedAt: string;\n readonly sessionId?: string;\n readonly cwd?: string;\n readonly title?: string;\n};\n\nexport type TranscriptEntry = {\n readonly source: TranscriptSourceName;\n readonly filePath: string;\n readonly timestamp?: string;\n readonly role: string;\n readonly text: string;\n};\n\nexport type TranscriptListOptions = {\n readonly source: TranscriptScopeName;\n readonly limit: number;\n};\n\nexport type TranscriptReadOptions = {\n readonly source: TranscriptScopeName;\n readonly target: string;\n readonly limit: number;\n readonly includeInternal: boolean;\n};\n\nexport type TranscriptGrepOptions = {\n readonly source: TranscriptScopeName;\n readonly query: string;\n readonly limit: number;\n readonly fileLimit: number;\n readonly includeInternal: boolean;\n};\n\nexport type JsonObject = Record<string, unknown>;\n","import { Box, Text } from \"ink\";\n\nimport { singleLine } from \"../../shared/command-utils.js\";\nimport type { TranscriptRecord } from \"./reader.js\";\n\nexport function TranscriptRecordList({ records }: { readonly records: readonly TranscriptRecord[] }) {\n if (records.length === 0) {\n return <Text color=\"yellow\">No transcript files found.</Text>;\n }\n\n return (\n <Box flexDirection=\"column\">\n {records.map((record, index) => (\n <Box flexDirection=\"column\" key={`${record.source}-${record.filePath}-${index}`} marginBottom={1}>\n <Text>\n <Text color=\"cyan\">{index + 1}. </Text>\n <Text bold>{record.source}</Text>\n <Text dimColor> {record.updatedAt}</Text>\n </Text>\n <Text>{record.filePath}</Text>\n {record.sessionId ? (\n <Text dimColor>\n session {record.sessionId}\n </Text>\n ) : null}\n {record.cwd ? <Text dimColor>cwd {record.cwd}</Text> : null}\n {record.title ? <Text>{singleLine(record.title)}</Text> : null}\n </Box>\n ))}\n </Box>\n );\n}\n"],"mappings":"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","names":["fs","fs","path","fs","path","path","path","options","fs","args","options","jsx","args","options"]}
|
|
1
|
+
{"version":3,"sources":["../../src/commands/transcripts.tsx","../../src/features/transcripts/run-transcript-command.ts","../../src/features/transcripts/reader.ts","../../src/features/transcripts/jsonl.ts","../../src/features/transcripts/paths.ts","../../src/features/transcripts/discovery.ts","../../src/features/transcripts/types.ts","../../src/features/transcripts/transcript-output.tsx"],"sourcesContent":["import { option } from \"pastel\";\nimport { z } from \"zod\";\n\nimport { GlobalOptionsSchema, TranscriptArgsSchema } from \"../cli/options.js\";\nimport {\n runTranscriptCommand,\n type TranscriptCommandOptions,\n} from \"../features/transcripts/run-transcript-command.js\";\nimport { CommandRunner } from \"../cli/command-runner.js\";\n\nexport const description = \"List, read, and grep local Claude/Codex transcript JSONL files\";\nexport const args = TranscriptArgsSchema;\nexport const options = GlobalOptionsSchema.extend({\n source: z\n .enum([\"all\", \"codex\", \"claude\"])\n .optional()\n .describe(\n option({\n description: \"Transcript source. Default: all\",\n valueDescription: \"all|codex|claude\",\n })\n ),\n limit: z\n .number()\n .optional()\n .describe(\n option({\n description: \"Maximum records or entries\",\n valueDescription: \"n\",\n })\n ),\n fileLimit: z\n .number()\n .optional()\n .describe(\n option({\n description: \"Maximum recent files to scan for grep\",\n valueDescription: \"n\",\n })\n ),\n includeInternal: z\n .boolean()\n .optional()\n .describe(\n option({\n description: \"Include developer/system/internal transcript entries\",\n })\n ),\n json: z\n .boolean()\n .optional()\n .describe(\n option({\n description: \"Print raw JSON\",\n })\n ),\n});\n\ntype TranscriptsCommandProps = {\n readonly args: string[];\n readonly options: TranscriptCommandOptions;\n};\n\nexport default function TranscriptsCommand({ args, options }: TranscriptsCommandProps) {\n return <CommandRunner run={(output) => runTranscriptCommand(args, options, output)} />;\n}\n","import { createElement } from \"react\";\n\nimport { renderCngkitHelp } from \"../../cli/help-specs.js\";\nimport {\n coerceLimit,\n formatJson,\n optionalJoinedArgument,\n shouldPrintJson,\n type JsonOutputOptions,\n type NumberOption,\n} from \"../../shared/command-utils.js\";\nimport type { GlobalCommandOptions } from \"../../shared/config.js\";\nimport type { CommandOutput } from \"../../shared/output/types.js\";\nimport {\n grepTranscriptEntries,\n listTranscriptRecords,\n readTranscriptEntries,\n type TranscriptEntry,\n type TranscriptScopeName,\n} from \"./reader.js\";\nimport { TranscriptRecordList } from \"./transcript-output.js\";\n\nexport type TranscriptCommandOptions = GlobalCommandOptions &\n JsonOutputOptions & {\n source?: string;\n limit?: NumberOption;\n fileLimit?: NumberOption;\n includeInternal?: boolean;\n };\n\nexport async function runTranscriptCommand(\n args: string[] | undefined,\n options: TranscriptCommandOptions,\n output: CommandOutput\n): Promise<void> {\n const [action = \"list\", ...actionArgs] = args ?? [];\n const source = normalizeTranscriptSource(options.source);\n const limit = coerceLimit(options.limit, action === \"list\" ? 12 : 80, 500);\n const includeInternal = options.includeInternal === true;\n\n switch (action) {\n case \"help\":\n output.component(renderCngkitHelp(\"transcripts\"));\n return;\n case \"list\": {\n const records = await listTranscriptRecords({ source, limit });\n if (shouldPrintJson(options)) {\n output.raw(formatJson({ records }));\n return;\n }\n\n output.component(createElement(TranscriptRecordList, { records }));\n return;\n }\n case \"read\": {\n const target = actionArgs[0];\n if (!target) {\n throw new Error(\"Missing transcript target. Usage: cngkit transcripts read <path-or-id>\");\n }\n\n const entries = await readTranscriptEntries({\n source,\n target,\n limit,\n includeInternal,\n });\n\n if (shouldPrintJson(options)) {\n output.raw(formatJson({ entries }));\n return;\n }\n\n output.raw(formatTranscriptEntries(entries));\n return;\n }\n case \"grep\": {\n const query = optionalJoinedArgument(actionArgs);\n if (!query) {\n throw new Error(\"Missing query. Usage: cngkit transcripts grep <query>\");\n }\n\n const entries = await grepTranscriptEntries({\n source,\n query,\n limit,\n fileLimit: coerceLimit(options.fileLimit, 60, 5000),\n includeInternal,\n });\n\n if (shouldPrintJson(options)) {\n output.raw(formatJson({ entries }));\n return;\n }\n\n output.raw(formatTranscriptEntries(entries));\n return;\n }\n default:\n throw new Error(\"Unknown transcripts command. Usage: cngkit transcripts <list|read|grep>\");\n }\n}\n\nfunction formatTranscriptEntries(entries: TranscriptEntry[]): string {\n if (entries.length === 0) {\n return \"No transcript entries found.\";\n }\n\n return entries\n .map((entry) => {\n const when = entry.timestamp ? ` ${entry.timestamp}` : \"\";\n return `[${entry.source}] ${entry.role}${when}\\n${entry.text.trim()}`;\n })\n .join(\"\\n\\n\");\n}\n\nfunction normalizeTranscriptSource(value: string | undefined): TranscriptScopeName {\n if (value === undefined) {\n return \"all\";\n }\n\n switch (value) {\n case \"all\":\n case \"codex\":\n case \"claude\":\n return value;\n default:\n throw new Error(\"Unknown transcript source. Use one of: all, codex, claude.\");\n }\n}\n","// Public API entrypoint for transcript reading. Internal helpers live in\n// `./types.ts`, `./paths.ts`, `./jsonl.ts`, and `./discovery.ts`; only the\n// consumer-facing functions are exported here.\n\nimport { promises as fs } from \"node:fs\";\n\nimport { asObject, extractContentText, parseJsonObject, readString } from \"./jsonl.js\";\nimport {\n discoverTranscriptFiles,\n readTranscriptRecord,\n resolveTranscriptFile,\n} from \"./discovery.js\";\nimport type {\n TranscriptEntry,\n TranscriptGrepOptions,\n TranscriptListOptions,\n TranscriptRecord,\n TranscriptReadOptions,\n} from \"./types.js\";\n\nexport {\n TranscriptSourceNames,\n type TranscriptEntry,\n type TranscriptGrepOptions,\n type TranscriptListOptions,\n type TranscriptReadOptions,\n type TranscriptRecord,\n type TranscriptScopeName,\n type TranscriptSourceName,\n} from \"./types.js\";\n\nexport async function listTranscriptRecords(\n options: TranscriptListOptions\n): Promise<TranscriptRecord[]> {\n const files = await discoverTranscriptFiles(options.source);\n const records = await Promise.all(files.slice(0, options.limit).map(readTranscriptRecord));\n return records;\n}\n\nexport async function readTranscriptEntries(\n options: TranscriptReadOptions\n): Promise<TranscriptEntry[]> {\n const file = await resolveTranscriptFile(options.source, options.target);\n const entries = await readEntriesFromFile(file, options.includeInternal);\n return entries.slice(Math.max(0, entries.length - options.limit));\n}\n\nexport async function grepTranscriptEntries(\n options: TranscriptGrepOptions\n): Promise<TranscriptEntry[]> {\n const files = await discoverTranscriptFiles(options.source);\n const normalizedQuery = options.query.toLowerCase();\n const matches: TranscriptEntry[] = [];\n\n for (const file of files.slice(0, options.fileLimit)) {\n const entries = await readEntriesFromFile(file, options.includeInternal);\n\n for (const entry of entries) {\n if (entry.text.toLowerCase().includes(normalizedQuery)) {\n matches.push(entry);\n }\n\n if (matches.length >= options.limit) {\n return matches;\n }\n }\n }\n\n return matches;\n}\n\nasync function readEntriesFromFile(\n record: TranscriptRecord,\n includeInternal: boolean\n): Promise<TranscriptEntry[]> {\n const content = await fs.readFile(record.filePath, \"utf8\");\n const entries: TranscriptEntry[] = [];\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) {\n continue;\n }\n\n const parsed = parseJsonObject(line);\n if (!parsed) {\n continue;\n }\n\n const entry =\n record.source === \"codex\"\n ? parseCodexEntry(record, parsed, includeInternal)\n : parseClaudeEntry(record, parsed, includeInternal);\n\n if (entry) {\n entries.push(entry);\n }\n }\n\n return entries;\n}\n\nfunction parseCodexEntry(\n record: TranscriptRecord,\n parsed: Record<string, unknown>,\n includeInternal: boolean\n): TranscriptEntry | undefined {\n const payload = asObject(parsed.payload);\n if (!payload || parsed.type !== \"response_item\") {\n return undefined;\n }\n\n const role = readString(payload.role);\n if (!role || (!includeInternal && role !== \"user\" && role !== \"assistant\")) {\n return undefined;\n }\n\n const text = extractContentText(payload.content);\n if (!text) {\n return undefined;\n }\n\n return {\n source: record.source,\n filePath: record.filePath,\n timestamp: readString(parsed.timestamp),\n role,\n text,\n };\n}\n\nfunction parseClaudeEntry(\n record: TranscriptRecord,\n parsed: Record<string, unknown>,\n includeInternal: boolean\n): TranscriptEntry | undefined {\n const message = asObject(parsed.message);\n const role = readString(message?.role) ?? readString(parsed.type);\n\n if (!role || (!includeInternal && role !== \"user\" && role !== \"assistant\")) {\n return undefined;\n }\n\n const text = message ? extractContentText(message.content) : readString(parsed.content);\n if (!text) {\n return undefined;\n }\n\n return {\n source: record.source,\n filePath: record.filePath,\n timestamp: readString(parsed.timestamp),\n role,\n text,\n };\n}\n","import { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\n\nimport type { TranscriptRecord } from \"./types.js\";\nimport { statIfExists } from \"./paths.js\";\n\nexport async function readJsonlLines(filePath: string, limit: number): Promise<string[]> {\n const content = await fs.readFile(filePath, \"utf8\");\n return content.split(\"\\n\").filter(Boolean).slice(0, limit);\n}\n\nexport function parseJsonObject(line: string): Record<string, unknown> | undefined {\n try {\n const parsed: unknown = JSON.parse(line);\n return asObject(parsed);\n } catch {\n return undefined;\n }\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function asObject(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nexport function readString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value : undefined;\n}\n\nexport function extractContentText(value: unknown): string | undefined {\n if (typeof value === \"string\") {\n return value;\n }\n\n if (!Array.isArray(value)) {\n return undefined;\n }\n\n const parts = value.flatMap((item) => {\n if (typeof item === \"string\") {\n return [item];\n }\n\n const objectItem = asObject(item);\n if (!objectItem) {\n return [];\n }\n\n return [readString(objectItem.text), readString(objectItem.content)].filter(\n (part): part is string => Boolean(part)\n );\n });\n\n return parts.length > 0 ? parts.join(\"\\n\") : undefined;\n}\n\nexport async function discoverJsonlFiles(\n source: TranscriptRecord[\"source\"],\n rootPath: string\n): Promise<TranscriptRecord[]> {\n const stat = await statIfExists(rootPath);\n if (!stat) {\n return [];\n }\n\n if (stat.isFile()) {\n return [await recordFromPath(source, rootPath, stat.mtime)];\n }\n\n const records: TranscriptRecord[] = [];\n const entries = await fs.readdir(rootPath, { withFileTypes: true });\n\n for (const entry of entries) {\n const entryPath = path.join(rootPath, entry.name);\n if (entry.isDirectory()) {\n records.push(...(await discoverJsonlFiles(source, entryPath)));\n continue;\n }\n\n if (entry.isFile() && entry.name.endsWith(\".jsonl\")) {\n const entryStat = await fs.stat(entryPath);\n records.push(await recordFromPath(source, entryPath, entryStat.mtime));\n }\n }\n\n return records;\n}\n\nexport async function recordFromPath(\n source: TranscriptRecord[\"source\"],\n filePath: string,\n mtime: Date\n): Promise<TranscriptRecord> {\n return {\n source,\n filePath,\n updatedAt: mtime.toISOString(),\n };\n}\n","import os from \"node:os\";\nimport { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\n\nimport type { TranscriptSourceName } from \"./types.js\";\n\nexport async function statIfExists(filePath: string) {\n try {\n return await fs.stat(filePath);\n } catch (error) {\n if (isNodeError(error) && error.code === \"ENOENT\") {\n return undefined;\n }\n throw error;\n }\n}\n\nexport function isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error;\n}\n\nexport function expandHome(value: string): string {\n if (value === \"~\") {\n return os.homedir();\n }\n if (value.startsWith(\"~/\")) {\n return path.join(os.homedir(), value.slice(2));\n }\n return value;\n}\n\nexport function detectSourceFromPath(filePath: string): TranscriptSourceName {\n return filePath.includes(`${path.sep}.claude${path.sep}`) ? \"claude\" : \"codex\";\n}\n\nexport function truncateSingleLine(value: string, maxLength: number): string {\n const line = value.replace(/\\s+/g, \" \").trim();\n return line.length > maxLength ? `${line.slice(0, maxLength - 1)}...` : line;\n}\n","import path from \"node:path\";\n\nimport {\n asObject,\n discoverJsonlFiles,\n extractContentText,\n parseJsonObject,\n readJsonlLines,\n readString,\n recordFromPath,\n} from \"./jsonl.js\";\nimport { detectSourceFromPath, expandHome, statIfExists, truncateSingleLine } from \"./paths.js\";\nimport {\n TranscriptSourceNames,\n type TranscriptRecord,\n type TranscriptScopeName,\n type TranscriptSourceName,\n} from \"./types.js\";\n\nexport async function discoverTranscriptFiles(\n source: TranscriptScopeName\n): Promise<TranscriptRecord[]> {\n const sources = source === \"all\" ? TranscriptSourceNames : [source];\n const records = await Promise.all(sources.flatMap((sourceName) => sourceRoots(sourceName)));\n return records.flat().sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));\n}\n\nfunction sourceRoots(source: TranscriptSourceName): Promise<TranscriptRecord[]>[] {\n if (source === \"codex\") {\n return [\n discoverJsonlFiles(\"codex\", expandHome(\"~/.codex/sessions\")),\n discoverJsonlFiles(\"codex\", expandHome(\"~/.codex/archived_sessions\")),\n ];\n }\n\n return [\n discoverJsonlFiles(\"claude\", expandHome(\"~/.claude/projects\")),\n discoverJsonlFiles(\"claude\", expandHome(\"~/.claude/history.jsonl\")),\n ];\n}\n\nexport async function readTranscriptRecord(record: TranscriptRecord): Promise<TranscriptRecord> {\n const metadata = await readMetadataFromFile(record.source, record.filePath);\n return {\n ...record,\n ...metadata,\n };\n}\n\nexport async function readMetadataFromFile(\n source: TranscriptSourceName,\n filePath: string\n): Promise<Pick<TranscriptRecord, \"cwd\" | \"sessionId\" | \"title\">> {\n const lines = await readJsonlLines(filePath, 80);\n\n for (const line of lines) {\n const parsed = parseJsonObject(line);\n if (!parsed) {\n continue;\n }\n\n if (source === \"codex\") {\n const payload = asObject(parsed.payload);\n if (parsed.type === \"session_meta\" && payload) {\n return {\n cwd: readString(payload.cwd),\n sessionId: readString(payload.session_id) ?? readString(payload.id),\n title: readString(payload.cwd),\n };\n }\n }\n\n if (source === \"claude\") {\n const message = asObject(parsed.message);\n const role = readString(message?.role) ?? readString(parsed.type);\n const content = message ? extractContentText(message.content) : readString(parsed.content);\n if (content && (role === \"user\" || role === \"assistant\")) {\n return {\n cwd: readString(parsed.cwd) ?? readString(parsed.project),\n sessionId: readString(parsed.sessionId),\n title: truncateSingleLine(content, 120),\n };\n }\n }\n }\n\n return {\n sessionId: path.basename(filePath, \".jsonl\"),\n };\n}\n\nexport async function resolveTranscriptFile(\n source: TranscriptScopeName,\n target: string\n): Promise<TranscriptRecord> {\n const expandedTarget = expandHome(target);\n const directStat = await statIfExists(expandedTarget);\n if (directStat?.isFile()) {\n return recordFromPath(detectSourceFromPath(expandedTarget), expandedTarget, directStat.mtime);\n }\n\n const files = await discoverTranscriptFiles(source);\n const normalizedTarget = target.toLowerCase();\n const match = files.find((file) => {\n return (\n file.filePath.toLowerCase().includes(normalizedTarget) ||\n file.sessionId?.toLowerCase().includes(normalizedTarget)\n );\n });\n\n if (!match) {\n throw new Error(`No transcript matched \"${target}\". Run cngkit transcripts list first.`);\n }\n\n return match;\n}\n","export const TranscriptSourceNames = [\"codex\", \"claude\"] as const;\n\nexport type TranscriptSourceName = (typeof TranscriptSourceNames)[number];\nexport type TranscriptScopeName = TranscriptSourceName | \"all\";\n\nexport type TranscriptRecord = {\n readonly source: TranscriptSourceName;\n readonly filePath: string;\n readonly updatedAt: string;\n readonly sessionId?: string;\n readonly cwd?: string;\n readonly title?: string;\n};\n\nexport type TranscriptEntry = {\n readonly source: TranscriptSourceName;\n readonly filePath: string;\n readonly timestamp?: string;\n readonly role: string;\n readonly text: string;\n};\n\nexport type TranscriptListOptions = {\n readonly source: TranscriptScopeName;\n readonly limit: number;\n};\n\nexport type TranscriptReadOptions = {\n readonly source: TranscriptScopeName;\n readonly target: string;\n readonly limit: number;\n readonly includeInternal: boolean;\n};\n\nexport type TranscriptGrepOptions = {\n readonly source: TranscriptScopeName;\n readonly query: string;\n readonly limit: number;\n readonly fileLimit: number;\n readonly includeInternal: boolean;\n};\n\nexport type JsonObject = Record<string, unknown>;\n","import { Box, Text } from \"ink\";\n\nimport { singleLine } from \"../../shared/command-utils.js\";\nimport type { TranscriptRecord } from \"./reader.js\";\n\nexport function TranscriptRecordList({\n records,\n}: {\n readonly records: readonly TranscriptRecord[];\n}) {\n if (records.length === 0) {\n return <Text color=\"yellow\">No transcript files found.</Text>;\n }\n\n return (\n <Box flexDirection=\"column\">\n {records.map((record, index) => (\n <Box\n flexDirection=\"column\"\n key={`${record.source}-${record.filePath}-${index}`}\n marginBottom={1}\n >\n <Text>\n <Text color=\"cyan\">{index + 1}. </Text>\n <Text bold>{record.source}</Text>\n <Text dimColor> {record.updatedAt}</Text>\n </Text>\n <Text>{record.filePath}</Text>\n {record.sessionId ? <Text dimColor>session {record.sessionId}</Text> : null}\n {record.cwd ? <Text dimColor>cwd {record.cwd}</Text> : null}\n {record.title ? <Text>{singleLine(record.title)}</Text> : null}\n </Box>\n ))}\n </Box>\n );\n}\n"],"mappings":"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","names":["fs","fs","path","fs","path","path","path","options","fs","args","options","jsx","args","options"]}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/features/hooks/hooks-targets.ts","../src/features/hooks/run-hooks-install-command.ts","../src/features/hooks/hooks-output.tsx","../src/features/hooks/hooks-install-flow.ts","../src/features/hooks/hooks-handler.ts","../src/features/hooks/hooks-document-io.ts","../src/features/hooks/hooks-schemas.ts"],"sourcesContent":["import os from \"node:os\";\nimport path from \"node:path\";\n\nexport const hookToolIds = [\"all\", \"claude\", \"codex\"] as const;\n\nexport type HookToolId = (typeof hookToolIds)[number];\n\nexport type InstallTarget = {\n readonly tool: Exclude<HookToolId, \"all\">;\n readonly label: string;\n readonly configPath: string;\n readonly events: readonly string[];\n readonly statusMessages: boolean;\n};\n\nexport const claudeHookEvents = [\n \"SessionStart\",\n \"Setup\",\n \"InstructionsLoaded\",\n \"UserPromptSubmit\",\n \"UserPromptExpansion\",\n \"MessageDisplay\",\n \"PreToolUse\",\n \"PermissionRequest\",\n \"PermissionDenied\",\n \"PostToolUse\",\n \"PostToolUseFailure\",\n \"PostToolBatch\",\n \"Notification\",\n \"SubagentStart\",\n \"SubagentStop\",\n \"TaskCreated\",\n \"TaskCompleted\",\n \"Stop\",\n \"StopFailure\",\n \"TeammateIdle\",\n \"ConfigChange\",\n \"CwdChanged\",\n \"FileChanged\",\n \"WorktreeCreate\",\n \"WorktreeRemove\",\n \"PreCompact\",\n \"PostCompact\",\n \"SessionEnd\",\n \"Elicitation\",\n \"ElicitationResult\",\n] as const;\n\nexport const codexHookEvents = [\n \"SessionStart\",\n \"SubagentStart\",\n \"PreToolUse\",\n \"PermissionRequest\",\n \"PostToolUse\",\n \"PreCompact\",\n \"PostCompact\",\n \"UserPromptSubmit\",\n \"SubagentStop\",\n \"Stop\",\n] as const;\n\nexport function resolveInstallTargets(tool: HookToolId): InstallTarget[] {\n const homeDirectory = os.homedir();\n const targets: InstallTarget[] = [\n {\n tool: \"claude\",\n label: \"Claude Code\",\n configPath: path.join(homeDirectory, \".claude\", \"settings.json\"),\n events: claudeHookEvents,\n statusMessages: false,\n },\n {\n tool: \"codex\",\n label: \"Codex\",\n configPath: path.join(homeDirectory, \".codex\", \"hooks.json\"),\n events: codexHookEvents,\n statusMessages: true,\n },\n ];\n\n if (tool === \"all\") {\n return targets;\n }\n\n return targets.filter((target) => target.tool === tool);\n}\n","// Public API entrypoint for hooks install/uninstall. Implementation lives in\n// `./hooks-{schemas,targets,handler,document-io,install-flow}.ts`; this file\n// just dispatches and renders the result.\n\nimport { createElement } from \"react\";\n\nimport type { CommandOutput } from \"../../shared/output/types.js\";\nimport { HookTargetResults } from \"./hooks-output.js\";\nimport {\n installHooksForTarget,\n uninstallHooksForTarget,\n} from \"./hooks-install-flow.js\";\nimport { hookToolIds, resolveInstallTargets, type HookToolId } from \"./hooks-targets.js\";\n\nexport { hookToolIds };\nexport type { HookToolId } from \"./hooks-targets.js\";\n\nexport type HooksInstallCommandOptions = {\n readonly dryRun?: boolean;\n readonly tool?: HookToolId;\n};\n\nexport type HooksUninstallCommandOptions = {\n readonly dryRun?: boolean;\n readonly tool?: HookToolId;\n};\n\nexport async function runHooksInstallCommand(\n options: HooksInstallCommandOptions,\n output: CommandOutput\n): Promise<void> {\n const targets = resolveInstallTargets(options.tool ?? \"all\");\n const results = [];\n\n for (const target of targets) {\n const result = await installHooksForTarget(target, options.dryRun === true);\n results.push(result);\n }\n\n output.component(createElement(HookTargetResults, { results }));\n}\n\nexport async function runHooksUninstallCommand(\n options: HooksUninstallCommandOptions,\n output: CommandOutput\n): Promise<void> {\n const targets = resolveInstallTargets(options.tool ?? \"all\");\n const results = [];\n\n for (const target of targets) {\n const result = await uninstallHooksForTarget(target, options.dryRun === true);\n results.push(result);\n }\n\n output.component(createElement(HookTargetResults, { results }));\n}\n","import { Box, Text } from \"ink\";\n\nexport type HookTargetResult = {\n readonly action: string;\n readonly label: string;\n readonly configPath: string;\n readonly changedCount: number;\n readonly replacedCount?: number;\n readonly events: readonly string[];\n};\n\nexport function HookTargetResults({\n results,\n}: {\n readonly results: readonly HookTargetResult[];\n}) {\n return (\n <Box flexDirection=\"column\">\n {results.map((result) => (\n <Box flexDirection=\"column\" key={`${result.label}-${result.configPath}`} marginBottom={1}>\n <Text color=\"green\" bold>\n {result.action} {result.changedCount} {result.label} hook\n {result.changedCount === 1 ? \"\" : \"s\"}\n </Text>\n <Text>{result.configPath}</Text>\n {result.replacedCount !== undefined ? (\n <Text dimColor>replaced {result.replacedCount} existing cngkit handler(s)</Text>\n ) : null}\n <Text dimColor>events: {result.events.length > 0 ? result.events.join(\", \") : \"none\"}</Text>\n </Box>\n ))}\n </Box>\n );\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { HookTargetResult } from \"./hooks-output.js\";\nimport {\n createCngkitHookHandler,\n isCngkitHookHandler,\n} from \"./hooks-handler.js\";\nimport { parseHookConfig, parseHookGroups, readJsonDocument } from \"./hooks-document-io.js\";\nimport type { HookGroup } from \"./hooks-schemas.js\";\nimport type { InstallTarget } from \"./hooks-targets.js\";\n\nexport async function installHooksForTarget(\n target: InstallTarget,\n dryRun: boolean\n): Promise<HookTargetResult> {\n const document = await readJsonDocument(target.configPath);\n const hooks = parseHookConfig(document.hooks);\n let replacedHandlers = 0;\n\n for (const eventName of target.events) {\n const result = installHookEvent(hooks[eventName], eventName, target.statusMessages);\n hooks[eventName] = result.groups;\n replacedHandlers += result.removedHandlers;\n }\n\n document.hooks = hooks;\n\n if (!dryRun) {\n await fs.mkdir(path.dirname(target.configPath), { recursive: true });\n await fs.writeFile(target.configPath, `${JSON.stringify(document, null, 2)}\\n`);\n }\n\n const action = dryRun ? \"Would install\" : \"Installed\";\n return {\n action,\n label: target.label,\n configPath: target.configPath,\n changedCount: target.events.length,\n replacedCount: replacedHandlers,\n events: target.events,\n };\n}\n\nexport async function uninstallHooksForTarget(\n target: InstallTarget,\n dryRun: boolean\n): Promise<HookTargetResult> {\n const document = await readJsonDocument(target.configPath);\n const hooks = parseHookConfig(document.hooks);\n const removedEvents: string[] = [];\n let removedHandlers = 0;\n\n for (const [eventName, groups] of Object.entries(hooks)) {\n const result = uninstallHookEvent(groups);\n if (result.removedHandlers > 0) {\n removedEvents.push(eventName);\n removedHandlers += result.removedHandlers;\n }\n hooks[eventName] = result.groups;\n }\n\n document.hooks = Object.fromEntries(\n Object.entries(hooks).filter(([, groups]) => groups.length > 0)\n );\n\n if (!dryRun) {\n await fs.mkdir(path.dirname(target.configPath), { recursive: true });\n await fs.writeFile(target.configPath, `${JSON.stringify(document, null, 2)}\\n`);\n }\n\n const action = dryRun ? \"Would remove\" : \"Removed\";\n return {\n action,\n label: target.label,\n configPath: target.configPath,\n changedCount: removedHandlers,\n events: removedEvents,\n };\n}\n\nfunction installHookEvent(\n existingGroups: HookGroup[] | undefined,\n eventName: string,\n withStatusMessage: boolean\n): {\n readonly groups: HookGroup[];\n readonly removedHandlers: number;\n} {\n const result = uninstallHookEvent(existingGroups ?? []);\n\n return {\n groups: [\n ...result.groups,\n {\n hooks: [createCngkitHookHandler(eventName, withStatusMessage)],\n },\n ],\n removedHandlers: result.removedHandlers,\n };\n}\n\nfunction uninstallHookEvent(groups: HookGroup[] | undefined): {\n readonly groups: HookGroup[];\n readonly removedHandlers: number;\n} {\n let removedHandlers = 0;\n const cleanedGroups = parseHookGroups(groups)\n .map((group) => {\n if (group.hooks === undefined) {\n return group;\n }\n\n const hooks = group.hooks.filter((handler) => {\n const keep = !isCngkitHookHandler(handler);\n if (!keep) {\n removedHandlers += 1;\n }\n return keep;\n });\n\n return { ...group, hooks };\n })\n .filter((group) => {\n return group.hooks === undefined || group.hooks.length > 0;\n });\n\n return { groups: cleanedGroups, removedHandlers };\n}\n","import type { HookHandler } from \"./hooks-schemas.js\";\n\nexport const cngkitHookCommandPrefix = \"cngkit hookify ingest --event \";\n\nexport const legacyCngkitHookCommandPrefixes = [\n \"npx --yes cngkit@latest hookify ingest --event \",\n \"npm exec cngkit@latest hookify ingest --event \",\n \"npm exec --yes cngkit@latest hookify ingest --event \",\n] as const;\n\nexport function isCngkitHookHandler(handler: HookHandler): boolean {\n const command = handler.command?.trimStart();\n if (command === undefined) {\n return false;\n }\n\n return [cngkitHookCommandPrefix, ...legacyCngkitHookCommandPrefixes].some((prefix) =>\n command.startsWith(prefix)\n );\n}\n\nexport function createCngkitHookHandler(\n eventName: string,\n withStatusMessage: boolean\n): HookHandler {\n const handler: HookHandler = {\n type: \"command\",\n command: `${cngkitHookCommandPrefix}${eventName}`,\n };\n\n if (!withStatusMessage) {\n return handler;\n }\n\n return {\n ...handler,\n statusMessage: `Forwarding ${eventName} hook to cngkit`,\n };\n}\n","import fs from \"node:fs/promises\";\n\nimport { z } from \"zod\";\n\nimport {\n AgentSettingsDocumentSchema,\n HookGroupSchema,\n type AgentSettingsDocument,\n type HookConfig,\n type HookGroup,\n} from \"./hooks-schemas.js\";\n\nexport async function readJsonDocument(filePath: string): Promise<AgentSettingsDocument> {\n if (!(await fileExists(filePath))) {\n return {};\n }\n\n const content = await fs.readFile(filePath, \"utf8\");\n return AgentSettingsDocumentSchema.parse(JSON.parse(content));\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n return fs.access(filePath).then(\n () => true,\n () => false\n );\n}\n\nexport function parseHookConfig(value: AgentSettingsDocument[\"hooks\"]): HookConfig {\n // The runtime config may be malformed by other tools; fall back to an empty\n // hooks record so callers can still mutate and rewrite it without throwing.\n return z.record(z.string(), z.array(HookGroupSchema)).catch({}).parse(value ?? {});\n}\n\nexport function parseHookGroups(value: HookGroup[] | undefined): HookGroup[] {\n return z.array(HookGroupSchema).catch([]).parse(value ?? []);\n}\n","import { z } from \"zod\";\n\nexport const HookHandlerSchema = z\n .object({\n command: z.string().optional(),\n })\n .passthrough();\n\nexport const HookGroupSchema = z\n .object({\n hooks: z.array(HookHandlerSchema).optional(),\n })\n .passthrough();\n\nexport const HooksConfigSchema = z.record(z.string(), z.array(HookGroupSchema));\n\nexport const AgentSettingsDocumentSchema = z\n .object({\n hooks: HooksConfigSchema.optional(),\n })\n .passthrough();\n\nexport type HookHandler = z.infer<typeof HookHandlerSchema>;\nexport type HookGroup = z.infer<typeof HookGroupSchema>;\nexport type HookConfig = z.infer<typeof HooksConfigSchema>;\nexport type AgentSettingsDocument = z.infer<typeof AgentSettingsDocumentSchema>;\n"],"mappings":"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","names":["fs","path","z","z","fs","path"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/features/knowledges/knowledges-input.ts"],"sourcesContent":["import type { CngApi } from \"@cng/client\";\n\nconst storedTopicsRoot = \"skills/knowledges/topics\";\n\nexport function normalizeAudienceId(value: string | undefined): CngApi.HarnessAudienceId | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n switch (value) {\n case \"all\":\n case \"operators\":\n case \"builders\":\n case \"researchers\":\n case \"agent-makers\":\n return value;\n default:\n throw new Error(\n `Unknown audience \"${value}\". Run cngkit knowledges audiences to see supported values.`\n );\n }\n}\n\nexport function normalizeCatalogPath(value: string): string {\n const trimmed = value.trim();\n if (trimmed === \"/\" || trimmed === \"\") {\n return storedTopicsRoot;\n }\n\n const relativePath = trimmed.replace(/^\\/+/, \"\");\n if (relativePath === storedTopicsRoot || relativePath.startsWith(`${storedTopicsRoot}/`)) {\n return relativePath;\n }\n\n const topicRelativePath = relativePath.startsWith(\"topics/\")\n ? relativePath.slice(\"topics/\".length)\n : relativePath;\n\n const [firstSegment, ...restSegments] = relativePath.split(\"/\");\n if (!firstSegment) {\n return relativePath;\n }\n\n switch (firstSegment) {\n case \"concepts\":\n case \"domains\":\n case \"formats\":\n case \"languages\":\n case \"libraries\":\n case \"patterns\":\n case \"platforms\":\n case \"procedures\":\n case \"protocols\":\n case \"tools\":\n return `${storedTopicsRoot}/${firstSegment}${restSegments.length > 0 ? `/${restSegments.join(\"/\")}` : \"\"}`;\n default:\n return `${storedTopicsRoot}/${topicRelativePath}`;\n }\n}\n\nexport function normalizeFilesystemCatalogPath(value: string): string {\n const trimmed = value.trim();\n if (trimmed === \"/\" || trimmed === \"\") {\n return storedTopicsRoot;\n }\n\n return normalizeCatalogPath(trimmed);\n}\n\nexport function formatCatalogPathForDisplay(value: string): string {\n const normalized = value.replace(/\\/+$/, \"\");\n if (normalized === storedTopicsRoot) {\n return \"/\";\n }\n\n if (normalized.startsWith(`${storedTopicsRoot}/`)) {\n return `/${normalized.slice(storedTopicsRoot.length + 1)}`;\n }\n\n return value;\n}\n\nexport function normalizeGrepMode(value: string | undefined): CngApi.HarnessGrepOutputMode {\n if (value === undefined) {\n return \"content\";\n }\n\n switch (value) {\n case \"content\":\n case \"files_with_matches\":\n case \"count\":\n return value;\n default:\n throw new Error(\"Unknown grep mode. Use one of: content, files_with_matches, count.\");\n }\n}\n"],"mappings":";AAEA,IAAM,mBAAmB;AAElB,SAAS,oBAAoB,OAAiE;AACnG,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AAEA,UAAQ,OAAO;AAAA,IACb,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,YAAM,IAAI;AAAA,QACR,qBAAqB,KAAK;AAAA,MAC5B;AAAA,EACJ;AACF;AAEO,SAAS,qBAAqB,OAAuB;AAC1D,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,YAAY,OAAO,YAAY,IAAI;AACrC,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,QAAQ,QAAQ,QAAQ,EAAE;AAC/C,MAAI,iBAAiB,oBAAoB,aAAa,WAAW,GAAG,gBAAgB,GAAG,GAAG;AACxF,WAAO;AAAA,EACT;AAEA,QAAM,oBAAoB,aAAa,WAAW,SAAS,IACvD,aAAa,MAAM,UAAU,MAAM,IACnC;AAEJ,QAAM,CAAC,cAAc,GAAG,YAAY,IAAI,aAAa,MAAM,GAAG;AAC9D,MAAI,CAAC,cAAc;AACjB,WAAO;AAAA,EACT;AAEA,UAAQ,cAAc;AAAA,IACpB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,GAAG,gBAAgB,IAAI,YAAY,GAAG,aAAa,SAAS,IAAI,IAAI,aAAa,KAAK,GAAG,CAAC,KAAK,EAAE;AAAA,IAC1G;AACE,aAAO,GAAG,gBAAgB,IAAI,iBAAiB;AAAA,EACnD;AACF;AAEO,SAAS,+BAA+B,OAAuB;AACpE,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,YAAY,OAAO,YAAY,IAAI;AACrC,WAAO;AAAA,EACT;AAEA,SAAO,qBAAqB,OAAO;AACrC;AAEO,SAAS,4BAA4B,OAAuB;AACjE,QAAM,aAAa,MAAM,QAAQ,QAAQ,EAAE;AAC3C,MAAI,eAAe,kBAAkB;AACnC,WAAO;AAAA,EACT;AAEA,MAAI,WAAW,WAAW,GAAG,gBAAgB,GAAG,GAAG;AACjD,WAAO,IAAI,WAAW,MAAM,iBAAiB,SAAS,CAAC,CAAC;AAAA,EAC1D;AAEA,SAAO;AACT;AAEO,SAAS,kBAAkB,OAAyD;AACzF,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AAEA,UAAQ,OAAO;AAAA,IACb,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,YAAM,IAAI,MAAM,oEAAoE;AAAA,EACxF;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/features/knowledges/format/content-format.ts"],"sourcesContent":["import type { CngApi } from \"@cng/client\";\n\nimport { formatJson, shouldPrintJson, type JsonOutputOptions } from \"../../../shared/command-utils.js\";\nimport type { CommandOutput } from \"../../../shared/output/types.js\";\n\nexport function outputRawContent(\n data: CngApi.HarnessReadResponse,\n options: JsonOutputOptions,\n output: CommandOutput\n): void {\n if (shouldPrintJson(options)) {\n output.raw(formatJson(data));\n return;\n }\n\n output.raw(data.content);\n}\n"],"mappings":";;;;;;AAKO,SAAS,iBACd,MACA,SACA,QACM;AACN,MAAI,gBAAgB,OAAO,GAAG;AAC5B,WAAO,IAAI,WAAW,IAAI,CAAC;AAC3B;AAAA,EACF;AAEA,SAAO,IAAI,KAAK,OAAO;AACzB;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
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/local-events.ts","../src/features/coderoom/sync/session.ts","../src/features/coderoom/sync/protocol.ts","../src/features/coderoom/sync/remote-handler.ts"],"sourcesContent":["import process from \"node:process\";\n\nimport { createCngApiClient, readBackendHealth } from \"../../shared/api-client.js\";\nimport { resolveApiBaseUrl, type GlobalCommandOptions } from \"../../shared/config.js\";\nimport type { CommandOutput } from \"../../shared/output/types.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(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 options: ShareCommandOptions,\n output: CommandOutput\n): Promise<void> {\n const room = await createCoderoomRoom(options);\n\n output.success(`Share code: ${room.roomCode}`);\n await printBackendStatus(options, output);\n await runSyncSession(\"host\", room.roomCode, room.creatorToken, 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(\"guest\", roomCode, undefined, 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 creatorToken: string | undefined,\n options: GlobalCommandOptions,\n output: CommandOutput\n): Promise<void> {\n await startSyncSession({\n apiBaseUrl: resolveApiBaseUrl(options),\n roomCode,\n creatorToken,\n role,\n cwd: process.cwd(),\n output,\n });\n}\n\nasync function createCoderoomRoom(options: GlobalCommandOptions): Promise<{\n roomCode: string;\n creatorToken: string;\n}> {\n const client = createCngApiClient(options);\n return client.coderoom.createCoderoomRoom();\n}\n","// Public API entrypoint for the coderoom sync client. Implementation lives in\n// `./session.ts` (WebSocket lifecycle), `./local-events.ts` (file watcher +\n// outbound events), and `./remote-handler.ts` (inbound message dispatch).\n\nimport WebSocket from \"ws\";\n\nimport { createSuppressionTracker } from \"./files.js\";\nimport {\n createRepoWatcher,\n sendInitialSnapshot,\n type WatcherContext,\n} from \"./local-events.js\";\nimport { resolveRepoContext } from \"./paths.js\";\nimport { handleServerMessage } from \"./remote-handler.js\";\nimport { createSyncWebSocketUrl, waitForSessionClose } from \"./session.js\";\nimport type { CommandOutput } from \"../../../shared/output/types.js\";\n\nexport type SyncSessionRole = \"host\" | \"guest\";\n\nexport type StartSyncSessionOptions = {\n apiBaseUrl: string;\n roomCode: string;\n creatorToken?: string;\n role: SyncSessionRole;\n cwd: string;\n output: CommandOutput;\n};\n\nexport async function startSyncSession(options: StartSyncSessionOptions): Promise<void> {\n const repoContext = await resolveRepoContext(options.cwd);\n const suppressionTracker = createSuppressionTracker();\n const webSocketUrl = createSyncWebSocketUrl(options);\n const socket = new WebSocket(webSocketUrl);\n const state = {\n approved: options.role === \"host\",\n participantId: undefined as string | undefined,\n };\n\n options.output.success(`Room: ${options.roomCode}`);\n options.output.info(`Repo: ${repoContext.rootDir}`);\n\n const watcherContext: WatcherContext = {\n repoContext,\n socket,\n state,\n suppressionTracker,\n output: options.output,\n };\n const watcher = createRepoWatcher(watcherContext);\n\n socket.on(\"open\", () => {\n if (options.role === \"host\") {\n void sendInitialSnapshot(socket, repoContext, options.output);\n return;\n }\n\n options.output.info(\"Waiting for host approval...\");\n });\n\n socket.on(\"message\", (data) => {\n void handleServerMessage({\n data,\n socket,\n repoContext,\n state,\n suppressionTracker,\n output: options.output,\n });\n });\n\n await waitForSessionClose(socket, watcher);\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { ClientMessage, ServerFileMutationMessage } 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(context: RepoContext): AsyncGenerator<ClientMessage> {\n yield* collectDirectorySnapshot(context, context.rootDir);\n}\n\nasync function* collectDirectorySnapshot(\n context: RepoContext,\n directoryPath: string\n): AsyncGenerator<ClientMessage> {\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);\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 path: relativePath,\n contentBase64: content.toString(\"base64\"),\n mtimeMs: stat.mtimeMs,\n };\n }\n}\n\nexport async function buildFileMessage(\n context: RepoContext,\n relativePath: string\n): Promise<ClientMessage | 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 path: relativePath,\n contentBase64: content.toString(\"base64\"),\n mtimeMs: stat.mtimeMs,\n };\n}\n\nexport async function applyRemoteMessage(\n context: RepoContext,\n message: ServerFileMutationMessage,\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 fs from \"node:fs\";\n\nimport chokidar, { type FSWatcher } from \"chokidar\";\nimport WebSocket from \"ws\";\n\nimport type { CommandOutput } from \"../../../shared/output/types.js\";\nimport { buildFileMessage, collectSnapshotMessages, type SuppressionTracker } from \"./files.js\";\nimport { shouldSyncRelativePath, toRepoRelativePath, type RepoContext } from \"./paths.js\";\nimport { sendMessage } from \"./session.js\";\n\ntype SessionState = {\n approved: boolean;\n participantId?: string;\n};\n\nexport type WatcherContext = {\n repoContext: RepoContext;\n socket: WebSocket;\n state: SessionState;\n suppressionTracker: SuppressionTracker;\n output: CommandOutput;\n};\n\nexport function 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 if (relativePath?.split(\"/\").includes(\".git\") ?? false) {\n return true;\n }\n try {\n const stat = fs.statSync(candidatePath);\n return !stat.isFile() && !stat.isDirectory();\n } catch {\n return false;\n }\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 watcher.on(\"error\", (watcherError) => {\n context.output.warning(\n `watcher error: ${watcherError instanceof Error ? watcherError.message : String(watcherError)}`\n );\n });\n\n return watcher;\n}\n\nexport async function sendInitialSnapshot(\n socket: WebSocket,\n repoContext: RepoContext,\n output: CommandOutput\n): Promise<void> {\n let fileCount = 0;\n\n for await (const message of collectSnapshotMessages(repoContext)) {\n sendMessage(socket, message);\n fileCount += 1;\n }\n\n output.success(`sent snapshot ${fileCount} files`);\n}\n\nasync function sendLocalFileChange(context: WatcherContext, absolutePath: string): Promise<void> {\n if (!context.state.approved) {\n return;\n }\n\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, 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 if (!context.state.approved) {\n return;\n }\n\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 path: relativePath,\n mtimeMs: Date.now(),\n });\n context.output.warning(`sent delete ${relativePath}`);\n}\n","import os from \"node:os\";\nimport process from \"node:process\";\n\nimport { type FSWatcher } from \"chokidar\";\nimport WebSocket from \"ws\";\n\nimport { encodeClientMessage, type ClientMessage } from \"./protocol.js\";\nimport type { StartSyncSessionOptions } from \"./client.js\";\n\nexport function createSyncWebSocketUrl(options: StartSyncSessionOptions): string {\n const url = new URL(options.apiBaseUrl);\n url.protocol = url.protocol === \"http:\" ? \"ws:\" : \"wss:\";\n url.pathname = `/api/cng/coderoom/rooms/${encodeURIComponent(options.roomCode)}/ws`;\n url.search = \"\";\n url.hash = \"\";\n url.searchParams.set(\"role\", options.role);\n url.searchParams.set(\"displayName\", createDisplayName());\n if (options.creatorToken) {\n url.searchParams.set(\"creatorToken\", options.creatorToken);\n }\n return url.toString();\n}\n\nexport function sendMessage(socket: WebSocket, message: ClientMessage): void {\n if (socket.readyState === WebSocket.OPEN) {\n socket.send(encodeClientMessage(message));\n }\n}\n\nexport function createDisplayName(): string {\n const username = os.userInfo().username || \"user\";\n return `${username}@${os.hostname()}`;\n}\n\nexport async 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 { z } from \"zod\";\n\nexport const ClientFileMessageSchema = z.object({\n type: z.literal(\"file\"),\n path: z.string().min(1),\n contentBase64: z.string(),\n mtimeMs: z.number().finite(),\n});\n\nexport const ClientDeleteMessageSchema = z.object({\n type: z.literal(\"delete\"),\n path: z.string().min(1),\n mtimeMs: z.number().finite(),\n});\n\nexport const ClientJoinApprovalMessageSchema = z.object({\n type: z.literal(\"join-approval\"),\n joinRequestId: z.string().min(1),\n approved: z.boolean(),\n});\n\nexport const ClientMessageSchema = z.discriminatedUnion(\"type\", [\n ClientFileMessageSchema,\n ClientDeleteMessageSchema,\n ClientJoinApprovalMessageSchema,\n]);\n\nexport const ServerConnectedMessageSchema = z.object({\n type: z.literal(\"connected\"),\n roomCode: z.string(),\n participantId: z.string(),\n role: z.union([z.literal(\"host\"), z.literal(\"guest\")]),\n status: z.union([z.literal(\"approved\"), z.literal(\"pending\"), z.literal(\"denied\")]),\n});\n\nexport const ServerJoinPendingMessageSchema = z.object({\n type: z.literal(\"join-pending\"),\n participantId: z.string(),\n joinRequestId: z.string(),\n roomCode: z.string(),\n});\n\nexport const ServerJoinRequestMessageSchema = z.object({\n type: z.literal(\"join-request\"),\n joinRequestId: z.string(),\n participantId: z.string(),\n displayName: z.string(),\n requestedAt: z.number().finite(),\n});\n\nexport const ServerJoinApprovedMessageSchema = z.object({\n type: z.literal(\"join-approved\"),\n participantId: z.string(),\n});\n\nexport const ServerJoinDeniedMessageSchema = z.object({\n type: z.literal(\"join-denied\"),\n participantId: z.string(),\n reason: z.string(),\n});\n\nexport const ServerFileMessageSchema = z.object({\n type: z.literal(\"file\"),\n fileId: z.string(),\n path: z.string().min(1),\n sha256: z.string(),\n size: z.number().int().nonnegative(),\n contentBase64: z.string(),\n mtimeMs: z.number().finite(),\n updatedByParticipantId: z.string(),\n});\n\nexport const ServerDeleteMessageSchema = z.object({\n type: z.literal(\"delete\"),\n fileId: z.string().optional(),\n path: z.string().min(1),\n mtimeMs: z.number().finite(),\n updatedByParticipantId: z.string(),\n});\n\nexport const ServerFileAckMessageSchema = z.object({\n type: z.literal(\"file-ack\"),\n fileId: z.string(),\n path: z.string().min(1),\n sha256: z.string(),\n size: z.number().int().nonnegative(),\n storage: z.union([z.literal(\"durable-object\"), z.literal(\"r2\")]),\n});\n\nexport const ServerTreeStartMessageSchema = z.object({\n type: z.literal(\"tree-start\"),\n fileCount: z.number().int().nonnegative(),\n});\n\nexport const ServerTreeCompleteMessageSchema = z.object({\n type: z.literal(\"tree-complete\"),\n fileCount: z.number().int().nonnegative(),\n});\n\nexport const ServerErrorMessageSchema = z.object({\n type: z.literal(\"error\"),\n error: z.string(),\n});\n\nexport const ServerMessageSchema = z.discriminatedUnion(\"type\", [\n ServerConnectedMessageSchema,\n ServerJoinPendingMessageSchema,\n ServerJoinRequestMessageSchema,\n ServerJoinApprovedMessageSchema,\n ServerJoinDeniedMessageSchema,\n ServerFileMessageSchema,\n ServerDeleteMessageSchema,\n ServerFileAckMessageSchema,\n ServerTreeStartMessageSchema,\n ServerTreeCompleteMessageSchema,\n ServerErrorMessageSchema,\n]);\n\nexport type ClientMessage = z.infer<typeof ClientMessageSchema>;\nexport type ServerMessage = z.infer<typeof ServerMessageSchema>;\nexport type ServerFileMutationMessage = Extract<ServerMessage, { type: \"file\" | \"delete\" }>;\n\nexport function encodeClientMessage(message: ClientMessage): string {\n return JSON.stringify(ClientMessageSchema.parse(message));\n}\n\nexport function decodeServerMessage(value: unknown): ServerMessage | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n\n try {\n return ServerMessageSchema.parse(JSON.parse(value));\n } catch {\n return undefined;\n }\n}\n","import process from \"node:process\";\nimport readline from \"node:readline/promises\";\n\nimport WebSocket, { type RawData } from \"ws\";\n\nimport type { CommandOutput } from \"../../../shared/output/types.js\";\nimport { applyRemoteMessage, type SuppressionTracker } from \"./files.js\";\nimport type { RepoContext } from \"./paths.js\";\nimport { decodeServerMessage, type ServerMessage } from \"./protocol.js\";\nimport { sendMessage } from \"./session.js\";\n\ntype SessionState = {\n approved: boolean;\n participantId?: string;\n};\n\nexport type HandleServerMessageOptions = {\n data: RawData;\n socket: WebSocket;\n repoContext: RepoContext;\n state: SessionState;\n suppressionTracker: SuppressionTracker;\n output: CommandOutput;\n};\n\nexport async function handleServerMessage(options: HandleServerMessageOptions): Promise<void> {\n const decodedMessage = decodeServerMessage(options.data.toString());\n if (!decodedMessage) {\n return;\n }\n\n if (decodedMessage.type === \"connected\") {\n options.state.participantId = decodedMessage.participantId;\n options.state.approved = decodedMessage.status === \"approved\";\n options.output.muted(`Participant: ${decodedMessage.participantId}`);\n return;\n }\n\n if (decodedMessage.type === \"join-pending\") {\n options.output.info(`Join request sent: ${decodedMessage.joinRequestId}`);\n return;\n }\n\n if (decodedMessage.type === \"join-request\") {\n await approveJoinRequest(options.socket, decodedMessage, options.output);\n return;\n }\n\n if (decodedMessage.type === \"join-approved\") {\n options.state.approved = true;\n options.output.success(\"Join approved. Applying room file tree...\");\n return;\n }\n\n if (decodedMessage.type === \"join-denied\") {\n options.output.warning(`Join denied: ${decodedMessage.reason}`);\n options.socket.close();\n return;\n }\n\n if (decodedMessage.type === \"tree-start\") {\n options.output.info(`receiving room tree ${decodedMessage.fileCount} files`);\n return;\n }\n\n if (decodedMessage.type === \"tree-complete\") {\n options.output.success(`room tree complete ${decodedMessage.fileCount} files`);\n return;\n }\n\n if (decodedMessage.type === \"file-ack\") {\n options.output.muted(\n `stored ${decodedMessage.storage} ${decodedMessage.path} ${decodedMessage.sha256}`\n );\n return;\n }\n\n if (decodedMessage.type === \"error\") {\n options.output.warning(`server error: ${decodedMessage.error}`);\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 approveJoinRequest(\n socket: WebSocket,\n message: Extract<ServerMessage, { type: \"join-request\" }>,\n output: CommandOutput\n): Promise<void> {\n const approved = await askForApproval(message, output);\n sendMessage(socket, {\n type: \"join-approval\",\n joinRequestId: message.joinRequestId,\n approved,\n });\n output[approved ? \"success\" : \"warning\"](\n `${approved ? \"approved\" : \"denied\"} ${message.displayName}`\n );\n}\n\nasync function askForApproval(\n message: Extract<ServerMessage, { type: \"join-request\" }>,\n output: CommandOutput\n): Promise<boolean> {\n output.info(`Join request: ${message.displayName} (${message.joinRequestId})`);\n if (!process.stdin.isTTY) {\n output.warning(\"No interactive terminal available. Denying join request.\");\n return false;\n }\n\n const interfaceReader = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n const answer = await interfaceReader.question(\"Approve join request? [y/N] \");\n return answer.trim().toLowerCase() === \"y\" || answer.trim().toLowerCase() === \"yes\";\n } finally {\n interfaceReader.close();\n }\n}\n"],"mappings":"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","names":["process","WebSocket","path","path","fs","fs","process","process","WebSocket","process"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/help-specs.ts","../src/cli/help-components.tsx","../src/cli/help-topic-content.ts"],"sourcesContent":["import { createElement, type ReactElement } from \"react\";\n\nimport { HelpDocument } from \"./help-components.js\";\nimport { helpTopicDocuments } from \"./help-topic-content.js\";\n\nconst helpTopicNames = helpTopicDocuments\n .filter((topic) => topic.title !== \"cngkit\")\n .map((topic) => topic.title)\n .sort();\n\nconst helpTopicByAlias = new Map<string, (typeof helpTopicDocuments)[number]>();\n\nfor (const topic of helpTopicDocuments) {\n for (const alias of topic.aliases) {\n helpTopicByAlias.set(alias, topic);\n }\n}\n\nexport function renderCngkitHelp(topicName?: string): ReactElement {\n const normalizedTopicName = normalizeHelpTopicName(topicName);\n const topic = helpTopicByAlias.get(normalizedTopicName);\n\n if (topic) {\n return createElement(HelpDocument, { document: topic });\n }\n\n if (normalizedTopicName === \"\") {\n const defaultTopic = helpTopicByAlias.get(\"\");\n if (defaultTopic) {\n return createElement(HelpDocument, { document: defaultTopic });\n }\n }\n\n return createElement(HelpDocument, {\n document: {\n title: \"cngkit help\",\n aliases: [],\n heading: \"cngkit help\",\n blocks: [\n {\n kind: \"paragraph\",\n text: `No help topic named ${normalizedTopicName}.`,\n },\n {\n kind: \"section\",\n title: \"Available Topics\",\n },\n {\n kind: \"list\",\n items: helpTopicNames,\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit help <topic>\", \"cngkit <command> --help\"],\n },\n ],\n },\n });\n}\n\nexport function renderKnowledgesHelp(topicName?: string): ReactElement {\n const normalizedTopicName = normalizeHelpTopicName(topicName);\n const topicKey = normalizedTopicName ? `knowledges-${normalizedTopicName}` : \"knowledges\";\n return renderCngkitHelp(topicKey);\n}\n\nfunction normalizeHelpTopicName(value: string | undefined): string {\n return value?.trim().toLowerCase().replace(/\\s+/g, \"-\") ?? \"\";\n}\n","import { Box, Text } from \"ink\";\n\nimport type { HelpBlock, HelpTopicDocument } from \"./help-topic-content.js\";\n\ntype HelpDocumentProps = {\n readonly document: HelpTopicDocument;\n};\n\nexport function HelpDocument({ document }: HelpDocumentProps) {\n return (\n <Box flexDirection=\"column\">\n <Text bold color=\"magenta\">\n {document.heading}\n </Text>\n {document.blocks.map((block, index) => (\n <HelpBlockView block={block} key={`${block.kind}-${index}`} />\n ))}\n </Box>\n );\n}\n\nfunction HelpBlockView({ block }: { readonly block: HelpBlock }) {\n if (block.kind === \"section\") {\n return (\n <Box marginTop={1}>\n <Text bold color=\"blue\">\n {block.title}\n </Text>\n </Box>\n );\n }\n\n if (block.kind === \"paragraph\") {\n return (\n <Box>\n <Text wrap=\"wrap\">\n <InlineText text={block.text} />\n </Text>\n </Box>\n );\n }\n\n if (block.kind === \"list\") {\n return (\n <Box flexDirection=\"column\">\n {block.items.map((item, index) => (\n <Text key={`${item}-${index}`} wrap=\"wrap\">\n <Text color=\"cyan\">- </Text>\n <InlineText text={item} />\n </Text>\n ))}\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" marginLeft={2}>\n {block.lines.map((line, index) => (\n <Text color=\"green\" key={`${line}-${index}`}>\n {line}\n </Text>\n ))}\n </Box>\n );\n}\n\nfunction InlineText({ text }: { readonly text: string }) {\n return text.split(/(`[^`]+`)/g).map((part, index) => {\n const isCodeSpan = part.startsWith(\"`\") && part.endsWith(\"`\") && part.length > 1;\n\n if (isCodeSpan) {\n return (\n <Text color=\"cyan\" key={`${part}-${index}`}>\n {part.slice(1, -1)}\n </Text>\n );\n }\n\n return part;\n });\n}\n","export type HelpBlock =\n | {\n readonly kind: \"section\";\n readonly title: string;\n }\n | {\n readonly kind: \"paragraph\";\n readonly text: string;\n }\n | {\n readonly kind: \"list\";\n readonly items: readonly string[];\n }\n | {\n readonly kind: \"code\";\n readonly language?: string;\n readonly lines: readonly string[];\n };\n\nexport type HelpTopicDocument = {\n readonly title: string;\n readonly aliases: readonly string[];\n readonly heading: string;\n readonly blocks: readonly HelpBlock[];\n};\n\nexport const helpTopicDocuments = [\n {\n title: \"cngkit\",\n aliases: [\"\", \"overview\", \"help\"],\n heading: \"cngkit\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"CNG operator CLI for shared code rooms, safe local cleanup, local agent transcripts, and hosted Harness knowledges.\",\n },\n {\n kind: \"section\",\n title: \"Run Now\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"npx --yes cngkit@latest --help\",\n \"npx --yes cngkit@latest knowledges search Cloudflare --limit 3\",\n ],\n },\n {\n kind: \"section\",\n title: \"Installed Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit <command> [options]\"],\n },\n {\n kind: \"section\",\n title: \"Global Options\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit --format text|json|markdown ...\", \"cngkit --no-color ...\"],\n },\n {\n kind: \"section\",\n title: \"Commands\",\n },\n {\n kind: \"list\",\n items: [\n \"`cngkit login` - open browser login, or print the URL in headless shells.\",\n \"`cngkit coderoom ...` - share or join a live developer room for a working tree.\",\n \"`cngkit scrub [path]` - scan for secrets; rewrite only when `--yes` is passed.\",\n \"`cngkit transcripts ...` - list, read, and grep local Claude/Codex transcripts.\",\n \"`cngkit knowledges ...` - search and read the hosted Harness knowledge catalog.\",\n \"`cngkit hooks ...` - install Hookify forwarding hooks into supported AI coding tools.\",\n \"`cngkit hookify ...` - forward local hook events to Hookify.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Help Map\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"cngkit help <topic>\",\n \"cngkit <command> --help\",\n \"cngkit coderoom --help\",\n \"cngkit coderoom <subcommand> --help\",\n \"cngkit transcripts --help\",\n \"cngkit hooks --help\",\n \"cngkit hooks install --help\",\n \"cngkit hooks uninstall --help\",\n \"cngkit knowledges --help\",\n \"cngkit knowledges <subcommand> --help\",\n \"cngkit hookify --help\",\n \"cngkit hookify ingest --help\",\n ],\n },\n {\n kind: \"section\",\n title: \"AI And Scripts\",\n },\n {\n kind: \"list\",\n items: [\n \"Help renders as structured terminal text by default, even in pipes.\",\n \"Use `--format json` or `--json` on read-only data commands for typed payloads.\",\n \"Use `--format markdown` only when raw Markdown source is intentional.\",\n \"Use `--no-color` or `CNGKIT_COLOR=never` for logs, screenshots, and strict plain text.\",\n \"Use `npm_config_progress=false npx --yes cngkit@latest ...` for clean one-shot npx captures.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Backend\",\n },\n {\n kind: \"paragraph\",\n text: \"API: `https://curly.ng`\",\n },\n ],\n },\n {\n title: \"login\",\n aliases: [\"login\"],\n heading: \"cngkit login\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Open browser login. In headless shells, print the URL so an agent can show it to the operator.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"npx --yes cngkit@latest login\", \"cngkit login\"],\n },\n {\n kind: \"section\",\n title: \"Output\",\n },\n {\n kind: \"list\",\n items: [\n \"First line names the login URL being opened.\",\n \"If no browser opener exists, the CLI prints a direct URL.\",\n \"No credentials are printed or persisted by this command.\",\n ],\n },\n ],\n },\n {\n title: \"transcripts\",\n aliases: [\"transcripts\", \"transcript\"],\n heading: \"cngkit transcripts\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Read local Claude and Codex transcript JSONL files.\",\n },\n {\n kind: \"paragraph\",\n text: \"This is local-only operator tooling. It does not call the backend and it does not upload transcript content.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"cngkit transcripts list [--source all|codex|claude] [--limit <n>] [--json|--format json]\",\n \"cngkit transcripts read <path-or-session-id> [--source all|codex|claude] [--limit <n>] [--include-internal] [--json|--format json]\",\n \"cngkit transcripts grep <query> [--source all|codex|claude] [--limit <n>] [--file-limit <n>] [--include-internal] [--json|--format json]\",\n ],\n },\n {\n kind: \"section\",\n title: \"Sources\",\n },\n {\n kind: \"list\",\n items: [\n \"`~/.codex/sessions`\",\n \"`~/.codex/archived_sessions`\",\n \"`~/.claude/projects`\",\n \"`~/.claude/history.jsonl`\",\n ],\n },\n {\n kind: \"section\",\n title: \"Defaults\",\n },\n {\n kind: \"list\",\n items: [\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 },\n {\n kind: \"section\",\n title: \"Output\",\n },\n {\n kind: \"list\",\n items: [\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 },\n {\n title: \"hookify\",\n aliases: [\"hookify\"],\n heading: \"cngkit hookify\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Forward local hook events to Hookify.\",\n },\n {\n kind: \"paragraph\",\n text: \"Hookify is the hosted hook processing surface. The CLI stays small: it reads hook payloads locally, forwards raw stdin to the backend, prints the backend stdout, and exits with the backend exit code. If forwarding fails, it exits with code 0.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit hookify <subcommand> [options]\"],\n },\n {\n kind: \"section\",\n title: \"Subcommands\",\n },\n {\n kind: \"list\",\n items: [\"`ingest` - read a raw hook payload from stdin and forward it to the backend.\"],\n },\n ],\n },\n {\n title: \"hooks\",\n aliases: [\"hooks\"],\n heading: \"cngkit hooks\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Install local Hookify forwarding hooks into supported AI-assisted coding tools.\",\n },\n {\n kind: \"paragraph\",\n text: \"The installer writes user-level config for documented hook surfaces and preserves existing non-cngkit hooks. Re-running it is idempotent: old cngkit Hookify entries are replaced with one current entry per event.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit hooks <subcommand> [options]\"],\n },\n {\n kind: \"section\",\n title: \"Subcommands\",\n },\n {\n kind: \"list\",\n items: [\n \"`install` - install Hookify forwarding hooks into supported AI coding tools.\",\n \"`uninstall` - remove cngkit Hookify forwarding hooks from supported AI coding tools.\",\n ],\n },\n ],\n },\n {\n title: \"hooks install\",\n aliases: [\"hooks-install\"],\n heading: \"cngkit hooks install\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Install Hookify forwarding hooks into supported AI-assisted coding tools.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit hooks install [--tool all|claude|codex] [--dry-run]\"],\n },\n {\n kind: \"section\",\n title: \"Behavior\",\n },\n {\n kind: \"list\",\n items: [\n \"Configures Claude Code at `~/.claude/settings.json`.\",\n \"Configures Codex at `~/.codex/hooks.json`.\",\n \"Preserves existing hook handlers that do not call `cngkit hookify ingest`.\",\n \"Replaces older cngkit Hookify handlers to avoid duplicates.\",\n \"Uses `cngkit hookify ingest --event <EventName>` for every supported event, avoiding npm package resolution in hook hot paths.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Examples\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"cngkit hooks install --dry-run\",\n \"cngkit hooks install\",\n \"cngkit hooks install --tool codex\",\n ],\n },\n ],\n },\n {\n title: \"hooks uninstall\",\n aliases: [\"hooks-uninstall\"],\n heading: \"cngkit hooks uninstall\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Remove cngkit Hookify forwarding hooks from supported AI-assisted coding tools.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit hooks uninstall [--tool all|claude|codex] [--dry-run]\"],\n },\n {\n kind: \"section\",\n title: \"Behavior\",\n },\n {\n kind: \"list\",\n items: [\n \"Reads Claude Code at `~/.claude/settings.json`.\",\n \"Reads Codex at `~/.codex/hooks.json`.\",\n \"Removes cngkit Hookify handlers installed with either the current direct `cngkit hookify ingest` command or older `cngkit@latest` npm/npx commands.\",\n \"Preserves all non-cngkit hook handlers and all other settings.\",\n \"Reports the exact config file, handler count, and event names changed.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Examples\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"cngkit hooks uninstall --dry-run\",\n \"cngkit hooks uninstall\",\n \"cngkit hooks uninstall --tool claude\",\n ],\n },\n ],\n },\n {\n title: \"hookify ingest\",\n aliases: [\"hookify-ingest\"],\n heading: \"cngkit hookify ingest\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Read a raw hook payload from stdin and forward it to Hookify.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit hookify ingest [--event <name>] [--async]\"],\n },\n {\n kind: \"section\",\n title: \"Behavior\",\n },\n {\n kind: \"list\",\n items: [\n \"Reads stdin exactly as the hook provides it.\",\n \"Sends the payload to `POST /api/hookify/ingest` as `application/octet-stream`.\",\n \"Handles both immediate backend results and workflow-backed pending results.\",\n \"Polls `GET /api/hookify/requests/<requestId>` when the backend returns a pending request.\",\n \"Prints backend `stdout` without extra formatting.\",\n \"Writes backend `stderr` when present.\",\n \"Uses backend `exitCode` as the process exit code.\",\n \"Falls back to exit code `0` if the backend request fails.\",\n \"`--async` tells the backend that workflow-backed processing is acceptable; the local command still waits for the final hook result.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Example\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: ['printf \\'{\"hook\":\"PreToolUse\"}\\' | cngkit hookify ingest --event PreToolUse'],\n },\n ],\n },\n {\n title: \"coderoom\",\n aliases: [\"coderoom\", \"code-room\", \"repo-sync\"],\n heading: \"cngkit coderoom\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Create or join a temporary live room for sharing a working tree over the configured backend.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit coderoom <subcommand> [options]\"],\n },\n {\n kind: \"section\",\n title: \"Subcommands\",\n },\n {\n kind: \"list\",\n items: [\n \"`share` - create a server-owned live room from the current directory.\",\n \"`join <room-code>` - request access to another developer's live room from the current directory.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Common Flow\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"npx --yes cngkit@latest coderoom share\",\n \"npx --yes cngkit@latest coderoom join <room-code>\",\n ],\n },\n {\n kind: \"section\",\n title: \"Behavior\",\n },\n {\n kind: \"list\",\n items: [\n \"Creates rooms through `/api/cng/coderoom/rooms` and connects to `/api/cng/coderoom/rooms/:roomCode/ws` on the configured backend.\",\n \"Uses WebSocket transport backed by the `CoderoomRoom` Durable Object.\",\n \"The server creates room codes, creator tokens, participant IDs, join request IDs, and file IDs.\",\n \"Joiners wait in a lobby until the room host approves them.\",\n \"The Durable Object stores the room file tree with hashes; large file bodies are stored in R2.\",\n \"The host sends an initial snapshot, then approved participants send file and delete events.\",\n \"Last received change wins.\",\n \"Current rooms are live collaboration state, not a source-control replacement.\",\n ],\n },\n ],\n },\n {\n title: \"coderoom share\",\n aliases: [\"coderoom-share\"],\n heading: \"cngkit coderoom share\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Start a live repository sync room from the current directory.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit coderoom share\"],\n },\n {\n kind: \"section\",\n title: \"Behavior\",\n },\n {\n kind: \"list\",\n items: [\n \"Creates the room through `/api/cng/coderoom/rooms`, then connects to `/api/cng/coderoom/rooms/:roomCode/ws`.\",\n \"Uses WebSocket transport backed by the `CoderoomRoom` Durable Object.\",\n \"Prints the server-created share code.\",\n \"Prompts the host to approve or deny each join request.\",\n \"Sends an initial snapshot, then file and delete events after the room is open.\",\n \"Last received change wins.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Filesystem Contract\",\n },\n {\n kind: \"list\",\n items: [\n \"Preserves `.git/`.\",\n \"Preserves files ignored by the repo's `.gitignore`.\",\n \"Sends regular files as base64 payloads in the sync protocol.\",\n \"Stores small file bodies in Durable Object storage and large file bodies in R2.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Output\",\n },\n {\n kind: \"list\",\n items: [\n \"Prints room code, repo root, server-assigned participant id, backend health, join requests, and concise sync events.\",\n \"Keeps running until the socket closes or the process receives a termination signal.\",\n ],\n },\n ],\n },\n {\n title: \"coderoom join\",\n aliases: [\"coderoom-join\"],\n heading: \"cngkit coderoom join\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Join an existing live repository sync room from the current directory.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit coderoom join <room-code>\"],\n },\n {\n kind: \"section\",\n title: \"Behavior\",\n },\n {\n kind: \"paragraph\",\n text: \"Same transport and filesystem contract as `cngkit coderoom share`. The supplied room code selects the Durable Object room, then the joiner waits until the host approves access.\",\n },\n {\n kind: \"section\",\n title: \"Output\",\n },\n {\n kind: \"list\",\n items: [\n \"Prints backend health, room code, repo root, server-assigned participant id, approval state, and concise sync events.\",\n \"Missing room code exits with a usage error.\",\n ],\n },\n ],\n },\n {\n title: \"scrub\",\n aliases: [\"scrub\"],\n heading: \"cngkit scrub\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Scan a file or directory for secrets with TruffleHog. Report-only is the default.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit scrub [path]\", \"cngkit scrub [path] --yes\"],\n },\n {\n kind: \"section\",\n title: \"Safety\",\n },\n {\n kind: \"list\",\n items: [\n \"Default mode does not rewrite files.\",\n \"Inline masking rewrites files and requires `--yes`.\",\n \"Raw and redacted secret values are never printed.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Requirements\",\n },\n {\n kind: \"list\",\n items: [\"`trufflehog` must be available on `PATH`.\"],\n },\n {\n kind: \"section\",\n title: \"Mask Format\",\n },\n {\n kind: \"code\",\n language: \"text\",\n lines: [\"[CNGKIT_SECRET:<detector>:<verified|unverified>]\"],\n },\n ],\n },\n {\n title: \"knowledges\",\n aliases: [\"knowledges\", \"knowledge\"],\n heading: \"cngkit knowledges\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Search and read the hosted Harness knowledges catalog from the configured backend.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges <subcommand> [options]\"],\n },\n {\n kind: \"section\",\n title: \"Subcommands\",\n },\n {\n kind: \"list\",\n items: [\n \"`status` - print remote catalog state.\",\n \"`audiences` - list valid audience filters.\",\n \"`search <query>` - search over Postgres-backed knowledges records.\",\n \"`list [query]` - list known topics.\",\n \"`files [query]` - list uploaded catalog files.\",\n \"`ls [path]` - list remote catalog directory entries.\",\n \"`tree [path]` - print a remote catalog directory tree.\",\n \"`cat <file-path>` - print a remote catalog file as raw text.\",\n \"`head <file-path>` - print the first lines of a remote catalog file.\",\n \"`tail <file-path>` - print the last lines of a remote catalog file.\",\n \"`stat <path>` - print remote catalog path metadata.\",\n \"`find [path]` - find remote catalog paths by name and type.\",\n \"`realpath <path>` - normalize a topics-root catalog path.\",\n \"`read <file-path>` - Claude-style file read.\",\n \"`grep <pattern>` - Claude-style content search.\",\n \"`glob [pattern]` - Claude-style file discovery.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Progressive Help\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"cngkit help knowledges <subcommand>\",\n \"cngkit knowledges <subcommand> --help\",\n \"cngkit knowledges read --help\",\n \"cngkit knowledges ls --help\",\n \"cngkit knowledges tree --help\",\n \"cngkit knowledges cat --help\",\n \"cngkit knowledges head --help\",\n \"cngkit knowledges tail --help\",\n \"cngkit knowledges find --help\",\n \"cngkit knowledges stat --help\",\n \"cngkit knowledges realpath --help\",\n \"cngkit knowledges grep --help\",\n \"cngkit knowledges glob --help\",\n ],\n },\n {\n kind: \"section\",\n title: \"Common Examples\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"npx --yes cngkit@latest knowledges search Cloudflare --limit 3\",\n \"npx --yes cngkit@latest knowledges ls /\",\n \"npx --yes cngkit@latest knowledges tree /libraries --depth 2\",\n \"npx --yes cngkit@latest knowledges cat /libraries/lib-cloudflare/TOPIC.md\",\n \"npx --yes cngkit@latest knowledges head /libraries/lib-cloudflare/TOPIC.md -n 20\",\n \"npx --yes cngkit@latest knowledges tail /libraries/lib-cloudflare/TOPIC.md -n 20\",\n 'npx --yes cngkit@latest knowledges find /libraries -name \"*cloudflare*\" -type f',\n \"npx --yes cngkit@latest knowledges stat /libraries/lib-cloudflare/TOPIC.md\",\n \"npx --yes cngkit@latest knowledges realpath /libraries/lib-cloudflare\",\n \"npx --yes cngkit@latest knowledges read /libraries/lib-cloudflare/TOPIC.md --limit 80\",\n \"npx --yes cngkit@latest knowledges grep Cloudflare --path /libraries/lib-cloudflare --output-mode files_with_matches\",\n 'npx --yes cngkit@latest knowledges glob \"**/*.md\" --path /libraries/lib-cloudflare',\n ],\n },\n {\n kind: \"section\",\n title: \"AI-Friendly Output\",\n },\n {\n kind: \"list\",\n items: [\n \"Default output is structured text intended to be directly usable by people and agents.\",\n \"`ls` prints one name per line; directories end with `/`. Use `--long` or `-l` for type, path, and metadata fields.\",\n \"`tree` prints a deterministic plain-text tree; directories end with `/`.\",\n \"`cat`, `head`, and `tail` print raw file content only in text mode.\",\n \"`find` prints one resolved path per line.\",\n \"`read` renders Markdown files by default and prints exact source with `--format markdown`.\",\n \"`grep --output-mode content` prints `path:line` blocks.\",\n \"`grep --output-mode files_with_matches` and `glob` print one path per line.\",\n \"`--format json` and `--json` print typed backend payloads for machine consumption.\",\n ],\n },\n ],\n },\n {\n title: \"knowledges status\",\n aliases: [\"knowledges-status\", \"status\"],\n heading: \"cngkit knowledges status\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Print remote Harness catalog state.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges status [--json|--format json]\"],\n },\n {\n kind: \"section\",\n title: \"Output\",\n },\n {\n kind: \"list\",\n items: [\n \"Text mode prints catalog name, file count, blob count, and database binding.\",\n \"`--format json` and `--json` print the backend data payload.\",\n ],\n },\n ],\n },\n {\n title: \"knowledges audiences\",\n aliases: [\"knowledges-audiences\", \"audiences\"],\n heading: \"cngkit knowledges audiences\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"List valid audience filters for catalog browsing.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges audiences [--json|--format json]\"],\n },\n {\n kind: \"section\",\n title: \"Use When\",\n },\n {\n kind: \"paragraph\",\n text: \"Run this before `cngkit knowledges files --audience <id>`.\",\n },\n ],\n },\n {\n title: \"knowledges search\",\n aliases: [\"knowledges-search\", \"search\"],\n heading: \"cngkit knowledges search\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Search the hosted Harness index for relevant skills and topics.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges search <query> [--limit <n>] [--json|--format json]\"],\n },\n {\n kind: \"section\",\n title: \"Defaults\",\n },\n {\n kind: \"list\",\n items: [\"`--limit`: `5`\"],\n },\n {\n kind: \"section\",\n title: \"Example\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"npx --yes cngkit@latest knowledges search Cloudflare --limit 3\"],\n },\n ],\n },\n {\n title: \"knowledges list\",\n aliases: [\"knowledges-list\", \"list\"],\n heading: \"cngkit knowledges list\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"List hosted Harness topics, optionally filtered by query.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges list [query] [--limit <n>] [--json|--format json]\"],\n },\n {\n kind: \"section\",\n title: \"Defaults\",\n },\n {\n kind: \"list\",\n items: [\"`--limit`: `25`\"],\n },\n {\n kind: \"section\",\n title: \"Example\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges list cloudflare --limit 10\"],\n },\n ],\n },\n {\n title: \"knowledges files\",\n aliases: [\"knowledges-files\", \"files\"],\n heading: \"cngkit knowledges files\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"List uploaded Harness catalog files, optionally filtered by query or audience.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"cngkit knowledges files [query] [--audience <id>] [--limit <n>] [--json|--format json]\",\n ],\n },\n {\n kind: \"section\",\n title: \"Defaults\",\n },\n {\n kind: \"list\",\n items: [\"`--limit`: `25`\", \"`--audience`: omitted\"],\n },\n {\n kind: \"section\",\n title: \"Example\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"cngkit knowledges files cloudflare --limit 10\",\n 'cngkit knowledges files \"vector search\" --audience builders',\n ],\n },\n ],\n },\n {\n title: \"knowledges ls\",\n aliases: [\"knowledges-ls\", \"ls\"],\n heading: \"cngkit knowledges ls\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"List immediate children for a hosted Harness catalog directory.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"cngkit knowledges ls [path] [--limit <n>] [--json|--format json]\",\n \"cngkit knowledges ls [path] --long\",\n ],\n },\n {\n kind: \"section\",\n title: \"Inputs\",\n },\n {\n kind: \"list\",\n items: [\n \"`path`: topics-root path prefix. Default: `/`, the hosted equivalent of `~/.agents/topics`.\",\n \"`--limit`: maximum entries. Default: `100`. CLI max: `1000`.\",\n \"`--long`, `-l`: print type, path, and tab-separated metadata.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Output\",\n },\n {\n kind: \"list\",\n items: [\n \"Text mode prints one entry name per line. Directories end with `/`.\",\n \"Long text mode prints one entry per line as tab-separated `type`, `path`, and metadata fields.\",\n \"Directories are sorted before files, then by path.\",\n \"`--format json` and `--json` print `{ path, entries, total_entries, truncated }`.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Examples\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"cngkit knowledges ls /\",\n \"cngkit knowledges ls /libraries/lib-cloudflare\",\n \"cngkit knowledges ls /libraries/lib-cloudflare -l\",\n ],\n },\n ],\n },\n {\n title: \"knowledges tree\",\n aliases: [\"knowledges-tree\", \"tree\"],\n heading: \"cngkit knowledges tree\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Print a plain-text tree for a hosted Harness catalog directory.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges tree [path] [--depth <n>] [--limit <n>] [--json|--format json]\"],\n },\n {\n kind: \"section\",\n title: \"Defaults\",\n },\n {\n kind: \"list\",\n items: [\"`path`: `/`\", \"`--depth`: `3`\", \"`--limit`: `500`\"],\n },\n {\n kind: \"section\",\n title: \"Output\",\n },\n {\n kind: \"list\",\n items: [\n \"Text mode prints deterministic indented lines.\",\n \"Directories end with `/`.\",\n \"`--format json` and `--json` print `{ path, entries, total_entries, truncated, depth }`.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Example\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges tree /libraries --depth 2\"],\n },\n ],\n },\n {\n title: \"knowledges cat\",\n aliases: [\"knowledges-cat\", \"cat\"],\n heading: \"cngkit knowledges cat\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Print a hosted Harness catalog file as raw text.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges cat <file-path> [--json|--format json]\"],\n },\n {\n kind: \"section\",\n title: \"Output\",\n },\n {\n kind: \"list\",\n items: [\n \"Text mode prints returned file content only.\",\n \"`--format json` and `--json` print the typed backend read payload.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Example\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges cat /libraries/lib-cloudflare/TOPIC.md\"],\n },\n ],\n },\n {\n title: \"knowledges head\",\n aliases: [\"knowledges-head\", \"head\"],\n heading: \"cngkit knowledges head\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Print the first lines of a hosted Harness catalog file as raw text.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges head <file-path> [-n <lines>] [--json|--format json]\"],\n },\n {\n kind: \"section\",\n title: \"Defaults\",\n },\n {\n kind: \"list\",\n items: [\"`-n`, `--lines`: `10`\"],\n },\n {\n kind: \"section\",\n title: \"Output\",\n },\n {\n kind: \"list\",\n items: [\n \"Text mode prints returned file content only.\",\n \"`--format json` and `--json` print the typed backend read payload.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Example\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges head /libraries/lib-cloudflare/TOPIC.md -n 20\"],\n },\n ],\n },\n {\n title: \"knowledges tail\",\n aliases: [\"knowledges-tail\", \"tail\"],\n heading: \"cngkit knowledges tail\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Print the last lines of a hosted Harness catalog file as raw text.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges tail <file-path> [-n <lines>] [--json|--format json]\"],\n },\n {\n kind: \"section\",\n title: \"Defaults\",\n },\n {\n kind: \"list\",\n items: [\"`-n`, `--lines`: `10`\"],\n },\n {\n kind: \"section\",\n title: \"Output\",\n },\n {\n kind: \"list\",\n items: [\n \"Text mode prints returned file content only.\",\n \"`--format json` and `--json` print the typed backend tail payload.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Example\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges tail /libraries/lib-cloudflare/TOPIC.md -n 20\"],\n },\n ],\n },\n {\n title: \"knowledges find\",\n aliases: [\"knowledges-find\", \"find\"],\n heading: \"cngkit knowledges find\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Find hosted Harness catalog paths below a directory.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"cngkit knowledges find [path] [-name <pattern>] [-type f|d] [--max-depth <n>] [--limit <n>] [--json|--format json]\",\n ],\n },\n {\n kind: \"section\",\n title: \"Defaults\",\n },\n {\n kind: \"list\",\n items: [\"`path`: `/`\", \"`--limit`: `500`\"],\n },\n {\n kind: \"section\",\n title: \"Output\",\n },\n {\n kind: \"list\",\n items: [\n \"Text mode prints one resolved path per line.\",\n \"Directory paths end with `/`.\",\n \"`--format json` and `--json` print `{ path, entries, total_entries, truncated }`.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Example\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: ['cngkit knowledges find /libraries -name \"*cloudflare*\" -type f'],\n },\n ],\n },\n {\n title: \"knowledges stat\",\n aliases: [\"knowledges-stat\", \"stat\"],\n heading: \"cngkit knowledges stat\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Print metadata for one hosted Harness catalog file or inferred directory.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges stat <path> [--json|--format json]\"],\n },\n {\n kind: \"section\",\n title: \"Inputs\",\n },\n {\n kind: \"list\",\n items: [\n \"`path`: topics-root path. `/libraries/lib-cloudflare/TOPIC.md` means `~/.agents/topics/libraries/lib-cloudflare/TOPIC.md`.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Output\",\n },\n {\n kind: \"list\",\n items: [\n \"Text mode prints stable `key=value` lines.\",\n \"`--format json` and `--json` print the typed backend path metadata.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Example\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges stat /libraries/lib-cloudflare/TOPIC.md\"],\n },\n ],\n },\n {\n title: \"knowledges realpath\",\n aliases: [\"knowledges-realpath\", \"realpath\"],\n heading: \"cngkit knowledges realpath\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Normalize a topics-root catalog path without calling the backend.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges realpath <path> [--json|--format json]\"],\n },\n {\n kind: \"section\",\n title: \"Inputs\",\n },\n {\n kind: \"list\",\n items: [\n \"`path`: topics-root catalog path.\",\n \"`/` is the hosted equivalent of `~/.agents/topics`.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Output\",\n },\n {\n kind: \"list\",\n items: [\n \"Text mode prints the normalized topics-root path.\",\n \"`--format json` and `--json` print `{ path }`.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Examples\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"cngkit knowledges realpath /\",\n \"cngkit knowledges realpath /libraries/lib-cloudflare\",\n ],\n },\n ],\n },\n {\n title: \"knowledges read\",\n aliases: [\"knowledges-read\", \"read\"],\n heading: \"cngkit knowledges read\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Read a hosted Harness catalog file by path.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"cngkit knowledges read <file-path> [--offset <n>] [--limit <n>] [--json|--format json|--format markdown]\",\n ],\n },\n {\n kind: \"section\",\n title: \"Inputs\",\n },\n {\n kind: \"list\",\n items: [\n \"`file-path`: topics-root file path. `/libraries/lib-cloudflare/TOPIC.md` means `~/.agents/topics/libraries/lib-cloudflare/TOPIC.md`.\",\n \"`--offset`: zero-based starting line. Default: `0`.\",\n \"`--limit`: maximum lines. Default in CLI: `200`. Backend max: `2000`.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Output\",\n },\n {\n kind: \"list\",\n items: [\n \"Text mode renders Markdown files for terminal reading.\",\n \"`--format markdown` prints the exact returned file content.\",\n \"If truncated, a final bracketed truncation note is printed after the content.\",\n \"`--format json` and `--json` print `{ file_path, content, total_lines, offset, limit, truncated }`.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Example\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"npx --yes cngkit@latest knowledges read /libraries/lib-cloudflare/TOPIC.md --limit 80\",\n ],\n },\n ],\n },\n {\n title: \"knowledges grep\",\n aliases: [\"knowledges-grep\", \"grep\"],\n heading: \"cngkit knowledges grep\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Search inside hosted Harness catalog files with a JavaScript regular expression.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"cngkit knowledges grep <pattern> [--path <path>] [--include <glob>] [--output-mode <mode>] [--context <n>] [--case-insensitive] [--json|--format json]\",\n ],\n },\n {\n kind: \"section\",\n title: \"Inputs\",\n },\n {\n kind: \"list\",\n items: [\n \"`pattern`: JavaScript regular expression source.\",\n \"`--path`: topics-root 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 },\n {\n kind: \"section\",\n title: \"Output\",\n },\n {\n kind: \"list\",\n items: [\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 \"`--format json` and `--json` print the typed backend response union.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Examples\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n \"npx --yes cngkit@latest knowledges grep Cloudflare --path /libraries/lib-cloudflare --output-mode files_with_matches\",\n 'npx --yes cngkit@latest knowledges grep \"Postgres|Hyperdrive\" --path /libraries/lib-cloudflare --context 2',\n ],\n },\n ],\n },\n {\n title: \"knowledges glob\",\n aliases: [\"knowledges-glob\", \"glob\"],\n heading: \"cngkit knowledges glob\",\n blocks: [\n {\n kind: \"paragraph\",\n text: \"Find hosted Harness catalog files by glob pattern.\",\n },\n {\n kind: \"section\",\n title: \"Usage\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\"cngkit knowledges glob [pattern] [--path <path>] [--json|--format json]\"],\n },\n {\n kind: \"section\",\n title: \"Inputs\",\n },\n {\n kind: \"list\",\n items: [\n \"`pattern`: supported glob pattern. CLI default: `**/*.md`.\",\n \"`--path`: topics-root path prefix. Default: `/`.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Supported Patterns\",\n },\n {\n kind: \"list\",\n items: [\n \"`**/*.md`\",\n \"`**/TOPIC.md`\",\n \"`**/*.TOPIC.md`\",\n \"`**/SKILL.md`\",\n \"`*.md`\",\n \"`TOPIC.md`\",\n \"`*.TOPIC.md`\",\n \"`SKILL.md`\",\n ],\n },\n {\n kind: \"section\",\n title: \"Output\",\n },\n {\n kind: \"list\",\n items: [\n \"Text mode prints one file path per line.\",\n \"If truncated, a final bracketed truncation note is printed.\",\n \"`--format json` and `--json` print `{ files, total_files, truncated }`.\",\n ],\n },\n {\n kind: \"section\",\n title: \"Example\",\n },\n {\n kind: \"code\",\n language: \"bash\",\n lines: [\n 'npx --yes cngkit@latest knowledges glob \"**/*.md\" --path /libraries/lib-cloudflare',\n ],\n },\n ],\n },\n] as const satisfies readonly HelpTopicDocument[];\n"],"mappings":"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","names":[]}
|