@llmkb/claude-code 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -0
- package/dist/cli.js +3214 -0
- package/dist/cli.js.map +1 -0
- package/lib/color.ts +61 -0
- package/lib/config-validation.ts +332 -0
- package/lib/config.ts +61 -0
- package/lib/credentials.ts +164 -0
- package/lib/output.ts +130 -0
- package/lib/parser.ts +274 -0
- package/lib/skills.ts +554 -0
- package/lib/sync-spaces-config.ts +180 -0
- package/lib/sync-state.ts +152 -0
- package/lib/sync.ts +437 -0
- package/lib/types.ts +153 -0
- package/lib/watch-lock.ts +78 -0
- package/lib/writer.ts +409 -0
- package/package.json +55 -0
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../lib/types.ts","../lib/parser.ts","../lib/sync-state.ts","../bin/cli.ts","../src/commands/init.ts","../lib/writer.ts","../src/commands/hooks.ts","../lib/skills.ts","../src/commands/login.ts","../lib/config.ts","../lib/credentials.ts","../lib/sync-spaces-config.ts","../lib/color.ts","../src/commands/logout.ts","../src/commands/add.ts","../src/commands/remove.ts","../src/commands/spaces.ts","../src/commands/update.ts","../src/commands/whoami.ts","../src/commands/use.ts","../src/commands/status.ts","../src/commands/sync.ts","../lib/sync.ts","../lib/output.ts","../lib/watch-lock.ts","../src/commands/query.ts","../src/commands/doctor.ts","../lib/config-validation.ts"],"sourcesContent":["/** Shared TypeScript interfaces for the llmkb plugin config model.\n\nThese types define the schema for the per-project configuration files\n(``.llmkb/spaces.yml`` and ``.llmkb/config.yml``) used by all CLI commands,\nthe MCP server config, and the sync engine.\n\nConventions:\n- All field names follow the YAML key naming (lower_snake_case).\n- Optional fields are marked with ``?``.\n- Tokens MUST NOT appear in any config file — they live in the OS keychain or env vars.\n*/\n\n// ---------------------------------------------------------------------------\n// Space Definition (new PSM-4 format)\n// ---------------------------------------------------------------------------\n\n/** A project space entry — the primary space for file sync. */\nexport interface ProjectSpaceDef {\n /** Space UUID. */\n id: string;\n /** Optional human-readable name. */\n name?: string;\n /** Optional slug for MCP tool names. */\n slug?: string;\n /** Optional directory paths to sync from this project. */\n dirs?: string[];\n}\n\n/** A referenced space entry (additional spaces beyond project_space). */\nexport interface SpaceDef {\n /** Space UUID. */\n id: string;\n /** Optional human-readable name. */\n name?: string;\n /** Optional slug for MCP tool names. */\n slug?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Full Space Config (``.llmkb/spaces.yml``)\n// ---------------------------------------------------------------------------\n\nexport interface SpaceConfig {\n /** The project's primary space (file sync target). */\n project_space?: ProjectSpaceDef[];\n /** Additional spaces this project has access to. */\n spaces?: SpaceDef[];\n}\n\n// ---------------------------------------------------------------------------\n// Plugin Behavior Config (``.llmkb/config.yml``)\n// ---------------------------------------------------------------------------\n\nexport interface WatchSettings {\n enabled?: boolean;\n debounce_ms?: number;\n gitignore?: boolean;\n llmkbignore?: boolean;\n default_verbosity?: \"silent\" | \"verbose\" | \"debug\";\n}\n\nexport interface SyncSettings {\n concurrency?: number;\n retry_attempts?: number;\n retry_delay_ms?: number;\n}\n\nexport interface HookSettings {\n timeout_ms?: number;\n skip?: boolean;\n}\n\nexport interface PluginConfig {\n /** Backend API base URL (e.g. https://api.llmkb.ai). */\n llmkb_base_url?: string;\n watch?: WatchSettings;\n sync?: SyncSettings;\n hook?: HookSettings;\n debug?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Version Stamp\n// ---------------------------------------------------------------------------\n\n/** The version file at ``.llmkb/.llmkb-version`` stores just the semver string. */\n\n// ---------------------------------------------------------------------------\n// Exported utilities\n// ---------------------------------------------------------------------------\n\nexport const PACKAGE_VERSION = \"0.1.0\";\n\n/** Returns the default plugin behavior config used when ``config.yml`` is missing or all fields are commented. */\nexport function getDefaultPluginConfig(): PluginConfig {\n return {\n llmkb_base_url: \"https://api.llmkb.ai\",\n watch: {\n enabled: true,\n debounce_ms: 300,\n gitignore: true,\n llmkbignore: true,\n default_verbosity: \"silent\",\n },\n sync: {\n concurrency: 5,\n retry_attempts: 3,\n retry_delay_ms: 1000,\n },\n hook: {\n timeout_ms: 5000,\n skip: false,\n },\n debug: false,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Token Types\n// ---------------------------------------------------------------------------\n\n/** The only token type used by the plugin. */\nexport type TokenType = \"access_token\";\n\n// ---------------------------------------------------------------------------\n// Sync State Types\n// ---------------------------------------------------------------------------\n\nexport type SyncFileStatus = \"synced\" | \"pending\" | \"failed\";\n\nexport interface SyncFileEntry {\n sha256: string;\n lastUploaded: string | null;\n status: SyncFileStatus;\n}\n\nexport interface SyncState {\n space: string;\n lastSyncAt: string;\n files: Record<string, SyncFileEntry>;\n}\n\nexport interface RenameEntry {\n oldPath: string;\n newPath: string;\n}\n\nexport interface FileChangeSet {\n newFiles: string[];\n changedFiles: string[];\n unchangedFiles: string[];\n renamed: RenameEntry[];\n}\n","/** YAML config reader/writer for .llmkb configuration files.\n\nProvides typed, comment-preserving read/write for ``spaces.yml``\nand ``config.yml``, plus a project-root discovery utility.\n\nUses the ``yaml`` package (eemeli/yaml) which preserves comments,\nformatting, and line positions on round-trip via ``parseDocument``.\n*/\n\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join, dirname, resolve } from \"node:path\";\nimport { parse, stringify, parseDocument } from \"yaml\";\nimport type { SpaceConfig, PluginConfig, ProjectSpaceDef, SpaceDef } from \"./types.js\";\nimport { PACKAGE_VERSION } from \"./types.js\";\nimport { writeFile as writeVersion } from \"node:fs/promises\";\n\n// ---------------------------------------------------------------------------\n// Project Root Discovery\n// ---------------------------------------------------------------------------\n\n/**\n * Walk up from ``startDir`` looking for a ``.llmkb/`` directory.\n * Returns the first ancestor directory that contains ``.llmkb/``,\n * or ``null`` if none is found before the filesystem root.\n */\nexport function findProjectRoot(startDir: string = process.cwd()): string | null {\n let current = resolve(startDir);\n\n // Safety: stop at filesystem root\n while (current !== dirname(current)) {\n if (existsSync(join(current, \".llmkb\"))) {\n return current;\n }\n current = dirname(current);\n }\n // Check root too (edge case)\n if (existsSync(join(current, \".llmkb\"))) {\n return current;\n }\n return null;\n}\n\n/** Shortcut to get the ``.llmkb/`` directory path from the project root. */\nexport function llmkbDir(projectDir: string): string {\n return join(projectDir, \".llmkb\");\n}\n\n// ---------------------------------------------------------------------------\n// Space Config\n// ---------------------------------------------------------------------------\n\n/** Read and parse ``spaces.yml`` from the given project root.\n *\n * Automatically migrates old-format files (pre-0.1.0 with ``active`` and\n * ``spaces[{name, label, access, endpoint, token_env}]``) to the new format\n * (``project_space`` + ``spaces[{id, name}]``).\n */\nexport async function readSpaceConfig(projectDir: string): Promise<SpaceConfig | null> {\n const filePath = join(projectDir, \".llmkb\", \"spaces.yml\");\n if (!existsSync(filePath)) return null;\n\n try {\n const content = await readFile(filePath, \"utf-8\");\n const raw = parse(content) as Record<string, unknown> | null;\n\n // Comment-only YAML files parse to null — treat as empty config\n if (raw === null) {\n return {};\n }\n\n // Detect old format: has \"active\" field or uses name-based SpaceDef\n if (raw.active !== undefined || isOldSpaceFormat(raw)) {\n const migrated = migrateOldSpaceConfig(raw);\n // Write migrated config back and bump version stamp\n await writeSpaceConfig(projectDir, migrated);\n await writeVersion(\n join(projectDir, \".llmkb\", \".llmkb-version\"),\n PACKAGE_VERSION + \"\\n\",\n \"utf-8\",\n );\n return migrated;\n }\n\n return raw as SpaceConfig;\n } catch {\n return null;\n }\n}\n\n/** Detect whether a parsed config uses the old space-definition format. */\nfunction isOldSpaceFormat(raw: Record<string, unknown>): boolean {\n if (!raw.spaces || !Array.isArray(raw.spaces)) return false;\n return raw.spaces.length > 0 && typeof raw.spaces[0] === \"object\" &&\n raw.spaces[0] !== null && \"name\" in (raw.spaces[0] as Record<string, unknown>) &&\n !(\"id\" in (raw.spaces[0] as Record<string, unknown>));\n}\n\n/** Migrate old-format SpaceConfig to new format.\n *\n * Old format:\n * spaces: [{name, label, access, endpoint, token_env}]\n * active: \"my-space\"\n * token_groups: {...}\n *\n * New format:\n * project_space: [{id, name, dirs}]\n * spaces: [{id, name}]\n */\nfunction migrateOldSpaceConfig(old: Record<string, unknown>): SpaceConfig {\n const result: SpaceConfig = {};\n\n const oldSpaces = (old.spaces as Array<Record<string, unknown>>) ?? [];\n const activeName = (old.active as string) ?? oldSpaces[0]?.name;\n\n if (oldSpaces.length > 0) {\n // If there was an active space, promote it to project_space\n if (activeName) {\n const activeDef = oldSpaces.find((s) => s.name === activeName);\n const projectEntry: ProjectSpaceDef = {\n id: String(activeDef?.name ?? activeName),\n name: String(activeDef?.label ?? activeName),\n };\n result.project_space = [projectEntry];\n }\n\n // All spaces become id-based references\n result.spaces = oldSpaces.map((s) => ({\n id: String(s.name),\n name: s.label ? String(s.label) : String(s.name),\n }));\n }\n\n return result;\n}\n\n/**\n * Write ``spaces.yml`` from a typed object.\n * Uses the YAML stringifier for clean output.\n */\nexport async function writeSpaceConfig(\n projectDir: string,\n config: SpaceConfig,\n): Promise<void> {\n const filePath = join(projectDir, \".llmkb\", \"spaces.yml\");\n const yaml = stringify(config, { lineWidth: 120 });\n await writeFile(filePath, yaml + \"\\n\", \"utf-8\");\n}\n\n/**\n * Append a space entry to the ``spaces`` list in ``spaces.yml``.\n */\nexport async function addSpaceEntry(\n projectDir: string,\n spaceId: string,\n spaceName?: string,\n): Promise<boolean> {\n let config = await readSpaceConfig(projectDir);\n // Initialize empty config for template/empty YAML\n if (!config) config = {};\n if (!config.spaces) config.spaces = [];\n // Avoid duplicates\n if (!config.spaces.some((s) => s.id === spaceId)) {\n config.spaces.push({ id: spaceId, name: spaceName });\n }\n await writeSpaceConfig(projectDir, config);\n return true;\n}\n\n/**\n * Remove a space entry from the ``spaces`` list in ``spaces.yml`` by id.\n */\nexport async function removeSpaceEntry(\n projectDir: string,\n spaceId: string,\n): Promise<boolean> {\n const config = await readSpaceConfig(projectDir);\n if (!config?.spaces) return false;\n const idx = config.spaces.findIndex((s) => s.id === spaceId);\n if (idx === -1) return false;\n config.spaces.splice(idx, 1);\n await writeSpaceConfig(projectDir, config);\n return true;\n}\n\n/**\n * Update the project_space ID in ``spaces.yml``.\n */\nexport async function updateProjectSpace(\n projectDir: string,\n spaceId: string,\n): Promise<boolean> {\n const config = await readSpaceConfig(projectDir);\n if (!config) return false;\n if (!config.project_space || config.project_space.length === 0) {\n config.project_space = [{ id: spaceId }];\n } else {\n config.project_space[0]!.id = spaceId;\n }\n await writeSpaceConfig(projectDir, config);\n return true;\n}\n\n/**\n * Delete all space entries from ``spaces.yml``, keeping project_space.\n */\nexport async function deleteAllSpaces(projectDir: string): Promise<boolean> {\n const config = await readSpaceConfig(projectDir);\n if (!config) return false;\n config.spaces = [];\n await writeSpaceConfig(projectDir, config);\n return true;\n}\n\n/**\n * Update a single field in ``spaces.yml`` while preserving comments.\n * Uses ``parseDocument`` for comment-safe round-trip.\n * Returns ``true`` if the field was found and updated.\n *\n * Note: In the new data model, the ``active`` field no longer exists.\n * Use ``updateProjectSpace()`` to update the project space instead.\n */\nexport async function updateSpaceConfigField<T extends keyof SpaceConfig>(\n projectDir: string,\n field: T,\n value: SpaceConfig[T],\n): Promise<boolean> {\n const filePath = join(projectDir, \".llmkb\", \"spaces.yml\");\n if (!existsSync(filePath)) return false;\n\n try {\n const content = await readFile(filePath, \"utf-8\");\n const doc = parseDocument(content);\n doc.set(field, value);\n await writeFile(filePath, String(doc) + \"\\n\", \"utf-8\");\n return true;\n } catch {\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Plugin Config (config.yml)\n// ---------------------------------------------------------------------------\n\n/** Read and parse ``config.yml`` from the given project root. */\nexport async function readPluginConfig(projectDir: string): Promise<PluginConfig | null> {\n const filePath = join(projectDir, \".llmkb\", \"config.yml\");\n if (!existsSync(filePath)) return null;\n\n try {\n const content = await readFile(filePath, \"utf-8\");\n return parse(content) as PluginConfig;\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Version Stamp\n// ---------------------------------------------------------------------------\n\n/** Read the version stamp from ``.llmkb/.llmkb-version``. */\nexport async function readVersionStamp(projectDir: string): Promise<string | null> {\n const filePath = join(projectDir, \".llmkb\", \".llmkb-version\");\n if (!existsSync(filePath)) return null;\n\n try {\n const content = await readFile(filePath, \"utf-8\");\n return content.trim();\n } catch {\n return null;\n }\n}\n","/** Content-addressed sync-state manager (.llmkb/sync-state.json).\n\nTracks file uploads by SHA256 hash, enabling incremental sync where\nunchanged files skip server reprocessing entirely.\n\nPattern: read -> compute -> compare -> classify -> write\n*/\n\nimport { readFile, writeFile, unlink, mkdir } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { createHash } from \"node:crypto\";\nimport { createReadStream } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport type { SyncState, SyncFileEntry, FileChangeSet, RenameEntry } from \"./types.js\";\n\nconst SYNC_STATE_FILE = \".llmkb/sync-state.json\";\n\n// ---------------------------------------------------------------------------\n// Path helpers\n// ---------------------------------------------------------------------------\n\nfunction statePath(projectDir: string): string {\n return resolve(projectDir, SYNC_STATE_FILE);\n}\n\nfunction llmkbDir(projectDir: string): string {\n return resolve(projectDir, \".llmkb\");\n}\n\n// ---------------------------------------------------------------------------\n// SHA256 streaming computation (memory-safe for large files)\n// ---------------------------------------------------------------------------\n\n/** Compute SHA256 hash of a file using streaming reads (O(1) memory). */\nexport async function computeSha256(filePath: string): Promise<string> {\n return new Promise<string>((resolve, reject) => {\n const hash = createHash(\"sha256\");\n const stream = createReadStream(filePath);\n stream.on(\"data\", (chunk) => hash.update(chunk));\n stream.on(\"end\", () => resolve(hash.digest(\"hex\")));\n stream.on(\"error\", reject);\n });\n}\n\n// ---------------------------------------------------------------------------\n// Read / Write\n// ---------------------------------------------------------------------------\n\n/** Read the sync state file. Returns null if missing or malformed. */\nexport async function readSyncState(projectDir: string): Promise<SyncState | null> {\n const filePath = statePath(projectDir);\n if (!existsSync(filePath)) return null;\n try {\n const raw = await readFile(filePath, \"utf-8\");\n return JSON.parse(raw) as SyncState;\n } catch {\n return null;\n }\n}\n\n/** Write the sync state file. Creates .llmkb/ if missing. */\nexport async function writeSyncState(projectDir: string, state: SyncState): Promise<void> {\n const dir = llmkbDir(projectDir);\n if (!existsSync(dir)) {\n await mkdir(dir, { recursive: true });\n }\n await writeFile(statePath(projectDir), JSON.stringify(state, null, 2) + \"\\n\", \"utf-8\");\n}\n\n// ---------------------------------------------------------------------------\n// Update helpers\n// ---------------------------------------------------------------------------\n\n/** Update a single file entry in the sync state. */\nexport async function updateSyncEntry(\n projectDir: string,\n relativePath: string,\n entry: SyncFileEntry,\n): Promise<void> {\n const state = (await readSyncState(projectDir)) ?? {\n space: \"\",\n lastSyncAt: new Date().toISOString(),\n files: {},\n };\n state.files[relativePath] = entry;\n state.lastSyncAt = new Date().toISOString();\n await writeSyncState(projectDir, state);\n}\n\n/** Clear the sync state entirely (e.g., on space switch). */\nexport async function clearSyncState(projectDir: string): Promise<void> {\n const filePath = statePath(projectDir);\n if (existsSync(filePath)) {\n await unlink(filePath);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Comparison\n// ---------------------------------------------------------------------------\n\n/** Classify an array of (relativePath, absolutePath) pairs against the current\n * sync state into new/changed/unchanged/renamed groups.\n *\n * @param files Array of [relativePath, absolutePath] tuples.\n * @param state Current sync state (null for first run).\n * @returns Classified file sets with computed SHA256 hashes.\n */\nexport async function getChangedFiles(\n files: Array<[string, string]>,\n state: SyncState | null,\n): Promise<FileChangeSet> {\n const newFiles: string[] = [];\n const changedFiles: string[] = [];\n const unchangedFiles: string[] = [];\n const renamed: RenameEntry[] = [];\n\n // Build a reverse index: sha256 -> old path (for rename detection)\n const hashToPath = new Map<string, string>();\n if (state) {\n for (const [path, entry] of Object.entries(state.files)) {\n hashToPath.set(entry.sha256, path);\n }\n }\n\n for (const [relPath, absPath] of files) {\n const hash = await computeSha256(absPath);\n\n if (!state) {\n // First run — everything is new\n newFiles.push(relPath);\n continue;\n }\n\n const existingEntry = state.files[relPath];\n if (!existingEntry) {\n // Check if it's a rename (same hash, different path)\n const oldPath = hashToPath.get(hash);\n if (oldPath && oldPath !== relPath) {\n renamed.push({ oldPath, newPath: relPath });\n continue;\n }\n newFiles.push(relPath);\n } else if (existingEntry.sha256 !== hash) {\n changedFiles.push(relPath);\n } else {\n unchangedFiles.push(relPath);\n }\n }\n\n return { newFiles, changedFiles, unchangedFiles, renamed };\n}\n","#!/usr/bin/env node\n\nimport { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, resolve } from \"node:path\";\nimport { Command } from \"commander\";\nimport { initCommand } from \"../src/commands/init.js\";\nimport { loginCommand } from \"../src/commands/login.js\";\nimport { logoutCommand } from \"../src/commands/logout.js\";\nimport { addCommand } from \"../src/commands/add.js\";\nimport { removeCommand } from \"../src/commands/remove.js\";\nimport { spacesCommand } from \"../src/commands/spaces.js\";\nimport { updateCommand } from \"../src/commands/update.js\";\nimport { whoamiCommand } from \"../src/commands/whoami.js\";\nimport { useCommand } from \"../src/commands/use.js\";\nimport { statusCommand } from \"../src/commands/status.js\";\nimport { syncCommand } from \"../src/commands/sync.js\";\nimport { queryCommand } from \"../src/commands/query.js\";\nimport { doctorCommand } from \"../src/commands/doctor.js\";\nimport { hooksCommand } from \"../src/commands/hooks.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst pkg = JSON.parse(\n readFileSync(resolve(__dirname, \"../package.json\"), \"utf-8\"),\n);\n\nconst program = new Command();\n\nprogram\n .name(\"llmkb\")\n .description(\n \"llmkb Claude Code plugin — manage spaces, sync code, and query your knowledge base\",\n )\n .version(pkg.version);\n\nprogram.addCommand(initCommand);\nprogram.addCommand(loginCommand);\nprogram.addCommand(logoutCommand);\nprogram.addCommand(addCommand);\nprogram.addCommand(removeCommand);\nprogram.addCommand(spacesCommand);\nprogram.addCommand(updateCommand);\nprogram.addCommand(whoamiCommand);\nprogram.addCommand(useCommand);\nprogram.addCommand(statusCommand);\nprogram.addCommand(syncCommand);\nprogram.addCommand(queryCommand);\nprogram.addCommand(doctorCommand);\nprogram.addCommand(hooksCommand);\n\nprogram.parse();\n","/** ``llmkb init`` — scaffold config files and skills.\n\nUsage:\n llmkb init\n llmkb init --platform cursor\n llmkb init --non-interactive\n*/\n\nimport { Command } from \"commander\";\nimport * as readline from \"node:readline/promises\";\nimport { stdin, stdout } from \"node:process\";\nimport { resolve } from \"node:path\";\nimport { scaffoldConfig } from \"../../lib/writer.js\";\nimport { installSkills } from \"../../lib/skills.js\";\nimport type { SpaceDef } from \"../../lib/types.js\";\n\n// ---------------------------------------------------------------------------\n// Interactive Helpers\n// ---------------------------------------------------------------------------\n\nfunction rl(): readline.Interface {\n return readline.createInterface({ input: stdin, output: stdout });\n}\n\nasync function promptSpace(\n rl: readline.Interface,\n index: number,\n): Promise<SpaceDef | null> {\n console.log(`\\n--- Space #${index + 1} ---`);\n const id = await rl.question(\" Space UUID (e.g. b6087faa-...): \");\n if (!id.trim()) return null;\n\n const name = await rl.question(` Name (optional): `);\n\n return {\n id: id.trim(),\n ...(name.trim() ? { name: name.trim() } : {}),\n };\n}\n\nasync function interactiveSetup(): Promise<{ spaceDefs: SpaceDef[] }> {\n const rli = rl();\n const spaceDefs: SpaceDef[] = [];\n\n try {\n console.log(\"llmkb init — interactive setup\");\n console.log(\"Configure one or more spaces for this project.\");\n console.log(\"Press Enter with an empty space UUID to finish.\\n\");\n\n let index = 0;\n while (true) {\n const def = await promptSpace(rli, index);\n if (!def) break;\n spaceDefs.push(def);\n index++;\n }\n\n if (spaceDefs.length === 0) {\n console.log(\"\\nNo spaces configured. A template config will be created.\");\n } else {\n console.log(`\\nConfigured ${spaceDefs.length} space(s).`);\n }\n } finally {\n rli.close();\n }\n\n return { spaceDefs };\n}\n\n// ---------------------------------------------------------------------------\n// Command\n// ---------------------------------------------------------------------------\n\nexport const initCommand = new Command(\"init\")\n .description(\"Scaffold llmkb config files and skills\")\n .argument(\"[directory]\", \"Target directory (defaults to cwd)\")\n .option(\n \"-p, --platform <type>\",\n \"Target platform: claude or cursor\",\n \"claude\",\n )\n .option(\"--with-skills\", \"Install Claude Code skills\")\n .option(\"--without-skills\", \"Skip skill installation\")\n .option(\"--with-hooks\", \"Install Claude Code hooks (default: false)\", false)\n .option(\n \"--non-interactive\",\n \"Skip confirmation prompts (for CI/headless environments)\",\n )\n .action(\n async (\n directory: string | undefined,\n opts: {\n platform: string;\n withSkills?: boolean;\n withoutSkills?: boolean;\n withHooks: boolean;\n nonInteractive?: boolean;\n },\n ) => {\n const targetDir = directory ? resolve(process.cwd(), directory) : process.cwd();\n const platform =\n opts.platform === \"cursor\" ? (\"cursor\" as const) : (\"claude\" as const);\n const interactive = !opts.nonInteractive;\n const installSkillsFlag = opts.withSkills ?? !opts.withoutSkills;\n\n // Interactive setup: prompt for spaces\n let spaceDefs: SpaceDef[] | undefined;\n\n if (interactive) {\n const result = await interactiveSetup();\n spaceDefs = result.spaceDefs;\n }\n\n if (interactive) {\n console.log(\n \"\\nThis will create the following files in the current directory:\",\n );\n console.log(\" - .claude-plugin/plugin.json\");\n console.log(\n ` - ${platform === \"cursor\" ? \".cursor/mcp.json\" : \".mcp.json\"}`,\n );\n console.log(\" - .llmkb/spaces.yml\");\n console.log(\" - .llmkb/config.yml\");\n console.log(\" - .llmkb/.llmkb-version\");\n console.log(\" - .claude/skills/llmkb/ (5 skills)\");\n if (opts.withHooks) {\n console.log(\" - .claude/hooks/llmkb/ (hooks.json + scripts)\\n\");\n }\n }\n\n try {\n const { filesWritten } = await scaffoldConfig({\n platform,\n spaceDefs,\n projectDir: targetDir,\n withHooks: opts.withHooks,\n });\n console.log(`Created ${filesWritten.length} config file(s):`);\n for (const f of filesWritten) {\n console.log(` ✔ ${f}`);\n }\n\n if (installSkillsFlag) {\n const skillCount = await installSkills(platform, targetDir);\n console.log(\n ` ✔ ${skillCount} skills installed to .claude/skills/llmkb/`,\n );\n }\n\n const loginSpace = spaceDefs?.[0]?.id;\n if (loginSpace) {\n console.log(\n `\\nRun \\`llmkb login --project-space ${loginSpace}\\` to authenticate.`,\n );\n }\n\n console.log(\"\\nPost-install note:\");\n console.log(\n \" Docker --profile mvp : Used for MCP tools only (what this config creates).\",\n );\n console.log(\n \" Docker --profile poc : Use for full stack with Nuxt frontend on port 3000.\",\n );\n console.log(\n \" See infra/mcp/claude_desktop_config.example.json for the alternative.\",\n );\n console.log(\"\\nDone. Run `llmkb status` to verify the installation.\");\n } catch (err) {\n console.error(\"Error:\", (err as Error).message);\n process.exit(1);\n }\n },\n );\n","/** Idempotent config-file scaffolder.\n\nCreates the files that ``llmkb init`` places into the project root:\n``.claude-plugin/plugin.json``, ``.mcp.json``, ``.llmkb/spaces.yml``,\n``.llmkb/config.yml``, and a version stamp at ``.llmkb/.llmkb-version``.\n\nSupports ``--platform cursor`` to write Cursor-specific paths instead.\n*/\n\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { stringify } from \"yaml\";\nimport {\n PACKAGE_VERSION,\n getDefaultPluginConfig,\n type SpaceConfig,\n type SpaceDef,\n} from \"./types.js\";\nimport { readVersionStamp } from \"./parser.js\";\nimport { writeHooks } from \"../src/commands/hooks.js\";\n\nexport interface ScaffoldOptions {\n /** Project root directory (defaults to ``process.cwd()``). */\n projectDir?: string;\n /** Target platform for config file paths. */\n platform?: \"claude\" | \"cursor\";\n /** Optional space name to pre-fill in the config. */\n spaceName?: string;\n /** Optional list of spaces for interactive multi-space setup. */\n spaceDefs?: SpaceDef[];\n /** Force overwrite even if version stamp matches. */\n force?: boolean;\n /** Also scaffold hook files. */\n withHooks?: boolean;\n}\n\nfunction projectPath(projectDir: string, ...parts: string[]): string {\n return resolve(projectDir, ...parts);\n}\n\nasync function ensureDir(filePath: string): Promise<void> {\n await mkdir(filePath, { recursive: true });\n}\n\n/** Plugin metadata file (required by Claude Code for discovery). */\nconst PLUGIN_JSON = {\n name: \"llmkb\",\n description:\n \"LLM-powered knowledge base with wiki generation, semantic search, and knowledge graphs. Sync codebases, query spaces, and explore architecture from Claude.\",\n version: PACKAGE_VERSION,\n author: { name: \"llmkb\" },\n homepage: \"https://llmkb.ai\",\n keywords: [\"knowledge-base\", \"wiki\", \"mcp\"],\n};\n\n/** MCP server registration (Docker stdio transport via --profile mvp). */\nconst MCP_JSON_CLAUDE = {\n mcpServers: {\n llmkb: {\n description:\n \"llmkb wiki — search, read, and write your knowledge base via MCP tools\",\n command: \"docker\",\n args: [\n \"compose\",\n \"--profile\",\n \"mvp\",\n \"exec\",\n \"-i\",\n \"api\",\n \"python\",\n \"-m\",\n \"app.mcp.stdio\",\n ],\n },\n },\n};\n\nconst MCP_JSON_CURSOR = {\n mcpServers: {\n llmkb: {\n description:\n \"llmkb wiki — search, read, and write your knowledge base via MCP tools\",\n command: \"docker\",\n args: [\n \"compose\",\n \"--profile\",\n \"mvp\",\n \"exec\",\n \"-i\",\n \"api\",\n \"python\",\n \"-m\",\n \"app.mcp.stdio\",\n ],\n },\n },\n};\n\n/** Build the ``spaces.yml`` content as a typed YAML document. */\nfunction buildSpaceConfig(spaceDefs: SpaceDef[]): SpaceConfig {\n const config: SpaceConfig = {};\n if (spaceDefs.length > 0) {\n config.project_space = [{ id: spaceDefs[0]!.id }];\n config.spaces = spaceDefs;\n }\n return config;\n}\n\n/** Build the default ``spaces.yml`` content with optional single-space pre-fill. */\nfunction spacesYml(projectSpaceId?: string): string {\n if (!projectSpaceId) {\n // Emit a fully commented-out template\n return [\n `# llmkb space configuration`,\n `# Managed by \\`llmkb init\\`. Edit to add or remove spaces.`,\n `#`,\n `# Example:`,\n `# project_space:`,\n `# - id: b6087faa-0bf0-4935-98b2-f3100905b99c`,\n `# slug: my_project`,\n `# name: \"My Project\"`,\n `# dirs: ['app', 'src']`,\n `# spaces:`,\n `# - id: c599f13a-2d75-4e4e-8fb3-03afbac7e115`,\n `# name: \"Reference Library\"`,\n `# slug: reference_library`,\n ``,\n ].join(\"\\n\");\n }\n\n const config: SpaceConfig = {\n project_space: [{ id: projectSpaceId }],\n };\n return (\n `# llmkb space configuration\\n` +\n `# Managed by \\`llmkb init\\`. Edit to add or remove spaces.\\n\\n` +\n stringify(config, { lineWidth: 120 })\n );\n}\n\n/** Build ``.llmkb/config.yml`` with commented-out defaults. */\nfunction configYml(): string {\n const defaults = getDefaultPluginConfig();\n\n return [\n `# .llmkb/config.yml — plugin behavior settings`,\n `# Managed by \\`llmkb init\\`. Uncomment fields to override defaults.`,\n ``,\n `# llmkb_base_url: ${defaults.llmkb_base_url}`,\n `#`,\n `# watch:`,\n `# enabled: ${defaults.watch!.enabled}`,\n `# debounce_ms: ${defaults.watch!.debounce_ms}`,\n `# gitignore: ${defaults.watch!.gitignore}`,\n `# llmkbignore: ${defaults.watch!.llmkbignore}`,\n `# default_verbosity: ${defaults.watch!.default_verbosity}`,\n `#`,\n `# sync:`,\n `# concurrency: ${defaults.sync!.concurrency}`,\n `# retry_attempts: ${defaults.sync!.retry_attempts}`,\n `# retry_delay_ms: ${defaults.sync!.retry_delay_ms}`,\n `#`,\n `# hook:`,\n `# timeout_ms: ${defaults.hook!.timeout_ms}`,\n `# skip: ${defaults.hook!.skip}`,\n `#`,\n `# debug: ${defaults.debug}`,\n ``,\n ].join(\"\\n\");\n}\n\n/** Scaffold .claude-plugin/plugin.json */\nasync function writePluginJson(projectDir: string): Promise<void> {\n const dir = projectPath(projectDir, \".claude-plugin\");\n await ensureDir(dir);\n await writeFile(\n join(dir, \"plugin.json\"),\n JSON.stringify(PLUGIN_JSON, null, 2) + \"\\n\",\n \"utf-8\",\n );\n}\n\n/** Scaffold .mcp.json (Claude) or .cursor/mcp.json (Cursor). */\nasync function writeMcpJson(\n projectDir: string,\n platform: \"claude\" | \"cursor\",\n): Promise<void> {\n if (platform === \"cursor\") {\n const dir = projectPath(projectDir, \".cursor\");\n await ensureDir(dir);\n await writeFile(\n join(dir, \"mcp.json\"),\n JSON.stringify(MCP_JSON_CURSOR, null, 2) + \"\\n\",\n \"utf-8\",\n );\n } else {\n await writeFile(\n projectPath(projectDir, \".mcp.json\"),\n JSON.stringify(MCP_JSON_CLAUDE, null, 2) + \"\\n\",\n \"utf-8\",\n );\n }\n}\n\n/** Scaffold .llmkb/spaces.yml, .llmkb/config.yml, and .llmkb/.llmkb-version.\n\nIdempotent: if ``.llmkb/.llmkb-version`` exists and matches the current\npackage version, all llmkb writes are skipped — the user's customizations\nare preserved. Call ``scaffoldConfig`` with ``force: true`` to bypass.\n\n@returns The list of files actually written (empty if skipped by idempotency).\n*/\nasync function writeLlmkbDir(\n projectDir: string,\n spaceName?: string,\n spaceDefs?: SpaceDef[],\n force?: boolean,\n): Promise<string[]> {\n const dir = projectPath(projectDir, \".llmkb\");\n const written: string[] = [];\n\n // Idempotency check: skip if version stamp matches\n if (!force) {\n const stamp = await readVersionStamp(projectDir);\n if (stamp === PACKAGE_VERSION) return written;\n }\n\n await ensureDir(dir);\n\n // Write spaces.yml\n if (spaceDefs && spaceDefs.length > 0) {\n const config = buildSpaceConfig(spaceDefs);\n await writeFile(\n join(dir, \"spaces.yml\"),\n stringify(config, { lineWidth: 120 }),\n \"utf-8\",\n );\n } else {\n await writeFile(\n join(dir, \"spaces.yml\"),\n spacesYml(spaceName) + \"\\n\",\n \"utf-8\",\n );\n }\n written.push(\".llmkb/spaces.yml\");\n\n // Write config.yml with commented-out defaults\n await writeFile(join(dir, \"config.yml\"), configYml(), \"utf-8\");\n written.push(\".llmkb/config.yml\");\n\n // Write version stamp\n await writeFile(join(dir, \".llmkb-version\"), PACKAGE_VERSION + \"\\n\", \"utf-8\");\n written.push(\".llmkb/.llmkb-version\");\n\n return written;\n}\n\n/** All cursor rule files for the llmkb knowledge base. */\nconst CURSOR_RULES: Array<{\n name: string;\n description: string;\n globs: string[];\n content: string;\n}> = [\n {\n name: \"llmkb-guide.mdc\",\n description:\n \"llmkb overview, architecture, getting started, and how to use llmkb spaces\",\n globs: [\"*\"],\n content: [\n \"llmkb is an AI-powered knowledge base. It uses a three-layer model: raw sources (PDFs, code, markdown) -> LLM-generated wiki pages -> knowledge graph.\",\n \"\",\n \"- Run `docker compose --profile mvp ps` to verify the MCP server is running\",\n \"- Use `space_search(space_name, query)` to find relevant wiki pages\",\n \"- Use `space_read(space_name, path)` to read a specific wiki page\",\n \"- Use `space_graph(space_name, mode, entity)` to explore entity relationships\",\n \"- Check `llmkb status` to verify setup is correct\",\n ].join(\"\\n\"),\n },\n {\n name: \"llmkb-query.mdc\",\n description:\n \"Search and read wiki content via MCP tools — use space_search and space_read\",\n globs: [\"*\"],\n content: [\n \"When asked to find information, always:\",\n \"\",\n \"1. Start with `space_search` to locate relevant wiki pages:\",\n ` space_search(space_name: \"my-project\", query: \"<user's question>\")`,\n \"2. Read the full content of the best matching page:\",\n ` space_read(space_name: \"my-project\", path: \"/path/to/page\")`,\n \"3. For relationship context, use:\",\n ` space_graph(space_name: \"my-project\", mode: \"neighbours\", entity: \"<entity name>\")`,\n ].join(\"\\n\"),\n },\n {\n name: \"llmkb-sync.mdc\",\n description:\n \"File sync and upload rules — run llmkb sync after making significant changes\",\n globs: [\"*\"],\n content: [\n \"Files modified under this project should be synced to the configured llmkb space.\",\n \"\",\n \"- Run `llmkb sync` from the project root after significant changes\",\n \"- For continuous syncing: `llmkb sync --watch`\",\n \"- Files are content-addressed (SHA256); unchanged files skip re-processing\",\n \"- Respects .gitignore and .llmkbignore patterns\",\n \"- After syncing, use `llmkb status` to check ingestion progress\",\n ].join(\"\\n\"),\n },\n {\n name: \"llmkb-exploring.mdc\",\n description:\n \"Architecture and graph exploration — use space_graph for entity relationships\",\n globs: [\"*\"],\n content: [\n \"When asked about code architecture or entity relationships:\",\n \"\",\n \"1. Start with `space_guide` for a structured overview:\",\n ` space_guide(space_name: \"my-project\")`,\n \"2. Explore entity neighbourhoods:\",\n ` space_graph(space_name: \"my-project\", mode: \"neighbours\", entity: \"<entity>\")`,\n \"3. Find paths between entities:\",\n ` space_graph(space_name: \"my-project\", mode: \"path\", source: \"<source>\", target: \"<target>\")`,\n \"4. Follow up with `space_search` for deeper context\",\n ].join(\"\\n\"),\n },\n {\n name: \"llmkb-admin.mdc\",\n description:\n \"Space management, token setup, credentials, configuration, and llmkb CLI commands\",\n globs: [\"*\"],\n content: [\n \"When setting up or managing llmkb:\",\n \"\",\n \"- `llmkb init` — scaffold project config files and skills\",\n \"- `llmkb init --no-with-skills` — config-only setup (skip skills)\",\n \"- `llmkb init --platform cursor` — use Cursor-compatible paths\",\n \"- `llmkb login --project-space <id>` — store access token in keychain\",\n \"- `llmkb whoami` — show current user identity and access token status\",\n \"- `llmkb status` — verify versions, config, and installed skills\",\n \"- Set LLMKB_ACCESS_TOKEN env var for CI/headless environments\",\n ].join(\"\\n\"),\n },\n];\n\n/** Scaffold .cursor/rules/llmkb/ with all rule files. */\nasync function writeCursorRules(projectDir: string): Promise<void> {\n const rulesDir = projectPath(projectDir, \".cursor\", \"rules\", \"llmkb\");\n await ensureDir(rulesDir);\n for (const rule of CURSOR_RULES) {\n const frontmatter = [\n \"---\",\n `name: ${rule.name}`,\n `description: ${rule.description}`,\n `globs: ${JSON.stringify(rule.globs)}`,\n \"---\",\n \"\",\n ].join(\"\\n\");\n await writeFile(\n join(rulesDir, rule.name),\n frontmatter + rule.content + \"\\n\",\n \"utf-8\",\n );\n }\n}\n\n/** Run the full scaffold. Creates all config files idempotently. */\nexport async function scaffoldConfig(\n opts: ScaffoldOptions,\n): Promise<{ filesWritten: string[] }> {\n const projectDir = opts.projectDir ?? process.cwd();\n const platform = opts.platform ?? \"claude\";\n const spaceName = opts.spaceName;\n const spaceDefs = opts.spaceDefs;\n\n const filesWritten: string[] = [];\n\n await writePluginJson(projectDir);\n filesWritten.push(\".claude-plugin/plugin.json\");\n\n await writeMcpJson(projectDir, platform);\n filesWritten.push(platform === \"cursor\" ? \".cursor/mcp.json\" : \".mcp.json\");\n\n if (platform === \"cursor\") {\n await writeCursorRules(projectDir);\n filesWritten.push(\".cursor/rules/llmkb/ (5 rule files)\");\n }\n\n const llmkbFiles = await writeLlmkbDir(\n projectDir,\n spaceName,\n spaceDefs,\n opts.force,\n );\n for (const f of llmkbFiles) {\n filesWritten.push(f);\n }\n\n if (opts.withHooks) {\n const hookFiles = await writeHooks(projectDir, opts.force);\n for (const f of hookFiles) {\n filesWritten.push(f);\n }\n }\n\n return { filesWritten };\n}\n","/** ``llmkb hooks install/uninstall`` — manage cross-platform Claude Code hooks.\n\nUsage:\n llmkb hooks install\n llmkb hooks install --force\n llmkb hooks uninstall\n llmkb hooks status\n*/\n\nimport { Command } from \"commander\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, writeFile, rm } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\nconst HOOKS_DIR = \".claude/hooks/llmkb\";\n\n/** Hook configuration JSON (Claude Code hooks.json format). */\nfunction hooksJson(): string {\n return JSON.stringify(\n {\n hooks: {\n PreToolUse: [\n {\n matcher: \"Read|Bash\",\n hooks: [\n {\n type: \"command\",\n command:\n \"node ${CLAUDE_PLUGIN_ROOT}/hooks/llmkb-hook.js --pre --tool ${TOOL_NAME}\",\n timeout: 5,\n statusMessage: \"Checking llmkb space context...\",\n },\n ],\n },\n ],\n PostToolUse: [\n {\n matcher: \"Edit|Write|Bash\",\n hooks: [\n {\n type: \"command\",\n command:\n \"node ${CLAUDE_PLUGIN_ROOT}/hooks/llmkb-hook.js --post --tool ${TOOL_NAME} --exit-code ${EXIT_CODE}\",\n timeout: 5,\n statusMessage: \"Checking sync freshness...\",\n },\n ],\n },\n ],\n },\n },\n null,\n 2,\n );\n}\n\n/** Primary Node.js hook script that handles PreToolUse and PostToolUse events. */\nfunction hookScript(): string {\n return `#!/usr/bin/env node\n// llmkb Claude Code hook — PreToolUse (space context) + PostToolUse (sync freshness)\n// Input: --pre/--post, --tool <name>, --exit-code <code>\n// Stdin: { hook_event_name, tool_name, tool_input, cwd }\n// Stdout: JSON { hookSpecificOutput: { hookEventName, additionalContext } }\n\nconst fs = require(\"fs\");\nconst path = require(\"path\");\nconst { spawnSync } = require(\"child_process\");\n\n// --- Config ---\nconst HOOK_TIMEOUT = parseInt(process.env.LLMKB_HOOK_TIMEOUT_MS || \"5000\", 10);\nconst HOOK_SKIP = process.env.LLMKB_HOOK_SKIP === \"1\" || process.env.LLMKB_HOOK_SKIP === \"true\";\nconst DEBUG = process.env.LLMKB_DEBUG === \"1\" || process.env.LLMKB_DEBUG === \"true\";\nconst POWERSHELL_PATH = process.env.LLMKB_HOOK_POWERSHELL_PATH || \"powershell.exe\";\n\nfunction log(msg) {\n if (DEBUG) process.stderr.write(\"[llmkb hook] \" + msg + \"\\\\n\");\n}\n\nfunction findProjectRoot(startDir) {\n let dir = startDir;\n for (let i = 0; i < 10; i++) {\n if (fs.existsSync(path.join(dir, \".llmkb\", \"spaces.yml\"))) return dir;\n const parent = path.dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n return null;\n}\n\nfunction getActiveSpace(projectRoot) {\n try {\n const content = fs.readFileSync(path.join(projectRoot, \".llmkb\", \"spaces.yml\"), \"utf-8\");\n const match = content.match(/^active:\\\\s*(\\\\S+)/m);\n return match ? match[1] : null;\n } catch { return null; }\n}\n\nfunction handlePreToolUse(input) {\n if (HOOK_SKIP) return;\n const cwd = input.cwd || process.cwd();\n const projectRoot = findProjectRoot(cwd);\n if (!projectRoot) return; // silent skip\n const space = getActiveSpace(projectRoot);\n if (!space) return;\n log(\"active space: \" + space);\n console.log(JSON.stringify({\n hookSpecificOutput: {\n hookEventName: \"PreToolUse\",\n additionalContext: \"llmkb space: \" + space\n }\n }));\n}\n\nfunction handlePostToolUse(input) {\n if (HOOK_SKIP) return;\n const toolName = input.tool_name || \"\";\n if (toolName !== \"Edit\" && toolName !== \"Write\" && toolName !== \"Bash\") return;\n const exitCode = input.tool_output ? input.tool_output.exit_code : 0;\n if (exitCode !== 0) return;\n const cwd = input.cwd || process.cwd();\n const projectRoot = findProjectRoot(cwd);\n if (!projectRoot) return;\n log(\"post-tool: suggesting sync freshness check\");\n console.log(JSON.stringify({\n hookSpecificOutput: {\n hookEventName: \"PostToolUse\",\n additionalContext: \"Files may have changed. Consider running \\`llmkb sync\\` to update the space.\"\n }\n }));\n}\n\nfunction main() {\n try {\n const args = process.argv.slice(2);\n const isPre = args.includes(\"--pre\");\n const isPost = args.includes(\"--post\");\n const raw = fs.readFileSync(0, \"utf-8\").trim();\n const input = raw ? JSON.parse(raw) : {};\n\n if (isPre) handlePreToolUse(input);\n else if (isPost) handlePostToolUse(input);\n } catch (err) {\n if (DEBUG) process.stderr.write(\"[llmkb hook] error: \" + (err.message || \"\") + \"\\\\n\");\n }\n}\n\nmain();\n`;\n}\n\n/** Windows PowerShell fallback hook script. */\nfunction ps1Script(): string {\n return `# llmkb Claude Code hook — PowerShell fallback for Windows\n# Input: --pre/--post, --tool <name>, --exit-code <code>\n# Stdin: JSON { hook_event_name, tool_name, tool_input, cwd }\n\nparam(\n [switch]$pre,\n [switch]$post,\n [string]$tool = \"\",\n [int]$exitCode = 0\n)\n\n$skip = $env:LLMKB_HOOK_SKIP\nif ($skip -eq \"1\" -or $skip -eq \"true\") { exit 0 }\n\n$debug = $env:LLMKB_DEBUG\nfunction Log($msg) {\n if ($debug -eq \"1\" -or $debug -eq \"true\") {\n [Console.Error]::WriteLine(\"[llmkb hook] $msg\")\n }\n}\n\n# Walk up to find .llmkb/spaces.yml\n$dir = (Get-Location).Path\nfor ($i = 0; $i -lt 10; $i++) {\n $check = Join-Path $dir \".llmkb\" \"spaces.yml\"\n if (Test-Path $check) {\n $content = Get-Content $check -Raw\n if ($content -match 'active:\\\\s*(\\\\S+)') {\n $space = $Matches[1]\n if ($pre) {\n $result = @{\n hookSpecificOutput = @{\n hookEventName = \"PreToolUse\"\n additionalContext = \"llmkb space: $space\"\n }\n }\n ConvertTo-Json $result -Compress\n }\n }\n break\n }\n $parent = Split-Path $dir -Parent\n if ($parent -eq $dir) { break }\n $dir = $parent\n}\n`;\n}\n\n/** Write all hook files to the project. */\nexport async function writeHooks(\n projectDir: string,\n force?: boolean,\n): Promise<string[]> {\n const hooksDir = resolve(projectDir, HOOKS_DIR);\n const written: string[] = [];\n\n await mkdir(hooksDir, { recursive: true });\n\n // hooks.json\n const hooksJsonPath = join(hooksDir, \"hooks.json\");\n if (!existsSync(hooksJsonPath) || force) {\n await writeFile(hooksJsonPath, hooksJson() + \"\\n\", \"utf-8\");\n written.push(\".claude/hooks/llmkb/hooks.json\");\n }\n\n // llmkb-hook.js\n const hookJsPath = join(hooksDir, \"llmkb-hook.js\");\n if (!existsSync(hookJsPath) || force) {\n await writeFile(hookJsPath, hookScript(), \"utf-8\");\n written.push(\".claude/hooks/llmkb/llmkb-hook.js\");\n }\n\n // Windows fallback\n const ps1Path = join(hooksDir, \"llmkb-hook.ps1\");\n if (!existsSync(ps1Path) || force) {\n await writeFile(ps1Path, ps1Script(), \"utf-8\");\n written.push(\".claude/hooks/llmkb/llmkb-hook.ps1\");\n }\n\n return written;\n}\n\n/** Remove all hook files from the project. */\nasync function removeHooks(projectDir: string): Promise<boolean> {\n const hooksDir = resolve(projectDir, HOOKS_DIR);\n if (existsSync(hooksDir)) {\n await rm(hooksDir, { recursive: true, force: true });\n return true;\n }\n return false;\n}\n\n/** Check whether hooks are installed. */\nfunction hooksInstalled(projectDir: string): boolean {\n const hooksDir = resolve(projectDir, HOOKS_DIR);\n return existsSync(join(hooksDir, \"hooks.json\"));\n}\n\n// ---------------------------------------------------------------------------\n// Command\n// ---------------------------------------------------------------------------\n\nexport const hooksCommand = new Command(\"hooks\")\n .description(\"Manage Claude Code hooks for llmkb context enrichment\")\n .addCommand(\n new Command(\"install\")\n .description(\"Install llmkb hooks\")\n .option(\"-f, --force\", \"Overwrite existing hook files\")\n .action(async (opts: { force?: boolean }) => {\n const projectDir = process.cwd();\n try {\n const files = await writeHooks(projectDir, opts.force);\n if (files.length > 0) {\n console.log(`Installed ${files.length} hook file(s):`);\n for (const f of files) console.log(` ✔ ${f}`);\n } else {\n console.log(\"Hooks already installed. Use --force to overwrite.\");\n }\n } catch (err) {\n console.error(\"Error installing hooks:\", (err as Error).message);\n process.exit(1);\n }\n }),\n )\n .addCommand(\n new Command(\"uninstall\")\n .description(\"Remove llmkb hooks\")\n .action(async () => {\n const projectDir = process.cwd();\n const removed = await removeHooks(projectDir);\n if (removed) {\n console.log(\"Hooks removed.\");\n } else {\n console.log(\"No hooks found.\");\n }\n }),\n )\n .addCommand(\n new Command(\"status\")\n .description(\"Check whether hooks are installed\")\n .action(() => {\n const projectDir = process.cwd();\n if (hooksInstalled(projectDir)) {\n console.log(\"llmkb hooks are installed.\");\n } else {\n console.log(\n \"llmkb hooks are not installed. Run `llmkb hooks install`.\",\n );\n }\n }),\n );\n","/** Skill installer for ``llmkb init``.\n\nCopies built-in SKILL.md files from the package into\n``.claude/skills/llmkb/<name>/`` and stamps each skill directory with\n``.llmkb-version`` so ``llmkb status`` can detect version mismatches.\n\nFor Cursor, writes ``.mdc`` rule files to ``.cursor/rules/llmkb/`` instead.\n*/\n\nimport { mkdir, writeFile, readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { PACKAGE_VERSION } from \"./types.js\";\n\nexport interface SkillDef {\n name: string;\n description: string;\n body: string;\n}\n\n/** Built-in llmkb skill definitions. */\nconst SKILLS: SkillDef[] = [\n {\n name: \"llmkb-guide\",\n description:\n \"Use when the user asks how llmkb works, how to get started, or what llmkb can do. Examples: 'How do I use llmkb?', 'What is llmkb?', 'Get started with llmkb', 'Show me the llmkb architecture'\",\n body: [\n \"## Overview\",\n \"\",\n \"llmkb is an AI-powered knowledge base that transforms documents into an organized, interlinked wiki and knowledge graph. It uses a three-layer model: raw sources (PDFs, code, markdown) → LLM-generated wiki pages → structured knowledge graph with entity relationships.\",\n \"\",\n \"## Quick Start\",\n \"\",\n \"```\",\n \"llmkb status -- check your current configuration\",\n \"llmkb whoami -- show active space and credentials\",\n \"docker compose --profile mvp ps -- verify MCP server is running\",\n \"```\",\n \"\",\n \"## Workflow\",\n \"\",\n \"### 1. Verify Setup\",\n \"\",\n \"Start by checking that everything is configured:\",\n \"\",\n \"- Run `llmkb status` to confirm version stamps match\",\n \"- Run `llmkb whoami` to verify credentials are stored\",\n \"- Check `docker compose --profile mvp ps` to confirm the API container is running\",\n \"\",\n \"### 2. Search the Wiki\",\n \"\",\n \"Use `space_search` with a specific query targeting your space:\",\n \"\",\n \"```\",\n \"-- space_search example --\",\n `space_search(space_name: \"my-project\", query: \"authentication flow\")`,\n \"-- result: ranked list of wiki pages with snippets and confidence scores --\",\n \"```\",\n \"\",\n \"### 3. Read a Page\",\n \"\",\n \"Get the full content of a wiki page:\",\n \"\",\n \"```\",\n \"-- space_read example --\",\n `space_read(space_name: \"my-project\", path: \"/docs/architecture\")`,\n \"-- result: full wiki content with frontmatter, body, and metadata --\",\n \"```\",\n \"\",\n \"### 4. Explore the Graph\",\n \"\",\n \"When you need to understand how concepts connect:\",\n \"\",\n \"```\",\n \"-- space_graph example --\",\n `space_graph(space_name: \"my-project\", mode: \"neighbours\", entity: \"AuthModule\")`,\n \"-- result: entity nodes, relationship edges, and community clusters --\",\n \"```\",\n \"\",\n \"### 5. Save New Information\",\n \"\",\n \"Write directly to a space when you discover something new:\",\n \"\",\n \"```\",\n \"-- space_write example --\",\n `space_write(`,\n ` space_name: \"my-project\",`,\n ` path: \"/notes/api-pattern\",`,\n ` content: \"# API Pattern\\\\nThe project uses repository pattern with SQLAlchemy.\"`,\n `)`,\n \"-- result: new wiki page created in the space --\",\n \"```\",\n \"\",\n \"## Troubleshooting\",\n \"\",\n \"| Error | Cause | Fix |\",\n \"|-------|-------|-----|\",\n '| \"Space not found\" | Wrong space name | Run `llmkb use` to see configured spaces |',\n '| \"Token required\" | Private space needs auth | Run `llmkb login --space <name>` |',\n \"| MCP server timeout | Docker not running | `docker compose --profile mvp ps` to check |\",\n \"| Version mismatch | Skills or config out of date | `llmkb init` to re-install |\",\n \"\",\n \"## Self-Check\",\n \"\",\n \"- [ ] Active space configured via `llmkb status`\",\n \"- [ ] Tokens stored in keychain or env vars\",\n \"- [ ] MCP server reachable: `docker compose --profile mvp ps`\",\n \"- [ ] Version stamps match package version\",\n ].join(\"\\n\"),\n },\n {\n name: \"llmkb-query\",\n description:\n \"Use when searching or reading wiki content via MCP tools. Examples: 'Search the wiki for X', 'Read this wiki page', 'Find relevant documentation', 'Look up authentication patterns', 'What does the wiki say about pgvector?'\",\n body: [\n \"## Overview\",\n \"\",\n \"Search and read your llmkb wiki using hybrid full-text + vector search and knowledge graph navigation. Start with `space_search` to find relevant pages, then use `space_read` to get full content.\",\n \"\",\n \"## Quick Start\",\n \"\",\n \"```\",\n \"-- search for information --\",\n `space_search(space_name: \"my-project\", query: \"pgvector indexing\")`,\n \"\",\n \"-- read a specific page --\",\n `space_read(space_name: \"my-project\", path: \"/docs/indexing-strategy\")`,\n \"```\",\n \"\",\n \"## Workflow\",\n \"\",\n \"### 1. Find Relevant Content\",\n \"\",\n \"Start with `space_search` to locate relevant wiki pages:\",\n \"\",\n \"```\",\n \"-- search with a specific query --\",\n `space_search(space_name: \"my-project\", query: \"authentication flow\")`,\n \"\",\n \"-- search with confidence filter --\",\n `space_search(space_name: \"my-project\", query: \"database schema\", min_confidence: 0.8)`,\n \"```\",\n \"\",\n \"Returns ranked results with paths, snippets, confidence scores, and entity types.\",\n \"\",\n \"### 2. Read Full Content\",\n \"\",\n \"Once you have identified the right page, read it fully:\",\n \"\",\n \"```\",\n \"-- read by path --\",\n `space_read(space_name: \"my-project\", path: \"/docs/architecture\")`,\n \"\",\n \"-- result includes frontmatter (type, category, source_pages) and full body content --\",\n \"```\",\n \"\",\n \"### 3. Get a Space Overview\",\n \"\",\n \"For a structured summary of a space's content:\",\n \"\",\n \"```\",\n \"-- overview of all entities and pages --\",\n `space_guide(space_name: \"my-project\")`,\n \"-- result: summary of entity types, page categories, and top-level relationships --\",\n \"```\",\n \"\",\n \"### 4. Explore Entity Relationships\",\n \"\",\n \"When search results surface an entity, dig into its connections:\",\n \"\",\n \"```\",\n \"-- find neighbours of a specific entity --\",\n `space_graph(space_name: \"my-project\", mode: \"neighbours\", entity: \"AuthModule\")`,\n \"-- result: all entities directly connected to AuthModule with relationship types --\",\n \"```\",\n \"\",\n \"## Troubleshooting\",\n \"\",\n \"| Error | Cause | Fix |\",\n \"|-------|-------|-----|\",\n \"| Empty results | Query too narrow | Broaden terms or check space has content with `space_guide` |\",\n '| \"Space not found\" | Wrong space name | `llmkb status` to list configured spaces |',\n \"| Path not found | Page path incorrect | Search first with `space_search` to find the exact path |\",\n \"| Token error | Expired credentials | `llmkb login --space <name>` |\",\n \"\",\n \"## Self-Check\",\n \"\",\n \"- [ ] Used `space_search` first to find relevant pages\",\n \"- [ ] Used `space_read` to get full context when snippet is insufficient\",\n \"- [ ] Verified the space name matches a configured space\",\n \"- [ ] Used `space_graph` for deeper relationship exploration when needed\",\n ].join(\"\\n\"),\n },\n {\n name: \"llmkb-sync\",\n description:\n \"Use when syncing local files to an llmkb space for ingestion. Examples: 'Upload these docs', 'Sync this folder to my wiki', 'Ingest this README', 'Watch this directory for changes', 'Upload my codebase'\",\n body: [\n \"## Overview\",\n \"\",\n \"Sync local files and codebases to your llmkb spaces for processing and wiki generation. Files are content-addressed (SHA256) so unchanged files skip re-processing. Supports PDF, Markdown, code files, images, and audio.\",\n \"\",\n \"## Quick Start\",\n \"\",\n \"```\",\n \"llmkb sync -- sync current directory to active space\",\n \"llmkb sync --space my-project -- sync to a specific space\",\n \"llmkb sync --watch -- watch directory for changes\",\n \"```\",\n \"\",\n \"## Workflow\",\n \"\",\n \"### 1. Sync Files to a Space\",\n \"\",\n \"Navigate to the directory containing files you want to ingest and run:\",\n \"\",\n \"```\",\n \"cd /path/to/your/project\",\n \"llmkb sync --space my-project\",\n \"```\",\n \"\",\n \"The command will:\",\n \"\",\n \"1. Walk the directory recursively\",\n \"2. Compute SHA256 hashes for each file\",\n \"3. Skip unchanged files (cached in `.llmkb/sync-state.json`)\",\n \"4. Upload new/changed files via TUS protocol\",\n \"5. Report progress per file\",\n \"\",\n \"### 2. Watch for Changes\",\n \"\",\n \"Keep a directory synced automatically:\",\n \"\",\n \"```\",\n \"llmkb sync --watch --space my-project\",\n \"```\",\n \"\",\n \"Watcher behaviour:\",\n \"\",\n \"- Respects `.gitignore` and `.llmkbignore` patterns\",\n \"- Debounces rapid file changes\",\n \"- Detects file renames by content hash (not path)\",\n \"- Press Ctrl+C to stop watching\",\n \"\",\n \"### 3. Check Sync Status\",\n \"\",\n \"After syncing, verify ingestion progress:\",\n \"\",\n \"```\",\n \"llmkb status --space my-project\",\n \"```\",\n \"\",\n \"### 4. Query Synced Content\",\n \"\",\n \"Once processing completes, search the newly ingested content:\",\n \"\",\n \"```\",\n `space_search(space_name: \"my-project\", query: \"topics from the synced files\")`,\n \"```\",\n \"\",\n \"## Troubleshooting\",\n \"\",\n \"| Error | Cause | Fix |\",\n \"|-------|-------|-----|\",\n \"| File skipped | Matches .gitignore or .llmkbignore | Check ignore files |\",\n \"| Upload failed | TUS endpoint unreachable | Verify Docker is running |\",\n \"| Hash mismatch | File changed during upload | Re-run `llmkb sync` |\",\n '| \"No space configured\" | No active space | `llmkb use <space-name>` |',\n \"| Sync slow | Large directory | Use `--verbose` to see progress; files over 5MB use chunked TUS uploads |\",\n \"\",\n \"## Self-Check\",\n \"\",\n \"- [ ] Files upload successfully (check terminal output for each file)\",\n \"- [ ] Ingestion job progresses through phases\",\n \"- [ ] Wiki pages generated after processing completes\",\n \"- [ ] Unchanged files are skipped (cached by SHA256)\",\n ].join(\"\\n\"),\n },\n {\n name: \"llmkb-exploring\",\n description:\n \"Use when exploring architecture, codebase structure, and entity relationships. Examples: 'How does X work?', 'Show me the codebase architecture', 'What connections exist in this space?', 'Find relationships between these concepts', 'Map the auth module dependencies'\",\n body: [\n \"## Overview\",\n \"\",\n \"Explore entity relationships, knowledge graph structure, and how different pieces of information connect in your llmkb spaces. Use graph queries to discover neighbours, find paths between entities, and get structured space overviews.\",\n \"\",\n \"## Quick Start\",\n \"\",\n \"```\",\n \"-- explore neighbours of an entity --\",\n `space_graph(space_name: \"my-project\", mode: \"neighbours\", entity: \"AuthModule\")`,\n \"\",\n \"-- find path between two entities --\",\n `space_graph(space_name: \"my-project\", mode: \"path\", source: \"ServiceA\", target: \"ServiceB\")`,\n \"```\",\n \"\",\n \"## Workflow\",\n \"\",\n \"### 1. Get a Space Overview\",\n \"\",\n \"Start with `space_guide` for a high-level summary:\",\n \"\",\n \"```\",\n `space_guide(space_name: \"my-project\")`,\n \"-- result: entity count, relationship count, page categories, top-level clusters --\",\n \"```\",\n \"\",\n \"### 2. Explore Neighbourhoods\",\n \"\",\n \"Drill into a specific entity to see its direct connections:\",\n \"\",\n \"```\",\n `space_graph(space_name: \"my-project\", mode: \"neighbours\", entity: \"AuthModule\")`,\n \"-- result: all entities directly connected to AuthModule with relationship types and confidence scores --\",\n \"```\",\n \"\",\n \"### 3. Find Paths\",\n \"\",\n \"Discover how two entities connect through intermediate nodes:\",\n \"\",\n \"```\",\n `space_graph(space_name: \"my-project\", mode: \"path\", source: \"Database\", target: \"UserService\")`,\n \"-- result: shortest path showing each hop with relationship type --\",\n \"```\",\n \"\",\n \"### 4. Search Within the Exploration\",\n \"\",\n \"When you find interesting entities, search for more details:\",\n \"\",\n \"```\",\n `space_search(space_name: \"my-project\", query: \"user authentication\")`,\n \"```\",\n \"\",\n \"## Troubleshooting\",\n \"\",\n \"| Error | Cause | Fix |\",\n \"|-------|-------|-----|\",\n \"| Empty graph | Space has no processed content | Run `llmkb sync` to upload files first |\",\n '| \"Entity not found\" | Wrong entity name | Use `space_search` to find the exact label |',\n \"| No path found | Entities not connected in the graph | Try broader search to find bridging entities |\",\n \"| Graph too large | Too many neighbours | Narrow the entity or use `space_search` instead |\",\n \"\",\n \"## Self-Check\",\n \"\",\n \"- [ ] Started with `space_guide` for orientation\",\n \"- [ ] Used `space_graph` with `neighbours` mode for direct connections\",\n \"- [ ] Used `space_graph` with `path` mode for indirect connections\",\n \"- [ ] Followed up with `space_search` for deeper context\",\n ].join(\"\\n\"),\n },\n {\n name: \"llmkb-admin\",\n description:\n \"Use when managing spaces, tokens, configuration, or credentials. Examples: 'Show my space members', 'Configure a new space', 'Manage API tokens', 'Switch active space', 'Check my credentials', 'Set up a new project with llmkb'\",\n body: [\n \"## Overview\",\n \"\",\n \"Manage llmkb spaces, API tokens, configuration settings, and credentials. The CLI provides commands for switching spaces, authenticating, and verifying setup.\",\n \"\",\n \"## Quick Start\",\n \"\",\n \"```\",\n \"llmkb status -- check version stamps and active config\",\n \"llmkb use my-project -- switch active space\",\n \"llmkb login --space admin -- store credentials for a space\",\n \"```\",\n \"\",\n \"## Workflow\",\n \"\",\n \"### 1. Initialise a Project\",\n \"\",\n \"Set up a new project with llmkb:\",\n \"\",\n \"```\",\n \"cd /path/to/project\",\n \"llmkb init --space my-project\",\n \"```\",\n \"\",\n \"This creates:\",\n \"\",\n \"- `.claude-plugin/plugin.json` — plugin metadata for discovery\",\n \"- `.mcp.json` — MCP server registration with Docker stdio transport\",\n \"- `.llmkb/spaces.yml` — space configuration\",\n \"- `.llmkb/config.yml` — plugin behaviour settings\",\n \"- `.claude/skills/llmkb/` — 5 Claude Code skills\",\n \"\",\n \"For Cursor: `llmkb init --platform cursor` writes equivalent `.cursor/` files.\",\n \"\",\n \"To skip skill installation: `llmkb init --no-with-skills` (for config-only setup).\",\n \"\",\n \"### 2. Authenticate\",\n \"\",\n \"Store credentials for a space after init:\",\n \"\",\n \"```\",\n \"llmkb login --space my-project\",\n \"```\",\n \"\",\n \"This stores the space token in the OS keychain. For CI/headless environments, set the `LLMKB_TOKEN` environment variable instead.\",\n \"\",\n \"### 3. Switch Spaces\",\n \"\",\n \"When working with multiple spaces:\",\n \"\",\n \"```\",\n \"llmkb use client-project\",\n \"llmkb login --space client-project\",\n \"llmkb status --space client-project\",\n \"```\",\n \"\",\n \"### 4. Verify Setup\",\n \"\",\n \"Check that everything is configured correctly:\",\n \"\",\n \"```\",\n \"llmkb status\",\n \"llmkb whoami\",\n \"```\",\n \"\",\n \"The `status` command warns on:\",\n \"\",\n \"- Config version mismatch: `llmkb init` to update\",\n \"- Skill version mismatch: `llmkb init` to re-install skills\",\n \"- Missing or expired tokens\",\n \"\",\n \"### 5. Token Management\",\n \"\",\n \"- Space tokens grant read access to a specific space\",\n \"- Admin tokens grant write/admin access\",\n \"- Tokens are stored in the OS keychain (requires `keychain` package)\",\n \"- Set `LLMKB_TOKEN` / `LLMKB_ADMIN_TOKEN` env vars for CI\",\n \"- Token groups allow sharing a single token across multiple spaces\",\n \"\",\n \"## Troubleshooting\",\n \"\",\n \"| Error | Cause | Fix |\",\n \"|-------|-------|-----|\",\n '| \"Version mismatch\" | Config or skills out of date | `llmkb init` to update |',\n '| \"Not found: .llmkb/\" | Project not initialised | `llmkb init` first |',\n \"| Keychain access denied | Missing keychain permission | Fall back to `LLMKB_TOKEN` env var |\",\n \"| Token expired | Credentials rotated | `llmkb login --space <name>` |\",\n \"| Multiple spaces confusing | Wrong active space | `llmkb use <name>` to switch |\",\n \"\",\n \"## Self-Check\",\n \"\",\n \"- [ ] Project initialised with `llmkb init`\",\n \"- [ ] Tokens stored and accessible (keychain or env vars)\",\n \"- [ ] Correct space is active via `llmkb use`\",\n \"- [ ] Version stamps match package version (`llmkb status`)\",\n \"- [ ] MCP server is running: `docker compose --profile mvp ps`\",\n ].join(\"\\n\"),\n },\n];\n\n/**\n * Install all built-in skills to the appropriate platform path.\n *\n * For Claude Code: writes SKILL.md files to `.claude/skills/llmkb/<name>/`.\n * For Cursor: writes `.mdc` rule files to `.cursor/rules/llmkb/`.\n *\n * Creates idempotent copies — safe to re-run.\n *\n * @param platform Target platform: \"claude\" (default) or \"cursor\".\n * @returns The number of skills installed.\n */\nexport async function installSkills(\n platform: \"claude\" | \"cursor\" = \"claude\",\n projectDir?: string,\n): Promise<number> {\n if (platform === \"cursor\") {\n // Cursor skills are handled by writer.ts writeCursorRules()\n // This function only handles Claude Code SKILL.md installation\n return 0;\n }\n\n const projectRoot = projectDir ?? process.cwd();\n const targetDir = join(projectRoot, \".claude\", \"skills\", \"llmkb\");\n\n for (const skill of SKILLS) {\n const skillDir = join(targetDir, skill.name);\n await mkdir(skillDir, { recursive: true });\n\n const trigger = skill.name.replace(\"llmkb-\", \"/llmkb-\");\n\n const frontmatter = [\n \"---\",\n `name: ${skill.name}`,\n `description: ${skill.description}`,\n `trigger: ${trigger}`,\n \"---\",\n \"\",\n ].join(\"\\n\");\n\n await writeFile(\n join(skillDir, \"SKILL.md\"),\n frontmatter + skill.body + \"\\n\",\n \"utf-8\",\n );\n\n // Version stamp\n await writeFile(\n join(skillDir, \".llmkb-version\"),\n PACKAGE_VERSION + \"\\n\",\n \"utf-8\",\n );\n }\n\n return SKILLS.length;\n}\n\n/**\n * Check version stamps of all installed skills against the current package version.\n *\n * @param skillsDir Absolute path to `.claude/skills/llmkb/`.\n * @returns Array of version mismatches, one per skill directory.\n */\nexport async function checkSkillVersions(\n skillsDir: string,\n): Promise<{ name: string; installed: string; current: string }[]> {\n const mismatches: { name: string; installed: string; current: string }[] = [];\n\n if (!existsSync(skillsDir)) return mismatches;\n\n const { readdir } = await import(\"node:fs/promises\");\n const entries = await readdir(skillsDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const versionPath = join(skillsDir, entry.name, \".llmkb-version\");\n try {\n const content = await readFile(versionPath, \"utf-8\");\n const installedVersion = content.split(\"\\n\")[0]?.trim();\n if (installedVersion && installedVersion !== PACKAGE_VERSION) {\n mismatches.push({\n name: entry.name,\n installed: installedVersion,\n current: PACKAGE_VERSION,\n });\n }\n } catch {\n // No version stamp file — treat as mismatch\n mismatches.push({\n name: entry.name,\n installed: \"(none)\",\n current: PACKAGE_VERSION,\n });\n }\n }\n\n return mismatches;\n}\n","/** ``llmkb login --project-space <id>`` — authenticate with user-level access token. */\n\nimport { Command } from \"commander\";\nimport { getConfig } from \"../../lib/config.js\";\nimport { getToken, setToken } from \"../../lib/credentials.js\";\nimport {\n findProjectRoot,\n writeSpaceConfig,\n} from \"../../lib/parser.js\";\nimport type { SpaceConfig } from \"../../lib/types.js\";\nimport { syncRelatedSpaces } from \"../../lib/sync-spaces-config.js\";\nimport { createInterface } from \"node:readline/promises\";\nimport { success, error, warning, info, muted } from \"../../lib/color.js\";\n\nfunction prompt(query: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return rl.question(query).finally(() => rl.close());\n}\n\ninterface MeResponse {\n data?: {\n attributes?: {\n user_id?: string;\n email?: string;\n token_status?: string;\n expires_at?: string | null;\n };\n };\n errors?: Array<{ detail?: string }>;\n}\n\ninterface SpacesResponse {\n data?: Array<{\n attributes?: {\n space_id?: string;\n space_name?: string;\n slug?: string;\n role?: string;\n };\n }>;\n errors?: Array<{ detail?: string }>;\n}\n\nasync function validateToken(\n endpoint: string,\n token: string,\n): Promise<{\n valid: boolean;\n user_id?: string;\n email?: string;\n token_status?: string;\n error?: string;\n}> {\n try {\n const url = `${endpoint.replace(/\\/+$/, \"\")}/api/v1/auth/me`;\n const res = await fetch(url, {\n method: \"GET\",\n headers: { Authorization: `Bearer ${token}` },\n });\n const body = (await res.json()) as MeResponse;\n if (res.ok && body.data?.attributes?.token_status === \"active\") {\n return {\n valid: true,\n user_id: body.data.attributes.user_id,\n email: body.data.attributes.email,\n token_status: body.data.attributes.token_status,\n };\n }\n const detail = body.errors?.[0]?.detail ?? body.data?.attributes?.token_status ?? \"Token rejected\";\n return { valid: false, error: detail };\n } catch (err) {\n return {\n valid: false,\n error: `Cannot reach server: ${(err as Error).message}`,\n };\n }\n}\n\nasync function discoverSpaces(\n endpoint: string,\n token: string,\n): Promise<Array<{ space_id: string; space_name: string; slug: string; role: string }>> {\n try {\n const url = `${endpoint.replace(/\\/+$/, \"\")}/api/v1/auth/spaces`;\n const res = await fetch(url, {\n headers: { Authorization: `Bearer ${token}` },\n });\n const body = (await res.json()) as SpacesResponse;\n if (res.ok && body.data) {\n return body.data\n .filter((d) => d.attributes?.space_id)\n .map((d) => ({\n space_id: d.attributes!.space_id!,\n space_name: d.attributes!.space_name ?? d.attributes!.space_id!,\n slug: d.attributes!.slug ?? \"\",\n role: d.attributes!.role ?? \"guest\",\n }));\n }\n return [];\n } catch {\n return [];\n }\n}\n\nexport const loginCommand = new Command(\"login\")\n .description(\"Authenticate with an access token and configure the project space\")\n .requiredOption(\"-p, --project-space <id>\", \"Project space UUID to use as primary space\")\n .action(async (opts: { projectSpace: string }) => {\n const config = getConfig();\n const projectSpaceId = opts.projectSpace;\n const endpoint = config.endpoint;\n\n // Check if already logged in\n const existing = await getToken();\n if (existing) {\n console.log(info(\"Already logged in.\"));\n const ans = await prompt(`${warning(\"Re-authenticate? (y/N):\")} `);\n if (ans.toLowerCase() !== \"y\") {\n console.log(muted(\"Aborted.\"));\n return;\n }\n }\n\n const accessToken = await prompt(`${info(\"Access token (paste, then Enter):\")} `);\n if (!accessToken.trim()) {\n console.log(error(\"Access token is required.\"));\n process.exit(1);\n }\n\n console.log(` ${muted(\"Validating token against\")} ${info(endpoint)}${muted(\"...\")}`);\n const result = await validateToken(endpoint, accessToken.trim());\n if (!result.valid) {\n console.log(`${error(\"Authentication failed:\")} ${result.error}`);\n process.exit(1);\n }\n\n console.log(` ${success(\"✔ Authenticated as\")} ${info(result.email ?? result.user_id ?? \"unknown\")} ${muted(`(status: ${result.token_status})`)}`);\n\n // Store in keychain\n await setToken(accessToken.trim());\n console.log(` ${success(\"✔ Access token stored in keychain.\")}`);\n\n // Discover accessible spaces\n console.log(` ${muted(\"Discovering accessible spaces...\")}`);\n const spaces = await discoverSpaces(endpoint, accessToken.trim());\n console.log(` ${info(`Found ${spaces.length} space(s).`)}`);\n\n // Write .llmkb/spaces.yml with new format\n const projectRoot = findProjectRoot();\n const spaceConfig: SpaceConfig = {\n project_space: [{ id: projectSpaceId }],\n spaces: spaces.map((s) => ({\n id: s.space_id,\n name: s.space_name,\n slug: s.slug || undefined,\n })),\n };\n\n if (projectRoot) {\n await writeSpaceConfig(projectRoot, spaceConfig);\n\n // LL-2: Sync related spaces from backend to .llmkb/spaces.yml\n const syncResult = await syncRelatedSpaces(projectRoot, endpoint, accessToken.trim());\n if (syncResult.added > 0) {\n console.log(` ${info(`ℹ Also synced ${syncResult.added} related space(s) from space relations.`)}`);\n }\n\n console.log(` ${success(\"✔ Project space set to\")} ${info(projectSpaceId)}`);\n }\n\n console.log(`\\n${success(\"Logged in.\")} ${muted(\"Accessible spaces:\")}`);\n for (const s of spaces) {\n const roleColor = s.role === \"owner\" || s.role === \"admin\" ? success : warning;\n console.log(` ${muted(s.space_id)} ${roleColor(`(${s.role})`)}`);\n }\n\n // Verify the connection\n const verifyResult = await validateToken(endpoint, accessToken.trim());\n if (verifyResult.valid) {\n console.log(` ${success(\"✔ Connection verified.\")} ${muted(`User: ${verifyResult.email}`)}`);\n }\n });\n","/** Configuration for the llmkb plugin.\n\nConfiguration is resolved in priority order:\n1. ``.llmkb/config.yml`` — project-level settings\n2. Environment variables — CI/headless override\n3. Built-in defaults\n\nCall ``getConfig()`` on startup — it is synchronous for env-only,\nbut also provides ``resolveEndpoint()`` for config-file-aware resolution.\n*/\n\nimport { env } from \"node:process\";\n\n/** Resolved plugin configuration. */\nexport interface PluginConfig {\n /** llmkb API endpoint (default ``http://localhost:8000``). */\n endpoint: string;\n}\n\nconst DEFAULT_ENDPOINT = \"http://localhost:8000\";\n\n/** Read configuration from environment variables.\n *\n * For config-file-aware resolution (reading ``llmkb_base_url`` from\n * ``.llmkb/config.yml``), use ``resolveEndpoint()`` or the `doctor`\n * command instead.\n */\nexport function getConfig(): PluginConfig {\n return {\n endpoint: env[\"LLMKB_ENDPOINT\"] ?? DEFAULT_ENDPOINT,\n };\n}\n\n/**\n * Resolve the API endpoint with config-file awareness.\n *\n * Priority: ``.llmkb/config.yml`` → ``LLMKB_ENDPOINT`` env → default.\n *\n * This is async because it reads the config file from disk.\n * CLI commands that are called once per session (login, sync, query)\n * should use this instead of ``getConfig()``.\n */\nexport async function resolveEndpoint(): Promise<string> {\n const envEndpoint = env[\"LLMKB_ENDPOINT\"];\n if (envEndpoint) return envEndpoint;\n\n try {\n const { findProjectRoot, readPluginConfig } = await import(\"./parser.js\");\n const root = findProjectRoot();\n if (root) {\n const pluginCfg = await readPluginConfig(root);\n if (pluginCfg?.llmkb_base_url) {\n return pluginCfg.llmkb_base_url;\n }\n }\n } catch {\n // ignore — fall back to default\n }\n\n return DEFAULT_ENDPOINT;\n}\n","/** OS keychain integration with environment-variable fallback for access_token.\n\nTokens are resolved in a 2-step chain:\n1. ``LLMKB_ACCESS_TOKEN`` env var\n2. OS keychain: ``llmkb/user/access_token``\n3. Error\n\nNever writes tokens to config files or checked-in files.\n*/\n\nimport { env } from \"node:process\";\n\n// ---------------------------------------------------------------------------\n// Keychain integration (lazy-loaded)\n// ---------------------------------------------------------------------------\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet kcGetPassword: any | null = null;\nlet kcSetPassword: any | null = null;\nlet kcDeletePassword: any | null = null;\nlet keychainAvailable = false;\n\nasync function ensureKeychain(): Promise<boolean> {\n if (keychainAvailable) return true;\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const mod: any = await import(\"keychain\");\n const kc = mod.default ?? mod;\n if (typeof kc.setPassword === \"function\") {\n kcGetPassword = kc.getPassword.bind(kc);\n kcSetPassword = kc.setPassword.bind(kc);\n kcDeletePassword = kc.deletePassword.bind(kc);\n keychainAvailable = true;\n return true;\n }\n return false;\n } catch {\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Credential Store interface\n// ---------------------------------------------------------------------------\n\nexport interface CredentialStore {\n getToken(): Promise<string | null>;\n setToken(token: string): Promise<void>;\n deleteToken(): Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// 2-Step Token Resolution\n//\n// 1. LLMKB_ACCESS_TOKEN env var\n// 2. OS keychain llmkb/user/access_token\n// 3. Error\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve the user's access token.\n *\n * Tries environment variable first (CI/headless), then OS keychain.\n */\nexport async function getToken(): Promise<string | null> {\n // Step 1: LLMKB_ACCESS_TOKEN env var\n const envVal = env[\"LLMKB_ACCESS_TOKEN\"];\n if (envVal) return envVal;\n\n // Step 2: OS keychain\n const kcToken = await keychainGet();\n if (kcToken) return kcToken;\n\n return null;\n}\n\n/**\n * Resolve an access token, throwing a descriptive error if not found.\n * Convenience wrapper around ``getToken`` for call sites that expect a\n * mandatory token.\n */\nexport async function requireToken(): Promise<string> {\n const token = await getToken();\n if (!token) {\n throw new Error(\n \"No access token found. Set LLMKB_ACCESS_TOKEN env var or run `llmkb login --project-space <id>`.\",\n );\n }\n return token;\n}\n\n// ---------------------------------------------------------------------------\n// Keychain primitives\n// ---------------------------------------------------------------------------\n\nasync function keychainGet(): Promise<string | null> {\n const available = await ensureKeychain();\n if (!available) return null;\n\n return new Promise<string | null>((resolve) => {\n try {\n kcGetPassword(\n { service: \"llmkb\", account: \"user/access_token\" },\n (err: Error | null, password: string | null) => {\n if (err) resolve(null);\n else resolve(password);\n },\n );\n } catch {\n resolve(null);\n }\n });\n}\n\n// ---------------------------------------------------------------------------\n// Token storage (keychain write)\n// ---------------------------------------------------------------------------\n\n/**\n * Store an access token in the OS keychain.\n *\n * @throws If the keychain is unavailable (no fallback for writes — env vars\n * are read-only).\n */\nexport async function setToken(token: string): Promise<void> {\n const available = await ensureKeychain();\n if (!available) {\n throw new Error(\n \"Keychain is not available. Set LLMKB_ACCESS_TOKEN env var instead.\",\n );\n }\n\n return new Promise<void>((resolve, reject) => {\n kcSetPassword(\n {\n service: \"llmkb\",\n account: \"user/access_token\",\n password: token,\n },\n (err: Error | null) => {\n if (err) reject(err);\n else resolve();\n },\n );\n });\n}\n\n/**\n * Remove the access token from the OS keychain.\n */\nexport async function deleteToken(): Promise<void> {\n const available = await ensureKeychain();\n if (!available) return;\n\n return new Promise<void>((resolve, reject) => {\n kcDeletePassword(\n { service: \"llmkb\", account: \"user/access_token\" },\n (err: Error | null) => {\n if (err) reject(err);\n else resolve();\n },\n );\n });\n}\n","/** Sync related spaces from the backend into ``.llmkb/spaces.yml``.\n\nReads the ``project_space`` ID from the local config, fetches all\nrelated spaces from the backend ``space_relations`` endpoint, and\nappends any that are not yet listed in the ``spaces`` array.\n\nCalled by:\n - ``llmkb doctor`` (LD-1) — sync before checking space access\n - ``llmkb sync`` (LS-4) — sync as the final post-sync step\n - ``llmkb login`` (LL-2) — sync after discovering user spaces\n*/\n\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { readSpaceConfig, addSpaceEntry, removeSpaceEntry, writeSpaceConfig } from \"./parser.js\";\n\n// ---------------------------------------------------------------------------\n// Response shapes from the backend\n// ---------------------------------------------------------------------------\n\ninterface RelationsResponse {\n data?: Array<{\n attributes?: {\n relatedSpaceId?: string;\n relatedSpaceName?: string;\n relatedSpaceSlug?: string;\n };\n }>;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport interface SyncSpacesResult {\n added: number;\n alreadyPresent: number;\n removed: number;\n}\n\n/**\n * Fetch all related spaces from the backend and sync them into\n * ``.llmkb/spaces.yml``.\n *\n * 1. Adds any new related spaces not yet in the ``spaces`` list.\n * 2. Removes any spaces that were previously synced but are no\n * longer related (tracked via ``.llmkb/sync-relations.json``).\n *\n * Manually-added spaces (not added by this sync) are never removed.\n */\nexport async function syncRelatedSpaces(\n projectDir: string,\n endpoint: string,\n token: string,\n): Promise<SyncSpacesResult> {\n const config = await readSpaceConfig(projectDir);\n if (!config?.project_space?.length) {\n return { added: 0, alreadyPresent: 0, removed: 0 };\n }\n\n const projectSpaceId = config.project_space[0]!.id;\n\n // Fetch related spaces from the backend (authoritative list)\n const relations = await fetchRelatedSpaces(endpoint, token, projectSpaceId);\n const backendIds = new Set(relations.map((r) => r.id));\n\n // Read previously synced relation IDs\n const syncedIdsPath = join(projectDir, \".llmkb\", \"sync-relations.json\");\n const prevSyncedIds = await readSyncedIds(syncedIdsPath);\n\n let added = 0;\n let alreadyPresent = 0;\n let removed = 0;\n\n // Phase 0: Remove duplicate project_space entries from the spaces list\n if (config.spaces) {\n for (const s of config.spaces) {\n if (s.id === projectSpaceId) {\n await removeSpaceEntry(projectDir, s.id);\n removed++;\n }\n }\n }\n\n // Phase 1: Add new relations\n for (const rel of relations) {\n if (rel.id === projectSpaceId) continue;\n\n const existingIds = new Set([\n ...(config.spaces ?? []).map((s) => s.id),\n ...(config.project_space ?? []).map((s) => s.id),\n ]);\n\n if (existingIds.has(rel.id)) {\n alreadyPresent++;\n } else {\n await addSpaceEntry(projectDir, rel.id, rel.name);\n added++;\n }\n }\n\n // Phase 2: Remove stale entries that were previously synced\n // Only remove entries that OUR sync added (tracked in sync-relations.json),\n // never manually-added spaces.\n if (prevSyncedIds.size > 0 && config.spaces) {\n for (const s of config.spaces) {\n if (prevSyncedIds.has(s.id) && !backendIds.has(s.id)) {\n await removeSpaceEntry(projectDir, s.id);\n removed++;\n }\n }\n }\n\n // Update the synced IDs tracking file\n await writeSyncedIds(syncedIdsPath, backendIds);\n\n return { added, alreadyPresent, removed };\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n// ---------------------------------------------------------------------------\n// Synced-IDs tracking\n// ---------------------------------------------------------------------------\n\nconst SYNC_RELATIONS_FILE = \"sync-relations.json\";\n\nasync function readSyncedIds(filePath: string): Promise<Set<string>> {\n try {\n if (existsSync(filePath)) {\n const raw = await readFile(filePath, \"utf-8\");\n const parsed = JSON.parse(raw) as string[];\n return new Set(parsed);\n }\n } catch {\n // Corrupted file — start fresh\n }\n return new Set();\n}\n\nasync function writeSyncedIds(\n filePath: string,\n ids: Set<string>,\n): Promise<void> {\n await writeFile(filePath, JSON.stringify([...ids], null, 2) + \"\\n\", \"utf-8\");\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nasync function fetchRelatedSpaces(\n endpoint: string,\n token: string,\n spaceId: string,\n): Promise<Array<{ id: string; name?: string }>> {\n try {\n const url = `${endpoint.replace(/\\/+$/, \"\")}/api/spaces/${encodeURIComponent(spaceId)}/relations`;\n const res = await fetch(url, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!res.ok) return [];\n\n const body = (await res.json()) as RelationsResponse;\n if (!body.data) return [];\n\n return body.data\n .filter((d) => d.attributes?.relatedSpaceId)\n .map((d) => ({\n id: d.attributes!.relatedSpaceId!,\n name: d.attributes?.relatedSpaceName ?? undefined,\n }));\n } catch {\n return [];\n }\n}\n","/** Terminal color helpers for llmkb output.\n\nUses picocolors (14× smaller, 2× faster than chalk).\nRespects NO_COLOR env var automatically.\n*/\n\nimport pc from \"picocolors\";\n\n// ---------------------------------------------------------------------------\n// Severity helpers\n// ---------------------------------------------------------------------------\n\nexport const success = pc.green;\nexport const error = pc.red;\nexport const warning = pc.yellow;\nexport const info = pc.cyan;\nexport const highlight = (s: string) => pc.bold(pc.white(s));\nexport const muted = pc.dim;\n\n// ---------------------------------------------------------------------------\n// Icon-label mapping\n// ---------------------------------------------------------------------------\n\nconst ICON_COLORS: Record<string, (s: string) => string> = {\n \"✔\": success,\n \"✓\": success,\n \"✖\": error,\n \"✗\": error,\n \"⚠\": warning,\n \"ℹ\": info,\n \"⌚\": info,\n};\n\n/** Apply color to an icon label (e.g. ``\"✔\"`` → green). */\nexport function label(icon: string, text: string): string {\n const colorFn = ICON_COLORS[icon];\n if (colorFn) {\n return `${colorFn(icon)} ${text}`;\n }\n return `${icon} ${text}`;\n}\n\n/** Color a status badge: active→green, expired→yellow, revoked→red, etc. */\nexport function badge(status: string): string {\n switch (status?.toLowerCase()) {\n case \"active\":\n case \"present\":\n case \"complete\":\n case \"passed\":\n return pc.green(status);\n case \"expired\":\n case \"missing\":\n case \"failed\":\n return pc.red(status);\n case \"pending\":\n case \"warning\":\n return pc.yellow(status);\n default:\n return status;\n }\n}\n","/** ``llmkb logout`` — remove the access token from the OS keychain. */\n\nimport { Command } from \"commander\";\nimport { deleteToken } from \"../../lib/credentials.js\";\nimport { success, muted } from \"../../lib/color.js\";\n\nexport const logoutCommand = new Command(\"logout\")\n .description(\"Remove the access token from the OS keychain\")\n .action(async () => {\n await deleteToken();\n console.log(`${success(\"✔\")} ${muted(\"Access token removed from keychain.\")}`);\n });\n","/** ``llmkb add --space <id> [--name <name>]`` — add a space to .llmkb/spaces.yml. */\n\nimport { Command } from \"commander\";\nimport { findProjectRoot, addSpaceEntry } from \"../../lib/parser.js\";\nimport { success, error, info } from \"../../lib/color.js\";\n\nexport const addCommand = new Command(\"add\")\n .description(\"Add a space to .llmkb/spaces.yml\")\n .requiredOption(\"-s, --space <id>\", \"Space UUID to add\")\n .option(\"-n, --name <name>\", \"Optional space name\")\n .action(async (opts: { space: string; name?: string }) => {\n const projectRoot = findProjectRoot();\n if (!projectRoot) {\n console.log(error(\"No .llmkb/ directory found. Run `llmkb init` first.\"));\n process.exit(1);\n }\n\n const ok = await addSpaceEntry(projectRoot, opts.space, opts.name);\n if (ok) {\n console.log(`${success(\"✔\")} Space ${info(opts.space)} added to .llmkb/spaces.yml.`);\n } else {\n console.log(error(\"Could not find or parse .llmkb/spaces.yml.\"));\n process.exit(1);\n }\n });\n","/** ``llmkb remove --space <id>`` — remove a space from .llmkb/spaces.yml by id. */\n\nimport { Command } from \"commander\";\nimport { findProjectRoot, removeSpaceEntry } from \"../../lib/parser.js\";\nimport { success, error, info, warning } from \"../../lib/color.js\";\n\nexport const removeCommand = new Command(\"remove\")\n .description(\"Remove a space from .llmkb/spaces.yml by id\")\n .requiredOption(\"-s, --space <id>\", \"Space UUID to remove\")\n .action(async (opts: { space: string }) => {\n const projectRoot = findProjectRoot();\n if (!projectRoot) {\n console.log(error(\"No .llmkb/ directory found. Run `llmkb init` first.\"));\n process.exit(1);\n }\n\n const ok = await removeSpaceEntry(projectRoot, opts.space);\n if (ok) {\n console.log(`${success(\"✔\")} Space ${info(opts.space)} removed from .llmkb/spaces.yml.`);\n } else {\n console.log(warning(`Space \"${opts.space}\" not found in .llmkb/spaces.yml.`));\n process.exit(1);\n }\n });\n","/** ``llmkb spaces`` — list all configured spaces. */\n\nimport { Command } from \"commander\";\nimport { findProjectRoot, readSpaceConfig, deleteAllSpaces } from \"../../lib/parser.js\";\nimport { createInterface } from \"node:readline/promises\";\nimport { success, error, warning, info, muted } from \"../../lib/color.js\";\n\nfunction prompt(query: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return rl.question(query).finally(() => rl.close());\n}\n\nexport const spacesCommand = new Command(\"spaces\")\n .description(\"List all spaces in .llmkb/spaces.yml\")\n .option(\"--delete-all\", \"Remove all space entries (requires confirmation)\")\n .action(async (opts: { deleteAll?: boolean }) => {\n const projectRoot = findProjectRoot();\n if (!projectRoot) {\n console.log(error(\"No .llmkb/ directory found. Run `llmkb init` first.\"));\n process.exit(1);\n }\n\n const config = await readSpaceConfig(projectRoot);\n if (!config) {\n console.log(warning(\"No .llmkb/spaces.yml found.\"));\n return;\n }\n\n if (opts.deleteAll) {\n console.log(warning(\"This will remove ALL space entries from .llmkb/spaces.yml.\"));\n const ans = await prompt(`${warning(\"Continue? (y/N):\")} `);\n if (ans.toLowerCase() !== \"y\") {\n console.log(muted(\"Aborted.\"));\n return;\n }\n await deleteAllSpaces(projectRoot);\n console.log(success(\"All space entries removed.\"));\n return;\n }\n\n if (config.project_space && config.project_space.length > 0) {\n console.log(info(\"Project space:\"));\n for (const ps of config.project_space) {\n console.log(` ${ps.id}${ps.name ? success(` (${ps.name})`) : \"\"}`);\n }\n }\n\n if (config.spaces && config.spaces.length > 0) {\n console.log(info(\"Additional spaces:\"));\n for (const s of config.spaces) {\n console.log(` ${muted(s.id)}${s.name ? ` (${s.name})` : \"\"}`);\n }\n }\n\n if (\n (!config.project_space || config.project_space.length === 0) &&\n (!config.spaces || config.spaces.length === 0)\n ) {\n console.log(warning(\"No spaces configured.\"));\n }\n });\n","/** ``llmkb update --project-space <id>`` — update the project space id. */\n\nimport { Command } from \"commander\";\nimport { findProjectRoot, updateProjectSpace } from \"../../lib/parser.js\";\nimport { success, error, info } from \"../../lib/color.js\";\n\nexport const updateCommand = new Command(\"update\")\n .description(\"Update the project space in .llmkb/spaces.yml\")\n .requiredOption(\"-p, --project-space <id>\", \"New project space UUID\")\n .action(async (opts: { projectSpace: string }) => {\n const projectRoot = findProjectRoot();\n if (!projectRoot) {\n console.log(error(\"No .llmkb/ directory found. Run `llmkb init` first.\"));\n process.exit(1);\n }\n\n const ok = await updateProjectSpace(projectRoot, opts.projectSpace);\n if (ok) {\n console.log(`${success(\"✔\")} Project space updated to ${info(opts.projectSpace)}.`);\n } else {\n console.log(error(\"Could not update project space in .llmkb/spaces.yml.\"));\n process.exit(1);\n }\n });\n","/** ``llmkb whoami`` — show authenticated user identity and credential status. */\n\nimport { Command } from \"commander\";\nimport { getConfig } from \"../../lib/config.js\";\nimport { getToken } from \"../../lib/credentials.js\";\nimport { success, error, warning, info, muted } from \"../../lib/color.js\";\n\nexport const whoamiCommand = new Command(\"whoami\")\n .description(\"Show current authenticated user and access token status\")\n .action(async () => {\n const config = getConfig();\n\n const token = await getToken();\n if (!token) {\n console.log(error(\"Not logged in.\"));\n console.log(`Run ${info(\"`llmkb login --project-space <id>`\")} to authenticate.`);\n return;\n }\n\n console.log(`${muted(\"Access token:\")} ${success(\"✔ present\")}`);\n\n try {\n const url = `${config.endpoint}/api/v1/auth/me`;\n const res = await fetch(url, {\n method: \"GET\",\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (res.ok) {\n const body = (await res.json()) as {\n data?: { attributes?: { user_id?: string; email?: string; token_status?: string; expires_at?: string | null } };\n };\n const attrs = body.data?.attributes;\n if (attrs) {\n console.log(` ${muted(\"User:\")} ${info(attrs.email ?? attrs.user_id)}`);\n console.log(` ${muted(\"Token status:\")} ${success(attrs.token_status ?? \"active\")}`);\n if (attrs.expires_at) {\n console.log(` ${muted(\"Expires at:\")} ${attrs.expires_at}`);\n }\n }\n } else {\n const statusText = res.status === 401 ? error(\"invalid or expired\") : warning(`server returned ${res.status}`);\n console.log(` ${muted(\"Token status:\")} ${statusText}`);\n console.log(` ${muted(\"Endpoint:\")} ${config.endpoint}`);\n }\n } catch {\n console.log(` ${muted(\"Endpoint:\")} ${warning(config.endpoint + \" (unreachable)\")}`);\n }\n });\n","/** ``llmkb use <space-id>`` — update the project space in .llmkb/spaces.yml. */\n\nimport { Command } from \"commander\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getConfig } from \"../../lib/config.js\";\nimport { getToken } from \"../../lib/credentials.js\";\nimport { findProjectRoot, updateProjectSpace } from \"../../lib/parser.js\";\nimport { readVersionStamp } from \"../../lib/parser.js\";\nimport { PACKAGE_VERSION } from \"../../lib/types.js\";\nimport { success, error, warning, info, muted } from \"../../lib/color.js\";\n\nexport const useCommand = new Command(\"use\")\n .description(\"Set the project space in .llmkb/spaces.yml\")\n .argument(\"<space-id>\", \"Space UUID to set as project space\")\n .action(async (spaceId: string) => {\n const config = getConfig();\n const projectRoot = findProjectRoot();\n\n if (!projectRoot) {\n console.log(error(\"No .llmkb/ directory found. Run `llmkb init` first.\"));\n process.exit(1);\n }\n\n const spacesFile = join(projectRoot, \".llmkb\", \"spaces.yml\");\n if (!existsSync(spacesFile)) {\n console.log(error(\"No .llmkb/spaces.yml found. Run `llmkb init` first.\"));\n process.exit(1);\n }\n\n const stamp = await readVersionStamp(projectRoot);\n if (stamp && stamp !== PACKAGE_VERSION) {\n console.log(warning(` ⚠ Version stamp mismatch (${stamp}). Re-run \\`llmkb init\\` to update.`));\n }\n\n const token = await getToken();\n if (!token) {\n console.log(warning(\"No access token found.\"));\n console.log(`Run ${info(\"`llmkb login --project-space <id>`\")} to authenticate.`);\n }\n\n const url = `${config.endpoint}/api/v1/auth/me`;\n try {\n const res = await fetch(url, {\n method: \"GET\",\n headers: token ? { Authorization: `Bearer ${token}` } : {},\n });\n if (!res.ok) {\n console.log(warning(`Warning: Cannot reach server — returned ${res.status}`));\n }\n } catch {\n console.log(warning(`Warning: Cannot reach ${config.endpoint} — server may be offline`));\n }\n\n const updated = await updateProjectSpace(projectRoot, spaceId);\n if (updated) {\n console.log(`${success(\"✔\")} Project space set to ${info(spaceId)}.`);\n } else {\n console.log(error(\"Failed to update .llmkb/spaces.yml.\"));\n process.exit(1);\n }\n });\n","/** ``llmkb status`` — print version stamps, config info, and access token status. */\n\nimport { Command } from \"commander\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n findProjectRoot,\n readSpaceConfig,\n readVersionStamp,\n} from \"../../lib/parser.js\";\nimport { PACKAGE_VERSION } from \"../../lib/types.js\";\nimport { checkSkillVersions } from \"../../lib/skills.js\";\nimport { getToken } from \"../../lib/credentials.js\";\nimport { success, error, warning, info, muted, badge } from \"../../lib/color.js\";\n\nexport const statusCommand = new Command(\"status\")\n .description(\"Show version stamps, configuration, and access token status\")\n .action(async () => {\n console.log(`${info(\"llmkb status\")}\\n`);\n\n // Package version\n console.log(` ${muted(\"Package version:\")} ${PACKAGE_VERSION}`);\n\n // Access token\n const token = await getToken();\n const tokenStatus = token ? success(\"✔ present\") : error(\"✗ missing\");\n console.log(` ${muted(\"Access token:\")} ${tokenStatus}`);\n\n // Project root detection\n const projectRoot = findProjectRoot();\n if (!projectRoot) {\n console.log(` ${muted(\"Project root:\")} ${warning(\"(not found — run `llmkb init`)\")}`);\n console.log(` ${muted(\"Config version:\")} ${warning(\"(not found)\")}`);\n console.log(` ${muted(\"Skills installed:\")} 0`);\n return;\n }\n console.log(` ${muted(\"Project root:\")} ${projectRoot}`);\n\n // Config version stamp\n const configVersion = await readVersionStamp(projectRoot);\n if (configVersion) {\n const versionOk = configVersion === PACKAGE_VERSION;\n console.log(` ${muted(\"Config version:\")} ${versionOk ? success(configVersion) : warning(configVersion)}`);\n if (!versionOk) {\n console.log(` ${warning(\"⚠ Version mismatch! Re-run `llmkb init` to update config.\")}`);\n }\n } else {\n console.log(` ${muted(\"Config version:\")} ${warning(\"(not found — run `llmkb init`)\")}`);\n }\n\n // Space config summary\n const spaceConfig = await readSpaceConfig(projectRoot);\n if (spaceConfig) {\n if (spaceConfig.project_space && spaceConfig.project_space.length > 0) {\n const ps = spaceConfig.project_space[0]!;\n console.log(` ${muted(\"Project space:\")} ${info(ps.id)}${ps.name ? ` (${ps.name})` : \"\"}`);\n } else {\n console.log(` ${muted(\"Project space:\")} ${warning(\"(not configured)\")}`);\n }\n const spaceCount = spaceConfig.spaces?.length ?? 0;\n console.log(` ${muted(\"Spaces defined:\")} ${spaceCount}`);\n if (spaceCount > 0 && spaceConfig.spaces) {\n console.log(` ${muted(spaceConfig.spaces.map((s) => s.id).join(\", \"))}`);\n }\n } else {\n console.log(` ${muted(\"Project space:\")} ${warning(\"(not configured)\")}`);\n }\n\n // Skill version stamps\n const skillsDir = join(projectRoot, \".claude\", \"skills\", \"llmkb\");\n if (existsSync(skillsDir)) {\n const mismatches = await checkSkillVersions(skillsDir);\n const entryCount = await (\n await import(\"node:fs/promises\")\n )\n .readdir(skillsDir, { withFileTypes: true })\n .then((e) => e.filter((x) => x.isDirectory()).length)\n .catch(() => 0);\n\n console.log(` ${muted(\"Skills installed:\")} ${entryCount}`);\n for (const m of mismatches) {\n console.log(` ${warning(` ${m.name}: ${m.installed} ⚠ mismatch`)}`);\n }\n if (mismatches.length > 0) {\n console.log(` ${warning(\"⚠ Some skills have version mismatches. Re-run `llmkb init`.\")}`);\n }\n } else {\n console.log(` ${muted(\"Skills installed:\")} 0 (run ` + \"`llmkb init`\" + \")\");\n }\n });\n","/** ``llmkb sync <path>`` — upload local files to the configured space.\n\nContent-addressed incremental sync with progress bars, ignore-file\nfiltering, rename detection, and watch mode.\n*/\n\nimport { Command } from \"commander\";\nimport { join } from \"node:path\";\nimport { getConfig } from \"../../lib/config.js\";\nimport { findProjectRoot, readSpaceConfig } from \"../../lib/parser.js\";\nimport {\n readSyncState,\n writeSyncState,\n clearSyncState,\n} from \"../../lib/sync-state.js\";\nimport { runSync, walkFiles } from \"../../lib/sync.js\";\nimport {\n ProgressBar,\n writeJson,\n writeLine,\n writeDetail,\n writeWarning,\n isTTY,\n} from \"../../lib/output.js\";\nimport type { JsonResult } from \"../../lib/output.js\";\nimport type { SyncState, SyncFileEntry } from \"../../lib/types.js\";\nimport { getToken } from \"../../lib/credentials.js\";\nimport { findProjectRoot } from \"../../lib/parser.js\";\nimport { syncRelatedSpaces } from \"../../lib/sync-spaces-config.js\";\nimport { acquireWatchLock, releaseWatchLock } from \"../../lib/watch-lock.js\";\n\n// ---------------------------------------------------------------------------\n// Watch mode (lazy import chokidar)\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_SKIP_PATTERNS = [\n \"node_modules/**\",\n \".git/**\",\n \".llmkb/**\",\n \".claude/**\",\n \".cursor/**\",\n \".next/**\",\n \"dist/**\",\n \".venv/**\",\n \"__pycache__/**\",\n \"*.pyc\",\n \"*.exe\",\n \"*.dll\",\n \"*.so\",\n \"*.dylib\",\n \"*.bin\",\n \"**/__tests__/**\",\n \"**/__snapshots__/**\",\n \"**/test/**\",\n \"**/tests/**\",\n \"**/*.test.*\",\n \"**/*.spec.*\",\n \"**/fixtures/**\",\n \"**/coverage/**\",\n \"*.log\",\n \"tmp/**\",\n \"temp/**\",\n];\n\nasync function startWatch(\n targetPath: string,\n space: string,\n opts: { debounceMs: number; json: boolean; verbose: boolean; debug: boolean },\n): Promise<void> {\n // Acquire watch lock to prevent duplicate watchers\n const projectRoot = findProjectRoot();\n if (projectRoot) {\n const lockReleased = await acquireWatchLock(projectRoot);\n if (!lockReleased) {\n writeLine(\n \"Another watcher is already running. Use --force to override or stop the existing watcher.\",\n \"✖\",\n );\n process.exit(1);\n }\n process.on(\"exit\", () => releaseWatchLock(projectRoot));\n process.on(\"SIGINT\", () => {\n releaseWatchLock(projectRoot);\n process.exit(0);\n });\n process.on(\"SIGTERM\", () => {\n releaseWatchLock(projectRoot);\n process.exit(0);\n });\n }\n\n const chokidar = await import(\"chokidar\");\n const ignore = await import(\"ignore\");\n const { readFile } = await import(\"node:fs/promises\");\n const { existsSync } = await import(\"node:fs\");\n\n // Build ignore filter from .gitignore + .llmkbignore + defaults\n const ig = ignore.default();\n ig.add([\n \"node_modules/**\",\n \".git/**\",\n \".llmkb/**\",\n \".claude/**\",\n \".cursor/**\",\n \".next/**\",\n \"dist/**\",\n \".venv/**\",\n \"__pycache__/**\",\n \"*.pyc\",\n \"*.exe\",\n \"*.dll\",\n \"*.so\",\n \"*.dylib\",\n \"*.bin\",\n ]);\n for (const fn of [\".gitignore\", \".llmkbignore\"]) {\n const fp = join(targetPath, fn);\n if (existsSync(fp)) {\n ig.add(String(await readFile(fp)));\n }\n }\n\n function fmtIgnoreRule(rel: string): string | null {\n // Determine which rule matched by re-checking component patterns\n for (const p of DEFAULT_SKIP_PATTERNS) {\n if (ig.ignores(rel)) return `(${p})`;\n }\n if (/(^|[\\/\\\\])\\../.test(rel)) return \"(dotfile)\";\n return null;\n }\n\n function isWatched(filePath: string): boolean {\n const rel = join(targetPath, filePath);\n const ignored = ig.ignores(rel) || /(^|[\\/\\\\])\\../.test(rel);\n if (ignored && opts.debug) {\n const rule = fmtIgnoreRule(rel);\n writeDetail(`[debug] skip ${rel} ${rule ?? \"\"}`);\n }\n return !ignored;\n }\n\n const watcher = chokidar.watch(targetPath, {\n ignored: (path: string) => !isWatched(path),\n persistent: true,\n ignoreInitial: true,\n });\n\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n const onChange = async (filePath: string) => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(async () => {\n if (opts.debug) writeDetail(`[debug] detected: ${filePath}`);\n try {\n await performSync(targetPath, space, { ...opts, watchEvent: filePath });\n } catch (err) {\n writeLine(`Sync error: ${(err as Error).message}`, \"✖\");\n }\n }, opts.debounceMs);\n };\n\n watcher.on(\"change\", onChange);\n watcher.on(\"add\", onChange);\n watcher.on(\"unlink\", (p: string) => {\n if (opts.verbose) writeDetail(`[watch] removed: ${p}`);\n });\n\n writeLine(\n `Watching ${targetPath} for changes (debounce: ${opts.debounceMs}ms)...`,\n \"⌚\",\n );\n}\n\n// ---------------------------------------------------------------------------\n// Core sync logic\n// ---------------------------------------------------------------------------\n\n/** Run the full sync workflow: validate config, walk, upload, write state, trigger dedup.\n *\n * Exported for testing — internal callers should use the CLI command directly.\n */\nexport async function performSync(\n targetPath: string,\n space: string,\n opts: {\n dryRun?: boolean;\n force?: boolean;\n json?: boolean;\n verbose?: boolean;\n watchEvent?: string;\n },\n): Promise<void> {\n const config = getConfig();\n const endpoint = config.endpoint;\n const projectRoot = findProjectRoot();\n if (!projectRoot) {\n writeLine(\"No .llmkb/ directory found. Run `llmkb init` first.\", \"✖\");\n process.exit(1);\n }\n\n const spaceConfig = await readSpaceConfig(projectRoot);\n const activeSpace = space || spaceConfig?.project_space?.[0]?.id;\n if (!activeSpace) {\n writeLine(\n \"No space specified. Use --space <id> or configure a project space.\",\n \"✖\",\n );\n process.exit(1);\n }\n\n // Check we have an access token\n const token = await getToken();\n if (!token && !opts.dryRun) {\n writeLine(\n `No credentials. Run \\`llmkb login --project-space <id>\\`.`,\n \"✖\",\n );\n process.exit(1);\n }\n\n const startTime = Date.now();\n const syncState: SyncState | null = opts.force\n ? null\n : await readSyncState(projectRoot);\n\n if (opts.force) {\n await clearSyncState(projectRoot);\n }\n\n // Dry-run: just show what would happen\n if (opts.dryRun) {\n const walkResult = await walkFiles({\n projectDir: projectRoot,\n targetDir: targetPath,\n });\n const changes = await import(\"../../lib/sync-state.js\").then((m) =>\n m.getChangedFiles(walkResult.files, syncState),\n );\n\n if (opts.json) {\n writeJson({\n command: \"sync\",\n success: true,\n data: {\n space: activeSpace,\n dryRun: true,\n newFiles: changes.newFiles,\n changedFiles: changes.changedFiles,\n unchangedFiles: changes.unchangedFiles,\n renamed: changes.renamed,\n skipped: walkResult.skipped.map((s) => ({\n path: s.path,\n reason: s.reason,\n })),\n },\n meta: {\n durationMs: Date.now() - startTime,\n totalItems: walkResult.files.length,\n processedItems: changes.newFiles.length + changes.changedFiles.length,\n skippedItems: walkResult.skipped.length,\n renamedItems: changes.renamed.length,\n },\n });\n } else {\n writeLine(`Dry-run for space \"${activeSpace}\":`, \"ℹ\");\n for (const f of changes.newFiles) writeDetail(`[new] ${f}`);\n for (const f of changes.changedFiles) writeDetail(`[changed] ${f}`);\n for (const f of changes.unchangedFiles) writeDetail(`[unchanged] ${f}`);\n for (const r of changes.renamed)\n writeDetail(`[rename] ${r.oldPath} → ${r.newPath}`);\n for (const s of walkResult.skipped)\n writeDetail(`[skip] ${s.path} (${s.reason})`);\n writeLine(\n `${changes.newFiles.length} new, ${changes.changedFiles.length} changed, ` +\n `${changes.unchangedFiles.length} unchanged, ${changes.renamed.length} renamed, ` +\n `${walkResult.skipped.length} skipped`,\n );\n }\n return;\n }\n\n // Walk files once — reused for progress bar and state writing (Gap 19 fix)\n const filesResult = await walkFiles({\n projectDir: projectRoot,\n targetDir: targetPath,\n });\n const totalFiles = filesResult.files.length;\n const bar =\n isTTY() && !opts.json\n ? new ProgressBar({ total: totalFiles || 1, label: \"Syncing\" })\n : null;\n\n const result = await runSync(activeSpace, syncState, {\n path: targetPath,\n onFile: (_relPath, _status) => {\n bar?.increment();\n },\n });\n\n bar?.stop();\n\n // Nothing to upload — show tailored message based on root cause\n if (result.uploaded === 0 && result.errors.length === 0) {\n if (opts.json) {\n writeJson({\n command: \"sync\",\n success: true,\n data: result,\n meta: { durationMs: Date.now() - startTime },\n });\n } else {\n const { status, reason, unchanged, renamed, skipped } = result;\n if (status === \"no_files\") {\n writeWarning(reason ?? \"No files to sync.\");\n } else if (unchanged === 0 && renamed === 0 && skipped === 0) {\n // No walk result at all (edge case: empty directory)\n writeWarning(\"No files found in sync target. The directory appears to be empty.\");\n } else {\n writeLine(\n `No changes detected — all files up to date (${unchanged} unchanged, ${renamed} renamed, ${skipped} skipped).`,\n \"✔\",\n );\n }\n }\n return;\n }\n\n // Write sync state using the files we already walked — no second walk needed\n const newState: SyncState = {\n space: activeSpace,\n lastSyncAt: new Date().toISOString(),\n files: {},\n };\n for (const [relPath, absPath] of filesResult.files) {\n try {\n const hash = await import(\"../../lib/sync-state.js\").then((m) =>\n m.computeSha256(absPath),\n );\n newState.files[relPath] = {\n sha256: hash,\n lastUploaded: new Date().toISOString(),\n status: \"synced\" as const,\n };\n } catch {\n // Skip files that can't be hashed (e.g. directories, deleted files)\n // — they'll be re-synced on next run\n }\n }\n await writeSyncState(projectRoot, newState);\n\n // Trigger server-side entity dedup after sync (Gap 17 fix)\n if (token) {\n triggerDedup(endpoint, activeSpace, token).catch((err) => {\n if (opts.json) {\n writeJson({\n command: \"dedup\",\n success: false,\n data: null,\n error: (err as Error).message,\n });\n } else if (opts.verbose) {\n writeDetail(`Dedup skipped: ${(err as Error).message}`);\n }\n // Non-blocking — dedup is best-effort post-sync\n });\n }\n\n // LS-4: Sync related spaces from backend to .llmkb/spaces.yml\n if (projectRoot && token) {\n const syncSpacesResult = await syncRelatedSpaces(projectRoot, endpoint, token).catch(() => null);\n if (opts.verbose && syncSpacesResult && syncSpacesResult.added > 0) {\n writeDetail(`Related spaces: ${syncSpacesResult.added} new space(s) synced to spaces.yml`);\n }\n }\n\n const duration = Date.now() - startTime;\n\n if (opts.json) {\n writeJson({\n command: \"sync\",\n success: result.errors.length === 0,\n data: result,\n meta: {\n durationMs: duration,\n totalItems:\n result.uploaded +\n result.unchanged +\n result.skipped +\n result.renamed +\n result.errors.length,\n processedItems: result.uploaded,\n skippedItems: result.skipped,\n renamedItems: result.renamed,\n },\n });\n } else {\n writeLine(\n `Sync complete: ${result.uploaded} uploaded, ${result.unchanged} unchanged, ` +\n `${result.skipped} skipped, ${result.renamed} renamed, ${result.errors.length} errors (${duration}ms)`,\n \"✔\",\n );\n }\n\n // Print ingestion job URL if batch sync created one\n if (result.ingestionJobUrl && !opts.json) {\n writeLine(`Ingestion job: ${result.ingestionJobUrl}`, \"ℹ\");\n }\n\n if (result.errors.length > 0 && !opts.json) {\n for (const e of result.errors) {\n writeDetail(`✖ ${e.path}: ${e.error}`);\n }\n process.exitCode = 1;\n }\n}\n\n/** Trigger server-side entity dedup for the space after sync completes.\n *\n * The backend mounts v1 routers at /api with sub-routers at /spaces/,\n * so the full path is /api/spaces/{space_name}/dedup.\n * Non-blocking — dedup is best-effort post-sync.\n */\nasync function triggerDedup(\n endpoint: string,\n space: string,\n token: string,\n): Promise<void> {\n const url = `${endpoint}/api/spaces/${encodeURIComponent(space)}/dedup`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"unknown\");\n throw new Error(`Dedup failed (${res.status}): ${body}`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Command\n// ---------------------------------------------------------------------------\n\nexport const syncCommand = new Command(\"sync\")\n .description(\"Sync local files to an llmkb space\")\n .argument(\"[path]\", \"Directory or file to sync\", \".\")\n .option(\"-s, --space <id>\", \"Space UUID (overrides project_space)\")\n .option(\"-n, --dry-run\", \"Show what would be uploaded without uploading\")\n .option(\"-f, --force\", \"Re-upload everything, bypassing cache\")\n .option(\"-w, --watch\", \"Watch for file changes and auto-sync\")\n .option(\"--debounce <ms>\", \"Watch debounce in ms\", \"300\")\n .option(\"--json\", \"Output JSON for machine parsing\")\n .option(\"--verbose\", \"Detailed output including skipped files\")\n .option(\n \"--debug\",\n \"Show all events including ignored files with matching rule\",\n )\n .action(\n async (\n path: string,\n opts: {\n space?: string;\n dryRun?: boolean;\n force?: boolean;\n watch?: boolean;\n debounce: string;\n json?: boolean;\n verbose?: boolean;\n debug?: boolean;\n },\n ) => {\n try {\n const resolvedSpace = opts.space ?? \"\";\n\n if (opts.watch) {\n await startWatch(path, resolvedSpace, {\n debounceMs: parseInt(opts.debounce, 10) || 300,\n json: opts.json ?? false,\n verbose: opts.verbose ?? false,\n debug: opts.debug ?? false,\n });\n return;\n }\n\n await performSync(path, resolvedSpace, {\n dryRun: opts.dryRun,\n force: opts.force,\n json: opts.json,\n verbose: opts.verbose,\n });\n } catch (err) {\n if (opts.json) {\n writeJson({\n command: \"sync\",\n success: false,\n data: null,\n error: (err as Error).message,\n });\n } else {\n writeLine(`Error: ${(err as Error).message}`, \"✖\");\n }\n process.exit(1);\n }\n },\n );\n","/** File sync engine for ``llmkb sync``.\n\nWalks a directory, applies ``.gitignore`` + ``.llmkbignore`` filtering,\ncomputes SHA256 hashes, uploads new/changed files via TUS, and detects\nrenames by content identity.\n\nBatch ingestion: Creates one ``IngestionJob`` upfront, uploads all files\ninto it via ``/complete?postpone_ingestion=true&ingestion_job_id=``, then\nprints the job URL for the user to track progress in the UI.\n*/\n\nimport { readdir, stat as fsStat, readFile } from \"node:fs/promises\";\nimport { join, relative, resolve } from \"node:path\";\nimport ignore from \"ignore\";\nimport * as tus from \"tus-js-client\";\nimport { existsSync } from \"node:fs\";\nimport { getConfig } from \"./config.js\";\nimport { getToken } from \"./credentials.js\";\nimport { readSpaceConfig } from \"./parser.js\";\nimport { computeSha256 } from \"./sync-state.js\";\nimport { findProjectRoot } from \"./parser.js\";\nimport type { SyncState, FileChangeSet } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst IGNORE_FILES = [\".gitignore\", \".llmkbignore\"] as const;\n\n/** Default patterns always skipped (binary, hidden dirs, large artifacts, test artifacts).\n *\n * Python-side mirror at ``api/app/mcp/tools/entity_filter.py`` in the llmkb-ai repo.\n * Keep both lists in sync. */\nconst DEFAULT_SKIP_PATTERNS = [\n \"node_modules/**\",\n \".git/**\",\n \".llmkb/**\",\n \".claude/**\",\n \".cursor/**\",\n \".next/**\",\n \"dist/**\",\n \".venv/**\",\n \"__pycache__/**\",\n \"*.pyc\",\n \"*.exe\",\n \"*.dll\",\n \"*.so\",\n \"*.dylib\",\n \"*.bin\",\n // Test & ephemeral artifacts — exclude by default to avoid polluting\n // the knowledge graph with test fixtures, snapshots, and build artifacts.\n \"**/__tests__/**\",\n \"**/__snapshots__/**\",\n \"**/test/**\",\n \"**/tests/**\",\n \"**/*.test.*\",\n \"**/*.spec.*\",\n \"**/fixtures/**\",\n \"**/coverage/**\",\n \"*.log\",\n \"tmp/**\",\n \"temp/**\",\n];\n\n// ---------------------------------------------------------------------------\n// File Walking\n// ---------------------------------------------------------------------------\n\nexport interface WalkOptions {\n /** Project root directory (for ignore file lookup). */\n projectDir: string;\n /** Target directory to walk (defaults to projectDir). */\n targetDir?: string;\n /** Whether to respect .gitignore. */\n respectGitignore?: boolean;\n /** Whether to respect .llmkbignore. */\n respectLlmkbignore?: boolean;\n}\n\nexport interface WalkResult {\n files: Array<[string, string]>; // [relativePath, absolutePath]\n skipped: Array<{ path: string; reason: string }>;\n}\n\n/** Build an ignore filter from .gitignore, .llmkbignore, and default patterns.\n\nReads ignore files from the project root first, then from the target\ndirectory — patterns from either source are applied.\n*/\nasync function buildFilter(\n projectDir: string,\n targetDir: string,\n respectGitignore: boolean,\n respectLlmkbignore: boolean,\n): Promise<(path: string) => boolean> {\n const ig = ignore().add(DEFAULT_SKIP_PATTERNS);\n\n const searchDirs = [projectDir, targetDir];\n const seen = new Set<string>();\n\n for (const baseDir of searchDirs) {\n for (const fileName of IGNORE_FILES) {\n const shouldRespect =\n fileName === \".gitignore\" ? respectGitignore : respectLlmkbignore;\n if (!shouldRespect) continue;\n\n const filePath = join(baseDir, fileName);\n if (seen.has(filePath)) continue;\n seen.add(filePath);\n\n if (existsSync(filePath)) {\n // Skip directories that collide with ignore-file names\n const st = await fsStat(filePath);\n if (!st.isFile()) continue;\n const content = await readFile(filePath, \"utf-8\");\n ig.add(content);\n }\n }\n }\n\n return (testPath: string) => ig.ignores(testPath);\n}\n\n/** Recursively walk a directory, returning files filtered by ignore rules. */\nexport async function walkFiles(\n opts: WalkOptions,\n): Promise<WalkResult> {\n const projectDir = resolve(opts.projectDir);\n const targetDir = resolve(opts.targetDir ?? projectDir);\n const respectGitignore = opts.respectGitignore ?? true;\n const respectLlmkbignore = opts.respectLlmkbignore ?? true;\n\n const isIgnored = await buildFilter(projectDir, targetDir, respectGitignore, respectLlmkbignore);\n const files: Array<[string, string]> = [];\n const skipped: Array<{ path: string; reason: string }> = [];\n\n async function walk(dir: string): Promise<void> {\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n skipped.push({ path: relative(targetDir, dir), reason: \"unreadable\" });\n return;\n }\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n const relPath = relative(targetDir, fullPath);\n\n if (entry.name.startsWith(\".\") && !IGNORE_FILES.includes(entry.name as typeof IGNORE_FILES[number])) {\n skipped.push({ path: relPath, reason: \"hidden\" });\n continue;\n }\n\n if (isIgnored(relPath)) {\n skipped.push({ path: relPath, reason: \"ignored\" });\n continue;\n }\n\n if (entry.isDirectory()) {\n // Recurse into directories\n await walk(fullPath);\n } else if (entry.isFile()) {\n files.push([relPath, fullPath]);\n } else if (entry.isSymbolicLink()) {\n // Follow symlinks — stat to verify it's a file, not a dir symlink\n try {\n const st = await fsStat(fullPath);\n if (st.isFile()) {\n files.push([relPath, fullPath]);\n } else {\n skipped.push({ path: relPath, reason: \"symlink-to-dir\" });\n }\n } catch {\n skipped.push({ path: relPath, reason: \"broken-symlink\" });\n }\n } else {\n skipped.push({ path: relPath, reason: \"not-a-file\" });\n }\n }\n }\n\n await walk(targetDir);\n return { files, skipped };\n}\n\n// ---------------------------------------------------------------------------\n// TUS Upload\n// ---------------------------------------------------------------------------\n\nexport interface UploadOptions {\n /** Target space name. */\n space: string;\n /** Relative path of the file within the space. */\n relativePath: string;\n /** Absolute path to the file on disk. */\n absolutePath: string;\n /** llmkb API endpoint. */\n endpoint: string;\n /** Auth token. */\n token: string;\n /** Upload progress callback. */\n onProgress?: (bytesSent: number, bytesTotal: number) => void;\n}\n\n/** Upload a single file via TUS protocol (chunks only, no finalization). Returns the upload URL. */\nexport async function tusUpload(\n opts: UploadOptions,\n): Promise<string> {\n // Safety check: verify it's a file, not a directory\n const st = await fsStat(opts.absolutePath);\n if (!st.isFile()) {\n throw new Error(`Not a file: ${opts.relativePath}`);\n }\n const fileBuffer = await readFile(opts.absolutePath);\n const fileName = opts.relativePath.split(\"/\").pop() ?? opts.relativePath;\n\n return new Promise<string>((resolve, reject) => {\n const upload = new tus.Upload(\n fileBuffer,\n {\n endpoint: `${opts.endpoint}/api/spaces/${opts.space}/uploads`,\n metadata: {\n filename: opts.relativePath,\n filetype: \"application/octet-stream\",\n },\n headers: {\n Authorization: `Bearer ${opts.token}`,\n },\n chunkSize: 5 * 1024 * 1024, // 5 MB chunks\n retryDelays: [0, 1000, 3000, 5000],\n removeFingerprintOnSuccess: true,\n onError: (err: Error) => reject(err),\n onProgress: (bytesSent: number, bytesTotal: number) => {\n opts.onProgress?.(bytesSent, bytesTotal);\n },\n onSuccess: () => {\n resolve(upload.url ?? \"\");\n },\n },\n );\n upload.start();\n });\n}\n\n/** Finalize a TUS upload by calling /complete. Returns the upload URL on success. */\nexport async function finalizeUpload(\n uploadUrl: string,\n token: string,\n ingestionJobId?: string,\n): Promise<string> {\n const params = new URLSearchParams({ postpone_ingestion: \"true\" });\n if (ingestionJobId) {\n params.set(\"ingestion_job_id\", ingestionJobId);\n }\n const completeUrl = `${uploadUrl}/complete?${params.toString()}`;\n const res = await fetch(completeUrl, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Tus-Resumable\": \"1.0.0\",\n },\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n const shortId = uploadUrl.split(\"/\").pop() ?? \"unknown\";\n throw new Error(`Upload completion failed for ${shortId} (${res.status}): ${body}`);\n }\n return uploadUrl;\n}\n\n// ---------------------------------------------------------------------------\n// Sync Engine\n// ---------------------------------------------------------------------------\n\nexport interface SyncOptions {\n /** Path to sync (directory or file). */\n path: string;\n /** Comma-separated list of skip reasons to ignore (for --dry-run filtering). */\n skipReasons?: string[];\n /** Callback for each file upload attempt. */\n onFile?: (relPath: string, status: \"uploading\" | \"skipped\" | \"renamed\" | \"unchanged\" | \"failed\", detail?: string) => void;\n}\n\nexport interface SyncResult {\n uploaded: number;\n skipped: number;\n unchanged: number;\n renamed: number;\n errors: Array<{ path: string; error: string }>;\n /** Ingestion job ID(s) after batch finalization. */\n ingestionJobIds?: string[];\n /** URL of the first ingestion job (for the sync command to display). */\n ingestionJobUrl?: string;\n /** Machine-readable outcome: \"synced\" | \"no_files\" | \"up_to_date\". */\n status?: \"synced\" | \"no_files\" | \"up_to_date\";\n /** Human-readable explanation when status is not \"synced\". */\n reason?: string;\n}\n\n/** Run the full sync: walk -> compare -> upload -> update state. */\nexport async function runSync(\n space: string,\n syncState: SyncState | null,\n opts: SyncOptions,\n): Promise<SyncResult> {\n const projectRoot = findProjectRoot();\n if (!projectRoot) throw new Error(\"No .llmkb/ directory found. Run `llmkb init` first.\");\n\n const config = getConfig();\n const endpoint = config.endpoint;\n const token = await getToken();\n\n const result: SyncResult = { uploaded: 0, skipped: 0, unchanged: 0, renamed: 0, errors: [] };\n\n // Walk files\n const walkResult = await walkFiles({\n projectDir: projectRoot,\n targetDir: resolve(opts.path),\n });\n\n for (const s of walkResult.skipped) {\n result.skipped++;\n opts.onFile?.(s.path, \"skipped\", s.reason);\n }\n\n if (walkResult.files.length === 0) {\n result.status = \"no_files\";\n const filteredCount = walkResult.skipped.length;\n if (filteredCount > 0) {\n result.reason = `No files to sync — all ${filteredCount} file(s) were filtered out by .gitignore / .llmkbignore rules.`;\n } else {\n result.reason = \"No files found in sync target. The directory appears to be empty.\";\n }\n return result;\n }\n\n // Classify files\n const changes = await import(\"./sync-state.js\").then((m) =>\n m.getChangedFiles(walkResult.files, syncState),\n );\n\n // Process unchanged\n for (const f of changes.unchangedFiles) {\n result.unchanged++;\n opts.onFile?.(f, \"unchanged\");\n }\n\n // Process renamed\n for (const r of changes.renamed) {\n result.renamed++;\n opts.onFile?.(r.newPath, \"renamed\", `${r.oldPath} → ${r.newPath}`);\n }\n\n // Upload new + changed — collect upload URLs for batch finalization\n const toUpload = [...changes.newFiles, ...changes.changedFiles];\n if (toUpload.length === 0) {\n result.status = \"up_to_date\";\n result.reason = `No changes detected — all files are up to date (${walkResult.files.length} files, unchanged: ${result.unchanged}, renamed: ${result.renamed}, skipped: ${result.skipped}).`;\n return result;\n }\n const uploadUrls: string[] = [];\n const ingestionJobId: string | undefined = undefined;\n // No pre-flight job creation — start_ingestion_batch on the backend\n // handles job creation and document association. Passing undefined as\n // ingestionJobId means /complete sets ingestion_job_id=NULL, and the\n // batch endpoint picks up all pending docs regardless.\n\n for (const relPath of toUpload) {\n const absPath = join(resolve(opts.path), relPath);\n\n if (!token) {\n result.errors.push({ path: relPath, error: \"No token found\" });\n opts.onFile?.(relPath, \"failed\", \"no token\");\n continue;\n }\n\n try {\n const absEntry = walkResult.files.find(([, a]) => a === absPath);\n const absPathResolved = absEntry?.[1] ?? absPath;\n const url = await tusUpload({\n space,\n relativePath: relPath,\n absolutePath: absPathResolved,\n endpoint,\n token,\n });\n uploadUrls.push(url);\n result.uploaded++;\n opts.onFile?.(relPath, \"uploading\");\n } catch (err) {\n result.errors.push({ path: relPath, error: (err as Error).message });\n opts.onFile?.(relPath, \"failed\", (err as Error).message);\n }\n }\n\n // Finalize all uploads into the pre-created job\n if (uploadUrls.length > 0) {\n for (const url of uploadUrls) {\n try {\n await finalizeUpload(url, token!, ingestionJobId);\n } catch (err) {\n const shortId = url.split(\"/\").pop() ?? \"unknown\";\n result.errors.push({ path: shortId, error: (err as Error).message });\n opts.onFile?.(shortId, \"failed\", (err as Error).message);\n }\n }\n // Trigger the ingestion pipeline for all finalized documents\n if (token) {\n try {\n const ingestRes = await fetch(\n `${endpoint}/api/spaces/${space}/uploads/start-ingest`,\n {\n method: \"POST\",\n headers: { Authorization: `Bearer ${token}` },\n },\n );\n if (ingestRes.ok) {\n const ingestBody = (await ingestRes.json()) as {\n data?: { attributes?: { job_id?: string; url?: string } };\n };\n // Use the real job URL from the batch endpoint (more accurate\n // than the pre-flight placeholder URL).\n const realUrl = ingestBody.data?.attributes?.url;\n if (realUrl) {\n result.ingestionJobUrl = realUrl;\n }\n }\n } catch {\n // Non-fatal — documents are stored, ingestion can be triggered manually\n }\n }\n }\n\n result.status = \"synced\";\n return result;\n}\n","/** Output formatting for sync and query commands.\n\nAuto-detects TTY vs pipe output. In TTY mode, renders progress bars\nusing ``cli-progress`` and colored output. In pipe/JSON mode, writes\nstructured JSON.\n*/\n\nimport { stdout } from \"node:process\";\nimport cliProgress from \"cli-progress\";\nimport { success, error, warning, info, muted, label as colorLabel } from \"./color.js\";\n\n// ---------------------------------------------------------------------------\n// TTY detection\n// ---------------------------------------------------------------------------\n\n/** Whether the current output stream is a TTY (interactive terminal). */\nexport function isTTY(): boolean {\n return stdout.isTTY ?? false;\n}\n\n// ---------------------------------------------------------------------------\n// Progress bar (TTY mode)\n// ---------------------------------------------------------------------------\n\nexport interface ProgressBarOptions {\n /** Total number of items to process. */\n total: number;\n /** Label shown in the progress bar. */\n label?: string;\n}\n\n/** A thin wrapper around cli-progress for sync operations. */\nexport class ProgressBar {\n private bar: cliProgress.SingleBar | null = null;\n private label: string;\n\n constructor(opts: ProgressBarOptions) {\n this.label = opts.label ?? \"Progress\";\n if (isTTY()) {\n this.bar = new cliProgress.SingleBar(\n {\n format:\n `{label} [{bar}] {percentage}% | {value}/{total} | {eta_formatted}`,\n barCompleteChar: \"█\",\n barIncompleteChar: \"░\",\n hideCursor: true,\n },\n cliProgress.Presets.shades_classic,\n );\n this.bar.start(opts.total, 0, { label: this.label });\n }\n }\n\n /** Advance the progress bar by one step. */\n increment(): void {\n if (this.bar) this.bar.increment();\n }\n\n /** Set the current value directly. */\n update(value: number): void {\n if (this.bar) this.bar.update(value);\n }\n\n /** Finalise the progress bar. */\n stop(): void {\n if (this.bar) this.bar.stop();\n }\n}\n\n// ---------------------------------------------------------------------------\n// JSON output mode\n// ---------------------------------------------------------------------------\n\n/** A stable schema for ``--json`` output from sync and query commands. */\nexport interface JsonResult {\n command: string;\n success: boolean;\n data: unknown;\n meta?: {\n durationMs: number;\n totalItems?: number;\n processedItems?: number;\n skippedItems?: number;\n renamedItems?: number;\n };\n error?: string;\n}\n\n/** Write a JSON result to stdout (used in ``--json`` mode). */\nexport function writeJson(result: JsonResult): void {\n stdout.write(JSON.stringify(result, null, 2) + \"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Line output (TTY mode)\n// ---------------------------------------------------------------------------\n\n/** Write a status line with optional icon (auto-colored by icon type). */\nexport function writeLine(message: string, icon?: string): void {\n if (icon) {\n stdout.write(`${colorLabel(icon, message)}\\n`);\n } else {\n stdout.write(`${message}\\n`);\n }\n}\n\n/** Write an indented detail line (dimmed for visual hierarchy). */\nexport function writeDetail(message: string): void {\n stdout.write(` ${muted(message)}\\n`);\n}\n\n/** Write a success line with green checkmark. */\nexport function writeSuccess(message: string): void {\n stdout.write(`${success(\"✔\")} ${success(message)}\\n`);\n}\n\n/** Write an error line with red cross. */\nexport function writeError(message: string): void {\n stdout.write(`${error(\"✖\")} ${error(message)}\\n`);\n}\n\n/** Write a warning line with yellow warning sign. */\nexport function writeWarning(message: string): void {\n stdout.write(`${warning(\"⚠\")} ${warning(message)}\\n`);\n}\n\n/** Write an info line with cyan info symbol. */\nexport function writeInfo(message: string): void {\n stdout.write(`${info(\"ℹ\")} ${info(message)}\\n`);\n}\n","/** Advisory file lock for chokidar watch mode.\n\nPrevents duplicate watchers in the same project. Uses a simple PID-file\npattern: writes the current PID to ``.llmkb/.watch.lock`` and checks\nliveness of the owning process before granting the lock.\n*/\n\nimport { writeFile, readFile, unlink } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\n\nconst LOCK_FILE = \".llmkb/.watch.lock\";\n\n/**\n * Acquire an advisory watch lock.\n *\n * Returns ``true`` if the lock was acquired (or if no project root was found).\n * Returns ``false`` if another watcher holds the lock and its PID is still alive.\n */\nexport async function acquireWatchLock(projectRoot: string): Promise<boolean> {\n if (!projectRoot) return true;\n const lockPath = join(projectRoot, LOCK_FILE);\n\n if (existsSync(lockPath)) {\n try {\n const content = await readFile(lockPath, \"utf-8\");\n const pid = parseInt(content.trim(), 10);\n\n if (Number.isFinite(pid) && pid > 0) {\n try {\n // Check if process is alive (ESRCH = dead, EPERM = alive but cross-user)\n process.kill(pid, 0);\n // Process is alive — lock is held\n return false;\n } catch (e) {\n // ESRCH means process is gone — we can take the lock\n if ((e as NodeJS.ErrnoException).code !== \"ESRCH\") {\n return false;\n }\n }\n }\n } catch {\n // Unreadable or corrupt lock — allow override\n }\n }\n\n await writeFile(lockPath, String(process.pid), \"utf-8\");\n return true;\n}\n\n/**\n * Release the advisory watch lock.\n */\nexport async function releaseWatchLock(projectRoot: string): Promise<void> {\n if (!projectRoot) return;\n const lockPath = join(projectRoot, LOCK_FILE);\n\n try {\n // Only unlink if we still own it\n if (existsSync(lockPath)) {\n const content = await readFile(lockPath, \"utf-8\");\n if (content.trim() === String(process.pid)) {\n await unlink(lockPath);\n }\n }\n } catch {\n // Best-effort cleanup\n }\n}\n\n/**\n * Check whether a watch lock currently exists.\n */\nexport function hasWatchLock(projectRoot: string): boolean {\n if (!projectRoot) return false;\n return existsSync(join(projectRoot, LOCK_FILE));\n}\n","/** ``llmkb query <text>`` — search an llmkb space over HTTP API.\n\nCalls the FastAPI search endpoint directly (not MCP SDK over stdio),\navoiding the 2-3s overhead of Docker exec per query.\n*/\n\nimport { Command } from \"commander\";\nimport { getConfig } from \"../../lib/config.js\";\nimport { findProjectRoot, readSpaceConfig } from \"../../lib/parser.js\";\nimport { getToken } from \"../../lib/credentials.js\";\nimport { writeJson, writeLine, writeDetail, isTTY } from \"../../lib/output.js\";\nimport type { JsonResult } from \"../../lib/output.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface SearchResult {\n id: string;\n path: string;\n title: string;\n score: number;\n excerpt?: string;\n matchType: \"keyword\" | \"vector\" | \"graph\" | \"fuzzy\";\n}\n\nexport interface SearchResponse {\n data: SearchResult[];\n meta: {\n total: number;\n query: string;\n space: string;\n durationMs: number;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Search\n// ---------------------------------------------------------------------------\n\nasync function search(\n space: string,\n query: string,\n endpoint: string,\n token: string,\n limit: number,\n): Promise<SearchResponse> {\n const url = `${endpoint}/api/v1/${space}/search?q=${encodeURIComponent(query)}&limit=${limit}`;\n const res = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: \"application/json\",\n },\n });\n\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`Search failed (${res.status}): ${body}`);\n }\n\n return (await res.json()) as SearchResponse;\n}\n\n// ---------------------------------------------------------------------------\n// Command\n// ---------------------------------------------------------------------------\n\nexport const queryCommand = new Command(\"query\")\n .description(\"Search an llmkb space and print ranked results\")\n .argument(\"<text>\", \"Search query text\")\n .option(\"-s, --space <id>\", \"Space UUID (overrides project_space)\")\n .option(\"-n, --limit <count>\", \"Max results\", \"10\")\n .option(\"--json\", \"Output JSON for machine parsing\")\n .action(async (text: string, opts: { space?: string; limit: string; json?: boolean }) => {\n const startTime = Date.now();\n const config = getConfig();\n\n try {\n const projectRoot = findProjectRoot();\n let endpoint = config.endpoint;\n let token: string | null = null;\n let activeSpace: string | null | undefined = opts.space;\n\n // Try to resolve from project config\n if (projectRoot) {\n const spaceConfig = await readSpaceConfig(projectRoot);\n if (spaceConfig) {\n activeSpace = activeSpace ?? spaceConfig.project_space?.[0]?.id;\n }\n }\n\n token = await getToken();\n if (!token) {\n throw new Error(\n \"No access token found. Set LLMKB_ACCESS_TOKEN env var or run \" +\n \"`llmkb login --project-space <id>`.\",\n );\n }\n\n const limit = parseInt(opts.limit, 10) || 10;\n const result = await search(activeSpace ?? \"\", text, endpoint, token, limit);\n\n if (opts.json) {\n writeJson({\n command: \"query\",\n success: true,\n data: result.data,\n meta: {\n durationMs: Date.now() - startTime,\n totalItems: result.meta.total,\n processedItems: result.data.length,\n },\n });\n } else {\n writeLine(`Search results for \"${text}\" in \"${activeSpace}\" (${result.meta.total} total):`, \"ℹ\");\n for (const r of result.data) {\n writeLine(`[${r.score.toFixed(2)}] ${r.title}`, \"●\");\n writeDetail(`${r.path} (${r.matchType})`);\n if (r.excerpt) writeDetail(r.excerpt);\n }\n writeDetail(`Completed in ${Date.now() - startTime}ms`);\n }\n } catch (err) {\n if (opts.json) {\n writeJson({\n command: \"query\",\n success: false,\n data: null,\n error: (err as Error).message,\n meta: { durationMs: Date.now() - startTime },\n });\n } else {\n writeLine(`Error: ${(err as Error).message}`, \"✖\");\n }\n process.exit(1);\n }\n });\n","/** ``llmkb doctor`` — run all configuration and permission checks. */\n\nimport { Command } from \"commander\";\nimport { getConfig } from \"../../lib/config.js\";\nimport { getToken } from \"../../lib/credentials.js\";\nimport { findProjectRoot, readSpaceConfig } from \"../../lib/parser.js\";\nimport {\n validateConfigYml,\n validateSpacesYml,\n validateAccessToken,\n checkBackendConnectivity,\n checkSpaceAccess,\n type ValidationResult,\n} from \"../../lib/config-validation.js\";\nimport type { SpaceConfig } from \"../../lib/types.js\";\nimport { syncRelatedSpaces } from \"../../lib/sync-spaces-config.js\";\nimport { success, error, warning, info, muted, highlight } from \"../../lib/color.js\";\n\nasync function report(label: string, result: ValidationResult): Promise<void> {\n const icon = result.passed ? success(\"✔\") : error(\"✖\");\n const msg = result.passed ? success(result.message) : error(result.message);\n console.log(` ${icon} ${label}: ${msg}`);\n if (result.detail) {\n console.log(` ${muted(result.detail)}`);\n }\n}\n\n/** Build a display map from space id → name from the local config. */\nfunction spaceNameMap(config: SpaceConfig): Record<string, string> {\n const map: Record<string, string> = {};\n for (const ps of config.project_space ?? []) {\n if (ps.name) map[ps.id] = ps.name;\n }\n for (const s of config.spaces ?? []) {\n if (s.name) map[s.id] = s.name;\n }\n return map;\n}\n\n/** Format a space id with its name if available. */\nfunction formatSpaceId(spaceId: string, nameMap: Record<string, string>): string {\n const name = nameMap[spaceId];\n return name ? `${spaceId} (${info(name)})` : muted(spaceId);\n}\n\nexport const doctorCommand = new Command(\"doctor\")\n .description(\"Diagnose configuration and permission issues\")\n .action(async () => {\n const config = getConfig();\n const endpoint = config.endpoint;\n\n console.log(`${info(\"llmkb doctor\")} ${muted(\"— diagnostic report\")}\\n`);\n\n const projectRoot = findProjectRoot();\n if (!projectRoot) {\n console.log(` ${error(\"✖ Project root: No .llmkb/ directory found.\")}`);\n console.log(` ${info(\"Run `llmkb init` to create one.\")}`);\n return;\n }\n console.log(` ${success(\"✔\")} ${muted(\"Project root:\")} ${projectRoot}\\n`);\n\n console.log(muted(\"1. Config file checks\"));\n const configResult = await validateConfigYml(projectRoot);\n await report(\"config.yml\", configResult);\n\n const spaceConfig = await readSpaceConfig(projectRoot);\n const spacesResult = await validateSpacesYml(projectRoot);\n await report(\"spaces.yml\", spacesResult);\n\n console.log(`\\n${muted(\"2. Backend connectivity\")}`);\n const connectivityResult = await checkBackendConnectivity(endpoint);\n await report(\"Backend\", connectivityResult);\n\n console.log(`\\n${muted(\"3. Authentication\")}`);\n const tokenResult = await validateAccessToken(endpoint);\n await report(\"Access token\", tokenResult);\n\n // LD-1: Sync related spaces from backend to .llmkb/spaces.yml\n if (tokenResult.passed && projectRoot && spaceConfig?.project_space?.length) {\n const token = await getToken();\n if (token) {\n const syncResult = await syncRelatedSpaces(projectRoot, endpoint, token);\n const parts: string[] = [];\n if (syncResult.added > 0) parts.push(`added ${syncResult.added}`);\n if (syncResult.removed > 0) parts.push(`removed ${syncResult.removed}`);\n if (syncResult.alreadyPresent > 0) parts.push(`${syncResult.alreadyPresent} already configured`);\n if (parts.length > 0) {\n console.log(` ${info(`ℹ Related spaces synced: ${parts.join(\", \")}.`)}`);\n }\n }\n }\n\n console.log(`\\n${muted(\"4. Space access\")}`);\n if (tokenResult.passed) {\n const token = await getToken();\n const nameMap = spaceConfig ? spaceNameMap(spaceConfig) : {};\n\n // Collect all space IDs with their type (project vs additional)\n type SpaceEntry = { id: string; isProject: boolean };\n const allSpaces: SpaceEntry[] = [];\n\n if (spaceConfig?.project_space) {\n for (const ps of spaceConfig.project_space) {\n allSpaces.push({ id: ps.id, isProject: true });\n }\n }\n if (spaceConfig?.spaces) {\n for (const s of spaceConfig.spaces) {\n if (!allSpaces.find((e) => e.id === s.id)) {\n allSpaces.push({ id: s.id, isProject: false });\n }\n }\n }\n\n if (allSpaces.length > 0) {\n for (const entry of allSpaces) {\n const accessResult = await checkSpaceAccess(endpoint, entry.id, token!, entry.isProject);\n const label = entry.isProject\n ? `${highlight(\"★ PROJECT\")} ${formatSpaceId(entry.id, nameMap)}`\n : formatSpaceId(entry.id, nameMap);\n await report(label, accessResult);\n }\n } else {\n console.log(` ${info(\"ℹ No spaces configured. Run `llmkb add --space <id>`.\")}`);\n }\n } else {\n console.log(` ${warning(\"⚠ Skipping space access checks — not authenticated.\")}`);\n }\n\n console.log(`\\n${success(\"Diagnostic complete.\")}`);\n });\n","/** Configuration validation utilities for the ``llmkb doctor`` command.\n\nProvides functions to validate ``.llmkb/config.yml``, ``.llmkb/spaces.yml``,\naccess token status, and backend connectivity.\n*/\n\nimport { readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { parse } from \"yaml\";\nimport { getToken } from \"./credentials.js\";\n\n// ---------------------------------------------------------------------------\n// Validation Result\n// ---------------------------------------------------------------------------\n\nexport interface ValidationResult {\n name: string;\n passed: boolean;\n message: string;\n detail?: string;\n}\n\n// ---------------------------------------------------------------------------\n// URL Validation\n// ---------------------------------------------------------------------------\n\n/** Validate that a URL has a proper scheme and host. */\nexport function validateBaseUrl(url: string): ValidationResult {\n try {\n const parsed = new URL(url);\n if (!parsed.protocol || !parsed.host) {\n return {\n name: \"Base URL format\",\n passed: false,\n message: \"URL missing scheme or host\",\n detail: `Got: ${url}`,\n };\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n return {\n name: \"Base URL format\",\n passed: false,\n message: `Unsupported protocol: ${parsed.protocol}`,\n detail: `Got: ${url}`,\n };\n }\n return {\n name: \"Base URL format\",\n passed: true,\n message: `Valid URL: ${url}`,\n };\n } catch {\n return {\n name: \"Base URL format\",\n passed: false,\n message: \"Invalid URL format\",\n detail: `Got: ${url}. Must include scheme (e.g., https://api.llmkb.ai)`,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Config.yml Validation\n// ---------------------------------------------------------------------------\n\n/** Validate ``.llmkb/config.yml`` — parse, check required keys, check for invalid keys. */\nexport async function validateConfigYml(projectDir: string): Promise<ValidationResult> {\n const filePath = join(projectDir, \".llmkb\", \"config.yml\");\n if (!existsSync(filePath)) {\n return {\n name: \"config.yml\",\n passed: false,\n message: \"File not found\",\n detail: \"Run `llmkb init` to create it.\",\n };\n }\n\n try {\n const content = await readFile(filePath, \"utf-8\");\n const cfg = parse(content) as Record<string, unknown> | null;\n\n // Comment-only YAML files parse to null — treat as empty config\n if (cfg === null) {\n return {\n name: \"config.yml\",\n passed: true,\n message: \"Valid config file (all defaults)\",\n };\n }\n\n if (cfg.llmkb_base_url !== undefined) {\n const urlResult = validateBaseUrl(String(cfg.llmkb_base_url));\n if (!urlResult.passed) {\n return {\n name: \"config.yml\",\n passed: false,\n message: \"llmkb_base_url has invalid value\",\n detail: urlResult.detail,\n };\n }\n }\n\n return {\n name: \"config.yml\",\n passed: true,\n message: \"Valid config file\",\n };\n } catch (err) {\n return {\n name: \"config.yml\",\n passed: false,\n message: \"Invalid YAML\",\n detail: (err as Error).message,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Spaces.yml Validation\n// ---------------------------------------------------------------------------\n\n/** Validate ``.llmkb/spaces.yml`` — parse, check required fields. */\nexport async function validateSpacesYml(projectDir: string): Promise<ValidationResult> {\n const filePath = join(projectDir, \".llmkb\", \"spaces.yml\");\n if (!existsSync(filePath)) {\n return {\n name: \"spaces.yml\",\n passed: false,\n message: \"File not found\",\n detail: \"Run `llmkb init` or `llmkb login` to create it.\",\n };\n }\n\n try {\n const content = await readFile(filePath, \"utf-8\");\n const cfg = parse(content) as Record<string, unknown>;\n\n if (cfg.project_space && Array.isArray(cfg.project_space)) {\n for (const ps of cfg.project_space) {\n if (!ps.id) {\n return {\n name: \"spaces.yml\",\n passed: false,\n message: \"project_space entry missing required 'id' field\",\n };\n }\n }\n }\n\n if (cfg.spaces && Array.isArray(cfg.spaces)) {\n for (const s of cfg.spaces) {\n if (!s.id) {\n return {\n name: \"spaces.yml\",\n passed: false,\n message: \"spaces entry missing required 'id' field\",\n };\n }\n }\n }\n\n return {\n name: \"spaces.yml\",\n passed: true,\n message: `Valid config (${(cfg.spaces as unknown[])?.length ?? 0} space(s))`,\n };\n } catch (err) {\n return {\n name: \"spaces.yml\",\n passed: false,\n message: \"Invalid YAML\",\n detail: (err as Error).message,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Access Token Validation\n// ---------------------------------------------------------------------------\n\n/** Check if an access token is stored in the keychain and is still valid. */\nexport async function validateAccessToken(endpoint: string): Promise<ValidationResult> {\n const token = await getToken();\n if (!token) {\n return {\n name: \"Access token\",\n passed: false,\n message: \"No access token found\",\n detail: \"Set LLMKB_ACCESS_TOKEN env var or run `llmkb login --project-space <id>`.\",\n };\n }\n\n try {\n const url = `${endpoint.replace(/\\/+$/, \"\")}/api/v1/auth/me`;\n const res = await fetch(url, {\n method: \"GET\",\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (res.ok) {\n const body = (await res.json()) as {\n data?: { attributes?: { token_status?: string; email?: string } };\n };\n const attrs = body.data?.attributes;\n const status = attrs?.token_status;\n if (status === \"active\") {\n return {\n name: \"Access token\",\n passed: true,\n message: `Token is valid (user: ${attrs?.email ?? \"unknown\"})`,\n };\n }\n return {\n name: \"Access token\",\n passed: false,\n message: `Token status: ${status}`,\n detail: \"Generate a new token at /settings/access-tokens.\",\n };\n }\n\n return {\n name: \"Access token\",\n passed: false,\n message: `Server returned ${res.status}`,\n detail: \"Token may be expired or invalid. Run `llmkb login --project-space <id>`.\",\n };\n } catch (err) {\n return {\n name: \"Access token\",\n passed: false,\n message: \"Cannot validate — server unreachable\",\n detail: (err as Error).message,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Backend Connectivity\n// ---------------------------------------------------------------------------\n\n/** Check if the backend server is reachable. */\nexport async function checkBackendConnectivity(endpoint: string): Promise<ValidationResult> {\n try {\n const url = `${endpoint.replace(/\\/+$/, \"\")}/health`;\n const res = await fetch(url);\n if (res.ok) {\n return {\n name: \"Backend connectivity\",\n passed: true,\n message: `Server reachable at ${endpoint}`,\n };\n }\n return {\n name: \"Backend connectivity\",\n passed: false,\n message: `Server returned ${res.status}`,\n detail: \"Check that the server is running.\",\n };\n } catch (err) {\n return {\n name: \"Backend connectivity\",\n passed: false,\n message: \"Server unreachable\",\n detail: (err as Error).message,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Space Access\n// ---------------------------------------------------------------------------\n\n/** Role hierarchy for write-permission checks. */\nconst WRITE_ROLES = new Set([\"owner\", \"admin\"]);\n\n/** Check if the user has access to a specific space and has write permission. */\nexport async function checkSpaceAccess(\n endpoint: string,\n spaceId: string,\n token: string,\n checkWrite?: boolean,\n): Promise<ValidationResult> {\n try {\n const url = `${endpoint.replace(/\\/+$/, \"\")}/api/v1/auth/spaces`;\n const res = await fetch(url, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (res.ok) {\n const body = (await res.json()) as {\n data?: Array<{ attributes?: { space_id?: string; role?: string } }>;\n };\n const space = body.data?.find((d) => d.attributes?.space_id === spaceId);\n if (space) {\n const role = space.attributes!.role ?? \"guest\";\n if (checkWrite && !WRITE_ROLES.has(role)) {\n return {\n name: `Space access (${spaceId})`,\n passed: false,\n message: `Access granted (role: ${role}) but no write permission`,\n detail: `Role \"${role}\" is read-only. Need owner or admin to sync. Ask the space owner to upgrade your role.`,\n };\n }\n return {\n name: `Space access (${spaceId})`,\n passed: true,\n message: `Access granted (role: ${role})${checkWrite ? \" — write permission OK\" : \"\"}`,\n };\n }\n return {\n name: `Space access (${spaceId})`,\n passed: false,\n message: \"No access to this space\",\n detail: \"Ask the space owner to invite you.\",\n };\n }\n\n return {\n name: `Space access (${spaceId})`,\n passed: false,\n message: `Server returned ${res.status}`,\n };\n } catch (err) {\n return {\n name: `Space access (${spaceId})`,\n passed: false,\n message: \"Cannot check — server unreachable\",\n detail: (err as Error).message,\n };\n }\n}\n"],"mappings":"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AA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,MAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,MAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,MAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,MAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AA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","names":["readFile","writeFile","mkdir","existsSync","resolve","dirname","resolve","Command","Command","resolve","mkdir","writeFile","join","resolve","stringify","existsSync","writeFile","join","resolve","resolve","mkdir","stringify","writeFile","join","mkdir","writeFile","readFile","existsSync","join","readdir","rl","Command","resolve","Command","env","resolve","readFile","writeFile","existsSync","join","existsSync","readFile","writeFile","createInterface","rl","createInterface","Command","Command","Command","Command","Command","Command","Command","Command","createInterface","prompt","rl","createInterface","Command","Command","Command","Command","Command","Command","existsSync","join","Command","join","existsSync","Command","existsSync","join","Command","join","existsSync","Command","join","readFile","join","resolve","existsSync","join","existsSync","readFile","resolve","stdout","stdout","stdout","writeFile","readFile","unlink","existsSync","join","DEFAULT_SKIP_PATTERNS","ignore","readFile","existsSync","join","Command","Command","Command","Command","readFile","existsSync","join","parse","join","existsSync","readFile","parse","label","Command","dirname","resolve","Command"]}
|