@fs/mycroft 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +2 -0
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/package.json +3 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
package/dist/cli.js
CHANGED
|
@@ -1220,7 +1220,7 @@ var onboardCommand = async () => {
|
|
|
1220
1220
|
}
|
|
1221
1221
|
const defaults = await loadConfig();
|
|
1222
1222
|
const path = configPath();
|
|
1223
|
-
stdout("\
|
|
1223
|
+
stdout("\nmycroft");
|
|
1224
1224
|
stdout("Press Enter or type -y to accept defaults.");
|
|
1225
1225
|
const dataDirInput = await prompt(`Data directory [${defaults.dataDir}]: `);
|
|
1226
1226
|
const dataDir = isDefault(dataDirInput) ? defaults.dataDir : dataDirInput;
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/config.ts","../src/commands/io.ts","../src/services/epub-parser.ts","../src/services/constants.ts","../src/services/ingest.ts","../src/services/chunker.ts","../src/services/embedder.ts","../src/services/vector-store.ts","../src/services/summarizer.ts","../src/db/schema.ts","../src/db/queries.ts","../src/commands/ingest.ts","../src/commands/prompt.ts","../src/commands/book/ingest.ts","../src/commands/list.ts","../src/commands/book/list.ts","../src/commands/utils.ts","../src/commands/show.ts","../src/commands/book/show.ts","../src/commands/ask.ts","../src/commands/book/ask.ts","../src/commands/search.ts","../src/commands/book/search.ts","../src/commands/delete.ts","../src/commands/book/delete.ts","../src/commands/config.ts","../src/commands/config/path.ts","../src/commands/init-config.ts","../src/commands/config/init.ts","../src/commands/resolve-config.ts","../src/commands/config/resolve.ts","../src/commands/onboard.ts","../src/commands/config/onboard.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from \"commander\";\nimport { setConfigOverrides } from \"./config\";\nimport { printError } from \"./commands/io\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { registerBookIngest } from \"./commands/book/ingest\";\nimport { registerBookList } from \"./commands/book/list\";\nimport { registerBookShow } from \"./commands/book/show\";\nimport { registerBookAsk } from \"./commands/book/ask\";\nimport { registerBookSearch } from \"./commands/book/search\";\nimport { registerBookDelete } from \"./commands/book/delete\";\nimport { registerConfigPath } from \"./commands/config/path\";\nimport { registerConfigInit } from \"./commands/config/init\";\nimport { registerConfigResolve } from \"./commands/config/resolve\";\nimport { registerConfigOnboard } from \"./commands/config/onboard\";\n\nconst resolveVersion = async () => {\n try {\n const currentDir = dirname(fileURLToPath(import.meta.url));\n const pkgPath = resolve(currentDir, \"../package.json\");\n const raw = await readFile(pkgPath, \"utf-8\");\n return JSON.parse(raw).version || \"0.1.0\";\n } catch {\n return \"0.1.0\";\n }\n};\n\nconst program = new Command();\nconst configureProgram = async () => {\n program\n .name(\"mycroft\")\n .description(\"Ingest EPUBs, build a local index, and answer questions\")\n .version(await resolveVersion())\n .option(\"--data-dir <path>\", \"Override data directory\")\n .hook(\"preAction\", (cmd) => {\n const opts = cmd.opts();\n if (opts.dataDir) {\n setConfigOverrides({ dataDir: opts.dataDir });\n }\n });\n};\n\nconst registerCommands = () => {\n const book = program.command(\"book\").description(\"Manage books and queries\");\n registerBookIngest(book);\n registerBookList(book);\n registerBookShow(book);\n registerBookAsk(book);\n registerBookSearch(book);\n registerBookDelete(book);\n\n const config = program.command(\"config\").description(\"Manage configuration\");\n registerConfigPath(config);\n registerConfigInit(config);\n registerConfigResolve(config);\n registerConfigOnboard(config);\n};\n\nprogram.exitOverride((error) => {\n if (error.code === \"commander.helpDisplayed\") {\n process.exit(0);\n }\n throw error;\n});\n\nconst main = async () => {\n try {\n await configureProgram();\n registerCommands();\n await program.parseAsync(process.argv);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n printError(message);\n process.exit(1);\n }\n};\n\nmain();\n","import { mkdir, readFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\n\nexport type ConfigModels = {\n embedding: string;\n summary: string;\n chat: string;\n};\n\nexport type AppConfig = {\n dataDir: string;\n askEnabled: boolean;\n models: ConfigModels;\n};\n\nconst DEFAULT_CONFIG: AppConfig = {\n dataDir: \"~/.local/share/mycroft\",\n askEnabled: true,\n models: {\n embedding: \"text-embedding-3-small\",\n summary: \"gpt-5-nano\",\n chat: \"gpt-5.1\",\n },\n};\n\nconst expandHome = (input: string): string => {\n if (!input.startsWith(\"~\")) return input;\n return join(homedir(), input.slice(1));\n};\n\nconst resolvePath = (input: string): string => resolve(expandHome(input));\n\nconst getConfigPath = (): string => {\n const override = process.env.MYCROFT_CONFIG;\n if (override) return resolvePath(override);\n return resolvePath(\"~/.config/mycroft/config.json\");\n};\n\nconst normalizeModels = (models?: Partial<ConfigModels>): ConfigModels => ({\n embedding: models?.embedding || DEFAULT_CONFIG.models.embedding,\n summary: models?.summary || DEFAULT_CONFIG.models.summary,\n chat: models?.chat || DEFAULT_CONFIG.models.chat,\n});\n\ntype ConfigOverrides = {\n dataDir?: string;\n};\n\nlet overrides: ConfigOverrides = {};\n\nexport const setConfigOverrides = (next: ConfigOverrides) => {\n overrides = { ...overrides, ...next };\n};\n\nconst normalizeConfig = (input: Partial<AppConfig> | null): AppConfig => {\n const dataDirEnv = process.env.MYCROFT_DATA_DIR;\n const dataDir = overrides.dataDir || dataDirEnv || input?.dataDir || DEFAULT_CONFIG.dataDir;\n return {\n dataDir,\n askEnabled: input?.askEnabled ?? DEFAULT_CONFIG.askEnabled,\n models: normalizeModels(input?.models),\n };\n};\n\nconst readConfigFile = async (path: string): Promise<Partial<AppConfig> | null> => {\n try {\n const contents = await readFile(path, \"utf-8\");\n return JSON.parse(contents) as Partial<AppConfig>;\n } catch {\n return null;\n }\n};\n\nexport const loadConfig = async (): Promise<AppConfig> => {\n const configPath = getConfigPath();\n const data = await readConfigFile(configPath);\n const normalized = normalizeConfig(data);\n return {\n ...normalized,\n dataDir: resolvePath(normalized.dataDir),\n };\n};\n\nexport const ensureConfigDirs = async (configPath?: string) => {\n const path = configPath || getConfigPath();\n await mkdir(dirname(path), { recursive: true });\n};\n\nexport const configPath = () => getConfigPath();\n","import chalk from \"chalk\";\n\nconst isTTY = () => Boolean(process.stdout.isTTY);\nexport const isInteractive = () => Boolean(process.stdin.isTTY && process.stdout.isTTY);\n\nexport const formatDim = (text: string) => (isTTY() ? chalk.dim(text) : text);\nexport const formatError = (text: string) => (isTTY() ? chalk.red(text) : text);\nexport const formatBold = (text: string) => (isTTY() ? chalk.bold(text) : text);\nexport const formatWarn = (text: string) => (isTTY() ? chalk.yellow(text) : text);\n\nexport const stdout = (message: string) => {\n process.stdout.write(message.endsWith(\"\\n\") ? message : `${message}\\n`);\n};\n\nexport const stderr = (message: string) => {\n process.stderr.write(message.endsWith(\"\\n\") ? message : `${message}\\n`);\n};\n\nexport const printError = (message: string) => {\n stderr(formatError(`Error: ${message}`));\n};\n\nexport const logInfo = (message: string) => {\n stderr(message);\n};\n\nexport const logWarn = (message: string) => {\n stderr(formatWarn(message));\n};\n\nexport const handleSigint = (onCancel?: () => void) => {\n const handler = () => {\n if (onCancel) onCancel();\n stderr(\"\\nCancelled.\");\n process.exit(130);\n };\n process.once(\"SIGINT\", handler);\n return () => process.off(\"SIGINT\", handler);\n};\n","import { initEpubFile } from \"@lingo-reader/epub-parser\";\nimport { basename } from \"node:path\";\nimport type { Chapter } from \"../shared/types\";\nimport { logInfo } from \"./constants\";\n\nexport type ParsedBook = {\n title: string;\n author: string | null;\n coverImagePath: string | null;\n chapters: Chapter[];\n chapterTitles: string[];\n narrativeStartIndex: number;\n narrativeEndIndex: number;\n};\n\nconst detectNarrativeBoundaries = (chapterTitles: string[]): { start: number; end: number } => {\n const frontMatterPattern = /^(about|contents|table of contents|dedication|preface|foreword|title|half.?title|copyright|epigraph|frontispiece|map)/i;\n const backMatterPattern = /^(acknowledgment|afterword|appendix|glossary|index|bibliography|about the author|also by|praise|copyright page|notes|bonus|preview|excerpt|major characters|locations)/i;\n const narrativePattern = /^(I|II|III|IV|V|VI|VII|VIII|IX|X|XI|XII|1|2|3|4|5|6|7|8|9|one|two|three|chapter|prologue|epilogue|part\\s)/i;\n\n let start = 0;\n let end = chapterTitles.length - 1;\n\n for (let i = 0; i < chapterTitles.length; i++) {\n const title = chapterTitles[i]?.trim() || \"\";\n\n if (narrativePattern.test(title) && !frontMatterPattern.test(title)) {\n start = i;\n break;\n }\n\n if (!frontMatterPattern.test(title) && title.length > 0) {\n if (title.length > 3) {\n start = i;\n break;\n }\n }\n }\n\n for (let i = chapterTitles.length - 1; i >= start; i--) {\n const title = chapterTitles[i]?.trim() || \"\";\n if (!backMatterPattern.test(title)) {\n end = i;\n break;\n }\n }\n\n logInfo(`[EPUB Parser] Detected narrative boundaries: chapters ${start} to ${end} (out of ${chapterTitles.length} total)`);\n if (start > 0) {\n logInfo(`[EPUB Parser] Front matter: ${chapterTitles.slice(0, start).join(\", \")}`);\n }\n if (end < chapterTitles.length - 1) {\n logInfo(`[EPUB Parser] Back matter: ${chapterTitles.slice(end + 1).join(\", \")}`);\n }\n\n return { start, end };\n};\n\nconst stripHtml = (html: string) =>\n html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, \" \")\n .replace(/<style[\\s\\S]*?<\\/style>/gi, \" \")\n .replace(/<[^>]+>/g, \" \")\n .replace(/ /g, \" \")\n .replace(/&/g, \"&\")\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/\\s+/g, \" \")\n .trim();\n\nconst originalWarn = console.warn;\nconst createWarnFilter = () => {\n const suppressedWarnings: string[] = [];\n console.warn = (msg: any, ...args: unknown[]) => {\n if (typeof msg === \"string\" && msg.includes(\"No element with id\") && msg.includes(\"parsing <metadata>\")) {\n suppressedWarnings.push(msg);\n return;\n }\n originalWarn(msg, ...args);\n };\n return suppressedWarnings;\n};\n\nexport const parseEpub = async (epubPath: string, resourceSaveDir?: string): Promise<ParsedBook> => {\n logInfo(`[EPUB Parser] Starting parse for: ${basename(epubPath)}`);\n\n const suppressedWarnings = createWarnFilter();\n\n try {\n const epubFile = await initEpubFile(epubPath, resourceSaveDir);\n await epubFile.loadEpub();\n logInfo(`[EPUB Parser] EPUB loaded successfully`);\n\n await epubFile.parse();\n\n if (suppressedWarnings.length > 0) {\n logInfo(`[EPUB Parser] Suppressed ${suppressedWarnings.length} metadata warnings (non-critical)`);\n }\n logInfo(`[EPUB Parser] Parse completed`);\n\n const fileBaseName = basename(epubPath, \".epub\");\n type EpubMetadata = ReturnType<typeof epubFile.getMetadata>;\n let metadata: EpubMetadata | null = null;\n try {\n metadata = epubFile.getMetadata();\n } catch {\n metadata = null;\n }\n const safeMetadata = metadata ?? ({} as EpubMetadata);\n const spine = epubFile.getSpine();\n const toc = epubFile.getToc();\n\n logInfo(`[EPUB Parser] Found ${spine.length} spine items, ${toc.length} TOC entries`);\n\n const titleById = new Map<string, string>();\n const walkToc = (items: typeof toc) => {\n items.forEach((item: (typeof toc)[number]) => {\n const resolved = epubFile.resolveHref(item.href);\n if (resolved?.id) titleById.set(resolved.id, item.label);\n if (item.children?.length) walkToc(item.children);\n });\n };\n walkToc(toc);\n const coverImagePath = epubFile.getCoverImage() || null;\n\n const chapters: Chapter[] = [];\n const chapterTitles: string[] = [];\n for (const [index, item] of spine.entries()) {\n const chapter = await epubFile.loadChapter(item.id);\n const content = stripHtml(chapter.html);\n if (!content) continue;\n const chapterTitle = titleById.get(item.id) || item.id || `Chapter ${index + 1}`;\n chapters.push({\n title: chapterTitle,\n content,\n });\n chapterTitles.push(chapterTitle);\n }\n\n epubFile.destroy();\n\n const author = safeMetadata.creator?.[0]?.contributor ?? null;\n\n logInfo(`[EPUB Parser] Extracted ${chapters.length} chapters with content`);\n logInfo(`[EPUB Parser] Title: \"${safeMetadata.title || fileBaseName || \"Untitled\"}\", Author: \"${author || \"Unknown\"}\"`);\n\n const { start: narrativeStartIndex, end: narrativeEndIndex } = detectNarrativeBoundaries(chapterTitles);\n\n return {\n title: safeMetadata.title || fileBaseName || \"Untitled\",\n author,\n coverImagePath,\n chapters,\n chapterTitles,\n narrativeStartIndex,\n narrativeEndIndex,\n };\n } finally {\n console.warn = originalWarn;\n }\n};\n","import { mkdir } from \"node:fs/promises\";\nimport { loadConfig } from \"../config\";\nimport { logInfo, logWarn } from \"../commands/io\";\n\nexport const CHUNK_SIZE: number = 1000;\nexport const CHUNK_OVERLAP: number = 100;\nexport const SEPARATORS = [\"\\n\\n\", \"\\n\", \". \", \" \", \"\"] as const;\n\nexport const SUMMARY_MAX_TOKENS = 30000;\nexport const SUMMARY_CONCURRENCY = 3;\nexport const SUMMARY_TARGET_WORDS = 250;\n\nexport type ResolvedPaths = {\n dataDir: string;\n booksDir: string;\n vectorsDir: string;\n dbPath: string;\n};\n\nexport const resolvePaths = async (): Promise<ResolvedPaths> => {\n const config = await loadConfig();\n const dataDir = config.dataDir;\n return {\n dataDir,\n booksDir: `${dataDir}/books`,\n vectorsDir: `${dataDir}/vectors`,\n dbPath: `${dataDir}/metadata.db`,\n };\n};\n\nexport const ensureDataDirs = async () => {\n const paths = await resolvePaths();\n await mkdir(paths.dataDir, { recursive: true });\n await mkdir(paths.booksDir, { recursive: true });\n await mkdir(paths.vectorsDir, { recursive: true });\n return paths;\n};\n\nexport const getModels = async () => {\n const config = await loadConfig();\n return config.models;\n};\n\nexport const isAskEnabled = async () => {\n const config = await loadConfig();\n return config.askEnabled;\n};\n\nexport const requireOpenAIKey = () => {\n if (!process.env.OPENAI_API_KEY) {\n throw new Error(\"OPENAI_API_KEY is not set. Export it to use embeddings and chat.\");\n }\n};\n\nexport { logInfo, logWarn };\n","import { randomUUID } from \"node:crypto\";\nimport { mkdir, unlink, copyFile } from \"node:fs/promises\";\nimport { parseEpub } from \"./epub-parser\";\nimport { chunkChapters } from \"./chunker\";\nimport { embedChunks } from \"./embedder\";\nimport { addChunksToIndex, deleteBookIndex } from \"./vector-store\";\nimport { summarizeAllChapters } from \"./summarizer\";\nimport { ensureDataDirs, logInfo, logWarn } from \"./constants\";\nimport { deleteBook, insertBook, updateBook } from \"../db/queries\";\nimport type { BookChunk } from \"../shared/types\";\n\nconst formatDuration = (ms: number) => {\n const seconds = Math.round(ms / 100) / 10;\n return `${seconds}s`;\n};\n\nexport const ingestEpub = async (\n filePath: string,\n selectedChapterIndices?: number[],\n options?: { summarize?: boolean }\n) => {\n const bookId = randomUUID();\n const paths = await ensureDataDirs();\n const fileName = `${bookId}.epub`;\n const bookPath = `${paths.booksDir}/${fileName}`;\n\n logInfo(`[Ingest] Starting ingestion for book ${bookId}`);\n\n await mkdir(paths.booksDir, { recursive: true });\n await copyFile(filePath, bookPath);\n logInfo(`[Ingest] EPUB file saved to ${bookPath}`);\n\n const parseStart = Date.now();\n const parsed = await parseEpub(bookPath);\n logInfo(`[Ingest] Parsed \"${parsed.title}\" with ${parsed.chapters.length} chapters (${formatDuration(Date.now() - parseStart)})`);\n logInfo(`[Ingest] Narrative chapters: ${parsed.narrativeStartIndex} to ${parsed.narrativeEndIndex}`);\n\n await insertBook({\n id: bookId,\n title: parsed.title,\n author: parsed.author,\n coverPath: parsed.coverImagePath,\n epubPath: bookPath,\n chapters: parsed.chapterTitles,\n narrativeStartIndex: parsed.narrativeStartIndex,\n narrativeEndIndex: parsed.narrativeEndIndex,\n });\n logInfo(`[Ingest] Book record inserted into database`);\n\n try {\n const chaptersToProcess = selectedChapterIndices\n ? parsed.chapters.filter((_, index) => selectedChapterIndices.includes(index))\n : parsed.chapters.slice(parsed.narrativeStartIndex, parsed.narrativeEndIndex + 1);\n\n const selectedIndices = selectedChapterIndices ||\n Array.from({ length: parsed.narrativeEndIndex - parsed.narrativeStartIndex + 1 },\n (_, i) => i + parsed.narrativeStartIndex);\n\n logInfo(`[Ingest] Processing ${chaptersToProcess.length} selected chapters (indices: ${selectedIndices.join(\", \")})`);\n\n let adjustedSummaries: BookChunk[] = [];\n if (options?.summarize !== false) {\n logInfo(`[Ingest] Generating summaries for ${chaptersToProcess.length} chapters...`);\n const summarizeStart = Date.now();\n const summaries = await summarizeAllChapters(chaptersToProcess);\n logInfo(`[Ingest] Generated ${summaries.length}/${chaptersToProcess.length} summaries (${formatDuration(Date.now() - summarizeStart)})`);\n\n const summaryRecords = summaries.map((s, idx) => ({\n ...s,\n chapterIndex: selectedIndices[idx] ?? s.chapterIndex,\n }));\n\n await updateBook(bookId, {\n summaries: JSON.stringify(summaryRecords),\n });\n\n adjustedSummaries = summaryRecords.map((s) => ({\n id: `${bookId}-summary-${s.chapterIndex}`,\n bookId,\n chapterIndex: s.chapterIndex,\n chapterTitle: s.chapterTitle,\n chunkIndex: -1,\n content: s.fullSummary,\n type: \"summary\" as const,\n }));\n logInfo(`[Ingest] Created ${adjustedSummaries.length} summary chunks`);\n }\n\n const chunksToProcess = parsed.chapters.map((chapter, index) =>\n selectedIndices.includes(index) ? chapter : { title: chapter.title, content: \"\" }\n );\n const chunks = chunkChapters(bookId, chunksToProcess).filter((chunk) => chunk.content.length > 0);\n logInfo(`[Ingest] Created ${chunks.length} chunks from selected chapters`);\n\n const allChunks = [...chunks, ...adjustedSummaries];\n const embedStart = Date.now();\n const embedded = await embedChunks(allChunks);\n logInfo(`[Ingest] Embedded ${embedded.length} total chunks (${formatDuration(Date.now() - embedStart)})`);\n\n await addChunksToIndex(bookId, embedded);\n logInfo(`[Ingest] Added chunks to vector index`);\n\n await updateBook(bookId, { chunkCount: embedded.length, indexedAt: Date.now() });\n logInfo(`[Ingest] Updated book record with chunk count: ${embedded.length}`);\n } catch (error) {\n logWarn(`[Ingest] Error during chunking/embedding: ${error instanceof Error ? error.message : String(error)}`);\n await deleteBookIndex(bookId);\n await unlink(bookPath).catch(() => undefined);\n await deleteBook(bookId).catch(() => undefined);\n throw error;\n }\n\n logInfo(`[Ingest] Ingestion complete for ${bookId}`);\n return { id: bookId };\n};\n","import type { Chapter, BookChunk } from \"../shared/types\";\nimport { CHUNK_OVERLAP, CHUNK_SIZE, SEPARATORS } from \"./constants\";\n\nconst splitRecursive = (text: string, separators: readonly string[]): string[] => {\n if (text.length <= CHUNK_SIZE || separators.length === 0) return [text];\n const [separator, ...rest] = separators;\n if (!separator) return [text];\n\n const parts = text.split(separator);\n if (parts.length === 1) return splitRecursive(text, rest);\n\n const chunks: string[] = [];\n let current = \"\";\n\n for (const part of parts) {\n const next = current ? `${current}${separator}${part}` : part;\n if (next.length <= CHUNK_SIZE) {\n current = next;\n continue;\n }\n\n if (current) chunks.push(current);\n current = part;\n }\n\n if (current) chunks.push(current);\n\n const refined: string[] = [];\n for (const chunk of chunks) {\n if (chunk.length <= CHUNK_SIZE) {\n refined.push(chunk);\n continue;\n }\n refined.push(...splitRecursive(chunk, rest));\n }\n\n return refined;\n};\n\nconst withOverlap = (chunks: string[]): string[] => {\n if (chunks.length <= 1 || CHUNK_OVERLAP === 0) return chunks;\n\n const merged: string[] = [];\n for (let i = 0; i < chunks.length; i += 1) {\n const current = chunks[i] ?? \"\";\n const previous = merged[merged.length - 1];\n if (!previous) {\n merged.push(current);\n continue;\n }\n\n const overlap = previous.slice(-CHUNK_OVERLAP);\n merged.push(`${overlap}${current}`);\n }\n\n return merged;\n};\n\nexport const chunkChapters = (bookId: string, chapters: Chapter[]): BookChunk[] => {\n const chunks: BookChunk[] = [];\n\n chapters.forEach((chapter, chapterIndex) => {\n const trimmed = chapter.content.trim();\n if (!trimmed) return;\n\n const rawChunks = splitRecursive(trimmed, SEPARATORS);\n const overlapped = withOverlap(rawChunks);\n overlapped.forEach((content, chunkIndex) => {\n const normalized = content.replace(/\\s+/g, \" \").trim();\n if (!normalized) return;\n chunks.push({\n id: `${bookId}-${chapterIndex}-${chunkIndex}`,\n bookId,\n chapterIndex,\n chapterTitle: chapter.title,\n chunkIndex,\n content: normalized,\n });\n });\n });\n\n return chunks;\n};\n","import { embedMany } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\nimport type { BookChunk } from \"../shared/types\";\nimport { getModels, logInfo } from \"./constants\";\n\nexport type EmbeddedChunk = BookChunk & {\n vector: number[];\n};\n\nconst MAX_TOKENS_PER_BATCH = 250_000;\nconst CHARS_PER_TOKEN = 4;\n\nexport const embedChunks = async (chunks: BookChunk[]): Promise<EmbeddedChunk[]> => {\n if (chunks.length === 0) return [];\n\n const batches: BookChunk[][] = [];\n let currentBatch: BookChunk[] = [];\n let currentTokens = 0;\n\n for (const chunk of chunks) {\n const estimatedTokens = Math.ceil(chunk.content.length / CHARS_PER_TOKEN);\n\n if (currentTokens + estimatedTokens > MAX_TOKENS_PER_BATCH && currentBatch.length > 0) {\n batches.push(currentBatch);\n currentBatch = [];\n currentTokens = 0;\n }\n\n currentBatch.push(chunk);\n currentTokens += estimatedTokens;\n }\n\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n }\n\n logInfo(`[Embedder] Processing ${chunks.length} chunks in ${batches.length} batch(es)`);\n\n const allEmbedded: EmbeddedChunk[] = [];\n const models = await getModels();\n\n for (let i = 0; i < batches.length; i++) {\n const batch = batches[i]!;\n const estimatedTokens = batch.reduce((sum, c) => sum + Math.ceil(c.content.length / CHARS_PER_TOKEN), 0);\n\n logInfo(`[Embedder] Batch ${i + 1}/${batches.length}: ${batch.length} chunks (~${estimatedTokens.toLocaleString()} tokens)`);\n\n const { embeddings } = await embedMany({\n model: openai.embeddingModel(models.embedding),\n values: batch.map((chunk) => chunk.content),\n });\n\n for (let j = 0; j < batch.length; j++) {\n allEmbedded.push({\n ...batch[j]!,\n vector: embeddings[j] ?? [],\n });\n }\n }\n\n logInfo(`[Embedder] Successfully embedded all ${allEmbedded.length} chunks`);\n\n return allEmbedded;\n};\n","import { LocalIndex } from \"vectra\";\nimport type { EmbeddedChunk } from \"./embedder\";\nimport type { BookChunk } from \"../shared/types\";\nimport { ensureDataDirs } from \"./constants\";\n\nexport type VectorMetadata = {\n bookId: string;\n chapterIndex: number;\n chapterTitle: string;\n chunkIndex: number;\n content: string;\n type?: \"chunk\" | \"summary\";\n};\n\nconst indexPathForBook = async (bookId: string) => {\n const paths = await ensureDataDirs();\n return `${paths.vectorsDir}/${bookId}`;\n};\n\nexport const createBookIndex = async (bookId: string): Promise<LocalIndex<VectorMetadata>> => {\n const index = new LocalIndex<VectorMetadata>(await indexPathForBook(bookId));\n const exists = await index.isIndexCreated();\n if (!exists) {\n await index.createIndex({\n version: 1,\n metadata_config: {\n indexed: [\"bookId\"],\n },\n });\n }\n return index;\n};\n\nexport const addChunksToIndex = async (bookId: string, chunks: EmbeddedChunk[]) => {\n const index = await createBookIndex(bookId);\n await index.batchInsertItems(\n chunks.map((chunk) => ({\n id: chunk.id,\n vector: chunk.vector,\n metadata: {\n bookId: chunk.bookId,\n chapterIndex: chunk.chapterIndex,\n chapterTitle: chunk.chapterTitle,\n chunkIndex: chunk.chunkIndex,\n content: chunk.content,\n type: chunk.type || \"chunk\",\n },\n }))\n );\n};\n\nexport const queryBookIndex = async (\n bookId: string,\n queryVector: number[],\n queryText: string,\n topK: number,\n maxChapterIndex?: number\n): Promise<(BookChunk & { score: number })[]> => {\n const index = await createBookIndex(bookId);\n const expandedTopK =\n maxChapterIndex === undefined || maxChapterIndex === null ? topK : Math.max(topK * 4, topK);\n const results = await index.queryItems(queryVector, queryText, expandedTopK);\n\n const mapped = results.map((result: (typeof results)[number]) => ({\n id: result.item.id ?? \"\",\n bookId,\n chapterIndex: result.item.metadata?.chapterIndex ?? 0,\n chapterTitle: result.item.metadata?.chapterTitle ?? \"\",\n chunkIndex: result.item.metadata?.chunkIndex ?? 0,\n content: result.item.metadata?.content ?? \"\",\n type: result.item.metadata?.type as \"chunk\" | \"summary\" | undefined,\n score: result.score,\n }));\n\n if (maxChapterIndex === undefined || maxChapterIndex === null) {\n return mapped.slice(0, topK);\n }\n\n return mapped.filter((item: (typeof mapped)[number]) => item.chapterIndex <= maxChapterIndex).slice(0, topK);\n};\n\nexport const deleteBookIndex = async (bookId: string) => {\n const index = new LocalIndex<VectorMetadata>(await indexPathForBook(bookId));\n const exists = await index.isIndexCreated();\n if (!exists) return;\n await index.deleteIndex();\n};\n","import { generateText } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\nimport type { Chapter, ChapterSummary } from \"../shared/types\";\nimport { SUMMARY_MAX_TOKENS, SUMMARY_CONCURRENCY, SUMMARY_TARGET_WORDS, getModels, logInfo, logWarn } from \"./constants\";\n\nconst CHARS_PER_TOKEN = 4;\n\nconst estimateTokens = (text: string): number => Math.ceil(text.length / CHARS_PER_TOKEN);\n\nconst SUMMARY_PROMPT = (title: string, chapterNum: number, content: string) => `You are analyzing a chapter from a book (fiction or nonfiction). Extract key information to help readers understand the chapter's content.\n\nChapter Title: ${title}\nChapter Number: ${chapterNum}\n\n---\n${content}\n---\n\nExtract the following information and respond ONLY with valid JSON (no markdown, no code blocks):\n\n{\n \"characters\": [\"Name - brief description (role, traits, first appearance)\", ...],\n \"events\": \"What happens in this chapter? (2-3 sentences)\",\n \"setting\": \"Where does this chapter take place?\",\n \"revelations\": \"Any important information revealed? (secrets, backstory, foreshadowing)\"\n}\n\nKeep the total response around ${SUMMARY_TARGET_WORDS} words.`;\n\ntype SummaryJSON = {\n characters: string[];\n events: string;\n setting: string;\n revelations: string;\n};\n\nconst splitIntoSections = (text: string, maxTokens: number): string[] => {\n const estimatedTokens = estimateTokens(text);\n\n if (estimatedTokens <= maxTokens) {\n return [text];\n }\n\n const numSections = Math.ceil(estimatedTokens / maxTokens);\n const charsPerSection = Math.floor(text.length / numSections);\n const sections: string[] = [];\n\n for (let i = 0; i < numSections; i++) {\n const start = i * charsPerSection;\n const end = i === numSections - 1 ? text.length : (i + 1) * charsPerSection;\n sections.push(text.slice(start, end));\n }\n\n return sections;\n};\n\nconst summarizeSection = async (text: string, title: string, sectionNum: number): Promise<string> => {\n const models = await getModels();\n const { text: summary } = await generateText({\n model: openai(models.summary),\n prompt: `Summarize this section from chapter \"${title}\" (Part ${sectionNum}). Focus on key events, characters, and revelations. Keep it concise (100-150 words):\\n\\n${text}`,\n temperature: 0.3,\n });\n\n return summary;\n};\n\nconst generateStructuredSummary = async (\n content: string,\n title: string,\n chapterIndex: number\n): Promise<ChapterSummary | null> => {\n try {\n const models = await getModels();\n const { text } = await generateText({\n model: openai(models.summary),\n prompt: SUMMARY_PROMPT(title, chapterIndex + 1, content),\n temperature: 0.3,\n });\n\n let jsonText = text.trim();\n if (jsonText.startsWith(\"```json\")) {\n jsonText = jsonText.slice(7, -3).trim();\n } else if (jsonText.startsWith(\"```\")) {\n jsonText = jsonText.slice(3, -3).trim();\n }\n\n const parsed: SummaryJSON = JSON.parse(jsonText);\n\n const fullSummary = `Chapter ${chapterIndex + 1}: ${title}\n\nCharacters: ${parsed.characters.join(\", \")}\n\nEvents: ${parsed.events}\n\nSetting: ${parsed.setting}\n\nRevelations: ${parsed.revelations}`;\n\n return {\n chapterIndex,\n chapterTitle: title,\n characters: parsed.characters,\n events: parsed.events,\n setting: parsed.setting,\n revelations: parsed.revelations,\n fullSummary,\n };\n } catch (error) {\n logWarn(`[Summarizer] Failed to parse summary JSON for \"${title}\": ${error instanceof Error ? error.message : String(error)}`);\n return null;\n }\n};\n\nexport const summarizeChapter = async (\n chapter: Chapter,\n chapterIndex: number\n): Promise<ChapterSummary | null> => {\n const tokens = estimateTokens(chapter.content);\n\n logInfo(`[Summarizer] Chapter ${chapterIndex + 1} \"${chapter.title}\": ~${tokens.toLocaleString()} tokens`);\n\n try {\n if (tokens < SUMMARY_MAX_TOKENS) {\n return await generateStructuredSummary(chapter.content, chapter.title, chapterIndex);\n }\n\n logInfo(`[Summarizer] Chapter ${chapterIndex + 1} exceeds token limit, using two-pass approach`);\n\n const sections = splitIntoSections(chapter.content, SUMMARY_MAX_TOKENS);\n logInfo(`[Summarizer] Split into ${sections.length} sections`);\n\n const sectionSummaries = await Promise.all(\n sections.map((section, i) => summarizeSection(section, chapter.title, i + 1))\n );\n\n const combined = sectionSummaries.join(\"\\n\\n\");\n\n return await generateStructuredSummary(combined, chapter.title, chapterIndex);\n } catch (error) {\n logWarn(`[Summarizer] Failed to summarize chapter ${chapterIndex + 1}: ${error instanceof Error ? error.message : String(error)}`);\n return null;\n }\n};\n\nexport const summarizeAllChapters = async (chapters: Chapter[]): Promise<ChapterSummary[]> => {\n const summaries: ChapterSummary[] = [];\n\n logInfo(`[Summarizer] Starting summarization of ${chapters.length} chapters (concurrency: ${SUMMARY_CONCURRENCY})`);\n\n for (let i = 0; i < chapters.length; i += SUMMARY_CONCURRENCY) {\n const batch = chapters.slice(i, i + SUMMARY_CONCURRENCY);\n const batchPromises = batch.map((chapter, batchIndex) => summarizeChapter(chapter, i + batchIndex));\n\n const batchResults = await Promise.all(batchPromises);\n\n for (const summary of batchResults) {\n if (summary) {\n summaries.push(summary);\n }\n }\n\n logInfo(`[Summarizer] Progress: ${Math.min(i + SUMMARY_CONCURRENCY, chapters.length)}/${chapters.length} chapters processed`);\n }\n\n logInfo(`[Summarizer] Completed: ${summaries.length}/${chapters.length} summaries generated`);\n\n return summaries;\n};\n","import Database from \"better-sqlite3\";\nimport { resolvePaths } from \"../services/constants\";\n\nconst resolveDbPath = async () => {\n const paths = await resolvePaths();\n return paths.dbPath;\n};\n\nexport const createDb = async (): Promise<Database> => {\n const db = new Database(await resolveDbPath());\n\n db.exec(`\n CREATE TABLE IF NOT EXISTS books (\n id TEXT PRIMARY KEY,\n title TEXT NOT NULL,\n author TEXT,\n cover_path TEXT,\n chapters TEXT,\n epub_path TEXT NOT NULL,\n chunk_count INTEGER DEFAULT 0,\n created_at INTEGER DEFAULT (strftime('%s','now')),\n indexed_at INTEGER,\n progress_chapter INTEGER\n );\n `);\n\n const columns = db\n .prepare(\"PRAGMA table_info(books)\")\n .all()\n .map((col: { name: string }) => col.name);\n\n const ensureColumn = (name: string, definition: string) => {\n if (!columns.includes(name)) {\n db.exec(`ALTER TABLE books ADD COLUMN ${definition}`);\n }\n };\n\n ensureColumn(\"chapters\", \"chapters TEXT\");\n ensureColumn(\"progress_chapter\", \"progress_chapter INTEGER\");\n ensureColumn(\"summaries\", \"summaries TEXT\");\n ensureColumn(\"narrative_start_index\", \"narrative_start_index INTEGER DEFAULT 0\");\n ensureColumn(\"narrative_end_index\", \"narrative_end_index INTEGER\");\n\n return db;\n};\n","import type Database from \"better-sqlite3\";\nimport type { BookRecord } from \"../shared/types\";\nimport { createDb } from \"./schema\";\n\nexport type BookInsert = Omit<\n BookRecord,\n \"createdAt\" | \"indexedAt\" | \"chunkCount\" | \"progressChapter\" | \"narrativeStartIndex\" | \"narrativeEndIndex\"\n> & {\n chunkCount?: number;\n indexedAt?: number | null;\n progressChapter?: number | null;\n summaries?: string;\n narrativeStartIndex?: number | null;\n narrativeEndIndex?: number | null;\n};\n\nconst mapRow = (row: any): BookRecord => ({\n id: row.id,\n title: row.title,\n author: row.author ?? null,\n coverPath: row.cover_path ?? null,\n epubPath: row.epub_path,\n chunkCount: row.chunk_count ?? 0,\n createdAt: row.created_at ?? 0,\n indexedAt: row.indexed_at ?? null,\n chapters: row.chapters ? JSON.parse(row.chapters) : [],\n progressChapter: row.progress_chapter ?? null,\n narrativeStartIndex: row.narrative_start_index ?? null,\n narrativeEndIndex: row.narrative_end_index ?? null,\n});\n\nlet dbPromise: Promise<Database> | null = null;\n\nconst getDb = async () => {\n if (!dbPromise) {\n dbPromise = createDb();\n }\n return dbPromise;\n};\n\nexport const insertBook = async (book: BookInsert): Promise<string> => {\n const db = await getDb();\n const statement = db.prepare(\n \"INSERT INTO books (id, title, author, cover_path, chapters, epub_path, chunk_count, indexed_at, progress_chapter, narrative_start_index, narrative_end_index) VALUES (@id, @title, @author, @coverPath, @chapters, @epubPath, @chunkCount, @indexedAt, @progressChapter, @narrativeStartIndex, @narrativeEndIndex)\"\n );\n statement.run({\n id: book.id,\n title: book.title,\n author: book.author,\n coverPath: book.coverPath,\n chapters: JSON.stringify(book.chapters ?? []),\n epubPath: book.epubPath,\n chunkCount: book.chunkCount ?? 0,\n indexedAt: book.indexedAt ?? null,\n progressChapter: book.progressChapter ?? null,\n narrativeStartIndex: book.narrativeStartIndex ?? null,\n narrativeEndIndex: book.narrativeEndIndex ?? null,\n });\n return book.id;\n};\n\nexport const updateBook = async (id: string, updates: Partial<BookInsert>) => {\n const fields: string[] = [];\n const params: Record<string, string | number | boolean | null> = { id };\n\n if (updates.title !== undefined) {\n fields.push(\"title = @title\");\n params.title = updates.title;\n }\n if (updates.author !== undefined) {\n fields.push(\"author = @author\");\n params.author = updates.author;\n }\n if (updates.coverPath !== undefined) {\n fields.push(\"cover_path = @coverPath\");\n params.coverPath = updates.coverPath;\n }\n if (updates.chapters !== undefined) {\n fields.push(\"chapters = @chapters\");\n params.chapters = JSON.stringify(updates.chapters);\n }\n if (updates.epubPath !== undefined) {\n fields.push(\"epub_path = @epubPath\");\n params.epubPath = updates.epubPath;\n }\n if (updates.chunkCount !== undefined) {\n fields.push(\"chunk_count = @chunkCount\");\n params.chunkCount = updates.chunkCount;\n }\n if (updates.indexedAt !== undefined) {\n fields.push(\"indexed_at = @indexedAt\");\n params.indexedAt = updates.indexedAt;\n }\n if (updates.progressChapter !== undefined) {\n fields.push(\"progress_chapter = @progressChapter\");\n params.progressChapter = updates.progressChapter;\n }\n if (updates.summaries !== undefined) {\n fields.push(\"summaries = @summaries\");\n params.summaries = updates.summaries;\n }\n if (updates.narrativeStartIndex !== undefined) {\n fields.push(\"narrative_start_index = @narrativeStartIndex\");\n params.narrativeStartIndex = updates.narrativeStartIndex;\n }\n if (updates.narrativeEndIndex !== undefined) {\n fields.push(\"narrative_end_index = @narrativeEndIndex\");\n params.narrativeEndIndex = updates.narrativeEndIndex;\n }\n\n if (fields.length === 0) return;\n\n const db = await getDb();\n db.prepare(`UPDATE books SET ${fields.join(\", \")} WHERE id = @id`).run(params);\n};\n\nexport const getBooks = async (): Promise<BookRecord[]> => {\n const db = await getDb();\n const rows = db.prepare(\"SELECT * FROM books ORDER BY created_at DESC\").all();\n return rows.map(mapRow);\n};\n\nexport const getBook = async (id: string): Promise<BookRecord | null> => {\n const db = await getDb();\n const row = db.prepare(\"SELECT * FROM books WHERE id = ?\").get(id);\n return row ? mapRow(row) : null;\n};\n\nexport const deleteBook = async (id: string) => {\n const db = await getDb();\n db.prepare(\"DELETE FROM books WHERE id = ?\").run(id);\n};\n","import { parseEpub } from \"../services/epub-parser\";\nimport { ingestEpub } from \"../services/ingest\";\nimport { ensureDataDirs, requireOpenAIKey } from \"../services/constants\";\nimport { access } from \"node:fs/promises\";\nimport { prompt } from \"./prompt\";\nimport { isInteractive, stdout } from \"./io\";\n\nconst parseIndexSelection = (input: string, max: number): number[] => {\n const trimmed = input.trim();\n if (!trimmed) return [];\n const tokens = trimmed.split(\",\").map((part) => part.trim()).filter(Boolean);\n const indices = new Set<number>();\n for (const token of tokens) {\n if (token.includes(\"-\")) {\n const [startRaw, endRaw] = token.split(\"-\");\n const start = Number(startRaw);\n const end = Number(endRaw);\n if (!Number.isFinite(start) || !Number.isFinite(end)) continue;\n for (let i = Math.min(start, end); i <= Math.max(start, end); i++) {\n if (i >= 0 && i < max) indices.add(i);\n }\n } else {\n const index = Number(token);\n if (Number.isFinite(index) && index >= 0 && index < max) indices.add(index);\n }\n }\n return Array.from(indices).sort((a, b) => a - b);\n};\n\nexport const ingestCommand = async (filePath: string, options: { manual?: boolean; summarize?: boolean }) => {\n requireOpenAIKey();\n await ensureDataDirs();\n try {\n await access(filePath);\n } catch {\n throw new Error(`File not found: ${filePath}`);\n }\n\n let selectedChapterIndices: number[] | undefined;\n if (options.manual) {\n if (!isInteractive()) {\n throw new Error(\"Manual chapter selection requires an interactive terminal.\");\n }\n const parsed = await parseEpub(filePath);\n if (parsed.chapterTitles.length === 0) {\n throw new Error(\"No chapters found in EPUB\");\n }\n\n stdout(\"Chapters:\");\n parsed.chapterTitles.forEach((title, index) => {\n const marker = index >= parsed.narrativeStartIndex && index <= parsed.narrativeEndIndex ? \"*\" : \" \";\n stdout(`${marker} [${index}] ${title}`);\n });\n stdout(\"\\nEnter chapter indices to ingest (e.g. 0-10,12). Press Enter for narrative range.\");\n const answer = await prompt(\"Selection: \");\n const indices = parseIndexSelection(answer, parsed.chapterTitles.length);\n if (indices.length > 0) {\n selectedChapterIndices = indices;\n } else {\n selectedChapterIndices = Array.from(\n { length: parsed.narrativeEndIndex - parsed.narrativeStartIndex + 1 },\n (_, i) => i + parsed.narrativeStartIndex\n );\n }\n }\n\n const result = await ingestEpub(filePath, selectedChapterIndices, { summarize: options.summarize ?? false });\n stdout(`\\nDone. Book indexed as ${result.id}`);\n};\n","import { createInterface } from \"node:readline/promises\";\nimport { handleSigint } from \"./io\";\n\nexport const prompt = async (question: string): Promise<string> => {\n const release = handleSigint();\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n try {\n const response = await rl.question(question);\n return response.trim();\n } finally {\n rl.close();\n release();\n }\n};\n\nexport const confirm = async (question: string): Promise<boolean> => {\n const response = await prompt(question);\n const normalized = response.trim().toLowerCase();\n return normalized === \"y\" || normalized === \"yes\";\n};\n","import { ingestCommand } from \"../ingest\";\n\nexport const registerBookIngest = (program: import(\"commander\").Command) => {\n program\n .command(\"ingest\")\n .description(\"Ingest an EPUB file\")\n .argument(\"<path>\", \"Path to the EPUB file\")\n .option(\"--manual\", \"Interactive chapter selection\")\n .option(\"--summary\", \"Enable AI chapter summaries\")\n .action(async (path: string, options: { manual?: boolean; summary?: boolean }) => {\n const summarize = Boolean(options.summary);\n await ingestCommand(path, { manual: options.manual, summarize });\n });\n};\n","import { getBooks } from \"../db/queries\";\nimport { ensureDataDirs } from \"../services/constants\";\nimport { stdout } from \"./io\";\n\nconst formatDate = (timestamp: number | null) => {\n if (!timestamp) return \"-\";\n return new Date(timestamp).toISOString().slice(0, 10);\n};\n\nexport const listCommand = async () => {\n await ensureDataDirs();\n const books = await getBooks();\n if (books.length === 0) {\n stdout(\"No books indexed yet.\");\n return;\n }\n\n stdout(\"ID | Title | Author | Chunks | Indexed | Status\");\n stdout(\"---------|-------|--------|--------|--------|-------\");\n for (const book of books) {\n const shortId = book.id.slice(0, 8);\n const title = book.title;\n const author = book.author || \"-\";\n const chunks = String(book.chunkCount ?? 0);\n const indexed = formatDate(book.indexedAt);\n const status = book.indexedAt ? \"[indexed]\" : \"[pending]\";\n stdout(`${shortId} | ${title} | ${author} | ${chunks} | ${indexed} | ${status}`);\n }\n};\n","import { listCommand } from \"../list\";\n\nexport const registerBookList = (program: import(\"commander\").Command) => {\n program\n .command(\"list\")\n .description(\"List indexed books\")\n .action(async () => {\n await listCommand();\n });\n};\n","import { getBooks } from \"../db/queries\";\n\nexport const resolveBookId = async (input: string): Promise<string | null> => {\n const books = await getBooks();\n const exact = books.find((book) => book.id === input);\n if (exact) return exact.id;\n const matches = books.filter((book) => book.id.startsWith(input));\n if (matches.length === 1) return matches[0]!.id;\n if (matches.length > 1) {\n throw new Error(`Ambiguous id prefix \"${input}\" (${matches.length} matches)`);\n }\n return null;\n};\n","import { getBook } from \"../db/queries\";\nimport { resolveBookId } from \"./utils\";\nimport { ensureDataDirs } from \"../services/constants\";\nimport { stdout } from \"./io\";\n\nexport const showCommand = async (id: string) => {\n await ensureDataDirs();\n const resolvedId = await resolveBookId(id);\n if (!resolvedId) {\n throw new Error(`Book not found: ${id}`);\n }\n const book = await getBook(resolvedId);\n if (!book) {\n throw new Error(`Book not found: ${id}`);\n }\n\n stdout(`Title: ${book.title}`);\n stdout(`Author: ${book.author ?? \"-\"}`);\n stdout(`ID: ${book.id}`);\n stdout(`Chunks: ${book.chunkCount}`);\n stdout(`Indexed: ${book.indexedAt ? new Date(book.indexedAt).toISOString() : \"-\"}`);\n stdout(`Narrative range: ${book.narrativeStartIndex ?? 0} to ${book.narrativeEndIndex ?? book.chapters.length - 1}`);\n stdout(`Progress chapter: ${book.progressChapter ?? \"-\"}`);\n stdout(\"\\nChapters:\");\n\n book.chapters.forEach((title: string, index: number) => {\n const marker = index === book.narrativeStartIndex ? \"[start]\" : index === book.narrativeEndIndex ? \"[end]\" : \"\";\n stdout(` [${index}] ${title} ${marker}`.trim());\n });\n};\n","import { showCommand } from \"../show\";\n\nexport const registerBookShow = (program: import(\"commander\").Command) => {\n program\n .command(\"show\")\n .description(\"Show full book metadata\")\n .argument(\"<id>\", \"Book id or prefix\")\n .action(async (id: string) => {\n await showCommand(id);\n });\n};\n","import { embed, streamText } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\nimport { getBook } from \"../db/queries\";\nimport { resolveBookId } from \"./utils\";\nimport { queryBookIndex } from \"../services/vector-store\";\nimport { ensureDataDirs, getModels, isAskEnabled, requireOpenAIKey } from \"../services/constants\";\nimport { handleSigint } from \"./io\";\n\nconst formatContext = (chunks: Array<{ content: string; chapterTitle: string; chapterIndex: number }>) =>\n chunks\n .map(\n (chunk, index) =>\n `Excerpt [${index + 1}] (${chunk.chapterTitle || `Chapter ${chunk.chapterIndex + 1}`}):\\n${chunk.content}`\n )\n .join(\"\\n\\n\");\n\nexport const askCommand = async (\n id: string,\n question: string,\n options: { topK: number; maxChapter?: number }\n) => {\n if (!(await isAskEnabled())) {\n throw new Error(\"Ask is disabled in config (askEnabled: false). Enable it to use this command.\");\n }\n\n requireOpenAIKey();\n await ensureDataDirs();\n\n const resolvedId = await resolveBookId(id);\n if (!resolvedId) {\n throw new Error(`Book not found: ${id}`);\n }\n const book = await getBook(resolvedId);\n if (!book) {\n throw new Error(`Book not found: ${id}`);\n }\n\n const models = await getModels();\n const { embedding } = await embed({\n model: openai.embeddingModel(models.embedding),\n value: question,\n });\n\n const narrativeStart = book.narrativeStartIndex ?? 0;\n const userProgress = book.progressChapter ?? null;\n const maxChapterIndex = options.maxChapter !== undefined\n ? narrativeStart + options.maxChapter\n : userProgress !== null\n ? narrativeStart + userProgress\n : undefined;\n\n const retrievalLimit = options.topK * 3;\n const allMatches = await queryBookIndex(resolvedId, embedding, question, retrievalLimit, maxChapterIndex);\n\n const summaries = allMatches.filter((m) => m.type === \"summary\");\n const chunks = allMatches.filter((m) => m.type !== \"summary\");\n\n const topSummaries = summaries.slice(0, 2);\n const topChunks = chunks.slice(0, Math.max(0, options.topK - topSummaries.length));\n const selectedMatches = [...topSummaries, ...topChunks];\n\n const context = formatContext(selectedMatches);\n\n const releaseSigint = handleSigint();\n const stream = streamText({\n model: openai(models.chat),\n system: `You are a reading companion helping readers understand this book.\n\nGuidelines:\n- Use the provided chapter summaries and excerpts to answer questions\n- Chapter summaries provide high-level context about characters, events, and plot\n- Excerpts provide specific details and quotes\n- When asked for recaps or \"what happened\", synthesize from summaries\n- Don't cite table of contents, front matter, or structural elements\n- If truly unsure, briefly say so - but try to answer from available context first\n- Cite sources using [1], [2], etc. at the end of relevant sentences\n- The context may be limited to earlier chapters only - don't infer beyond what's provided`,\n prompt: `Question: ${question}\\n\\n${context}`,\n });\n\n try {\n for await (const part of stream.textStream) {\n process.stdout.write(part);\n }\n } finally {\n releaseSigint();\n }\n\n if (selectedMatches.length > 0) {\n process.stdout.write(\"\\n\\nSources:\\n\");\n selectedMatches.forEach((match, index) => {\n const title = match.chapterTitle || `Chapter ${match.chapterIndex + 1}`;\n const excerpt = match.content.slice(0, 120).replace(/\\s+/g, \" \");\n process.stdout.write(`[${index + 1}] ${title}: ${excerpt}\\n`);\n });\n }\n};\n","import { askCommand } from \"../ask\";\n\nexport const registerBookAsk = (program: import(\"commander\").Command) => {\n program\n .command(\"ask\")\n .description(\"Ask a question about a book\")\n .argument(\"<id>\", \"Book id or prefix\")\n .argument(\"<question>\", \"Question to ask\")\n .option(\"--top-k <n>\", \"Number of passages to retrieve\", \"5\")\n .option(\"--max-chapter <n>\", \"Spoiler-free limit (0-based within narrative)\")\n .action(async (\n id: string,\n question: string,\n options: { topK: string; maxChapter?: string }\n ) => {\n const topK = Number(options.topK);\n if (!Number.isFinite(topK) || topK <= 0) {\n throw new Error(\"--top-k must be a positive number.\");\n }\n let maxChapter: number | undefined;\n if (options.maxChapter !== undefined) {\n const parsed = Number(options.maxChapter);\n if (!Number.isFinite(parsed) || parsed < 0) {\n throw new Error(\"--max-chapter must be a non-negative number.\");\n }\n maxChapter = parsed;\n }\n await askCommand(id, question, { topK, maxChapter });\n });\n};\n","import { embed } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\nimport { getBook } from \"../db/queries\";\nimport { resolveBookId } from \"./utils\";\nimport { queryBookIndex } from \"../services/vector-store\";\nimport { ensureDataDirs, getModels, requireOpenAIKey } from \"../services/constants\";\nimport { stdout } from \"./io\";\n\nexport const searchCommand = async (\n id: string,\n query: string,\n options: { topK: number; maxChapter?: number }\n) => {\n requireOpenAIKey();\n await ensureDataDirs();\n const resolvedId = await resolveBookId(id);\n if (!resolvedId) {\n throw new Error(`Book not found: ${id}`);\n }\n const book = await getBook(resolvedId);\n if (!book) {\n throw new Error(`Book not found: ${id}`);\n }\n\n const models = await getModels();\n const { embedding } = await embed({\n model: openai.embeddingModel(models.embedding),\n value: query,\n });\n\n const maxChapterIndex = options.maxChapter !== undefined\n ? (book.narrativeStartIndex ?? 0) + options.maxChapter\n : book.progressChapter !== null\n ? (book.narrativeStartIndex ?? 0) + (book.progressChapter ?? 0)\n : undefined;\n const results = await queryBookIndex(resolvedId, embedding, query, options.topK, maxChapterIndex);\n\n if (results.length === 0) {\n stdout(\"No results.\");\n return;\n }\n\n results.forEach((result, index) => {\n const chapterTitle = result.chapterTitle || `Chapter ${result.chapterIndex + 1}`;\n const excerpt = result.content.slice(0, 200).replace(/\\s+/g, \" \");\n stdout(`\\n#${index + 1} score=${result.score.toFixed(4)} type=${result.type || \"chunk\"}`);\n stdout(`${chapterTitle} (chapter ${result.chapterIndex})`);\n stdout(excerpt);\n });\n};\n","import { searchCommand } from \"../search\";\n\nexport const registerBookSearch = (program: import(\"commander\").Command) => {\n program\n .command(\"search\")\n .description(\"Vector search without LLM\")\n .argument(\"<id>\", \"Book id or prefix\")\n .argument(\"<query>\", \"Search query\")\n .option(\"--top-k <n>\", \"Number of passages to retrieve\", \"5\")\n .option(\"--max-chapter <n>\", \"Spoiler-free limit (0-based within narrative)\")\n .action(async (\n id: string,\n query: string,\n options: { topK: string; maxChapter?: string }\n ) => {\n const topK = Number(options.topK);\n if (!Number.isFinite(topK) || topK <= 0) {\n throw new Error(\"--top-k must be a positive number.\");\n }\n let maxChapter: number | undefined;\n if (options.maxChapter !== undefined) {\n const parsed = Number(options.maxChapter);\n if (!Number.isFinite(parsed) || parsed < 0) {\n throw new Error(\"--max-chapter must be a non-negative number.\");\n }\n maxChapter = parsed;\n }\n await searchCommand(id, query, { topK, maxChapter });\n });\n};\n","import { unlink } from \"node:fs/promises\";\nimport { deleteBook, getBook } from \"../db/queries\";\nimport { resolveBookId } from \"./utils\";\nimport { deleteBookIndex } from \"../services/vector-store\";\nimport { ensureDataDirs } from \"../services/constants\";\nimport { confirm } from \"./prompt\";\nimport { isInteractive, stdout } from \"./io\";\n\nexport const deleteCommand = async (id: string, options: { force?: boolean }) => {\n await ensureDataDirs();\n const resolvedId = await resolveBookId(id);\n if (!resolvedId) {\n throw new Error(`Book not found: ${id}`);\n }\n const book = await getBook(resolvedId);\n if (!book) {\n throw new Error(`Book not found: ${id}`);\n }\n\n if (!options.force) {\n if (!isInteractive()) {\n throw new Error(\"Delete confirmation requires an interactive terminal. Use --force to bypass.\");\n }\n const ok = await confirm(`Delete \"${book.title}\" (${book.id})? [y/N] `);\n if (!ok) {\n stdout(\"Cancelled.\");\n return;\n }\n }\n\n await deleteBook(resolvedId);\n await deleteBookIndex(resolvedId);\n if (book.epubPath) {\n await unlink(book.epubPath).catch(() => undefined);\n }\n stdout(`Deleted book ${book.id}`);\n};\n","import { deleteCommand } from \"../delete\";\n\nexport const registerBookDelete = (program: import(\"commander\").Command) => {\n program\n .command(\"delete\")\n .description(\"Remove book, EPUB, and vectors\")\n .argument(\"<id>\", \"Book id or prefix\")\n .option(\"--force\", \"Skip confirmation\")\n .action(async (id: string, options: { force?: boolean }) => {\n await deleteCommand(id, { force: options.force });\n });\n};\n","import { configPath } from \"../config\";\nimport { stdout } from \"./io\";\n\nexport const configCommand = async () => {\n const path = configPath();\n stdout(path);\n};\n","import { configCommand } from \"../config\";\n\nexport const registerConfigPath = (program: import(\"commander\").Command) => {\n program\n .command(\"path\")\n .description(\"Print config path\")\n .action(async () => {\n await configCommand();\n });\n};\n","import { ensureConfigDirs, configPath, loadConfig } from \"../config\";\nimport { mkdir, writeFile, access } from \"node:fs/promises\";\nimport { stdout } from \"./io\";\n\nexport const initConfigCommand = async () => {\n const path = configPath();\n await ensureConfigDirs(path);\n try {\n await access(path);\n stdout(`Config already exists: ${path}`);\n return;\n } catch {\n // file does not exist\n }\n const resolved = await loadConfig();\n const template = {\n dataDir: \"~/.local/share/mycroft\",\n askEnabled: resolved.askEnabled,\n models: resolved.models,\n };\n await writeFile(path, JSON.stringify(template, null, 2), \"utf-8\");\n await mkdir(resolved.dataDir, { recursive: true });\n stdout(`Created config at ${path}`);\n};\n","import { initConfigCommand } from \"../init-config\";\n\nexport const registerConfigInit = (program: import(\"commander\").Command) => {\n program\n .command(\"init\")\n .description(\"Create default config file\")\n .action(async () => {\n await initConfigCommand();\n });\n};\n","import { configPath, loadConfig } from \"../config\";\nimport { stdout } from \"./io\";\n\nexport const resolveConfigCommand = async () => {\n const path = configPath();\n const config = await loadConfig();\n stdout(`Config: ${path}`);\n stdout(`Data dir: ${config.dataDir}`);\n stdout(`Ask enabled: ${config.askEnabled}`);\n stdout(`Models: embedding=${config.models.embedding} summary=${config.models.summary} chat=${config.models.chat}`);\n};\n","import { resolveConfigCommand } from \"../resolve-config\";\n\nexport const registerConfigResolve = (program: import(\"commander\").Command) => {\n program\n .command(\"resolve\")\n .description(\"Print resolved config values\")\n .action(async () => {\n await resolveConfigCommand();\n });\n};\n","import { ensureConfigDirs, configPath, loadConfig } from \"../config\";\nimport { writeFile } from \"node:fs/promises\";\nimport { prompt } from \"./prompt\";\nimport { isInteractive, stdout } from \"./io\";\n\nconst isDefault = (input: string) => input === \"\" || input.toLowerCase() === \"-y\";\n\nconst parseBoolean = (input: string, fallback: boolean) => {\n if (isDefault(input)) return fallback;\n const normalized = input.toLowerCase();\n if ([\"y\", \"yes\", \"true\", \"1\"].includes(normalized)) return true;\n if ([\"n\", \"no\", \"false\", \"0\"].includes(normalized)) return false;\n return fallback;\n};\n\nexport const onboardCommand = async () => {\n if (!isInteractive()) {\n throw new Error(\"Onboarding requires an interactive terminal.\");\n }\n const defaults = await loadConfig();\n const path = configPath();\n\n stdout(\"\\nEPUB RAG setup\");\n stdout(\"Press Enter or type -y to accept defaults.\");\n\n const dataDirInput = await prompt(`Data directory [${defaults.dataDir}]: `);\n const dataDir = isDefault(dataDirInput) ? defaults.dataDir : dataDirInput;\n\n const askEnabledInput = await prompt(`Enable ask (LLM answers) [${defaults.askEnabled ? \"Y\" : \"N\"}]: `);\n const askEnabled = parseBoolean(askEnabledInput, defaults.askEnabled);\n\n const embeddingInput = await prompt(`Embedding model [${defaults.models.embedding}]: `);\n const embedding = isDefault(embeddingInput) ? defaults.models.embedding : embeddingInput;\n\n const summaryInput = await prompt(`Summary model [${defaults.models.summary}]: `);\n const summary = isDefault(summaryInput) ? defaults.models.summary : summaryInput;\n\n const chatInput = await prompt(`Chat model [${defaults.models.chat}]: `);\n const chat = isDefault(chatInput) ? defaults.models.chat : chatInput;\n\n await ensureConfigDirs(path);\n await writeFile(\n path,\n JSON.stringify(\n {\n dataDir,\n askEnabled,\n models: {\n embedding,\n summary,\n chat,\n },\n },\n null,\n 2\n ),\n \"utf-8\"\n );\n\n stdout(\"\\nSetup complete.\");\n stdout(`Config: ${path}`);\n stdout(`Data dir: ${dataDir}`);\n\n if (!process.env.OPENAI_API_KEY) {\n stdout(\"\\nOPENAI_API_KEY is not set.\");\n stdout(\"Export it to enable embeddings and chat:\");\n stdout(\" export OPENAI_API_KEY=\\\"...\\\"\");\n }\n\n stdout(\"\\nNext step:\");\n stdout(\" mycroft book ingest /path/to/book.epub\");\n};\n","import { onboardCommand } from \"../onboard\";\n\nexport const registerConfigOnboard = (program: import(\"commander\").Command) => {\n program\n .command(\"onboard\")\n .description(\"Initialize config and show next step\")\n .action(async () => {\n await onboardCommand();\n });\n};\n"],"mappings":"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","names":["configPath","readFile","dirname","resolve","mkdir","mkdir","mkdir","openai","CHARS_PER_TOKEN","openai","mkdir","program","program","program","openai","openai","program","embed","openai","embed","openai","program","unlink","unlink","program","program","mkdir","access","access","mkdir","program","program","writeFile","writeFile","program","dirname","resolve","readFile"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/config.ts","../src/commands/io.ts","../src/services/epub-parser.ts","../src/services/constants.ts","../src/services/ingest.ts","../src/services/chunker.ts","../src/services/embedder.ts","../src/services/vector-store.ts","../src/services/summarizer.ts","../src/db/schema.ts","../src/db/queries.ts","../src/commands/ingest.ts","../src/commands/prompt.ts","../src/commands/book/ingest.ts","../src/commands/list.ts","../src/commands/book/list.ts","../src/commands/utils.ts","../src/commands/show.ts","../src/commands/book/show.ts","../src/commands/ask.ts","../src/commands/book/ask.ts","../src/commands/search.ts","../src/commands/book/search.ts","../src/commands/delete.ts","../src/commands/book/delete.ts","../src/commands/config.ts","../src/commands/config/path.ts","../src/commands/init-config.ts","../src/commands/config/init.ts","../src/commands/resolve-config.ts","../src/commands/config/resolve.ts","../src/commands/onboard.ts","../src/commands/config/onboard.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from \"commander\";\nimport { setConfigOverrides } from \"./config\";\nimport { printError } from \"./commands/io\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { registerBookIngest } from \"./commands/book/ingest\";\nimport { registerBookList } from \"./commands/book/list\";\nimport { registerBookShow } from \"./commands/book/show\";\nimport { registerBookAsk } from \"./commands/book/ask\";\nimport { registerBookSearch } from \"./commands/book/search\";\nimport { registerBookDelete } from \"./commands/book/delete\";\nimport { registerConfigPath } from \"./commands/config/path\";\nimport { registerConfigInit } from \"./commands/config/init\";\nimport { registerConfigResolve } from \"./commands/config/resolve\";\nimport { registerConfigOnboard } from \"./commands/config/onboard\";\n\nconst resolveVersion = async () => {\n try {\n const currentDir = dirname(fileURLToPath(import.meta.url));\n const pkgPath = resolve(currentDir, \"../package.json\");\n const raw = await readFile(pkgPath, \"utf-8\");\n return JSON.parse(raw).version || \"0.1.0\";\n } catch {\n return \"0.1.0\";\n }\n};\n\nconst program = new Command();\nconst configureProgram = async () => {\n program\n .name(\"mycroft\")\n .description(\"Ingest EPUBs, build a local index, and answer questions\")\n .version(await resolveVersion())\n .option(\"--data-dir <path>\", \"Override data directory\")\n .hook(\"preAction\", (cmd) => {\n const opts = cmd.opts();\n if (opts.dataDir) {\n setConfigOverrides({ dataDir: opts.dataDir });\n }\n });\n};\n\nconst registerCommands = () => {\n const book = program.command(\"book\").description(\"Manage books and queries\");\n registerBookIngest(book);\n registerBookList(book);\n registerBookShow(book);\n registerBookAsk(book);\n registerBookSearch(book);\n registerBookDelete(book);\n\n const config = program.command(\"config\").description(\"Manage configuration\");\n registerConfigPath(config);\n registerConfigInit(config);\n registerConfigResolve(config);\n registerConfigOnboard(config);\n};\n\nprogram.exitOverride((error) => {\n if (error.code === \"commander.helpDisplayed\") {\n process.exit(0);\n }\n throw error;\n});\n\nconst main = async () => {\n try {\n await configureProgram();\n registerCommands();\n await program.parseAsync(process.argv);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n printError(message);\n process.exit(1);\n }\n};\n\nmain();\n","import { mkdir, readFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\n\nexport type ConfigModels = {\n embedding: string;\n summary: string;\n chat: string;\n};\n\nexport type AppConfig = {\n dataDir: string;\n askEnabled: boolean;\n models: ConfigModels;\n};\n\nconst DEFAULT_CONFIG: AppConfig = {\n dataDir: \"~/.local/share/mycroft\",\n askEnabled: true,\n models: {\n embedding: \"text-embedding-3-small\",\n summary: \"gpt-5-nano\",\n chat: \"gpt-5.1\",\n },\n};\n\nconst expandHome = (input: string): string => {\n if (!input.startsWith(\"~\")) return input;\n return join(homedir(), input.slice(1));\n};\n\nconst resolvePath = (input: string): string => resolve(expandHome(input));\n\nconst getConfigPath = (): string => {\n const override = process.env.MYCROFT_CONFIG;\n if (override) return resolvePath(override);\n return resolvePath(\"~/.config/mycroft/config.json\");\n};\n\nconst normalizeModels = (models?: Partial<ConfigModels>): ConfigModels => ({\n embedding: models?.embedding || DEFAULT_CONFIG.models.embedding,\n summary: models?.summary || DEFAULT_CONFIG.models.summary,\n chat: models?.chat || DEFAULT_CONFIG.models.chat,\n});\n\ntype ConfigOverrides = {\n dataDir?: string;\n};\n\nlet overrides: ConfigOverrides = {};\n\nexport const setConfigOverrides = (next: ConfigOverrides) => {\n overrides = { ...overrides, ...next };\n};\n\nconst normalizeConfig = (input: Partial<AppConfig> | null): AppConfig => {\n const dataDirEnv = process.env.MYCROFT_DATA_DIR;\n const dataDir = overrides.dataDir || dataDirEnv || input?.dataDir || DEFAULT_CONFIG.dataDir;\n return {\n dataDir,\n askEnabled: input?.askEnabled ?? DEFAULT_CONFIG.askEnabled,\n models: normalizeModels(input?.models),\n };\n};\n\nconst readConfigFile = async (path: string): Promise<Partial<AppConfig> | null> => {\n try {\n const contents = await readFile(path, \"utf-8\");\n return JSON.parse(contents) as Partial<AppConfig>;\n } catch {\n return null;\n }\n};\n\nexport const loadConfig = async (): Promise<AppConfig> => {\n const configPath = getConfigPath();\n const data = await readConfigFile(configPath);\n const normalized = normalizeConfig(data);\n return {\n ...normalized,\n dataDir: resolvePath(normalized.dataDir),\n };\n};\n\nexport const ensureConfigDirs = async (configPath?: string) => {\n const path = configPath || getConfigPath();\n await mkdir(dirname(path), { recursive: true });\n};\n\nexport const configPath = () => getConfigPath();\n","import chalk from \"chalk\";\n\nconst isTTY = () => Boolean(process.stdout.isTTY);\nexport const isInteractive = () => Boolean(process.stdin.isTTY && process.stdout.isTTY);\n\nexport const formatDim = (text: string) => (isTTY() ? chalk.dim(text) : text);\nexport const formatError = (text: string) => (isTTY() ? chalk.red(text) : text);\nexport const formatBold = (text: string) => (isTTY() ? chalk.bold(text) : text);\nexport const formatWarn = (text: string) => (isTTY() ? chalk.yellow(text) : text);\n\nexport const stdout = (message: string) => {\n process.stdout.write(message.endsWith(\"\\n\") ? message : `${message}\\n`);\n};\n\nexport const stderr = (message: string) => {\n process.stderr.write(message.endsWith(\"\\n\") ? message : `${message}\\n`);\n};\n\nexport const printError = (message: string) => {\n stderr(formatError(`Error: ${message}`));\n};\n\nexport const logInfo = (message: string) => {\n stderr(message);\n};\n\nexport const logWarn = (message: string) => {\n stderr(formatWarn(message));\n};\n\nexport const handleSigint = (onCancel?: () => void) => {\n const handler = () => {\n if (onCancel) onCancel();\n stderr(\"\\nCancelled.\");\n process.exit(130);\n };\n process.once(\"SIGINT\", handler);\n return () => process.off(\"SIGINT\", handler);\n};\n","import { initEpubFile } from \"@lingo-reader/epub-parser\";\nimport { basename } from \"node:path\";\nimport type { Chapter } from \"../shared/types\";\nimport { logInfo } from \"./constants\";\n\nexport type ParsedBook = {\n title: string;\n author: string | null;\n coverImagePath: string | null;\n chapters: Chapter[];\n chapterTitles: string[];\n narrativeStartIndex: number;\n narrativeEndIndex: number;\n};\n\nconst detectNarrativeBoundaries = (chapterTitles: string[]): { start: number; end: number } => {\n const frontMatterPattern = /^(about|contents|table of contents|dedication|preface|foreword|title|half.?title|copyright|epigraph|frontispiece|map)/i;\n const backMatterPattern = /^(acknowledgment|afterword|appendix|glossary|index|bibliography|about the author|also by|praise|copyright page|notes|bonus|preview|excerpt|major characters|locations)/i;\n const narrativePattern = /^(I|II|III|IV|V|VI|VII|VIII|IX|X|XI|XII|1|2|3|4|5|6|7|8|9|one|two|three|chapter|prologue|epilogue|part\\s)/i;\n\n let start = 0;\n let end = chapterTitles.length - 1;\n\n for (let i = 0; i < chapterTitles.length; i++) {\n const title = chapterTitles[i]?.trim() || \"\";\n\n if (narrativePattern.test(title) && !frontMatterPattern.test(title)) {\n start = i;\n break;\n }\n\n if (!frontMatterPattern.test(title) && title.length > 0) {\n if (title.length > 3) {\n start = i;\n break;\n }\n }\n }\n\n for (let i = chapterTitles.length - 1; i >= start; i--) {\n const title = chapterTitles[i]?.trim() || \"\";\n if (!backMatterPattern.test(title)) {\n end = i;\n break;\n }\n }\n\n logInfo(`[EPUB Parser] Detected narrative boundaries: chapters ${start} to ${end} (out of ${chapterTitles.length} total)`);\n if (start > 0) {\n logInfo(`[EPUB Parser] Front matter: ${chapterTitles.slice(0, start).join(\", \")}`);\n }\n if (end < chapterTitles.length - 1) {\n logInfo(`[EPUB Parser] Back matter: ${chapterTitles.slice(end + 1).join(\", \")}`);\n }\n\n return { start, end };\n};\n\nconst stripHtml = (html: string) =>\n html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, \" \")\n .replace(/<style[\\s\\S]*?<\\/style>/gi, \" \")\n .replace(/<[^>]+>/g, \" \")\n .replace(/ /g, \" \")\n .replace(/&/g, \"&\")\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/\\s+/g, \" \")\n .trim();\n\nconst originalWarn = console.warn;\nconst createWarnFilter = () => {\n const suppressedWarnings: string[] = [];\n console.warn = (msg: any, ...args: unknown[]) => {\n if (typeof msg === \"string\" && msg.includes(\"No element with id\") && msg.includes(\"parsing <metadata>\")) {\n suppressedWarnings.push(msg);\n return;\n }\n originalWarn(msg, ...args);\n };\n return suppressedWarnings;\n};\n\nexport const parseEpub = async (epubPath: string, resourceSaveDir?: string): Promise<ParsedBook> => {\n logInfo(`[EPUB Parser] Starting parse for: ${basename(epubPath)}`);\n\n const suppressedWarnings = createWarnFilter();\n\n try {\n const epubFile = await initEpubFile(epubPath, resourceSaveDir);\n await epubFile.loadEpub();\n logInfo(`[EPUB Parser] EPUB loaded successfully`);\n\n await epubFile.parse();\n\n if (suppressedWarnings.length > 0) {\n logInfo(`[EPUB Parser] Suppressed ${suppressedWarnings.length} metadata warnings (non-critical)`);\n }\n logInfo(`[EPUB Parser] Parse completed`);\n\n const fileBaseName = basename(epubPath, \".epub\");\n type EpubMetadata = ReturnType<typeof epubFile.getMetadata>;\n let metadata: EpubMetadata | null = null;\n try {\n metadata = epubFile.getMetadata();\n } catch {\n metadata = null;\n }\n const safeMetadata = metadata ?? ({} as EpubMetadata);\n const spine = epubFile.getSpine();\n const toc = epubFile.getToc();\n\n logInfo(`[EPUB Parser] Found ${spine.length} spine items, ${toc.length} TOC entries`);\n\n const titleById = new Map<string, string>();\n const walkToc = (items: typeof toc) => {\n items.forEach((item: (typeof toc)[number]) => {\n const resolved = epubFile.resolveHref(item.href);\n if (resolved?.id) titleById.set(resolved.id, item.label);\n if (item.children?.length) walkToc(item.children);\n });\n };\n walkToc(toc);\n const coverImagePath = epubFile.getCoverImage() || null;\n\n const chapters: Chapter[] = [];\n const chapterTitles: string[] = [];\n for (const [index, item] of spine.entries()) {\n const chapter = await epubFile.loadChapter(item.id);\n const content = stripHtml(chapter.html);\n if (!content) continue;\n const chapterTitle = titleById.get(item.id) || item.id || `Chapter ${index + 1}`;\n chapters.push({\n title: chapterTitle,\n content,\n });\n chapterTitles.push(chapterTitle);\n }\n\n epubFile.destroy();\n\n const author = safeMetadata.creator?.[0]?.contributor ?? null;\n\n logInfo(`[EPUB Parser] Extracted ${chapters.length} chapters with content`);\n logInfo(`[EPUB Parser] Title: \"${safeMetadata.title || fileBaseName || \"Untitled\"}\", Author: \"${author || \"Unknown\"}\"`);\n\n const { start: narrativeStartIndex, end: narrativeEndIndex } = detectNarrativeBoundaries(chapterTitles);\n\n return {\n title: safeMetadata.title || fileBaseName || \"Untitled\",\n author,\n coverImagePath,\n chapters,\n chapterTitles,\n narrativeStartIndex,\n narrativeEndIndex,\n };\n } finally {\n console.warn = originalWarn;\n }\n};\n","import { mkdir } from \"node:fs/promises\";\nimport { loadConfig } from \"../config\";\nimport { logInfo, logWarn } from \"../commands/io\";\n\nexport const CHUNK_SIZE: number = 1000;\nexport const CHUNK_OVERLAP: number = 100;\nexport const SEPARATORS = [\"\\n\\n\", \"\\n\", \". \", \" \", \"\"] as const;\n\nexport const SUMMARY_MAX_TOKENS = 30000;\nexport const SUMMARY_CONCURRENCY = 3;\nexport const SUMMARY_TARGET_WORDS = 250;\n\nexport type ResolvedPaths = {\n dataDir: string;\n booksDir: string;\n vectorsDir: string;\n dbPath: string;\n};\n\nexport const resolvePaths = async (): Promise<ResolvedPaths> => {\n const config = await loadConfig();\n const dataDir = config.dataDir;\n return {\n dataDir,\n booksDir: `${dataDir}/books`,\n vectorsDir: `${dataDir}/vectors`,\n dbPath: `${dataDir}/metadata.db`,\n };\n};\n\nexport const ensureDataDirs = async () => {\n const paths = await resolvePaths();\n await mkdir(paths.dataDir, { recursive: true });\n await mkdir(paths.booksDir, { recursive: true });\n await mkdir(paths.vectorsDir, { recursive: true });\n return paths;\n};\n\nexport const getModels = async () => {\n const config = await loadConfig();\n return config.models;\n};\n\nexport const isAskEnabled = async () => {\n const config = await loadConfig();\n return config.askEnabled;\n};\n\nexport const requireOpenAIKey = () => {\n if (!process.env.OPENAI_API_KEY) {\n throw new Error(\"OPENAI_API_KEY is not set. Export it to use embeddings and chat.\");\n }\n};\n\nexport { logInfo, logWarn };\n","import { randomUUID } from \"node:crypto\";\nimport { mkdir, unlink, copyFile } from \"node:fs/promises\";\nimport { parseEpub } from \"./epub-parser\";\nimport { chunkChapters } from \"./chunker\";\nimport { embedChunks } from \"./embedder\";\nimport { addChunksToIndex, deleteBookIndex } from \"./vector-store\";\nimport { summarizeAllChapters } from \"./summarizer\";\nimport { ensureDataDirs, logInfo, logWarn } from \"./constants\";\nimport { deleteBook, insertBook, updateBook } from \"../db/queries\";\nimport type { BookChunk } from \"../shared/types\";\n\nconst formatDuration = (ms: number) => {\n const seconds = Math.round(ms / 100) / 10;\n return `${seconds}s`;\n};\n\nexport const ingestEpub = async (\n filePath: string,\n selectedChapterIndices?: number[],\n options?: { summarize?: boolean }\n) => {\n const bookId = randomUUID();\n const paths = await ensureDataDirs();\n const fileName = `${bookId}.epub`;\n const bookPath = `${paths.booksDir}/${fileName}`;\n\n logInfo(`[Ingest] Starting ingestion for book ${bookId}`);\n\n await mkdir(paths.booksDir, { recursive: true });\n await copyFile(filePath, bookPath);\n logInfo(`[Ingest] EPUB file saved to ${bookPath}`);\n\n const parseStart = Date.now();\n const parsed = await parseEpub(bookPath);\n logInfo(`[Ingest] Parsed \"${parsed.title}\" with ${parsed.chapters.length} chapters (${formatDuration(Date.now() - parseStart)})`);\n logInfo(`[Ingest] Narrative chapters: ${parsed.narrativeStartIndex} to ${parsed.narrativeEndIndex}`);\n\n await insertBook({\n id: bookId,\n title: parsed.title,\n author: parsed.author,\n coverPath: parsed.coverImagePath,\n epubPath: bookPath,\n chapters: parsed.chapterTitles,\n narrativeStartIndex: parsed.narrativeStartIndex,\n narrativeEndIndex: parsed.narrativeEndIndex,\n });\n logInfo(`[Ingest] Book record inserted into database`);\n\n try {\n const chaptersToProcess = selectedChapterIndices\n ? parsed.chapters.filter((_, index) => selectedChapterIndices.includes(index))\n : parsed.chapters.slice(parsed.narrativeStartIndex, parsed.narrativeEndIndex + 1);\n\n const selectedIndices = selectedChapterIndices ||\n Array.from({ length: parsed.narrativeEndIndex - parsed.narrativeStartIndex + 1 },\n (_, i) => i + parsed.narrativeStartIndex);\n\n logInfo(`[Ingest] Processing ${chaptersToProcess.length} selected chapters (indices: ${selectedIndices.join(\", \")})`);\n\n let adjustedSummaries: BookChunk[] = [];\n if (options?.summarize !== false) {\n logInfo(`[Ingest] Generating summaries for ${chaptersToProcess.length} chapters...`);\n const summarizeStart = Date.now();\n const summaries = await summarizeAllChapters(chaptersToProcess);\n logInfo(`[Ingest] Generated ${summaries.length}/${chaptersToProcess.length} summaries (${formatDuration(Date.now() - summarizeStart)})`);\n\n const summaryRecords = summaries.map((s, idx) => ({\n ...s,\n chapterIndex: selectedIndices[idx] ?? s.chapterIndex,\n }));\n\n await updateBook(bookId, {\n summaries: JSON.stringify(summaryRecords),\n });\n\n adjustedSummaries = summaryRecords.map((s) => ({\n id: `${bookId}-summary-${s.chapterIndex}`,\n bookId,\n chapterIndex: s.chapterIndex,\n chapterTitle: s.chapterTitle,\n chunkIndex: -1,\n content: s.fullSummary,\n type: \"summary\" as const,\n }));\n logInfo(`[Ingest] Created ${adjustedSummaries.length} summary chunks`);\n }\n\n const chunksToProcess = parsed.chapters.map((chapter, index) =>\n selectedIndices.includes(index) ? chapter : { title: chapter.title, content: \"\" }\n );\n const chunks = chunkChapters(bookId, chunksToProcess).filter((chunk) => chunk.content.length > 0);\n logInfo(`[Ingest] Created ${chunks.length} chunks from selected chapters`);\n\n const allChunks = [...chunks, ...adjustedSummaries];\n const embedStart = Date.now();\n const embedded = await embedChunks(allChunks);\n logInfo(`[Ingest] Embedded ${embedded.length} total chunks (${formatDuration(Date.now() - embedStart)})`);\n\n await addChunksToIndex(bookId, embedded);\n logInfo(`[Ingest] Added chunks to vector index`);\n\n await updateBook(bookId, { chunkCount: embedded.length, indexedAt: Date.now() });\n logInfo(`[Ingest] Updated book record with chunk count: ${embedded.length}`);\n } catch (error) {\n logWarn(`[Ingest] Error during chunking/embedding: ${error instanceof Error ? error.message : String(error)}`);\n await deleteBookIndex(bookId);\n await unlink(bookPath).catch(() => undefined);\n await deleteBook(bookId).catch(() => undefined);\n throw error;\n }\n\n logInfo(`[Ingest] Ingestion complete for ${bookId}`);\n return { id: bookId };\n};\n","import type { Chapter, BookChunk } from \"../shared/types\";\nimport { CHUNK_OVERLAP, CHUNK_SIZE, SEPARATORS } from \"./constants\";\n\nconst splitRecursive = (text: string, separators: readonly string[]): string[] => {\n if (text.length <= CHUNK_SIZE || separators.length === 0) return [text];\n const [separator, ...rest] = separators;\n if (!separator) return [text];\n\n const parts = text.split(separator);\n if (parts.length === 1) return splitRecursive(text, rest);\n\n const chunks: string[] = [];\n let current = \"\";\n\n for (const part of parts) {\n const next = current ? `${current}${separator}${part}` : part;\n if (next.length <= CHUNK_SIZE) {\n current = next;\n continue;\n }\n\n if (current) chunks.push(current);\n current = part;\n }\n\n if (current) chunks.push(current);\n\n const refined: string[] = [];\n for (const chunk of chunks) {\n if (chunk.length <= CHUNK_SIZE) {\n refined.push(chunk);\n continue;\n }\n refined.push(...splitRecursive(chunk, rest));\n }\n\n return refined;\n};\n\nconst withOverlap = (chunks: string[]): string[] => {\n if (chunks.length <= 1 || CHUNK_OVERLAP === 0) return chunks;\n\n const merged: string[] = [];\n for (let i = 0; i < chunks.length; i += 1) {\n const current = chunks[i] ?? \"\";\n const previous = merged[merged.length - 1];\n if (!previous) {\n merged.push(current);\n continue;\n }\n\n const overlap = previous.slice(-CHUNK_OVERLAP);\n merged.push(`${overlap}${current}`);\n }\n\n return merged;\n};\n\nexport const chunkChapters = (bookId: string, chapters: Chapter[]): BookChunk[] => {\n const chunks: BookChunk[] = [];\n\n chapters.forEach((chapter, chapterIndex) => {\n const trimmed = chapter.content.trim();\n if (!trimmed) return;\n\n const rawChunks = splitRecursive(trimmed, SEPARATORS);\n const overlapped = withOverlap(rawChunks);\n overlapped.forEach((content, chunkIndex) => {\n const normalized = content.replace(/\\s+/g, \" \").trim();\n if (!normalized) return;\n chunks.push({\n id: `${bookId}-${chapterIndex}-${chunkIndex}`,\n bookId,\n chapterIndex,\n chapterTitle: chapter.title,\n chunkIndex,\n content: normalized,\n });\n });\n });\n\n return chunks;\n};\n","import { embedMany } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\nimport type { BookChunk } from \"../shared/types\";\nimport { getModels, logInfo } from \"./constants\";\n\nexport type EmbeddedChunk = BookChunk & {\n vector: number[];\n};\n\nconst MAX_TOKENS_PER_BATCH = 250_000;\nconst CHARS_PER_TOKEN = 4;\n\nexport const embedChunks = async (chunks: BookChunk[]): Promise<EmbeddedChunk[]> => {\n if (chunks.length === 0) return [];\n\n const batches: BookChunk[][] = [];\n let currentBatch: BookChunk[] = [];\n let currentTokens = 0;\n\n for (const chunk of chunks) {\n const estimatedTokens = Math.ceil(chunk.content.length / CHARS_PER_TOKEN);\n\n if (currentTokens + estimatedTokens > MAX_TOKENS_PER_BATCH && currentBatch.length > 0) {\n batches.push(currentBatch);\n currentBatch = [];\n currentTokens = 0;\n }\n\n currentBatch.push(chunk);\n currentTokens += estimatedTokens;\n }\n\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n }\n\n logInfo(`[Embedder] Processing ${chunks.length} chunks in ${batches.length} batch(es)`);\n\n const allEmbedded: EmbeddedChunk[] = [];\n const models = await getModels();\n\n for (let i = 0; i < batches.length; i++) {\n const batch = batches[i]!;\n const estimatedTokens = batch.reduce((sum, c) => sum + Math.ceil(c.content.length / CHARS_PER_TOKEN), 0);\n\n logInfo(`[Embedder] Batch ${i + 1}/${batches.length}: ${batch.length} chunks (~${estimatedTokens.toLocaleString()} tokens)`);\n\n const { embeddings } = await embedMany({\n model: openai.embeddingModel(models.embedding),\n values: batch.map((chunk) => chunk.content),\n });\n\n for (let j = 0; j < batch.length; j++) {\n allEmbedded.push({\n ...batch[j]!,\n vector: embeddings[j] ?? [],\n });\n }\n }\n\n logInfo(`[Embedder] Successfully embedded all ${allEmbedded.length} chunks`);\n\n return allEmbedded;\n};\n","import { LocalIndex } from \"vectra\";\nimport type { EmbeddedChunk } from \"./embedder\";\nimport type { BookChunk } from \"../shared/types\";\nimport { ensureDataDirs } from \"./constants\";\n\nexport type VectorMetadata = {\n bookId: string;\n chapterIndex: number;\n chapterTitle: string;\n chunkIndex: number;\n content: string;\n type?: \"chunk\" | \"summary\";\n};\n\nconst indexPathForBook = async (bookId: string) => {\n const paths = await ensureDataDirs();\n return `${paths.vectorsDir}/${bookId}`;\n};\n\nexport const createBookIndex = async (bookId: string): Promise<LocalIndex<VectorMetadata>> => {\n const index = new LocalIndex<VectorMetadata>(await indexPathForBook(bookId));\n const exists = await index.isIndexCreated();\n if (!exists) {\n await index.createIndex({\n version: 1,\n metadata_config: {\n indexed: [\"bookId\"],\n },\n });\n }\n return index;\n};\n\nexport const addChunksToIndex = async (bookId: string, chunks: EmbeddedChunk[]) => {\n const index = await createBookIndex(bookId);\n await index.batchInsertItems(\n chunks.map((chunk) => ({\n id: chunk.id,\n vector: chunk.vector,\n metadata: {\n bookId: chunk.bookId,\n chapterIndex: chunk.chapterIndex,\n chapterTitle: chunk.chapterTitle,\n chunkIndex: chunk.chunkIndex,\n content: chunk.content,\n type: chunk.type || \"chunk\",\n },\n }))\n );\n};\n\nexport const queryBookIndex = async (\n bookId: string,\n queryVector: number[],\n queryText: string,\n topK: number,\n maxChapterIndex?: number\n): Promise<(BookChunk & { score: number })[]> => {\n const index = await createBookIndex(bookId);\n const expandedTopK =\n maxChapterIndex === undefined || maxChapterIndex === null ? topK : Math.max(topK * 4, topK);\n const results = await index.queryItems(queryVector, queryText, expandedTopK);\n\n const mapped = results.map((result: (typeof results)[number]) => ({\n id: result.item.id ?? \"\",\n bookId,\n chapterIndex: result.item.metadata?.chapterIndex ?? 0,\n chapterTitle: result.item.metadata?.chapterTitle ?? \"\",\n chunkIndex: result.item.metadata?.chunkIndex ?? 0,\n content: result.item.metadata?.content ?? \"\",\n type: result.item.metadata?.type as \"chunk\" | \"summary\" | undefined,\n score: result.score,\n }));\n\n if (maxChapterIndex === undefined || maxChapterIndex === null) {\n return mapped.slice(0, topK);\n }\n\n return mapped.filter((item: (typeof mapped)[number]) => item.chapterIndex <= maxChapterIndex).slice(0, topK);\n};\n\nexport const deleteBookIndex = async (bookId: string) => {\n const index = new LocalIndex<VectorMetadata>(await indexPathForBook(bookId));\n const exists = await index.isIndexCreated();\n if (!exists) return;\n await index.deleteIndex();\n};\n","import { generateText } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\nimport type { Chapter, ChapterSummary } from \"../shared/types\";\nimport { SUMMARY_MAX_TOKENS, SUMMARY_CONCURRENCY, SUMMARY_TARGET_WORDS, getModels, logInfo, logWarn } from \"./constants\";\n\nconst CHARS_PER_TOKEN = 4;\n\nconst estimateTokens = (text: string): number => Math.ceil(text.length / CHARS_PER_TOKEN);\n\nconst SUMMARY_PROMPT = (title: string, chapterNum: number, content: string) => `You are analyzing a chapter from a book (fiction or nonfiction). Extract key information to help readers understand the chapter's content.\n\nChapter Title: ${title}\nChapter Number: ${chapterNum}\n\n---\n${content}\n---\n\nExtract the following information and respond ONLY with valid JSON (no markdown, no code blocks):\n\n{\n \"characters\": [\"Name - brief description (role, traits, first appearance)\", ...],\n \"events\": \"What happens in this chapter? (2-3 sentences)\",\n \"setting\": \"Where does this chapter take place?\",\n \"revelations\": \"Any important information revealed? (secrets, backstory, foreshadowing)\"\n}\n\nKeep the total response around ${SUMMARY_TARGET_WORDS} words.`;\n\ntype SummaryJSON = {\n characters: string[];\n events: string;\n setting: string;\n revelations: string;\n};\n\nconst splitIntoSections = (text: string, maxTokens: number): string[] => {\n const estimatedTokens = estimateTokens(text);\n\n if (estimatedTokens <= maxTokens) {\n return [text];\n }\n\n const numSections = Math.ceil(estimatedTokens / maxTokens);\n const charsPerSection = Math.floor(text.length / numSections);\n const sections: string[] = [];\n\n for (let i = 0; i < numSections; i++) {\n const start = i * charsPerSection;\n const end = i === numSections - 1 ? text.length : (i + 1) * charsPerSection;\n sections.push(text.slice(start, end));\n }\n\n return sections;\n};\n\nconst summarizeSection = async (text: string, title: string, sectionNum: number): Promise<string> => {\n const models = await getModels();\n const { text: summary } = await generateText({\n model: openai(models.summary),\n prompt: `Summarize this section from chapter \"${title}\" (Part ${sectionNum}). Focus on key events, characters, and revelations. Keep it concise (100-150 words):\\n\\n${text}`,\n temperature: 0.3,\n });\n\n return summary;\n};\n\nconst generateStructuredSummary = async (\n content: string,\n title: string,\n chapterIndex: number\n): Promise<ChapterSummary | null> => {\n try {\n const models = await getModels();\n const { text } = await generateText({\n model: openai(models.summary),\n prompt: SUMMARY_PROMPT(title, chapterIndex + 1, content),\n temperature: 0.3,\n });\n\n let jsonText = text.trim();\n if (jsonText.startsWith(\"```json\")) {\n jsonText = jsonText.slice(7, -3).trim();\n } else if (jsonText.startsWith(\"```\")) {\n jsonText = jsonText.slice(3, -3).trim();\n }\n\n const parsed: SummaryJSON = JSON.parse(jsonText);\n\n const fullSummary = `Chapter ${chapterIndex + 1}: ${title}\n\nCharacters: ${parsed.characters.join(\", \")}\n\nEvents: ${parsed.events}\n\nSetting: ${parsed.setting}\n\nRevelations: ${parsed.revelations}`;\n\n return {\n chapterIndex,\n chapterTitle: title,\n characters: parsed.characters,\n events: parsed.events,\n setting: parsed.setting,\n revelations: parsed.revelations,\n fullSummary,\n };\n } catch (error) {\n logWarn(`[Summarizer] Failed to parse summary JSON for \"${title}\": ${error instanceof Error ? error.message : String(error)}`);\n return null;\n }\n};\n\nexport const summarizeChapter = async (\n chapter: Chapter,\n chapterIndex: number\n): Promise<ChapterSummary | null> => {\n const tokens = estimateTokens(chapter.content);\n\n logInfo(`[Summarizer] Chapter ${chapterIndex + 1} \"${chapter.title}\": ~${tokens.toLocaleString()} tokens`);\n\n try {\n if (tokens < SUMMARY_MAX_TOKENS) {\n return await generateStructuredSummary(chapter.content, chapter.title, chapterIndex);\n }\n\n logInfo(`[Summarizer] Chapter ${chapterIndex + 1} exceeds token limit, using two-pass approach`);\n\n const sections = splitIntoSections(chapter.content, SUMMARY_MAX_TOKENS);\n logInfo(`[Summarizer] Split into ${sections.length} sections`);\n\n const sectionSummaries = await Promise.all(\n sections.map((section, i) => summarizeSection(section, chapter.title, i + 1))\n );\n\n const combined = sectionSummaries.join(\"\\n\\n\");\n\n return await generateStructuredSummary(combined, chapter.title, chapterIndex);\n } catch (error) {\n logWarn(`[Summarizer] Failed to summarize chapter ${chapterIndex + 1}: ${error instanceof Error ? error.message : String(error)}`);\n return null;\n }\n};\n\nexport const summarizeAllChapters = async (chapters: Chapter[]): Promise<ChapterSummary[]> => {\n const summaries: ChapterSummary[] = [];\n\n logInfo(`[Summarizer] Starting summarization of ${chapters.length} chapters (concurrency: ${SUMMARY_CONCURRENCY})`);\n\n for (let i = 0; i < chapters.length; i += SUMMARY_CONCURRENCY) {\n const batch = chapters.slice(i, i + SUMMARY_CONCURRENCY);\n const batchPromises = batch.map((chapter, batchIndex) => summarizeChapter(chapter, i + batchIndex));\n\n const batchResults = await Promise.all(batchPromises);\n\n for (const summary of batchResults) {\n if (summary) {\n summaries.push(summary);\n }\n }\n\n logInfo(`[Summarizer] Progress: ${Math.min(i + SUMMARY_CONCURRENCY, chapters.length)}/${chapters.length} chapters processed`);\n }\n\n logInfo(`[Summarizer] Completed: ${summaries.length}/${chapters.length} summaries generated`);\n\n return summaries;\n};\n","import Database from \"better-sqlite3\";\nimport { resolvePaths } from \"../services/constants\";\n\nconst resolveDbPath = async () => {\n const paths = await resolvePaths();\n return paths.dbPath;\n};\n\nexport const createDb = async (): Promise<Database> => {\n const db = new Database(await resolveDbPath());\n\n db.exec(`\n CREATE TABLE IF NOT EXISTS books (\n id TEXT PRIMARY KEY,\n title TEXT NOT NULL,\n author TEXT,\n cover_path TEXT,\n chapters TEXT,\n epub_path TEXT NOT NULL,\n chunk_count INTEGER DEFAULT 0,\n created_at INTEGER DEFAULT (strftime('%s','now')),\n indexed_at INTEGER,\n progress_chapter INTEGER\n );\n `);\n\n const columns = db\n .prepare(\"PRAGMA table_info(books)\")\n .all()\n .map((col: { name: string }) => col.name);\n\n const ensureColumn = (name: string, definition: string) => {\n if (!columns.includes(name)) {\n db.exec(`ALTER TABLE books ADD COLUMN ${definition}`);\n }\n };\n\n ensureColumn(\"chapters\", \"chapters TEXT\");\n ensureColumn(\"progress_chapter\", \"progress_chapter INTEGER\");\n ensureColumn(\"summaries\", \"summaries TEXT\");\n ensureColumn(\"narrative_start_index\", \"narrative_start_index INTEGER DEFAULT 0\");\n ensureColumn(\"narrative_end_index\", \"narrative_end_index INTEGER\");\n\n return db;\n};\n","import type Database from \"better-sqlite3\";\nimport type { BookRecord } from \"../shared/types\";\nimport { createDb } from \"./schema\";\n\nexport type BookInsert = Omit<\n BookRecord,\n \"createdAt\" | \"indexedAt\" | \"chunkCount\" | \"progressChapter\" | \"narrativeStartIndex\" | \"narrativeEndIndex\"\n> & {\n chunkCount?: number;\n indexedAt?: number | null;\n progressChapter?: number | null;\n summaries?: string;\n narrativeStartIndex?: number | null;\n narrativeEndIndex?: number | null;\n};\n\nconst mapRow = (row: any): BookRecord => ({\n id: row.id,\n title: row.title,\n author: row.author ?? null,\n coverPath: row.cover_path ?? null,\n epubPath: row.epub_path,\n chunkCount: row.chunk_count ?? 0,\n createdAt: row.created_at ?? 0,\n indexedAt: row.indexed_at ?? null,\n chapters: row.chapters ? JSON.parse(row.chapters) : [],\n progressChapter: row.progress_chapter ?? null,\n narrativeStartIndex: row.narrative_start_index ?? null,\n narrativeEndIndex: row.narrative_end_index ?? null,\n});\n\nlet dbPromise: Promise<Database> | null = null;\n\nconst getDb = async () => {\n if (!dbPromise) {\n dbPromise = createDb();\n }\n return dbPromise;\n};\n\nexport const insertBook = async (book: BookInsert): Promise<string> => {\n const db = await getDb();\n const statement = db.prepare(\n \"INSERT INTO books (id, title, author, cover_path, chapters, epub_path, chunk_count, indexed_at, progress_chapter, narrative_start_index, narrative_end_index) VALUES (@id, @title, @author, @coverPath, @chapters, @epubPath, @chunkCount, @indexedAt, @progressChapter, @narrativeStartIndex, @narrativeEndIndex)\"\n );\n statement.run({\n id: book.id,\n title: book.title,\n author: book.author,\n coverPath: book.coverPath,\n chapters: JSON.stringify(book.chapters ?? []),\n epubPath: book.epubPath,\n chunkCount: book.chunkCount ?? 0,\n indexedAt: book.indexedAt ?? null,\n progressChapter: book.progressChapter ?? null,\n narrativeStartIndex: book.narrativeStartIndex ?? null,\n narrativeEndIndex: book.narrativeEndIndex ?? null,\n });\n return book.id;\n};\n\nexport const updateBook = async (id: string, updates: Partial<BookInsert>) => {\n const fields: string[] = [];\n const params: Record<string, string | number | boolean | null> = { id };\n\n if (updates.title !== undefined) {\n fields.push(\"title = @title\");\n params.title = updates.title;\n }\n if (updates.author !== undefined) {\n fields.push(\"author = @author\");\n params.author = updates.author;\n }\n if (updates.coverPath !== undefined) {\n fields.push(\"cover_path = @coverPath\");\n params.coverPath = updates.coverPath;\n }\n if (updates.chapters !== undefined) {\n fields.push(\"chapters = @chapters\");\n params.chapters = JSON.stringify(updates.chapters);\n }\n if (updates.epubPath !== undefined) {\n fields.push(\"epub_path = @epubPath\");\n params.epubPath = updates.epubPath;\n }\n if (updates.chunkCount !== undefined) {\n fields.push(\"chunk_count = @chunkCount\");\n params.chunkCount = updates.chunkCount;\n }\n if (updates.indexedAt !== undefined) {\n fields.push(\"indexed_at = @indexedAt\");\n params.indexedAt = updates.indexedAt;\n }\n if (updates.progressChapter !== undefined) {\n fields.push(\"progress_chapter = @progressChapter\");\n params.progressChapter = updates.progressChapter;\n }\n if (updates.summaries !== undefined) {\n fields.push(\"summaries = @summaries\");\n params.summaries = updates.summaries;\n }\n if (updates.narrativeStartIndex !== undefined) {\n fields.push(\"narrative_start_index = @narrativeStartIndex\");\n params.narrativeStartIndex = updates.narrativeStartIndex;\n }\n if (updates.narrativeEndIndex !== undefined) {\n fields.push(\"narrative_end_index = @narrativeEndIndex\");\n params.narrativeEndIndex = updates.narrativeEndIndex;\n }\n\n if (fields.length === 0) return;\n\n const db = await getDb();\n db.prepare(`UPDATE books SET ${fields.join(\", \")} WHERE id = @id`).run(params);\n};\n\nexport const getBooks = async (): Promise<BookRecord[]> => {\n const db = await getDb();\n const rows = db.prepare(\"SELECT * FROM books ORDER BY created_at DESC\").all();\n return rows.map(mapRow);\n};\n\nexport const getBook = async (id: string): Promise<BookRecord | null> => {\n const db = await getDb();\n const row = db.prepare(\"SELECT * FROM books WHERE id = ?\").get(id);\n return row ? mapRow(row) : null;\n};\n\nexport const deleteBook = async (id: string) => {\n const db = await getDb();\n db.prepare(\"DELETE FROM books WHERE id = ?\").run(id);\n};\n","import { parseEpub } from \"../services/epub-parser\";\nimport { ingestEpub } from \"../services/ingest\";\nimport { ensureDataDirs, requireOpenAIKey } from \"../services/constants\";\nimport { access } from \"node:fs/promises\";\nimport { prompt } from \"./prompt\";\nimport { isInteractive, stdout } from \"./io\";\n\nconst parseIndexSelection = (input: string, max: number): number[] => {\n const trimmed = input.trim();\n if (!trimmed) return [];\n const tokens = trimmed.split(\",\").map((part) => part.trim()).filter(Boolean);\n const indices = new Set<number>();\n for (const token of tokens) {\n if (token.includes(\"-\")) {\n const [startRaw, endRaw] = token.split(\"-\");\n const start = Number(startRaw);\n const end = Number(endRaw);\n if (!Number.isFinite(start) || !Number.isFinite(end)) continue;\n for (let i = Math.min(start, end); i <= Math.max(start, end); i++) {\n if (i >= 0 && i < max) indices.add(i);\n }\n } else {\n const index = Number(token);\n if (Number.isFinite(index) && index >= 0 && index < max) indices.add(index);\n }\n }\n return Array.from(indices).sort((a, b) => a - b);\n};\n\nexport const ingestCommand = async (filePath: string, options: { manual?: boolean; summarize?: boolean }) => {\n requireOpenAIKey();\n await ensureDataDirs();\n try {\n await access(filePath);\n } catch {\n throw new Error(`File not found: ${filePath}`);\n }\n\n let selectedChapterIndices: number[] | undefined;\n if (options.manual) {\n if (!isInteractive()) {\n throw new Error(\"Manual chapter selection requires an interactive terminal.\");\n }\n const parsed = await parseEpub(filePath);\n if (parsed.chapterTitles.length === 0) {\n throw new Error(\"No chapters found in EPUB\");\n }\n\n stdout(\"Chapters:\");\n parsed.chapterTitles.forEach((title, index) => {\n const marker = index >= parsed.narrativeStartIndex && index <= parsed.narrativeEndIndex ? \"*\" : \" \";\n stdout(`${marker} [${index}] ${title}`);\n });\n stdout(\"\\nEnter chapter indices to ingest (e.g. 0-10,12). Press Enter for narrative range.\");\n const answer = await prompt(\"Selection: \");\n const indices = parseIndexSelection(answer, parsed.chapterTitles.length);\n if (indices.length > 0) {\n selectedChapterIndices = indices;\n } else {\n selectedChapterIndices = Array.from(\n { length: parsed.narrativeEndIndex - parsed.narrativeStartIndex + 1 },\n (_, i) => i + parsed.narrativeStartIndex\n );\n }\n }\n\n const result = await ingestEpub(filePath, selectedChapterIndices, { summarize: options.summarize ?? false });\n stdout(`\\nDone. Book indexed as ${result.id}`);\n};\n","import { createInterface } from \"node:readline/promises\";\nimport { handleSigint } from \"./io\";\n\nexport const prompt = async (question: string): Promise<string> => {\n const release = handleSigint();\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n try {\n const response = await rl.question(question);\n return response.trim();\n } finally {\n rl.close();\n release();\n }\n};\n\nexport const confirm = async (question: string): Promise<boolean> => {\n const response = await prompt(question);\n const normalized = response.trim().toLowerCase();\n return normalized === \"y\" || normalized === \"yes\";\n};\n","import { ingestCommand } from \"../ingest\";\n\nexport const registerBookIngest = (program: import(\"commander\").Command) => {\n program\n .command(\"ingest\")\n .description(\"Ingest an EPUB file\")\n .argument(\"<path>\", \"Path to the EPUB file\")\n .option(\"--manual\", \"Interactive chapter selection\")\n .option(\"--summary\", \"Enable AI chapter summaries\")\n .action(async (path: string, options: { manual?: boolean; summary?: boolean }) => {\n const summarize = Boolean(options.summary);\n await ingestCommand(path, { manual: options.manual, summarize });\n });\n};\n","import { getBooks } from \"../db/queries\";\nimport { ensureDataDirs } from \"../services/constants\";\nimport { stdout } from \"./io\";\n\nconst formatDate = (timestamp: number | null) => {\n if (!timestamp) return \"-\";\n return new Date(timestamp).toISOString().slice(0, 10);\n};\n\nexport const listCommand = async () => {\n await ensureDataDirs();\n const books = await getBooks();\n if (books.length === 0) {\n stdout(\"No books indexed yet.\");\n return;\n }\n\n stdout(\"ID | Title | Author | Chunks | Indexed | Status\");\n stdout(\"---------|-------|--------|--------|--------|-------\");\n for (const book of books) {\n const shortId = book.id.slice(0, 8);\n const title = book.title;\n const author = book.author || \"-\";\n const chunks = String(book.chunkCount ?? 0);\n const indexed = formatDate(book.indexedAt);\n const status = book.indexedAt ? \"[indexed]\" : \"[pending]\";\n stdout(`${shortId} | ${title} | ${author} | ${chunks} | ${indexed} | ${status}`);\n }\n};\n","import { listCommand } from \"../list\";\n\nexport const registerBookList = (program: import(\"commander\").Command) => {\n program\n .command(\"list\")\n .description(\"List indexed books\")\n .action(async () => {\n await listCommand();\n });\n};\n","import { getBooks } from \"../db/queries\";\n\nexport const resolveBookId = async (input: string): Promise<string | null> => {\n const books = await getBooks();\n const exact = books.find((book) => book.id === input);\n if (exact) return exact.id;\n const matches = books.filter((book) => book.id.startsWith(input));\n if (matches.length === 1) return matches[0]!.id;\n if (matches.length > 1) {\n throw new Error(`Ambiguous id prefix \"${input}\" (${matches.length} matches)`);\n }\n return null;\n};\n","import { getBook } from \"../db/queries\";\nimport { resolveBookId } from \"./utils\";\nimport { ensureDataDirs } from \"../services/constants\";\nimport { stdout } from \"./io\";\n\nexport const showCommand = async (id: string) => {\n await ensureDataDirs();\n const resolvedId = await resolveBookId(id);\n if (!resolvedId) {\n throw new Error(`Book not found: ${id}`);\n }\n const book = await getBook(resolvedId);\n if (!book) {\n throw new Error(`Book not found: ${id}`);\n }\n\n stdout(`Title: ${book.title}`);\n stdout(`Author: ${book.author ?? \"-\"}`);\n stdout(`ID: ${book.id}`);\n stdout(`Chunks: ${book.chunkCount}`);\n stdout(`Indexed: ${book.indexedAt ? new Date(book.indexedAt).toISOString() : \"-\"}`);\n stdout(`Narrative range: ${book.narrativeStartIndex ?? 0} to ${book.narrativeEndIndex ?? book.chapters.length - 1}`);\n stdout(`Progress chapter: ${book.progressChapter ?? \"-\"}`);\n stdout(\"\\nChapters:\");\n\n book.chapters.forEach((title: string, index: number) => {\n const marker = index === book.narrativeStartIndex ? \"[start]\" : index === book.narrativeEndIndex ? \"[end]\" : \"\";\n stdout(` [${index}] ${title} ${marker}`.trim());\n });\n};\n","import { showCommand } from \"../show\";\n\nexport const registerBookShow = (program: import(\"commander\").Command) => {\n program\n .command(\"show\")\n .description(\"Show full book metadata\")\n .argument(\"<id>\", \"Book id or prefix\")\n .action(async (id: string) => {\n await showCommand(id);\n });\n};\n","import { embed, streamText } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\nimport { getBook } from \"../db/queries\";\nimport { resolveBookId } from \"./utils\";\nimport { queryBookIndex } from \"../services/vector-store\";\nimport { ensureDataDirs, getModels, isAskEnabled, requireOpenAIKey } from \"../services/constants\";\nimport { handleSigint } from \"./io\";\n\nconst formatContext = (chunks: Array<{ content: string; chapterTitle: string; chapterIndex: number }>) =>\n chunks\n .map(\n (chunk, index) =>\n `Excerpt [${index + 1}] (${chunk.chapterTitle || `Chapter ${chunk.chapterIndex + 1}`}):\\n${chunk.content}`\n )\n .join(\"\\n\\n\");\n\nexport const askCommand = async (\n id: string,\n question: string,\n options: { topK: number; maxChapter?: number }\n) => {\n if (!(await isAskEnabled())) {\n throw new Error(\"Ask is disabled in config (askEnabled: false). Enable it to use this command.\");\n }\n\n requireOpenAIKey();\n await ensureDataDirs();\n\n const resolvedId = await resolveBookId(id);\n if (!resolvedId) {\n throw new Error(`Book not found: ${id}`);\n }\n const book = await getBook(resolvedId);\n if (!book) {\n throw new Error(`Book not found: ${id}`);\n }\n\n const models = await getModels();\n const { embedding } = await embed({\n model: openai.embeddingModel(models.embedding),\n value: question,\n });\n\n const narrativeStart = book.narrativeStartIndex ?? 0;\n const userProgress = book.progressChapter ?? null;\n const maxChapterIndex = options.maxChapter !== undefined\n ? narrativeStart + options.maxChapter\n : userProgress !== null\n ? narrativeStart + userProgress\n : undefined;\n\n const retrievalLimit = options.topK * 3;\n const allMatches = await queryBookIndex(resolvedId, embedding, question, retrievalLimit, maxChapterIndex);\n\n const summaries = allMatches.filter((m) => m.type === \"summary\");\n const chunks = allMatches.filter((m) => m.type !== \"summary\");\n\n const topSummaries = summaries.slice(0, 2);\n const topChunks = chunks.slice(0, Math.max(0, options.topK - topSummaries.length));\n const selectedMatches = [...topSummaries, ...topChunks];\n\n const context = formatContext(selectedMatches);\n\n const releaseSigint = handleSigint();\n const stream = streamText({\n model: openai(models.chat),\n system: `You are a reading companion helping readers understand this book.\n\nGuidelines:\n- Use the provided chapter summaries and excerpts to answer questions\n- Chapter summaries provide high-level context about characters, events, and plot\n- Excerpts provide specific details and quotes\n- When asked for recaps or \"what happened\", synthesize from summaries\n- Don't cite table of contents, front matter, or structural elements\n- If truly unsure, briefly say so - but try to answer from available context first\n- Cite sources using [1], [2], etc. at the end of relevant sentences\n- The context may be limited to earlier chapters only - don't infer beyond what's provided`,\n prompt: `Question: ${question}\\n\\n${context}`,\n });\n\n try {\n for await (const part of stream.textStream) {\n process.stdout.write(part);\n }\n } finally {\n releaseSigint();\n }\n\n if (selectedMatches.length > 0) {\n process.stdout.write(\"\\n\\nSources:\\n\");\n selectedMatches.forEach((match, index) => {\n const title = match.chapterTitle || `Chapter ${match.chapterIndex + 1}`;\n const excerpt = match.content.slice(0, 120).replace(/\\s+/g, \" \");\n process.stdout.write(`[${index + 1}] ${title}: ${excerpt}\\n`);\n });\n }\n};\n","import { askCommand } from \"../ask\";\n\nexport const registerBookAsk = (program: import(\"commander\").Command) => {\n program\n .command(\"ask\")\n .description(\"Ask a question about a book\")\n .argument(\"<id>\", \"Book id or prefix\")\n .argument(\"<question>\", \"Question to ask\")\n .option(\"--top-k <n>\", \"Number of passages to retrieve\", \"5\")\n .option(\"--max-chapter <n>\", \"Spoiler-free limit (0-based within narrative)\")\n .action(async (\n id: string,\n question: string,\n options: { topK: string; maxChapter?: string }\n ) => {\n const topK = Number(options.topK);\n if (!Number.isFinite(topK) || topK <= 0) {\n throw new Error(\"--top-k must be a positive number.\");\n }\n let maxChapter: number | undefined;\n if (options.maxChapter !== undefined) {\n const parsed = Number(options.maxChapter);\n if (!Number.isFinite(parsed) || parsed < 0) {\n throw new Error(\"--max-chapter must be a non-negative number.\");\n }\n maxChapter = parsed;\n }\n await askCommand(id, question, { topK, maxChapter });\n });\n};\n","import { embed } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\nimport { getBook } from \"../db/queries\";\nimport { resolveBookId } from \"./utils\";\nimport { queryBookIndex } from \"../services/vector-store\";\nimport { ensureDataDirs, getModels, requireOpenAIKey } from \"../services/constants\";\nimport { stdout } from \"./io\";\n\nexport const searchCommand = async (\n id: string,\n query: string,\n options: { topK: number; maxChapter?: number }\n) => {\n requireOpenAIKey();\n await ensureDataDirs();\n const resolvedId = await resolveBookId(id);\n if (!resolvedId) {\n throw new Error(`Book not found: ${id}`);\n }\n const book = await getBook(resolvedId);\n if (!book) {\n throw new Error(`Book not found: ${id}`);\n }\n\n const models = await getModels();\n const { embedding } = await embed({\n model: openai.embeddingModel(models.embedding),\n value: query,\n });\n\n const maxChapterIndex = options.maxChapter !== undefined\n ? (book.narrativeStartIndex ?? 0) + options.maxChapter\n : book.progressChapter !== null\n ? (book.narrativeStartIndex ?? 0) + (book.progressChapter ?? 0)\n : undefined;\n const results = await queryBookIndex(resolvedId, embedding, query, options.topK, maxChapterIndex);\n\n if (results.length === 0) {\n stdout(\"No results.\");\n return;\n }\n\n results.forEach((result, index) => {\n const chapterTitle = result.chapterTitle || `Chapter ${result.chapterIndex + 1}`;\n const excerpt = result.content.slice(0, 200).replace(/\\s+/g, \" \");\n stdout(`\\n#${index + 1} score=${result.score.toFixed(4)} type=${result.type || \"chunk\"}`);\n stdout(`${chapterTitle} (chapter ${result.chapterIndex})`);\n stdout(excerpt);\n });\n};\n","import { searchCommand } from \"../search\";\n\nexport const registerBookSearch = (program: import(\"commander\").Command) => {\n program\n .command(\"search\")\n .description(\"Vector search without LLM\")\n .argument(\"<id>\", \"Book id or prefix\")\n .argument(\"<query>\", \"Search query\")\n .option(\"--top-k <n>\", \"Number of passages to retrieve\", \"5\")\n .option(\"--max-chapter <n>\", \"Spoiler-free limit (0-based within narrative)\")\n .action(async (\n id: string,\n query: string,\n options: { topK: string; maxChapter?: string }\n ) => {\n const topK = Number(options.topK);\n if (!Number.isFinite(topK) || topK <= 0) {\n throw new Error(\"--top-k must be a positive number.\");\n }\n let maxChapter: number | undefined;\n if (options.maxChapter !== undefined) {\n const parsed = Number(options.maxChapter);\n if (!Number.isFinite(parsed) || parsed < 0) {\n throw new Error(\"--max-chapter must be a non-negative number.\");\n }\n maxChapter = parsed;\n }\n await searchCommand(id, query, { topK, maxChapter });\n });\n};\n","import { unlink } from \"node:fs/promises\";\nimport { deleteBook, getBook } from \"../db/queries\";\nimport { resolveBookId } from \"./utils\";\nimport { deleteBookIndex } from \"../services/vector-store\";\nimport { ensureDataDirs } from \"../services/constants\";\nimport { confirm } from \"./prompt\";\nimport { isInteractive, stdout } from \"./io\";\n\nexport const deleteCommand = async (id: string, options: { force?: boolean }) => {\n await ensureDataDirs();\n const resolvedId = await resolveBookId(id);\n if (!resolvedId) {\n throw new Error(`Book not found: ${id}`);\n }\n const book = await getBook(resolvedId);\n if (!book) {\n throw new Error(`Book not found: ${id}`);\n }\n\n if (!options.force) {\n if (!isInteractive()) {\n throw new Error(\"Delete confirmation requires an interactive terminal. Use --force to bypass.\");\n }\n const ok = await confirm(`Delete \"${book.title}\" (${book.id})? [y/N] `);\n if (!ok) {\n stdout(\"Cancelled.\");\n return;\n }\n }\n\n await deleteBook(resolvedId);\n await deleteBookIndex(resolvedId);\n if (book.epubPath) {\n await unlink(book.epubPath).catch(() => undefined);\n }\n stdout(`Deleted book ${book.id}`);\n};\n","import { deleteCommand } from \"../delete\";\n\nexport const registerBookDelete = (program: import(\"commander\").Command) => {\n program\n .command(\"delete\")\n .description(\"Remove book, EPUB, and vectors\")\n .argument(\"<id>\", \"Book id or prefix\")\n .option(\"--force\", \"Skip confirmation\")\n .action(async (id: string, options: { force?: boolean }) => {\n await deleteCommand(id, { force: options.force });\n });\n};\n","import { configPath } from \"../config\";\nimport { stdout } from \"./io\";\n\nexport const configCommand = async () => {\n const path = configPath();\n stdout(path);\n};\n","import { configCommand } from \"../config\";\n\nexport const registerConfigPath = (program: import(\"commander\").Command) => {\n program\n .command(\"path\")\n .description(\"Print config path\")\n .action(async () => {\n await configCommand();\n });\n};\n","import { ensureConfigDirs, configPath, loadConfig } from \"../config\";\nimport { mkdir, writeFile, access } from \"node:fs/promises\";\nimport { stdout } from \"./io\";\n\nexport const initConfigCommand = async () => {\n const path = configPath();\n await ensureConfigDirs(path);\n try {\n await access(path);\n stdout(`Config already exists: ${path}`);\n return;\n } catch {\n // file does not exist\n }\n const resolved = await loadConfig();\n const template = {\n dataDir: \"~/.local/share/mycroft\",\n askEnabled: resolved.askEnabled,\n models: resolved.models,\n };\n await writeFile(path, JSON.stringify(template, null, 2), \"utf-8\");\n await mkdir(resolved.dataDir, { recursive: true });\n stdout(`Created config at ${path}`);\n};\n","import { initConfigCommand } from \"../init-config\";\n\nexport const registerConfigInit = (program: import(\"commander\").Command) => {\n program\n .command(\"init\")\n .description(\"Create default config file\")\n .action(async () => {\n await initConfigCommand();\n });\n};\n","import { configPath, loadConfig } from \"../config\";\nimport { stdout } from \"./io\";\n\nexport const resolveConfigCommand = async () => {\n const path = configPath();\n const config = await loadConfig();\n stdout(`Config: ${path}`);\n stdout(`Data dir: ${config.dataDir}`);\n stdout(`Ask enabled: ${config.askEnabled}`);\n stdout(`Models: embedding=${config.models.embedding} summary=${config.models.summary} chat=${config.models.chat}`);\n};\n","import { resolveConfigCommand } from \"../resolve-config\";\n\nexport const registerConfigResolve = (program: import(\"commander\").Command) => {\n program\n .command(\"resolve\")\n .description(\"Print resolved config values\")\n .action(async () => {\n await resolveConfigCommand();\n });\n};\n","import { ensureConfigDirs, configPath, loadConfig } from \"../config\";\nimport { writeFile } from \"node:fs/promises\";\nimport { prompt } from \"./prompt\";\nimport { isInteractive, stdout } from \"./io\";\n\nconst isDefault = (input: string) => input === \"\" || input.toLowerCase() === \"-y\";\n\nconst parseBoolean = (input: string, fallback: boolean) => {\n if (isDefault(input)) return fallback;\n const normalized = input.toLowerCase();\n if ([\"y\", \"yes\", \"true\", \"1\"].includes(normalized)) return true;\n if ([\"n\", \"no\", \"false\", \"0\"].includes(normalized)) return false;\n return fallback;\n};\n\nexport const onboardCommand = async () => {\n if (!isInteractive()) {\n throw new Error(\"Onboarding requires an interactive terminal.\");\n }\n const defaults = await loadConfig();\n const path = configPath();\n\n stdout(\"\\nmycroft\");\n stdout(\"Press Enter or type -y to accept defaults.\");\n\n const dataDirInput = await prompt(`Data directory [${defaults.dataDir}]: `);\n const dataDir = isDefault(dataDirInput) ? defaults.dataDir : dataDirInput;\n\n const askEnabledInput = await prompt(`Enable ask (LLM answers) [${defaults.askEnabled ? \"Y\" : \"N\"}]: `);\n const askEnabled = parseBoolean(askEnabledInput, defaults.askEnabled);\n\n const embeddingInput = await prompt(`Embedding model [${defaults.models.embedding}]: `);\n const embedding = isDefault(embeddingInput) ? defaults.models.embedding : embeddingInput;\n\n const summaryInput = await prompt(`Summary model [${defaults.models.summary}]: `);\n const summary = isDefault(summaryInput) ? defaults.models.summary : summaryInput;\n\n const chatInput = await prompt(`Chat model [${defaults.models.chat}]: `);\n const chat = isDefault(chatInput) ? defaults.models.chat : chatInput;\n\n await ensureConfigDirs(path);\n await writeFile(\n path,\n JSON.stringify(\n {\n dataDir,\n askEnabled,\n models: {\n embedding,\n summary,\n chat,\n },\n },\n null,\n 2\n ),\n \"utf-8\"\n );\n\n stdout(\"\\nSetup complete.\");\n stdout(`Config: ${path}`);\n stdout(`Data dir: ${dataDir}`);\n\n if (!process.env.OPENAI_API_KEY) {\n stdout(\"\\nOPENAI_API_KEY is not set.\");\n stdout(\"Export it to enable embeddings and chat:\");\n stdout(\" export OPENAI_API_KEY=\\\"...\\\"\");\n }\n\n stdout(\"\\nNext step:\");\n stdout(\" mycroft book ingest /path/to/book.epub\");\n};\n","import { onboardCommand } from \"../onboard\";\n\nexport const registerConfigOnboard = (program: import(\"commander\").Command) => {\n program\n .command(\"onboard\")\n .description(\"Initialize config and show next step\")\n .action(async () => {\n await onboardCommand();\n });\n};\n"],"mappings":"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","names":["configPath","readFile","dirname","resolve","mkdir","mkdir","mkdir","openai","CHARS_PER_TOKEN","openai","mkdir","program","program","program","openai","openai","program","embed","openai","embed","openai","program","unlink","unlink","program","program","mkdir","access","access","mkdir","program","program","writeFile","writeFile","program","dirname","resolve","readFile"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fs/mycroft",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"license": "MIT",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"bin": {
|
|
6
7
|
"mycroft": "./bin/mycroft.js"
|
|
@@ -9,6 +10,7 @@
|
|
|
9
10
|
"bin",
|
|
10
11
|
"dist",
|
|
11
12
|
"README.md",
|
|
13
|
+
"LICENSE",
|
|
12
14
|
"completions"
|
|
13
15
|
],
|
|
14
16
|
"publishConfig": {
|