thought-cabinet 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/README.md +145 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2113 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
- package/src/agent-assets/agents/codebase-analyzer.md +147 -0
- package/src/agent-assets/agents/codebase-locator.md +126 -0
- package/src/agent-assets/agents/codebase-pattern-finder.md +241 -0
- package/src/agent-assets/agents/thoughts-analyzer.md +154 -0
- package/src/agent-assets/agents/thoughts-locator.md +122 -0
- package/src/agent-assets/agents/web-search-researcher.md +113 -0
- package/src/agent-assets/commands/commit.md +46 -0
- package/src/agent-assets/commands/create_plan.md +278 -0
- package/src/agent-assets/commands/implement_plan.md +91 -0
- package/src/agent-assets/commands/iterate_plan.md +254 -0
- package/src/agent-assets/commands/research_codebase.md +107 -0
- package/src/agent-assets/commands/validate_plan.md +178 -0
- package/src/agent-assets/settings.template.json +7 -0
- package/src/agent-assets/skills/generating-research-document/SKILL.md +41 -0
- package/src/agent-assets/skills/generating-research-document/document_template.md +97 -0
- package/src/agent-assets/skills/writing-plan/SKILL.md +162 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/thoughts/init.ts","../src/config.ts","../src/commands/thoughts/utils/config.ts","../src/commands/thoughts/utils/paths.ts","../src/commands/thoughts/utils/repository.ts","../src/templates/gitignore.ts","../src/templates/readme.ts","../src/templates/agentMd.ts","../src/templates/gitHooks.ts","../src/commands/thoughts/utils/symlinks.ts","../src/commands/thoughts/profile/utils.ts","../src/commands/thoughts/destroy.ts","../src/commands/thoughts/sync.ts","../src/commands/thoughts/status.ts","../src/commands/thoughts/config.ts","../src/commands/thoughts/profile/create.ts","../src/commands/thoughts/profile/list.ts","../src/commands/thoughts/profile/show.ts","../src/commands/thoughts/profile/delete.ts","../src/commands/thoughts.ts","../src/commands/agent/init.ts","../src/commands/agent/registry.ts","../src/commands/agent.ts","../src/commands/metadata/metadata.ts","../src/commands/metadata.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander'\nimport { thoughtsCommand } from './commands/thoughts.js'\nimport { agentCommand } from './commands/agent.js'\nimport { metadataCommand } from './commands/metadata.js'\nimport dotenv from 'dotenv'\nimport { createRequire } from 'node:module'\n\n// Load environment variables\ndotenv.config()\n\nconst require = createRequire(import.meta.url)\nconst { version } = require('../package.json') as { version: string }\n\nconst program = new Command()\n\nprogram\n .name('thoughtcabinet')\n .description(\n 'Thought Cabinet (thc) - thoughts management CLI for developer notes and documentation',\n )\n .version(version)\n\n// Add commands\nthoughtsCommand(program)\nagentCommand(program)\nmetadataCommand(program)\n\nprogram.parse(process.argv)\n","import fs from 'fs'\nimport path from 'path'\nimport { execSync } from 'child_process'\nimport chalk from 'chalk'\nimport * as p from '@clack/prompts'\nimport {\n ThoughtsConfig,\n loadThoughtsConfig,\n saveThoughtsConfig,\n getDefaultThoughtsRepo,\n ensureThoughtsRepoExists,\n createThoughtsDirectoryStructure,\n getCurrentRepoPath,\n getRepoNameFromPath,\n expandPath,\n getRepoThoughtsPath,\n getGlobalThoughtsPath,\n updateSymlinksForNewUsers,\n} from './utils/index.js'\nimport { validateProfile, resolveProfileForRepo, getRepoNameFromMapping } from './profile/utils.js'\nimport {\n generateClaudeMd,\n generatePreCommitHook,\n generatePostCommitHook,\n HOOK_VERSION,\n} from '../../templates/index.js'\n\ninterface InitOptions {\n force?: boolean\n configFile?: string\n directory?: string\n profile?: string\n}\n\nfunction sanitizeDirectoryName(name: string): string {\n return name.replace(/[^a-zA-Z0-9_-]/g, '_')\n}\n\nfunction checkExistingSetup(config?: ThoughtsConfig | null): {\n exists: boolean\n isValid: boolean\n message?: string\n} {\n const thoughtsDir = path.join(process.cwd(), 'thoughts')\n\n if (!fs.existsSync(thoughtsDir)) {\n return { exists: false, isValid: false }\n }\n\n // Check if it's a directory\n if (!fs.lstatSync(thoughtsDir).isDirectory()) {\n return { exists: true, isValid: false, message: 'thoughts exists but is not a directory' }\n }\n\n // Need config to check for user-specific symlinks\n if (!config) {\n return {\n exists: true,\n isValid: false,\n message: 'thoughts directory exists but configuration is missing',\n }\n }\n\n // Check for expected symlinks in new structure\n const userPath = path.join(thoughtsDir, config.user)\n const sharedPath = path.join(thoughtsDir, 'shared')\n const globalPath = path.join(thoughtsDir, 'global')\n\n const hasUser = fs.existsSync(userPath) && fs.lstatSync(userPath).isSymbolicLink()\n const hasShared = fs.existsSync(sharedPath) && fs.lstatSync(sharedPath).isSymbolicLink()\n const hasGlobal = fs.existsSync(globalPath) && fs.lstatSync(globalPath).isSymbolicLink()\n\n if (!hasUser || !hasShared || !hasGlobal) {\n return {\n exists: true,\n isValid: false,\n message: 'thoughts directory exists but symlinks are missing or broken',\n }\n }\n\n return { exists: true, isValid: true }\n}\n\nfunction setupGitHooks(repoPath: string): { updated: string[] } {\n const updated: string[] = []\n // Use git rev-parse to find the common git directory for hooks (handles worktrees)\n // In worktrees, hooks are stored in the common git directory, not the worktree-specific one\n let gitCommonDir: string\n try {\n gitCommonDir = execSync('git rev-parse --git-common-dir', {\n cwd: repoPath,\n encoding: 'utf8',\n stdio: 'pipe',\n }).trim()\n\n // If the path is relative, make it absolute\n if (!path.isAbsolute(gitCommonDir)) {\n gitCommonDir = path.join(repoPath, gitCommonDir)\n }\n } catch (error) {\n throw new Error(`Failed to find git common directory: ${error}`)\n }\n\n const hooksDir = path.join(gitCommonDir, 'hooks')\n\n // Ensure hooks directory exists (might not exist in some setups)\n if (!fs.existsSync(hooksDir)) {\n fs.mkdirSync(hooksDir, { recursive: true })\n }\n\n // Pre-commit hook\n const preCommitPath = path.join(hooksDir, 'pre-commit')\n const preCommitContent = generatePreCommitHook({ hookPath: preCommitPath })\n\n // Post-commit hook\n const postCommitPath = path.join(hooksDir, 'post-commit')\n const postCommitContent = generatePostCommitHook({ hookPath: postCommitPath })\n\n // Helper to check if hook needs updating\n const hookNeedsUpdate = (hookPath: string): boolean => {\n if (!fs.existsSync(hookPath)) return true\n const content = fs.readFileSync(hookPath, 'utf8')\n if (!content.includes('ThoughtCabinet thoughts')) return false // Not our hook\n\n // Check version\n const versionMatch = content.match(/# Version: (\\d+)/)\n if (!versionMatch) return true // Old hook without version\n\n const currentVersion = parseInt(versionMatch[1])\n return currentVersion < parseInt(HOOK_VERSION)\n }\n\n // Backup existing hooks if they exist and aren't ours (or need updating)\n if (fs.existsSync(preCommitPath)) {\n const content = fs.readFileSync(preCommitPath, 'utf8')\n if (!content.includes('ThoughtCabinet thoughts') || hookNeedsUpdate(preCommitPath)) {\n // Only backup non-ThoughtCabinet hooks to prevent recursion\n if (!content.includes('ThoughtCabinet thoughts')) {\n fs.renameSync(preCommitPath, `${preCommitPath}.old`)\n } else {\n // For outdated ThoughtCabinet hooks, just remove them\n fs.unlinkSync(preCommitPath)\n }\n }\n }\n\n if (fs.existsSync(postCommitPath)) {\n const content = fs.readFileSync(postCommitPath, 'utf8')\n if (!content.includes('ThoughtCabinet thoughts') || hookNeedsUpdate(postCommitPath)) {\n // Only backup non-ThoughtCabinet hooks to prevent recursion\n if (!content.includes('ThoughtCabinet thoughts')) {\n fs.renameSync(postCommitPath, `${postCommitPath}.old`)\n } else {\n // For outdated ThoughtCabinet hooks, just remove them\n fs.unlinkSync(postCommitPath)\n }\n }\n }\n\n // Write new hooks only if needed\n if (!fs.existsSync(preCommitPath) || hookNeedsUpdate(preCommitPath)) {\n fs.writeFileSync(preCommitPath, preCommitContent)\n fs.chmodSync(preCommitPath, '755')\n updated.push('pre-commit')\n }\n\n if (!fs.existsSync(postCommitPath) || hookNeedsUpdate(postCommitPath)) {\n fs.writeFileSync(postCommitPath, postCommitContent)\n fs.chmodSync(postCommitPath, '755')\n updated.push('post-commit')\n }\n\n return { updated }\n}\n\nexport async function thoughtsInitCommand(options: InitOptions): Promise<void> {\n try {\n // Check for interactive mode when needed\n if (!options.directory && !process.stdin.isTTY) {\n p.log.error('Not running in interactive terminal.')\n p.log.info('Use --directory flag to specify the repository directory name.')\n process.exit(1)\n }\n\n const currentRepo = getCurrentRepoPath()\n\n // Check if we're in a git repository\n try {\n execSync('git rev-parse --git-dir', { stdio: 'pipe' })\n } catch {\n p.log.error('Not in a git repository')\n process.exit(1)\n }\n\n // Load or create global config first\n let config = loadThoughtsConfig(options)\n\n // If no config exists, we need to set it up first\n if (!config) {\n p.intro(chalk.blue('Initial Thoughts Setup'))\n\n p.log.info(\"First, let's configure your global thoughts system.\")\n\n // Get thoughts repository location\n const defaultRepo = getDefaultThoughtsRepo()\n p.log.message(\n chalk.gray('This is where all your thoughts across all projects will be stored.'),\n )\n\n const thoughtsRepoInput = await p.text({\n message: 'Thoughts repository location:',\n initialValue: defaultRepo,\n placeholder: defaultRepo,\n })\n\n if (p.isCancel(thoughtsRepoInput)) {\n p.cancel('Operation cancelled.')\n process.exit(0)\n }\n const thoughtsRepo = (thoughtsRepoInput as string) || defaultRepo\n\n // Get directory names\n p.log.message(chalk.gray('Your thoughts will be organized into two main directories:'))\n p.log.message(chalk.gray('- Repository-specific thoughts (one subdirectory per project)'))\n p.log.message(chalk.gray('- Global thoughts (shared across all projects)'))\n\n const reposDirInput = await p.text({\n message: 'Directory name for repository-specific thoughts:',\n initialValue: 'repos',\n placeholder: 'repos',\n })\n\n if (p.isCancel(reposDirInput)) {\n p.cancel('Operation cancelled.')\n process.exit(0)\n }\n const reposDir = (reposDirInput as string) || 'repos'\n\n const globalDirInput = await p.text({\n message: 'Directory name for global thoughts:',\n initialValue: 'global',\n placeholder: 'global',\n })\n\n if (p.isCancel(globalDirInput)) {\n p.cancel('Operation cancelled.')\n process.exit(0)\n }\n const globalDir = (globalDirInput as string) || 'global'\n\n // Get user name\n const defaultUser = process.env.USER || 'user'\n let user = ''\n while (!user || user.toLowerCase() === 'global') {\n const userInput = await p.text({\n message: 'Your username:',\n initialValue: defaultUser,\n placeholder: defaultUser,\n validate: value => {\n if (value.toLowerCase() === 'global') {\n return 'Username cannot be \"global\" as it\\'s reserved for cross-project thoughts.'\n }\n return undefined\n },\n })\n\n if (p.isCancel(userInput)) {\n p.cancel('Operation cancelled.')\n process.exit(0)\n }\n user = (userInput as string) || defaultUser\n }\n\n config = {\n thoughtsRepo,\n reposDir,\n globalDir,\n user,\n repoMappings: {},\n }\n\n // Show what will be created\n p.note(\n `${chalk.cyan(thoughtsRepo)}/\\n` +\n ` ├── ${chalk.cyan(reposDir)}/ ${chalk.gray('(project-specific thoughts)')}\\n` +\n ` └── ${chalk.cyan(globalDir)}/ ${chalk.gray('(cross-project thoughts)')}`,\n 'Creating thoughts structure',\n )\n\n // Ensure thoughts repo exists\n ensureThoughtsRepoExists(thoughtsRepo, reposDir, globalDir)\n\n // Save initial config\n saveThoughtsConfig(config, options)\n p.log.success('Global thoughts configuration created')\n }\n\n // Validate profile if specified\n if (options.profile) {\n if (!validateProfile(config, options.profile)) {\n p.log.error(`Profile \"${options.profile}\" does not exist.`)\n p.log.message(chalk.gray('Available profiles:'))\n if (config.profiles) {\n Object.keys(config.profiles).forEach(name => {\n p.log.message(chalk.gray(` - ${name}`))\n })\n } else {\n p.log.message(chalk.gray(' (none)'))\n }\n p.log.warn('Create a profile first:')\n p.log.message(chalk.gray(` thoughtcabinet profile create ${options.profile}`))\n process.exit(1)\n }\n }\n\n // Resolve profile config early so we use the right thoughtsRepo throughout\n // Create a temporary mapping to resolve the profile (will be updated later with actual mapping)\n const tempProfileConfig =\n options.profile && config.profiles && config.profiles[options.profile]\n ? {\n thoughtsRepo: config.profiles[options.profile].thoughtsRepo,\n reposDir: config.profiles[options.profile].reposDir,\n globalDir: config.profiles[options.profile].globalDir,\n profileName: options.profile,\n }\n : {\n thoughtsRepo: config.thoughtsRepo,\n reposDir: config.reposDir,\n globalDir: config.globalDir,\n profileName: undefined,\n }\n\n // Now check for existing setup in current repo\n const setupStatus = checkExistingSetup(config)\n\n if (setupStatus.exists && !options.force) {\n if (setupStatus.isValid) {\n p.log.warn('Thoughts directory already configured for this repository.')\n\n const reconfigure = await p.confirm({\n message: 'Do you want to reconfigure?',\n initialValue: false,\n })\n\n if (p.isCancel(reconfigure) || !reconfigure) {\n p.cancel('Setup cancelled.')\n return\n }\n } else {\n p.log.warn(setupStatus.message || 'Thoughts setup is incomplete')\n\n const fix = await p.confirm({\n message: 'Do you want to fix the setup?',\n initialValue: true,\n })\n\n if (p.isCancel(fix) || !fix) {\n p.cancel('Setup cancelled.')\n return\n }\n }\n }\n\n // Ensure thoughts repo still exists (might have been deleted)\n const expandedRepo = expandPath(tempProfileConfig.thoughtsRepo)\n if (!fs.existsSync(expandedRepo)) {\n p.log.error(`Thoughts repository not found at ${tempProfileConfig.thoughtsRepo}`)\n p.log.warn('The thoughts repository may have been moved or deleted.')\n\n const recreate = await p.confirm({\n message: 'Do you want to recreate it?',\n initialValue: true,\n })\n\n if (p.isCancel(recreate) || !recreate) {\n p.log.info('Please update your configuration or restore the thoughts repository.')\n process.exit(1)\n }\n ensureThoughtsRepoExists(\n tempProfileConfig.thoughtsRepo,\n tempProfileConfig.reposDir,\n tempProfileConfig.globalDir,\n )\n }\n\n // Map current repository\n const reposDir = path.join(expandedRepo, tempProfileConfig.reposDir)\n\n // Ensure repos directory exists\n if (!fs.existsSync(reposDir)) {\n fs.mkdirSync(reposDir, { recursive: true })\n }\n\n // Get existing repo directories\n const existingRepos = fs.readdirSync(reposDir).filter(name => {\n const fullPath = path.join(reposDir, name)\n return fs.statSync(fullPath).isDirectory() && !name.startsWith('.')\n })\n\n // Check if current repo is already mapped\n const existingMapping = config.repoMappings[currentRepo]\n let mappedName = getRepoNameFromMapping(existingMapping)\n\n if (!mappedName) {\n if (options.directory) {\n // Non-interactive mode with --directory option\n const sanitizedDir = sanitizeDirectoryName(options.directory)\n\n if (!existingRepos.includes(sanitizedDir)) {\n p.log.error(`Directory \"${sanitizedDir}\" not found in thoughts repository.`)\n p.log.error('In non-interactive mode (--directory), you must specify a directory')\n p.log.error('name that already exists in the thoughts repository.')\n p.log.warn('Available directories:')\n existingRepos.forEach(repo => p.log.message(chalk.gray(` - ${repo}`)))\n process.exit(1)\n }\n\n mappedName = sanitizedDir\n p.log.success(\n `Using existing: ${tempProfileConfig.thoughtsRepo}/${tempProfileConfig.reposDir}/${mappedName}`,\n )\n } else {\n // Interactive mode\n p.intro(chalk.blue('Repository Setup'))\n\n p.log.info(`Setting up thoughts for: ${chalk.cyan(currentRepo)}`)\n p.log.message(\n chalk.gray(\n `This will create a subdirectory in ${tempProfileConfig.thoughtsRepo}/${tempProfileConfig.reposDir}/`,\n ),\n )\n p.log.message(chalk.gray('to store thoughts specific to this repository.'))\n\n if (existingRepos.length > 0) {\n const selectOptions = [\n ...existingRepos.map(repo => ({ value: repo, label: `Use existing: ${repo}` })),\n { value: '__create_new__', label: 'Create new directory' },\n ]\n\n const selection = await p.select({\n message: 'Select or create a thoughts directory for this repository:',\n options: selectOptions,\n })\n\n if (p.isCancel(selection)) {\n p.cancel('Operation cancelled.')\n process.exit(0)\n }\n\n if (selection === '__create_new__') {\n // Create new\n const defaultName = getRepoNameFromPath(currentRepo)\n p.log.message(\n chalk.gray(\n `This name will be used for the directory: ${tempProfileConfig.thoughtsRepo}/${tempProfileConfig.reposDir}/[name]`,\n ),\n )\n\n const nameInput = await p.text({\n message: \"Directory name for this project's thoughts:\",\n initialValue: defaultName,\n placeholder: defaultName,\n })\n\n if (p.isCancel(nameInput)) {\n p.cancel('Operation cancelled.')\n process.exit(0)\n }\n mappedName = (nameInput as string) || defaultName\n\n // Sanitize the name\n mappedName = sanitizeDirectoryName(mappedName)\n p.log.success(\n `Will create: ${tempProfileConfig.thoughtsRepo}/${tempProfileConfig.reposDir}/${mappedName}`,\n )\n } else {\n mappedName = selection as string\n p.log.success(\n `Will use existing: ${tempProfileConfig.thoughtsRepo}/${tempProfileConfig.reposDir}/${mappedName}`,\n )\n }\n } else {\n // No existing repos, just create new\n const defaultName = getRepoNameFromPath(currentRepo)\n p.log.message(\n chalk.gray(\n `This name will be used for the directory: ${tempProfileConfig.thoughtsRepo}/${tempProfileConfig.reposDir}/[name]`,\n ),\n )\n\n const nameInput = await p.text({\n message: \"Directory name for this project's thoughts:\",\n initialValue: defaultName,\n placeholder: defaultName,\n })\n\n if (p.isCancel(nameInput)) {\n p.cancel('Operation cancelled.')\n process.exit(0)\n }\n mappedName = (nameInput as string) || defaultName\n\n // Sanitize the name\n mappedName = sanitizeDirectoryName(mappedName)\n p.log.success(\n `Will create: ${tempProfileConfig.thoughtsRepo}/${tempProfileConfig.reposDir}/${mappedName}`,\n )\n }\n }\n\n // Update config with profile-aware mapping\n if (options.profile) {\n config.repoMappings[currentRepo] = {\n repo: mappedName,\n profile: options.profile,\n }\n } else {\n // Keep string format for backward compatibility\n config.repoMappings[currentRepo] = mappedName\n }\n saveThoughtsConfig(config, options)\n }\n\n // Ensure mappedName is resolved when mapping already existed\n if (!mappedName) {\n mappedName = getRepoNameFromMapping(config.repoMappings[currentRepo])!\n }\n\n // Resolve profile config for directory creation\n const profileConfig = resolveProfileForRepo(config, currentRepo)\n\n // Create directory structure using profile config\n createThoughtsDirectoryStructure(profileConfig, mappedName, config.user)\n\n // Create thoughts directory in current repo\n const thoughtsDir = path.join(currentRepo, 'thoughts')\n if (fs.existsSync(thoughtsDir)) {\n // Handle searchable directories specially if they exist (might have read-only permissions)\n const searchableDir = path.join(thoughtsDir, 'searchable')\n if (fs.existsSync(searchableDir)) {\n try {\n // Reset permissions so we can delete it\n execSync(`chmod -R 755 \"${searchableDir}\"`, { stdio: 'pipe' })\n } catch {\n // Ignore chmod errors\n }\n }\n fs.rmSync(thoughtsDir, { recursive: true, force: true })\n }\n fs.mkdirSync(thoughtsDir)\n\n // Create symlinks - flipped structure for easier access\n const repoTarget = getRepoThoughtsPath(profileConfig, mappedName)\n const globalTarget = getGlobalThoughtsPath(profileConfig)\n\n // Direct symlinks to user and shared directories for repo-specific thoughts\n fs.symlinkSync(path.join(repoTarget, config.user), path.join(thoughtsDir, config.user), 'dir')\n fs.symlinkSync(path.join(repoTarget, 'shared'), path.join(thoughtsDir, 'shared'), 'dir')\n\n // Global directory as before\n fs.symlinkSync(globalTarget, path.join(thoughtsDir, 'global'), 'dir')\n\n // Check for other users and create symlinks\n const otherUsers = updateSymlinksForNewUsers(\n currentRepo,\n profileConfig,\n mappedName,\n config.user,\n )\n\n if (otherUsers.length > 0) {\n p.log.success(`Added symlinks for other users: ${otherUsers.join(', ')}`)\n }\n\n // Pull latest thoughts if remote exists\n try {\n execSync('git remote get-url origin', { cwd: expandedRepo, stdio: 'pipe' })\n // Remote exists, try to pull\n try {\n execSync('git pull --rebase', {\n stdio: 'pipe',\n cwd: expandedRepo,\n })\n p.log.success('Pulled latest thoughts from remote')\n } catch (error) {\n p.log.warn(`Could not pull latest thoughts: ${(error as Error).message}`)\n }\n } catch {\n // No remote configured, skip pull\n }\n\n // Generate CLAUDE.md\n const claudeMd = generateClaudeMd({\n thoughtsRepo: profileConfig.thoughtsRepo,\n reposDir: profileConfig.reposDir,\n repoName: mappedName,\n user: config.user,\n })\n fs.writeFileSync(path.join(thoughtsDir, 'CLAUDE.md'), claudeMd)\n\n // Setup git hooks\n const hookResult = setupGitHooks(currentRepo)\n if (hookResult.updated.length > 0) {\n p.log.step(`Updated git hooks: ${hookResult.updated.join(', ')}`)\n }\n\n p.log.success('Thoughts setup complete!')\n\n // Summary note\n const structureText =\n `${chalk.cyan(currentRepo)}/\\n` +\n ` └── thoughts/\\n` +\n ` ├── ${config.user}/ ${chalk.gray(`→ ${profileConfig.thoughtsRepo}/${profileConfig.reposDir}/${mappedName}/${config.user}/`)}\\n` +\n ` ├── shared/ ${chalk.gray(`→ ${profileConfig.thoughtsRepo}/${profileConfig.reposDir}/${mappedName}/shared/`)}\\n` +\n ` └── global/ ${chalk.gray(`→ ${profileConfig.thoughtsRepo}/${profileConfig.globalDir}/`)}\\n` +\n ` ├── ${config.user}/ ${chalk.gray('(your cross-repo notes)')}\\n` +\n ` └── shared/ ${chalk.gray('(team cross-repo notes)')}`\n\n p.note(structureText, 'Repository structure created')\n\n p.note(\n `${chalk.green('✓')} Pre-commit hook: Prevents committing thoughts/\\n` +\n `${chalk.green('✓')} Post-commit hook: Auto-syncs thoughts after commits`,\n 'Protection enabled',\n )\n\n p.outro(\n chalk.gray('Next steps:\\n') +\n chalk.gray(\n ` 1. Run ${chalk.cyan('thoughtcabinet sync')} to create the searchable index\\n`,\n ) +\n chalk.gray(\n ` 2. Create markdown files in ${chalk.cyan(`thoughts/${config.user}/`)} for your notes\\n`,\n ) +\n chalk.gray(` 3. Your thoughts will sync automatically when you commit code\\n`) +\n chalk.gray(` 4. Run ${chalk.cyan('thoughtcabinet status')} to check sync status`),\n )\n } catch (error) {\n p.log.error(`Error during thoughts init: ${error}`)\n process.exit(1)\n }\n}\n","import dotenv from 'dotenv'\nimport fs from 'fs'\nimport path from 'path'\nimport chalk from 'chalk'\n\n// Load environment variables\ndotenv.config()\n\nexport type RepoMappingObject = {\n repo: string\n profile?: string\n}\n\nexport type ProfileConfig = {\n thoughtsRepo: string\n reposDir: string\n globalDir: string\n}\n\nexport type ConfigFile = {\n thoughts?: {\n thoughtsRepo: string\n reposDir: string\n globalDir: string\n user: string\n repoMappings: Record<string, string | RepoMappingObject>\n profiles?: Record<string, ProfileConfig>\n }\n}\n\nexport class ConfigResolver {\n public static DEFAULT_CONFIG_FILE = 'config.json'\n public configFile: ConfigFile\n private configFilePath: string\n\n constructor(options: { configFile?: string } = {}) {\n this.configFile = this.loadConfigFile(options.configFile)\n this.configFilePath = this.getConfigFilePath(options.configFile)\n }\n\n loadConfigFile(configFile?: string): ConfigFile {\n if (configFile) {\n const configContent = fs.readFileSync(configFile, 'utf8')\n return JSON.parse(configContent)\n }\n\n // these do not merge today\n const configPaths = [ConfigResolver.DEFAULT_CONFIG_FILE, getDefaultConfigPath()]\n\n for (const configPath of configPaths) {\n try {\n if (fs.existsSync(configPath)) {\n const configContent = fs.readFileSync(configPath, 'utf8')\n return JSON.parse(configContent)\n }\n } catch (error) {\n console.error(chalk.yellow(`Warning: Could not parse config file ${configPath}: ${error}`))\n }\n }\n\n return {}\n }\n\n private getConfigFilePath(configFile?: string): string {\n if (configFile) return configFile\n\n const configPaths = [ConfigResolver.DEFAULT_CONFIG_FILE, getDefaultConfigPath()]\n for (const configPath of configPaths) {\n try {\n if (fs.existsSync(configPath)) {\n return configPath\n }\n } catch {\n // Continue to next path\n }\n }\n return getDefaultConfigPath() // fallback\n }\n}\n\nexport function loadConfigFile(configFile?: string): ConfigFile {\n const resolver = new ConfigResolver({ configFile })\n return resolver.loadConfigFile(configFile)\n}\n\nexport function saveConfigFile(config: ConfigFile, configFile?: string): void {\n const configPath = configFile || getDefaultConfigPath()\n\n console.log(chalk.yellow(`Writing config to ${configPath}`))\n\n // Create directory if it doesn't exist\n const configDir = path.dirname(configPath)\n fs.mkdirSync(configDir, { recursive: true })\n\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2))\n\n console.log(chalk.green('Config saved successfully'))\n}\n\nexport function getDefaultConfigPath(): string {\n const xdgConfigHome = process.env.XDG_CONFIG_HOME || path.join(process.env.HOME || '', '.config')\n return path.join(xdgConfigHome, 'thought-cabinet', ConfigResolver.DEFAULT_CONFIG_FILE)\n}\n","import { ConfigResolver, saveConfigFile } from '../../../config.js'\nimport type { RepoMappingObject, ProfileConfig } from '../../../config.js'\n\n/**\n * Thoughts configuration interface\n */\nexport interface ThoughtsConfig {\n thoughtsRepo: string\n reposDir: string // Directory name within thoughtsRepo (e.g., \"repos\")\n globalDir: string // Directory name within thoughtsRepo (e.g., \"global\")\n user: string\n repoMappings: Record<string, string | RepoMappingObject>\n profiles?: Record<string, ProfileConfig>\n}\n\n/**\n * Resolved profile configuration interface\n */\nexport interface ResolvedProfileConfig {\n thoughtsRepo: string\n reposDir: string\n globalDir: string\n profileName?: string // undefined for default config\n}\n\n/**\n * Load thoughts configuration from config file\n */\nexport function loadThoughtsConfig(options: Record<string, unknown> = {}): ThoughtsConfig | null {\n const resolver = new ConfigResolver(options)\n return resolver.configFile.thoughts || null\n}\n\n/**\n * Save thoughts configuration to config file\n */\nexport function saveThoughtsConfig(\n thoughtsConfig: ThoughtsConfig,\n options: Record<string, unknown> = {},\n): void {\n const resolver = new ConfigResolver(options)\n resolver.configFile.thoughts = thoughtsConfig\n saveConfigFile(resolver.configFile, options.configFile as string | undefined)\n}\n","import path from 'path'\nimport os from 'os'\nimport type { ResolvedProfileConfig } from './config.js'\n\nexport function getDefaultThoughtsRepo(): string {\n return path.join(os.homedir(), 'thoughts')\n}\n\nexport function expandPath(filePath: string): string {\n if (filePath.startsWith('~/')) {\n return path.join(os.homedir(), filePath.slice(2))\n }\n return path.resolve(filePath)\n}\n\nexport function getCurrentRepoPath(): string {\n return process.cwd()\n}\n\nexport function getRepoNameFromPath(repoPath: string): string {\n // Extract a reasonable name from the repo path\n const parts = repoPath.split(path.sep)\n return parts[parts.length - 1] || 'unnamed_repo'\n}\n\n// Overloaded signatures for getRepoThoughtsPath\nexport function getRepoThoughtsPath(config: ResolvedProfileConfig, repoName: string): string\nexport function getRepoThoughtsPath(\n thoughtsRepo: string,\n reposDir: string,\n repoName: string,\n): string\nexport function getRepoThoughtsPath(\n thoughtsRepoOrConfig: string | ResolvedProfileConfig,\n reposDirOrRepoName: string,\n repoName?: string,\n): string {\n if (typeof thoughtsRepoOrConfig === 'string') {\n // Legacy signature: (thoughtsRepo, reposDir, repoName)\n return path.join(expandPath(thoughtsRepoOrConfig), reposDirOrRepoName, repoName!)\n }\n\n // New signature: (config, repoName)\n const config = thoughtsRepoOrConfig\n return path.join(expandPath(config.thoughtsRepo), config.reposDir, reposDirOrRepoName)\n}\n\n// Overloaded signatures for getGlobalThoughtsPath\nexport function getGlobalThoughtsPath(config: ResolvedProfileConfig): string\nexport function getGlobalThoughtsPath(thoughtsRepo: string, globalDir: string): string\nexport function getGlobalThoughtsPath(\n thoughtsRepoOrConfig: string | ResolvedProfileConfig,\n globalDir?: string,\n): string {\n if (typeof thoughtsRepoOrConfig === 'string') {\n // Legacy signature: (thoughtsRepo, globalDir)\n return path.join(expandPath(thoughtsRepoOrConfig), globalDir!)\n }\n\n // New signature: (config)\n const config = thoughtsRepoOrConfig\n return path.join(expandPath(config.thoughtsRepo), config.globalDir)\n}\n","import fs from 'fs'\nimport path from 'path'\nimport { execSync } from 'child_process'\nimport {\n generateGitignore,\n generateRepoReadme,\n generateGlobalReadme,\n} from '../../../templates/index.js'\nimport type { ResolvedProfileConfig } from './config.js'\nimport { expandPath, getRepoThoughtsPath, getGlobalThoughtsPath } from './paths.js'\n\n// Overloaded signatures for ensureThoughtsRepoExists\nexport function ensureThoughtsRepoExists(config: ResolvedProfileConfig): void\nexport function ensureThoughtsRepoExists(\n thoughtsRepo: string,\n reposDir: string,\n globalDir: string,\n): void\nexport function ensureThoughtsRepoExists(\n configOrThoughtsRepo: ResolvedProfileConfig | string,\n reposDir?: string,\n globalDir?: string,\n): void {\n let thoughtsRepo: string\n let effectiveReposDir: string\n let effectiveGlobalDir: string\n\n if (typeof configOrThoughtsRepo === 'string') {\n // Legacy signature: (thoughtsRepo, reposDir, globalDir)\n thoughtsRepo = configOrThoughtsRepo\n effectiveReposDir = reposDir!\n effectiveGlobalDir = globalDir!\n } else {\n // New signature: (config)\n thoughtsRepo = configOrThoughtsRepo.thoughtsRepo\n effectiveReposDir = configOrThoughtsRepo.reposDir\n effectiveGlobalDir = configOrThoughtsRepo.globalDir\n }\n\n const expandedRepo = expandPath(thoughtsRepo)\n\n // Create thoughts repo if it doesn't exist\n if (!fs.existsSync(expandedRepo)) {\n fs.mkdirSync(expandedRepo, { recursive: true })\n }\n\n // Create subdirectories\n const expandedRepos = path.join(expandedRepo, effectiveReposDir)\n const expandedGlobal = path.join(expandedRepo, effectiveGlobalDir)\n\n if (!fs.existsSync(expandedRepos)) {\n fs.mkdirSync(expandedRepos, { recursive: true })\n }\n\n if (!fs.existsSync(expandedGlobal)) {\n fs.mkdirSync(expandedGlobal, { recursive: true })\n }\n\n // Check if we're in a git repo (handle both .git directory and .git file for worktrees)\n const gitPath = path.join(expandedRepo, '.git')\n const isGitRepo =\n fs.existsSync(gitPath) && (fs.statSync(gitPath).isDirectory() || fs.statSync(gitPath).isFile())\n\n if (!isGitRepo) {\n // Initialize as git repo\n execSync('git init', { cwd: expandedRepo })\n\n // Create initial .gitignore\n const gitignore = generateGitignore()\n fs.writeFileSync(path.join(expandedRepo, '.gitignore'), gitignore)\n\n // Initial commit\n execSync('git add .gitignore', { cwd: expandedRepo })\n execSync('git commit -m \"Initial thoughts repository setup\"', { cwd: expandedRepo })\n }\n}\n\n// Overloaded signatures for createThoughtsDirectoryStructure\nexport function createThoughtsDirectoryStructure(\n config: ResolvedProfileConfig,\n repoName: string,\n user: string,\n): void\nexport function createThoughtsDirectoryStructure(\n thoughtsRepo: string,\n reposDir: string,\n globalDir: string,\n repoName: string,\n user: string,\n): void\nexport function createThoughtsDirectoryStructure(\n configOrThoughtsRepo: ResolvedProfileConfig | string,\n reposDirOrRepoName: string,\n globalDirOrUser: string,\n repoName?: string,\n user?: string,\n): void {\n let resolvedConfig: { thoughtsRepo: string; reposDir: string; globalDir: string }\n let effectiveRepoName: string\n let effectiveUser: string\n\n if (typeof configOrThoughtsRepo === 'string') {\n // Legacy signature: (thoughtsRepo, reposDir, globalDir, repoName, user)\n resolvedConfig = {\n thoughtsRepo: configOrThoughtsRepo,\n reposDir: reposDirOrRepoName,\n globalDir: globalDirOrUser,\n }\n effectiveRepoName = repoName!\n effectiveUser = user!\n } else {\n // New signature: (config, repoName, user)\n resolvedConfig = configOrThoughtsRepo\n effectiveRepoName = reposDirOrRepoName\n effectiveUser = globalDirOrUser\n }\n\n // Create repo-specific directories\n const repoThoughtsPath = getRepoThoughtsPath(\n resolvedConfig.thoughtsRepo,\n resolvedConfig.reposDir,\n effectiveRepoName,\n )\n const repoUserPath = path.join(repoThoughtsPath, effectiveUser)\n const repoSharedPath = path.join(repoThoughtsPath, 'shared')\n\n // Create global directories\n const globalPath = getGlobalThoughtsPath(resolvedConfig.thoughtsRepo, resolvedConfig.globalDir)\n const globalUserPath = path.join(globalPath, effectiveUser)\n const globalSharedPath = path.join(globalPath, 'shared')\n\n // Create all directories\n for (const dir of [repoUserPath, repoSharedPath, globalUserPath, globalSharedPath]) {\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n }\n\n // Create initial README files\n const repoReadme = generateRepoReadme({\n repoName: effectiveRepoName,\n user: effectiveUser,\n })\n\n const globalReadme = generateGlobalReadme({\n user: effectiveUser,\n })\n\n if (!fs.existsSync(path.join(repoThoughtsPath, 'README.md'))) {\n fs.writeFileSync(path.join(repoThoughtsPath, 'README.md'), repoReadme)\n }\n\n if (!fs.existsSync(path.join(globalPath, 'README.md'))) {\n fs.writeFileSync(path.join(globalPath, 'README.md'), globalReadme)\n }\n}\n","/**\n * Generates .gitignore content for thoughts repository\n */\nexport function generateGitignore(): string {\n return `# OS files\n.DS_Store\nThumbs.db\n\n# Editor files\n.vscode/\n.idea/\n*.swp\n*.swo\n*~\n\n# Temporary files\n*.tmp\n*.bak\n`\n}\n","/**\n * Parameters for generating repository-specific README\n */\nexport interface RepoReadmeParams {\n repoName: string\n user: string\n}\n\n/**\n * Parameters for generating global README\n */\nexport interface GlobalReadmeParams {\n user: string\n}\n\n/**\n * Generates README.md content for repository-specific thoughts directory\n */\nexport function generateRepoReadme({ repoName, user }: RepoReadmeParams): string {\n return `# ${repoName} Thoughts\n\nThis directory contains thoughts and notes specific to the ${repoName} repository.\n\n- \\`${user}/\\` - Your personal notes for this repository\n- \\`shared/\\` - Team-shared notes for this repository\n`\n}\n\n/**\n * Generates README.md content for global thoughts directory\n */\nexport function generateGlobalReadme({ user }: GlobalReadmeParams): string {\n return `# Global Thoughts\n\nThis directory contains thoughts and notes that apply across all repositories.\n\n- \\`${user}/\\` - Your personal cross-repository notes\n- \\`shared/\\` - Team-shared cross-repository notes\n`\n}\n","import path from 'path'\nimport os from 'os'\n\n/**\n * Parameters for generating agent markdown documentation\n */\nexport interface AgentMdParams {\n thoughtsRepo: string\n reposDir: string\n repoName: string\n user: string\n productName: string // 'Claude Code' | 'CodeBuddy Code' | etc.\n}\n\n/**\n * Generates agent markdown content explaining the thoughts directory structure\n */\nexport function generateAgentMd({\n thoughtsRepo,\n reposDir,\n repoName,\n user,\n productName,\n}: AgentMdParams): string {\n const reposPath = path.join(thoughtsRepo, reposDir, repoName).replace(os.homedir(), '~')\n const globalPath = path.join(thoughtsRepo, 'global').replace(os.homedir(), '~')\n\n return `# Thoughts Directory Structure\n\nThis directory contains developer thoughts and notes for the ${repoName} repository.\nIt is managed by the ThoughtCabinet thoughts system and should not be committed to the code repository.\n\n## Structure\n\n- \\`${user}/\\` → Your personal notes for this repository (symlink to ${reposPath}/${user})\n- \\`shared/\\` → Team-shared notes for this repository (symlink to ${reposPath}/shared)\n- \\`global/\\` → Cross-repository thoughts (symlink to ${globalPath})\n - \\`${user}/\\` - Your personal notes that apply across all repositories\n - \\`shared/\\` - Team-shared notes that apply across all repositories\n- \\`searchable/\\` → Hard links for search tools (auto-generated)\n\n## Searching in Thoughts\n\nThe \\`searchable/\\` directory contains hard links to all thoughts files accessible in this repository. This allows search tools to find content without following symlinks.\n\n**IMPORTANT**:\n- Files in \\`thoughts/searchable/\\` are hard links to the original files (editing either updates both)\n- For clarity and consistency, always reference files by their canonical path (e.g., \\`thoughts/${user}/todo.md\\`, not \\`thoughts/searchable/${user}/todo.md\\`)\n- The \\`searchable/\\` directory is automatically updated when you run \\`thoughtcabinet sync\\`\n\nThis design ensures that:\n1. Search tools can find all your thoughts content easily\n2. The symlink structure remains intact for git operations\n3. Files remain editable while maintaining consistent path references\n\n## Usage\n\nCreate markdown files in these directories to document:\n\n- Architecture decisions\n- Design notes\n- TODO items\n- Investigation results\n- Any other development thoughts\n\nQuick access:\n\n- \\`thoughts/${user}/\\` for your repo-specific notes (most common)\n- \\`thoughts/global/${user}/\\` for your cross-repo notes\n\nThese files will be automatically synchronized with your thoughts repository when you commit code changes (when using ${productName}).\n\n## Important\n\n- Never commit the thoughts/ directory to your code repository\n- The git pre-commit hook will prevent accidental commits\n- Use \\`thoughtcabinet sync\\` to manually sync changes\n- Use \\`thoughtcabinet status\\` to see sync status\n`\n}\n\n/**\n * Legacy parameters for backward compatibility\n */\nexport interface ClaudeMdParams {\n thoughtsRepo: string\n reposDir: string\n repoName: string\n user: string\n}\n\n/**\n * Generates CLAUDE.md content (backward compatibility wrapper)\n */\nexport function generateClaudeMd(params: ClaudeMdParams): string {\n return generateAgentMd({ ...params, productName: 'Claude Code' })\n}\n\n/**\n * Generates CODEBUDDY.md content\n */\nexport function generateCodebuddyMd(params: ClaudeMdParams): string {\n return generateAgentMd({ ...params, productName: 'CodeBuddy Code' })\n}\n","/**\n * Current hook version - increment when hooks need updating\n */\nexport const HOOK_VERSION = '1'\n\n/**\n * Parameters for generating pre-commit hook\n */\nexport interface PreCommitHookParams {\n hookPath: string\n}\n\n/**\n * Parameters for generating post-commit hook\n */\nexport interface PostCommitHookParams {\n hookPath: string\n}\n\n/**\n * Generates pre-commit Git hook content to prevent committing thoughts directory\n */\nexport function generatePreCommitHook({ hookPath }: PreCommitHookParams): string {\n return `#!/bin/bash\n# ThoughtCabinet thoughts protection - prevent committing thoughts directory\n# Version: ${HOOK_VERSION}\n\nif git diff --cached --name-only | grep -q \"^thoughts/\"; then\n echo \"❌ Cannot commit thoughts/ to code repository\"\n echo \"The thoughts directory should only exist in your separate thoughts repository.\"\n git reset HEAD -- thoughts/\n exit 1\nfi\n\n# Call any existing pre-commit hook\nif [ -f \"${hookPath}.old\" ]; then\n \"${hookPath}.old\" \"$@\"\nfi\n`\n}\n\n/**\n * Generates post-commit Git hook content for auto-syncing thoughts\n */\nexport function generatePostCommitHook({ hookPath }: PostCommitHookParams): string {\n return `#!/bin/bash\n# ThoughtCabinet thoughts auto-sync\n# Version: ${HOOK_VERSION}\n\n# Check if we're in a worktree\nif [ -f .git ]; then\n # Skip auto-sync in worktrees to avoid repository boundary confusion\n exit 0\nfi\n\n# Get the commit message\nCOMMIT_MSG=$(git log -1 --pretty=%B)\n\n# Auto-sync thoughts after each commit (only in non-worktree repos)\nthoughtcabinet sync --message \"Auto-sync with commit: $COMMIT_MSG\" >/dev/null 2>&1 &\n\n# Call any existing post-commit hook\nif [ -f \"${hookPath}.old\" ]; then\n \"${hookPath}.old\" \"$@\"\nfi\n`\n}\n","import fs from 'fs'\nimport path from 'path'\nimport type { ResolvedProfileConfig } from './config.js'\nimport { getRepoThoughtsPath } from './paths.js'\n\n// Overloaded signatures for updateSymlinksForNewUsers\nexport function updateSymlinksForNewUsers(\n currentRepoPath: string,\n config: ResolvedProfileConfig,\n repoName: string,\n currentUser: string,\n): string[]\nexport function updateSymlinksForNewUsers(\n currentRepoPath: string,\n thoughtsRepo: string,\n reposDir: string,\n repoName: string,\n currentUser: string,\n): string[]\nexport function updateSymlinksForNewUsers(\n currentRepoPath: string,\n configOrThoughtsRepo: ResolvedProfileConfig | string,\n reposDirOrRepoName: string,\n repoNameOrCurrentUser: string,\n currentUser?: string,\n): string[] {\n let resolvedConfig: { thoughtsRepo: string; reposDir: string }\n let effectiveRepoName: string\n let effectiveUser: string\n\n if (typeof configOrThoughtsRepo === 'string') {\n // Legacy signature: (currentRepoPath, thoughtsRepo, reposDir, repoName, currentUser)\n resolvedConfig = {\n thoughtsRepo: configOrThoughtsRepo,\n reposDir: reposDirOrRepoName,\n }\n effectiveRepoName = repoNameOrCurrentUser\n effectiveUser = currentUser!\n } else {\n // New signature: (currentRepoPath, config, repoName, currentUser)\n resolvedConfig = configOrThoughtsRepo\n effectiveRepoName = reposDirOrRepoName\n effectiveUser = repoNameOrCurrentUser\n }\n\n const thoughtsDir = path.join(currentRepoPath, 'thoughts')\n const repoThoughtsPath = getRepoThoughtsPath(\n resolvedConfig.thoughtsRepo,\n resolvedConfig.reposDir,\n effectiveRepoName,\n )\n const addedSymlinks: string[] = []\n\n if (!fs.existsSync(thoughtsDir) || !fs.existsSync(repoThoughtsPath)) {\n return addedSymlinks\n }\n\n // Get all user directories in the repo thoughts\n const entries = fs.readdirSync(repoThoughtsPath, { withFileTypes: true })\n const userDirs = entries\n .filter(entry => entry.isDirectory() && entry.name !== 'shared' && !entry.name.startsWith('.'))\n .map(entry => entry.name)\n\n // Check each user directory and create symlinks if missing\n for (const userName of userDirs) {\n const symlinkPath = path.join(thoughtsDir, userName)\n const targetPath = path.join(repoThoughtsPath, userName)\n\n // Skip if symlink already exists or if it's the current user (already handled)\n if (!fs.existsSync(symlinkPath) && userName !== effectiveUser) {\n try {\n fs.symlinkSync(targetPath, symlinkPath, 'dir')\n addedSymlinks.push(userName)\n } catch {\n // Ignore errors - might be permission issues\n }\n }\n }\n\n return addedSymlinks\n}\n","import type { RepoMappingObject } from '../../../config.js'\nimport type { ThoughtsConfig, ResolvedProfileConfig } from '../utils/config.js'\n\n/**\n * Resolves the profile config for a given repository path\n * Returns default config if no profile specified or profile not found\n */\nexport function resolveProfileForRepo(\n config: ThoughtsConfig,\n repoPath: string,\n): ResolvedProfileConfig {\n const mapping = config.repoMappings[repoPath]\n\n // Handle string format (legacy - no profile)\n if (typeof mapping === 'string') {\n return {\n thoughtsRepo: config.thoughtsRepo,\n reposDir: config.reposDir,\n globalDir: config.globalDir,\n profileName: undefined,\n }\n }\n\n // Handle object format\n if (mapping && typeof mapping === 'object') {\n const profileName = mapping.profile\n\n // If profile specified, look it up\n if (profileName && config.profiles && config.profiles[profileName]) {\n const profile = config.profiles[profileName]\n return {\n thoughtsRepo: profile.thoughtsRepo,\n reposDir: profile.reposDir,\n globalDir: profile.globalDir,\n profileName,\n }\n }\n\n // Object format but no profile or profile not found - use default\n return {\n thoughtsRepo: config.thoughtsRepo,\n reposDir: config.reposDir,\n globalDir: config.globalDir,\n profileName: undefined,\n }\n }\n\n // No mapping - use default\n return {\n thoughtsRepo: config.thoughtsRepo,\n reposDir: config.reposDir,\n globalDir: config.globalDir,\n profileName: undefined,\n }\n}\n\n/**\n * Gets the repo name from a mapping (handles both string and object formats)\n */\nexport function getRepoNameFromMapping(\n mapping: string | RepoMappingObject | undefined,\n): string | undefined {\n if (!mapping) return undefined\n if (typeof mapping === 'string') return mapping\n return mapping.repo\n}\n\n/**\n * Gets the profile name from a mapping (returns undefined for string format)\n */\nexport function getProfileNameFromMapping(\n mapping: string | RepoMappingObject | undefined,\n): string | undefined {\n if (!mapping) return undefined\n if (typeof mapping === 'string') return undefined\n return mapping.profile\n}\n\n/**\n * Validates that a profile exists in the configuration\n */\nexport function validateProfile(config: ThoughtsConfig, profileName: string): boolean {\n return !!(config.profiles && config.profiles[profileName])\n}\n\n/**\n * Sanitizes profile name (same rules as directory names)\n */\nexport function sanitizeProfileName(name: string): string {\n return name.replace(/[^a-zA-Z0-9_-]/g, '_')\n}\n","import fs from 'fs'\nimport path from 'path'\nimport { execSync } from 'child_process'\nimport chalk from 'chalk'\nimport { loadThoughtsConfig, saveThoughtsConfig, getCurrentRepoPath } from './utils/index.js'\nimport { getRepoNameFromMapping, getProfileNameFromMapping } from './profile/utils.js'\n\ninterface DestoryOptions {\n force?: boolean\n configFile?: string\n}\n\nexport async function thoughtsDestoryCommand(options: DestoryOptions): Promise<void> {\n try {\n const currentRepo = getCurrentRepoPath()\n const thoughtsDir = path.join(currentRepo, 'thoughts')\n\n // Check if thoughts directory exists\n if (!fs.existsSync(thoughtsDir)) {\n console.error(chalk.red('Error: Thoughts not initialized for this repository.'))\n process.exit(1)\n }\n\n // Load config\n const config = loadThoughtsConfig(options)\n if (!config) {\n console.error(chalk.red('Error: Thoughts configuration not found.'))\n process.exit(1)\n }\n\n const mapping = config.repoMappings[currentRepo]\n const mappedName = getRepoNameFromMapping(mapping)\n const profileName = getProfileNameFromMapping(mapping)\n\n if (!mappedName && !options.force) {\n console.error(chalk.red('Error: This repository is not in the thoughts configuration.'))\n console.error(chalk.yellow('Use --force to remove the thoughts directory anyway.'))\n process.exit(1)\n }\n\n console.log(chalk.blue('Removing thoughts setup from current repository...'))\n\n // Step 1: Handle searchable directory if it exists\n const searchableDir = path.join(thoughtsDir, 'searchable')\n if (fs.existsSync(searchableDir)) {\n console.log(chalk.gray('Removing searchable directory...'))\n try {\n // Reset permissions in case they're restricted\n execSync(`chmod -R 755 \"${searchableDir}\"`, { stdio: 'pipe' })\n } catch {\n // Ignore chmod errors\n }\n fs.rmSync(searchableDir, { recursive: true, force: true })\n }\n\n // Step 2: Remove the entire thoughts directory\n // IMPORTANT: This only removes the local thoughts/ directory containing symlinks\n // The actual thoughts content in the thoughts repository remains untouched\n console.log(chalk.gray('Removing thoughts directory (symlinks only)...'))\n try {\n fs.rmSync(thoughtsDir, { recursive: true, force: true })\n } catch (error) {\n console.error(chalk.red(`Error removing thoughts directory: ${error}`))\n console.error(chalk.yellow('You may need to manually remove: ' + thoughtsDir))\n process.exit(1)\n }\n\n // Step 3: Remove from config if mapped\n if (mappedName) {\n console.log(chalk.gray('Removing repository from thoughts configuration...'))\n delete config.repoMappings[currentRepo]\n saveThoughtsConfig(config, options)\n }\n\n console.log(chalk.green('✅ Thoughts removed from repository'))\n\n // Provide info about what was done\n if (mappedName) {\n console.log('')\n console.log(chalk.gray('Note: Your thoughts content remains safe in:'))\n\n if (profileName && config.profiles && config.profiles[profileName]) {\n const profile = config.profiles[profileName]\n console.log(chalk.gray(` ${profile.thoughtsRepo}/${profile.reposDir}/${mappedName}`))\n console.log(chalk.gray(` (profile: ${profileName})`))\n } else {\n console.log(chalk.gray(` ${config.thoughtsRepo}/${config.reposDir}/${mappedName}`))\n }\n\n console.log(chalk.gray('Only the local symlinks and configuration were removed.'))\n }\n } catch (error) {\n console.error(chalk.red(`Error during thoughts destroy: ${error}`))\n process.exit(1)\n }\n}\n","import fs from 'fs'\nimport path from 'path'\nimport { execSync, execFileSync } from 'child_process'\nimport chalk from 'chalk'\nimport {\n loadThoughtsConfig,\n getCurrentRepoPath,\n expandPath,\n updateSymlinksForNewUsers,\n} from './utils/index.js'\nimport { resolveProfileForRepo, getRepoNameFromMapping } from './profile/utils.js'\n\ninterface SyncOptions {\n message?: string\n configFile?: string\n}\n\nfunction checkGitStatus(repoPath: string): boolean {\n try {\n const status = execSync('git status --porcelain', {\n cwd: repoPath,\n encoding: 'utf8',\n stdio: 'pipe',\n })\n return status.trim().length > 0\n } catch {\n return false\n }\n}\n\nfunction syncThoughts(thoughtsRepo: string, message: string): void {\n const expandedRepo = expandPath(thoughtsRepo)\n\n try {\n // Stage all changes\n execSync('git add -A', { cwd: expandedRepo, stdio: 'pipe' })\n\n // Check if there are changes to commit\n const hasChanges = checkGitStatus(expandedRepo)\n\n if (hasChanges) {\n // Commit changes\n const commitMessage = message || `Sync thoughts - ${new Date().toISOString()}`\n execFileSync('git', ['commit', '-m', commitMessage], { cwd: expandedRepo, stdio: 'pipe' })\n\n console.log(chalk.green('✅ Thoughts synchronized'))\n } else {\n console.log(chalk.gray('No changes to commit'))\n }\n\n // Pull latest changes after committing (to avoid conflicts with staged changes)\n try {\n execSync('git pull --rebase', {\n stdio: 'pipe',\n cwd: expandedRepo,\n })\n } catch (error) {\n const errorStr = error.toString()\n if (\n errorStr.includes('CONFLICT (') ||\n errorStr.includes('Automatic merge failed') ||\n errorStr.includes('Patch failed at') ||\n errorStr.includes('When you have resolved this problem, run \"git rebase --continue\"')\n ) {\n console.error(chalk.red('Error: Merge conflict detected in thoughts repository'))\n console.error(chalk.red('Please resolve conflicts manually in:'), expandedRepo)\n console.error(chalk.red('Then run \"git rebase --continue\" and \"thoughtcabinet sync\" again'))\n process.exit(1)\n } else {\n // If pull fails for other reasons, show warning but continue\n // This handles cases like no upstream, network issues, etc.\n console.warn(chalk.yellow('Warning: Could not pull latest changes:'), error.message)\n }\n }\n\n // Check if remote exists and push any unpushed commits\n try {\n execSync('git remote get-url origin', { cwd: expandedRepo, stdio: 'pipe' })\n\n // Try to push\n console.log(chalk.gray('Pushing to remote...'))\n try {\n execSync('git push', { cwd: expandedRepo, stdio: 'pipe' })\n console.log(chalk.green('✅ Pushed to remote'))\n } catch {\n console.log(chalk.yellow('⚠️ Could not push to remote. You may need to push manually.'))\n }\n } catch {\n // No remote configured\n console.log(chalk.yellow('ℹ️ No remote configured for thoughts repository'))\n }\n } catch (error) {\n console.error(chalk.red(`Error syncing thoughts: ${error}`))\n process.exit(1)\n }\n}\n\nfunction createSearchDirectory(thoughtsDir: string): void {\n const searchDir = path.join(thoughtsDir, 'searchable')\n // Remove existing searchable directory if it exists\n if (fs.existsSync(searchDir)) {\n try {\n // Reset permissions so we can delete it\n execSync(`chmod -R 755 \"${searchDir}\"`, { stdio: 'pipe' })\n } catch {\n // Ignore chmod errors\n }\n fs.rmSync(searchDir, { recursive: true, force: true })\n }\n\n // Create new searchable directory\n fs.mkdirSync(searchDir, { recursive: true })\n\n // Function to recursively find all files through symlinks\n function findFilesFollowingSymlinks(\n dir: string,\n baseDir: string = dir,\n visited: Set<string> = new Set(),\n ): string[] {\n const files: string[] = []\n\n // Resolve symlinks to avoid cycles\n const realPath = fs.realpathSync(dir)\n if (visited.has(realPath)) {\n return files\n }\n visited.add(realPath)\n\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name)\n if (entry.isDirectory() && !entry.name.startsWith('.')) {\n files.push(...findFilesFollowingSymlinks(fullPath, baseDir, visited))\n } else if (entry.isSymbolicLink() && !entry.name.startsWith('.')) {\n try {\n const stat = fs.statSync(fullPath)\n if (stat.isDirectory()) {\n files.push(...findFilesFollowingSymlinks(fullPath, baseDir, visited))\n } else if (stat.isFile() && path.basename(fullPath) !== 'CLAUDE.md') {\n files.push(path.relative(baseDir, fullPath))\n }\n } catch {\n // Ignore broken symlinks\n }\n } else if (entry.isFile() && !entry.name.startsWith('.') && entry.name !== 'CLAUDE.md') {\n files.push(path.relative(baseDir, fullPath))\n }\n }\n\n return files\n }\n\n // Get all files accessible through the thoughts directory (following symlinks)\n const allFiles = findFilesFollowingSymlinks(thoughtsDir)\n\n // Create hard links in searchable directory\n let linkedCount = 0\n for (const relPath of allFiles) {\n const sourcePath = path.join(thoughtsDir, relPath)\n const targetPath = path.join(searchDir, relPath)\n\n // Create directory structure\n const targetDir = path.dirname(targetPath)\n if (!fs.existsSync(targetDir)) {\n fs.mkdirSync(targetDir, { recursive: true })\n }\n\n try {\n // Resolve symlink to get the real file path\n const realSourcePath = fs.realpathSync(sourcePath)\n // Create hard link to the real file\n fs.linkSync(realSourcePath, targetPath)\n linkedCount++\n } catch {\n // Silently skip files we can't link (e.g., different filesystems)\n }\n }\n\n console.log(chalk.gray(`Created ${linkedCount} hard links in searchable directory`))\n}\n\nexport async function thoughtsSyncCommand(options: SyncOptions): Promise<void> {\n try {\n // Check if thoughts are configured\n const config = loadThoughtsConfig(options)\n\n if (!config) {\n console.error(chalk.red('Error: Thoughts not configured. Run \"thoughtcabinet init\" first.'))\n process.exit(1)\n }\n\n // Check if current repo has thoughts setup\n const currentRepo = getCurrentRepoPath()\n const thoughtsDir = path.join(currentRepo, 'thoughts')\n\n if (!fs.existsSync(thoughtsDir)) {\n console.error(chalk.red('Error: Thoughts not initialized for this repository.'))\n console.error('Run \"thoughtcabinet init\" to set up thoughts.')\n process.exit(1)\n }\n\n // Get current repo mapping and resolve profile\n const mapping = config.repoMappings[currentRepo]\n const mappedName = getRepoNameFromMapping(mapping)\n const profileConfig = resolveProfileForRepo(config, currentRepo)\n\n if (mappedName) {\n // Update symlinks for any new users using profile config\n const newUsers = updateSymlinksForNewUsers(\n currentRepo,\n profileConfig,\n mappedName,\n config.user,\n )\n\n if (newUsers.length > 0) {\n console.log(chalk.green(`✓ Added symlinks for new users: ${newUsers.join(', ')}`))\n }\n }\n\n // Create searchable directory with hard links\n console.log(chalk.blue('Creating searchable index...'))\n createSearchDirectory(thoughtsDir)\n\n // Sync the thoughts repository using profile's thoughtsRepo\n console.log(chalk.blue('Syncing thoughts...'))\n syncThoughts(profileConfig.thoughtsRepo, options.message || '')\n } catch (error) {\n console.error(chalk.red(`Error during thoughts sync: ${error}`))\n process.exit(1)\n }\n}\n","import fs from 'fs'\nimport path from 'path'\nimport { execSync } from 'child_process'\nimport chalk from 'chalk'\nimport { loadThoughtsConfig, getCurrentRepoPath, expandPath } from './utils/index.js'\nimport {\n getRepoNameFromMapping,\n getProfileNameFromMapping,\n resolveProfileForRepo,\n} from './profile/utils.js'\n\nfunction getGitStatus(repoPath: string): string {\n try {\n return execSync('git status -sb', {\n cwd: repoPath,\n encoding: 'utf8',\n stdio: 'pipe',\n }).trim()\n } catch {\n return 'Not a git repository'\n }\n}\n\nfunction getUncommittedChanges(repoPath: string): string[] {\n try {\n const output = execSync('git status --porcelain', {\n cwd: repoPath,\n encoding: 'utf8',\n stdio: 'pipe',\n })\n\n return output\n .split('\\n')\n .filter(line => line.trim())\n .map(line => {\n const status = line.substring(0, 2)\n const file = line.substring(3)\n let statusText = ''\n\n if (status[0] === 'M' || status[1] === 'M') statusText = 'modified'\n else if (status[0] === 'A') statusText = 'added'\n else if (status[0] === 'D') statusText = 'deleted'\n else if (status[0] === '?') statusText = 'untracked'\n else if (status[0] === 'R') statusText = 'renamed'\n\n return ` ${chalk.yellow(statusText.padEnd(10))} ${file}`\n })\n } catch {\n return []\n }\n}\n\nfunction getLastCommit(repoPath: string): string {\n try {\n return execSync('git log -1 --pretty=format:\"%h %s (%cr)\"', {\n cwd: repoPath,\n encoding: 'utf8',\n stdio: 'pipe',\n }).trim()\n } catch {\n return 'No commits yet'\n }\n}\n\nfunction getRemoteStatus(repoPath: string): string {\n try {\n execSync('git remote get-url origin', { cwd: repoPath, stdio: 'pipe' })\n\n // Fetch to update remote refs\n try {\n execSync('git fetch', { cwd: repoPath, stdio: 'pipe' })\n } catch {\n // Fetch might fail, continue anyway\n }\n\n // Check if we're ahead/behind\n const status = execSync('git status -sb', {\n cwd: repoPath,\n encoding: 'utf8',\n stdio: 'pipe',\n })\n\n if (status.includes('ahead')) {\n const ahead = status.match(/ahead (\\d+)/)?.[1] || '?'\n return chalk.yellow(`${ahead} commits ahead of remote`)\n } else if (status.includes('behind')) {\n const behind = status.match(/behind (\\d+)/)?.[1] || '?'\n\n // Try to automatically pull if we're behind\n try {\n execSync('git pull --rebase', {\n stdio: 'pipe',\n cwd: repoPath,\n })\n console.log(chalk.green('✓ Automatically pulled latest changes'))\n\n // Re-check status after pull\n const newStatus = execSync('git status -sb', {\n encoding: 'utf8',\n cwd: repoPath,\n stdio: 'pipe',\n })\n\n if (newStatus.includes('behind')) {\n const newBehind = newStatus.match(/behind (\\d+)/)?.[1] || '?'\n return chalk.yellow(`${newBehind} commits behind remote (after pull)`)\n } else {\n return chalk.green('Up to date with remote (after pull)')\n }\n } catch {\n // Silent fail - status is read-only operation\n return chalk.yellow(`${behind} commits behind remote`)\n }\n } else {\n return chalk.green('Up to date with remote')\n }\n } catch {\n return chalk.gray('No remote configured')\n }\n}\n\ninterface StatusOptions {\n configFile?: string\n}\n\nexport async function thoughtsStatusCommand(options: StatusOptions): Promise<void> {\n try {\n // Check if thoughts are configured\n const config = loadThoughtsConfig(options)\n\n if (!config) {\n console.error(chalk.red('Error: Thoughts not configured. Run \"thoughtcabinet init\" first.'))\n process.exit(1)\n }\n\n console.log(chalk.blue('Thoughts Repository Status'))\n console.log(chalk.gray('='.repeat(50)))\n console.log('')\n\n // Show configuration\n console.log(chalk.yellow('Configuration:'))\n console.log(` Repository: ${chalk.cyan(config.thoughtsRepo)}`)\n console.log(` Repos directory: ${chalk.cyan(config.reposDir)}`)\n console.log(` Global directory: ${chalk.cyan(config.globalDir)}`)\n console.log(` User: ${chalk.cyan(config.user)}`)\n console.log(` Mapped repos: ${chalk.cyan(Object.keys(config.repoMappings).length)}`)\n console.log('')\n\n // Check current repo mapping\n const currentRepo = getCurrentRepoPath()\n const currentMapping = config.repoMappings[currentRepo]\n const mappedName = getRepoNameFromMapping(currentMapping)\n const profileName = getProfileNameFromMapping(currentMapping)\n const profileConfig = resolveProfileForRepo(config, currentRepo)\n\n if (mappedName) {\n console.log(chalk.yellow('Current Repository:'))\n console.log(` Path: ${chalk.cyan(currentRepo)}`)\n console.log(` Thoughts directory: ${chalk.cyan(`${profileConfig.reposDir}/${mappedName}`)}`)\n\n // Add profile info\n if (profileName) {\n console.log(` Profile: ${chalk.cyan(profileName)}`)\n } else {\n console.log(` Profile: ${chalk.gray('(default)')}`)\n }\n\n const thoughtsDir = path.join(currentRepo, 'thoughts')\n if (fs.existsSync(thoughtsDir)) {\n console.log(` Status: ${chalk.green('✓ Initialized')}`)\n } else {\n console.log(` Status: ${chalk.red('✗ Not initialized')}`)\n }\n } else {\n console.log(chalk.yellow('Current repository not mapped to thoughts'))\n }\n console.log('')\n\n // Show thoughts repository git status using profile's thoughtsRepo\n const expandedRepo = expandPath(profileConfig.thoughtsRepo)\n\n console.log(chalk.yellow('Thoughts Repository Git Status:'))\n if (profileName) {\n console.log(chalk.gray(` (using profile: ${profileName})`))\n }\n console.log(` ${getGitStatus(expandedRepo)}`)\n console.log(` Remote: ${getRemoteStatus(expandedRepo)}`)\n console.log(` Last commit: ${getLastCommit(expandedRepo)}`)\n console.log('')\n\n // Show uncommitted changes\n const changes = getUncommittedChanges(expandedRepo)\n if (changes.length > 0) {\n console.log(chalk.yellow('Uncommitted changes:'))\n changes.forEach(change => console.log(change))\n console.log('')\n console.log(chalk.gray('Run \"thoughtcabinet sync\" to commit these changes'))\n } else {\n console.log(chalk.green('✓ No uncommitted changes'))\n }\n } catch (error) {\n console.error(chalk.red(`Error checking thoughts status: ${error}`))\n process.exit(1)\n }\n}\n","import { spawn } from 'child_process'\nimport chalk from 'chalk'\nimport { loadThoughtsConfig } from './utils/index.js'\nimport { getRepoNameFromMapping, getProfileNameFromMapping } from './profile/utils.js'\nimport { getDefaultConfigPath } from '../../config.js'\n\ninterface ConfigOptions {\n edit?: boolean\n json?: boolean\n configFile?: string\n}\n\nexport async function thoughtsConfigCommand(options: ConfigOptions): Promise<void> {\n try {\n const configPath = options.configFile || getDefaultConfigPath()\n\n // Handle edit mode\n if (options.edit) {\n const editor = process.env.EDITOR || 'vi'\n spawn(editor, [configPath], { stdio: 'inherit' })\n return\n }\n\n // Load configuration\n const config = loadThoughtsConfig(options)\n\n if (!config) {\n console.error(chalk.red('No thoughts configuration found.'))\n console.error('Run \"thoughtcabinet init\" to create one.')\n process.exit(1)\n }\n\n // Handle JSON output\n if (options.json) {\n console.log(JSON.stringify(config, null, 2))\n return\n }\n\n // Display configuration\n console.log(chalk.blue('Thoughts Configuration'))\n console.log(chalk.gray('='.repeat(50)))\n console.log('')\n\n console.log(chalk.yellow('Settings:'))\n console.log(` Config file: ${chalk.cyan(configPath)}`)\n console.log(` Thoughts repository: ${chalk.cyan(config.thoughtsRepo)}`)\n console.log(` Repos directory: ${chalk.cyan(config.reposDir)}`)\n console.log(` Global directory: ${chalk.cyan(config.globalDir)}`)\n console.log(` User: ${chalk.cyan(config.user)}`)\n console.log('')\n\n console.log(chalk.yellow('Repository Mappings:'))\n const mappings = Object.entries(config.repoMappings)\n\n if (mappings.length === 0) {\n console.log(chalk.gray(' No repositories mapped yet'))\n } else {\n mappings.forEach(([repo, mapping]) => {\n const repoName = getRepoNameFromMapping(mapping)\n const profileName = getProfileNameFromMapping(mapping)\n\n console.log(` ${chalk.cyan(repo)}`)\n console.log(` → ${chalk.green(`${config.reposDir}/${repoName}`)}`)\n\n if (profileName) {\n console.log(` Profile: ${chalk.yellow(profileName)}`)\n } else {\n console.log(` Profile: ${chalk.gray('(default)')}`)\n }\n })\n }\n\n console.log('')\n\n // Add profiles section\n console.log(chalk.yellow('Profiles:'))\n if (!config.profiles || Object.keys(config.profiles).length === 0) {\n console.log(chalk.gray(' No profiles configured'))\n } else {\n Object.keys(config.profiles).forEach(name => {\n console.log(` ${chalk.cyan(name)}`)\n })\n }\n\n console.log('')\n console.log(chalk.gray('To edit configuration, run: thoughtcabinet config --edit'))\n } catch (error) {\n console.error(chalk.red(`Error showing thoughts config: ${error}`))\n process.exit(1)\n }\n}\n","import chalk from 'chalk'\nimport * as p from '@clack/prompts'\nimport {\n loadThoughtsConfig,\n saveThoughtsConfig,\n getDefaultThoughtsRepo,\n ensureThoughtsRepoExists,\n} from '../utils/index.js'\nimport { sanitizeProfileName, validateProfile } from './utils.js'\nimport type { ProfileConfig } from '../../../config'\n\ninterface CreateOptions {\n repo?: string\n reposDir?: string\n globalDir?: string\n configFile?: string\n}\n\nexport async function profileCreateCommand(\n profileName: string,\n options: CreateOptions,\n): Promise<void> {\n try {\n // Check for non-interactive mode\n if (!options.repo || !options.reposDir || !options.globalDir) {\n if (!process.stdin.isTTY) {\n p.log.error('Not running in interactive terminal.')\n p.log.info('Provide all options: --repo, --repos-dir, --global-dir')\n process.exit(1)\n }\n }\n\n // Load existing config\n const config = loadThoughtsConfig(options as Record<string, unknown>)\n\n if (!config) {\n p.log.error('Thoughts not configured.')\n p.log.info('Run \"thoughtcabinet init\" first to set up the base configuration.')\n process.exit(1)\n }\n\n // Sanitize profile name\n const sanitizedName = sanitizeProfileName(profileName)\n if (sanitizedName !== profileName) {\n p.log.warn(`Profile name sanitized: \"${profileName}\" → \"${sanitizedName}\"`)\n }\n\n p.intro(chalk.blue(`Creating Profile: ${sanitizedName}`))\n\n // Check if profile already exists\n if (validateProfile(config, sanitizedName)) {\n p.log.error(`Profile \"${sanitizedName}\" already exists.`)\n p.log.info('Use a different name or delete the existing profile first.')\n process.exit(1)\n }\n\n // Get profile configuration\n let thoughtsRepo: string\n let reposDir: string\n let globalDir: string\n\n if (options.repo && options.reposDir && options.globalDir) {\n // Non-interactive mode\n thoughtsRepo = options.repo\n reposDir = options.reposDir\n globalDir = options.globalDir\n } else {\n // Interactive mode\n const defaultRepo = getDefaultThoughtsRepo() + `-${sanitizedName}`\n p.log.info('Specify the thoughts repository location for this profile.')\n\n const repoInput = await p.text({\n message: 'Thoughts repository:',\n initialValue: defaultRepo,\n placeholder: defaultRepo,\n })\n\n if (p.isCancel(repoInput)) {\n p.cancel('Operation cancelled.')\n process.exit(0)\n }\n thoughtsRepo = (repoInput as string) || defaultRepo\n\n const reposDirInput = await p.text({\n message: 'Repository-specific thoughts directory:',\n initialValue: 'repos',\n placeholder: 'repos',\n })\n\n if (p.isCancel(reposDirInput)) {\n p.cancel('Operation cancelled.')\n process.exit(0)\n }\n reposDir = (reposDirInput as string) || 'repos'\n\n const globalDirInput = await p.text({\n message: 'Global thoughts directory:',\n initialValue: 'global',\n placeholder: 'global',\n })\n\n if (p.isCancel(globalDirInput)) {\n p.cancel('Operation cancelled.')\n process.exit(0)\n }\n globalDir = (globalDirInput as string) || 'global'\n }\n\n // Create profile config\n const profileConfig: ProfileConfig = {\n thoughtsRepo,\n reposDir,\n globalDir,\n }\n\n // Initialize profiles object if it doesn't exist\n if (!config.profiles) {\n config.profiles = {}\n }\n\n // Add profile\n config.profiles[sanitizedName] = profileConfig\n\n // Save config\n saveThoughtsConfig(config, options as Record<string, unknown>)\n\n // Create the profile's thoughts repository structure\n p.log.step('Initializing profile thoughts repository...')\n ensureThoughtsRepoExists(profileConfig)\n\n p.log.success(`Profile \"${sanitizedName}\" created successfully!`)\n\n p.note(\n `Name: ${chalk.cyan(sanitizedName)}\\n` +\n `Thoughts repository: ${chalk.cyan(thoughtsRepo)}\\n` +\n `Repos directory: ${chalk.cyan(reposDir)}\\n` +\n `Global directory: ${chalk.cyan(globalDir)}`,\n 'Profile Configuration',\n )\n\n p.outro(\n chalk.gray('Next steps:\\n') +\n chalk.gray(` 1. Run \"thoughtcabinet init --profile ${sanitizedName}\" in a repository\\n`) +\n chalk.gray(` 2. Your thoughts will sync to the profile's repository`),\n )\n } catch (error) {\n p.log.error(`Error creating profile: ${error}`)\n process.exit(1)\n }\n}\n","import chalk from 'chalk'\nimport { loadThoughtsConfig } from '../utils/index.js'\n\ninterface ListOptions {\n json?: boolean\n configFile?: string\n}\n\nexport async function profileListCommand(options: ListOptions): Promise<void> {\n try {\n const config = loadThoughtsConfig(options)\n\n if (!config) {\n console.error(chalk.red('Error: Thoughts not configured.'))\n process.exit(1)\n }\n\n if (options.json) {\n console.log(JSON.stringify(config.profiles || {}, null, 2))\n return\n }\n\n console.log(chalk.blue('Thoughts Profiles'))\n console.log(chalk.gray('='.repeat(50)))\n console.log('')\n\n // Show default config\n console.log(chalk.yellow('Default Configuration:'))\n console.log(` Thoughts repository: ${chalk.cyan(config.thoughtsRepo)}`)\n console.log(` Repos directory: ${chalk.cyan(config.reposDir)}`)\n console.log(` Global directory: ${chalk.cyan(config.globalDir)}`)\n console.log('')\n\n // Show profiles\n if (!config.profiles || Object.keys(config.profiles).length === 0) {\n console.log(chalk.gray('No profiles configured.'))\n console.log('')\n console.log(chalk.gray('Create a profile with: thoughtcabinet profile create <name>'))\n } else {\n console.log(chalk.yellow(`Profiles (${Object.keys(config.profiles).length}):`))\n console.log('')\n\n Object.entries(config.profiles).forEach(([name, profile]) => {\n console.log(chalk.cyan(` ${name}:`))\n console.log(` Thoughts repository: ${profile.thoughtsRepo}`)\n console.log(` Repos directory: ${profile.reposDir}`)\n console.log(` Global directory: ${profile.globalDir}`)\n console.log('')\n })\n }\n } catch (error) {\n console.error(chalk.red(`Error listing profiles: ${error}`))\n process.exit(1)\n }\n}\n","import chalk from 'chalk'\nimport { loadThoughtsConfig } from '../utils/index.js'\nimport { validateProfile } from './utils.js'\n\ninterface ShowOptions {\n json?: boolean\n configFile?: string\n}\n\nexport async function profileShowCommand(profileName: string, options: ShowOptions): Promise<void> {\n try {\n const config = loadThoughtsConfig(options)\n\n if (!config) {\n console.error(chalk.red('Error: Thoughts not configured.'))\n process.exit(1)\n }\n\n if (!validateProfile(config, profileName)) {\n console.error(chalk.red(`Error: Profile \"${profileName}\" not found.`))\n console.error('')\n console.error(chalk.gray('Available profiles:'))\n if (config.profiles) {\n Object.keys(config.profiles).forEach(name => {\n console.error(chalk.gray(` - ${name}`))\n })\n } else {\n console.error(chalk.gray(' (none)'))\n }\n process.exit(1)\n }\n\n const profile = config.profiles![profileName]\n\n if (options.json) {\n console.log(JSON.stringify(profile, null, 2))\n return\n }\n\n console.log(chalk.blue(`Profile: ${profileName}`))\n console.log(chalk.gray('='.repeat(50)))\n console.log('')\n console.log(chalk.yellow('Configuration:'))\n console.log(` Thoughts repository: ${chalk.cyan(profile.thoughtsRepo)}`)\n console.log(` Repos directory: ${chalk.cyan(profile.reposDir)}`)\n console.log(` Global directory: ${chalk.cyan(profile.globalDir)}`)\n console.log('')\n\n // Count repositories using this profile\n let repoCount = 0\n Object.values(config.repoMappings).forEach(mapping => {\n if (typeof mapping === 'object' && mapping.profile === profileName) {\n repoCount++\n }\n })\n\n console.log(chalk.yellow('Usage:'))\n console.log(` Repositories using this profile: ${chalk.cyan(repoCount)}`)\n } catch (error) {\n console.error(chalk.red(`Error showing profile: ${error}`))\n process.exit(1)\n }\n}\n","import chalk from 'chalk'\nimport * as p from '@clack/prompts'\nimport { loadThoughtsConfig, saveThoughtsConfig } from '../utils/index.js'\nimport { validateProfile } from './utils.js'\n\ninterface DeleteOptions {\n force?: boolean\n configFile?: string\n}\n\nexport async function profileDeleteCommand(\n profileName: string,\n options: DeleteOptions,\n): Promise<void> {\n try {\n // Check for non-interactive mode\n if (!options.force && !process.stdin.isTTY) {\n p.log.error('Not running in interactive terminal.')\n p.log.info('Use --force flag to delete without confirmation.')\n process.exit(1)\n }\n\n p.intro(chalk.blue(`Delete Profile: ${profileName}`))\n\n const config = loadThoughtsConfig(options)\n\n if (!config) {\n p.log.error('Thoughts not configured.')\n process.exit(1)\n }\n\n if (!validateProfile(config, profileName)) {\n p.log.error(`Profile \"${profileName}\" not found.`)\n process.exit(1)\n }\n\n // Check if any repositories are using this profile\n const usingRepos: string[] = []\n Object.entries(config.repoMappings).forEach(([repoPath, mapping]) => {\n if (typeof mapping === 'object' && mapping.profile === profileName) {\n usingRepos.push(repoPath)\n }\n })\n\n if (usingRepos.length > 0 && !options.force) {\n p.log.error(`Profile \"${profileName}\" is in use by ${usingRepos.length} repository(ies):`)\n usingRepos.forEach(repo => {\n p.log.message(chalk.gray(` - ${repo}`))\n })\n p.log.warn('Options:')\n p.log.message(chalk.gray(' 1. Run \"thoughtcabinet destroy\" in each repository'))\n p.log.message(\n chalk.gray(' 2. Use --force to delete anyway (repos will fall back to default config)'),\n )\n process.exit(1)\n }\n\n // Confirm deletion\n if (!options.force) {\n p.log.warn(`You are about to delete profile: ${chalk.cyan(profileName)}`)\n p.log.message(chalk.gray('This will remove the profile configuration.'))\n p.log.message(chalk.gray('The thoughts repository files will NOT be deleted.'))\n\n const confirmDelete = await p.confirm({\n message: `Delete profile \"${profileName}\"?`,\n initialValue: false,\n })\n\n if (p.isCancel(confirmDelete) || !confirmDelete) {\n p.cancel('Deletion cancelled.')\n return\n }\n }\n\n // Delete profile\n delete config.profiles![profileName]\n\n // If profiles is now empty, remove it entirely\n if (Object.keys(config.profiles!).length === 0) {\n delete config.profiles\n }\n\n // Save config\n saveThoughtsConfig(config, options)\n\n p.log.success(`Profile \"${profileName}\" deleted`)\n\n if (usingRepos.length > 0) {\n p.log.warn('Repositories using this profile will fall back to default config')\n }\n\n p.outro(chalk.green('Done'))\n } catch (error) {\n p.log.error(`Error deleting profile: ${error}`)\n process.exit(1)\n }\n}\n","import { Command } from 'commander'\nimport { thoughtsInitCommand } from './thoughts/init.js'\nimport { thoughtsDestoryCommand } from './thoughts/destroy.js'\nimport { thoughtsSyncCommand } from './thoughts/sync.js'\nimport { thoughtsStatusCommand } from './thoughts/status.js'\nimport { thoughtsConfigCommand } from './thoughts/config.js'\nimport { profileCreateCommand } from './thoughts/profile/create.js'\nimport { profileListCommand } from './thoughts/profile/list.js'\nimport { profileShowCommand } from './thoughts/profile/show.js'\nimport { profileDeleteCommand } from './thoughts/profile/delete.js'\n\nexport function thoughtsCommand(program: Command): void {\n const cmd = program\n\n cmd\n .command('init')\n .description('Initialize thoughts for current repository')\n .option('--force', 'Force reconfiguration even if already set up')\n .option('--config-file <path>', 'Path to config file')\n .option(\n '--directory <name>',\n 'Specify the repository directory name (skips interactive prompt)',\n )\n .option('--profile <name>', 'Use a specific thoughts profile')\n .action(thoughtsInitCommand)\n\n cmd\n .command('destroy')\n .description('Remove thoughts setup from current repository')\n .option('--force', 'Force removal even if not in configuration')\n .option('--config-file <path>', 'Path to config file')\n .action(thoughtsDestoryCommand)\n\n cmd\n .command('sync')\n .description('Manually sync thoughts to thoughts repository')\n .option('-m, --message <message>', 'Commit message for sync')\n .option('--config-file <path>', 'Path to config file')\n .action(thoughtsSyncCommand)\n\n cmd\n .command('status')\n .description('Show status of thoughts repository')\n .option('--config-file <path>', 'Path to config file')\n .action(thoughtsStatusCommand)\n\n cmd\n .command('config')\n .description('View or edit thoughts configuration')\n .option('--edit', 'Open configuration in editor')\n .option('--json', 'Output configuration as JSON')\n .option('--config-file <path>', 'Path to config file')\n .action(thoughtsConfigCommand)\n\n // Profile management commands\n const profile = cmd.command('profile').description('Manage thoughts profiles')\n\n profile\n .command('create <name>')\n .description('Create a new thoughts profile')\n .option('--repo <path>', 'Thoughts repository path')\n .option('--repos-dir <name>', 'Repos directory name')\n .option('--global-dir <name>', 'Global directory name')\n .option('--config-file <path>', 'Path to config file')\n .action(profileCreateCommand)\n\n profile\n .command('list')\n .description('List all thoughts profiles')\n .option('--json', 'Output as JSON')\n .option('--config-file <path>', 'Path to config file')\n .action(profileListCommand)\n\n profile\n .command('show <name>')\n .description('Show details of a specific profile')\n .option('--json', 'Output as JSON')\n .option('--config-file <path>', 'Path to config file')\n .action(profileShowCommand)\n\n profile\n .command('delete <name>')\n .description('Delete a thoughts profile')\n .option('--force', 'Force deletion even if in use')\n .option('--config-file <path>', 'Path to config file')\n .action(profileDeleteCommand)\n}\n","import fs from 'fs'\nimport path from 'path'\nimport chalk from 'chalk'\nimport * as p from '@clack/prompts'\nimport { fileURLToPath } from 'url'\nimport { dirname } from 'path'\nimport { AgentProduct } from './registry.js'\n\n// Get the directory of this module\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = dirname(__filename)\n\nexport interface AgentInitOptions {\n product: AgentProduct\n force?: boolean\n all?: boolean\n maxThinkingTokens?: number\n}\n\nfunction ensureGitignoreEntry(targetDir: string, entry: string, productName: string): void {\n const gitignorePath = path.join(targetDir, '.gitignore')\n\n // Read existing .gitignore or create empty\n let gitignoreContent = ''\n if (fs.existsSync(gitignorePath)) {\n gitignoreContent = fs.readFileSync(gitignorePath, 'utf8')\n }\n\n // Check if entry already exists\n const lines = gitignoreContent.split('\\n')\n if (lines.some(line => line.trim() === entry)) {\n return // Already exists\n }\n\n // Add entry with section comment\n const newContent =\n gitignoreContent +\n (gitignoreContent && !gitignoreContent.endsWith('\\n') ? '\\n' : '') +\n '\\n# ' +\n productName +\n ' local settings\\n' +\n entry +\n '\\n'\n\n fs.writeFileSync(gitignorePath, newContent)\n}\n\n/**\n * Recursively copy a directory\n * @returns Number of files copied\n */\nfunction copyDirectoryRecursive(sourceDir: string, targetDir: string): number {\n let filesCopied = 0\n\n // Create target directory\n fs.mkdirSync(targetDir, { recursive: true })\n\n const entries = fs.readdirSync(sourceDir, { withFileTypes: true })\n\n for (const entry of entries) {\n const sourcePath = path.join(sourceDir, entry.name)\n const targetPath = path.join(targetDir, entry.name)\n\n if (entry.isDirectory()) {\n // Recursively copy subdirectory\n filesCopied += copyDirectoryRecursive(sourcePath, targetPath)\n } else {\n // Copy file\n fs.copyFileSync(sourcePath, targetPath)\n filesCopied++\n }\n }\n\n return filesCopied\n}\n\nexport async function agentInitCommand(options: AgentInitOptions): Promise<void> {\n const { product } = options\n\n try {\n p.intro(chalk.blue(`Initialize ${product.name} Configuration`))\n\n // Check if running in interactive terminal\n if (!process.stdin.isTTY && !options.all) {\n p.log.error('Not running in interactive terminal.')\n p.log.info('Use --all flag to copy all files without prompting.')\n process.exit(1)\n }\n\n const targetDir = process.cwd()\n const agentTargetDir = path.join(targetDir, product.dirName)\n\n // Determine source location\n // Try multiple possible locations for the agent directory\n const possiblePaths = [\n // When installed via npm: package root is one level up from dist\n path.resolve(__dirname, '..', product.sourceDirName),\n // When running from repo: repo root is two levels up from dist\n path.resolve(__dirname, '../..', product.sourceDirName),\n ]\n\n let sourceAgentDir: string | null = null\n for (const candidatePath of possiblePaths) {\n if (fs.existsSync(candidatePath)) {\n sourceAgentDir = candidatePath\n break\n }\n }\n\n // Verify source directory exists\n if (!sourceAgentDir) {\n p.log.error(`Source ${product.dirName} directory not found in expected locations`)\n p.log.info('Searched paths:')\n possiblePaths.forEach(candidatePath => {\n p.log.info(` - ${candidatePath}`)\n })\n p.log.info('Are you running from the thoughtcabinet repository or npm package?')\n process.exit(1)\n }\n\n // Check if agent directory already exists\n if (fs.existsSync(agentTargetDir) && !options.force) {\n const overwrite = await p.confirm({\n message: `${product.dirName} directory already exists. Overwrite?`,\n initialValue: false,\n })\n\n if (p.isCancel(overwrite) || !overwrite) {\n p.cancel('Operation cancelled.')\n process.exit(0)\n }\n }\n\n let selectedCategories: string[]\n\n if (options.all) {\n selectedCategories = ['commands', 'agents', 'skills', 'settings']\n } else {\n // Interactive selection\n // Calculate actual file counts\n let commandsCount = 0\n let agentsCount = 0\n\n const commandsDir = path.join(sourceAgentDir, 'commands')\n const agentsDir = path.join(sourceAgentDir, 'agents')\n\n if (fs.existsSync(commandsDir)) {\n commandsCount = fs.readdirSync(commandsDir).length\n }\n\n if (fs.existsSync(agentsDir)) {\n agentsCount = fs.readdirSync(agentsDir).length\n }\n\n let skillsCount = 0\n const skillsDir = path.join(sourceAgentDir, 'skills')\n\n if (fs.existsSync(skillsDir)) {\n // Count skill folders (not files)\n skillsCount = fs\n .readdirSync(skillsDir, { withFileTypes: true })\n .filter(dirent => dirent.isDirectory()).length\n }\n\n p.note(\n 'Use ↑/↓ to move, press Space to select/deselect, press A to select/deselect all, press Enter to confirm. (Subsequent multi-selects apply; Ctrl+C to exit)',\n 'Multi-select instructions',\n )\n const selection = await p.multiselect({\n message: 'What would you like to copy?',\n options: [\n {\n value: 'commands',\n label: 'Commands',\n hint: `${commandsCount} workflow commands (planning, CI, research, etc.)`,\n },\n {\n value: 'agents',\n label: 'Agents',\n hint: `${agentsCount} specialized sub-agents for code analysis`,\n },\n {\n value: 'skills',\n label: 'Skills',\n hint: `${skillsCount} specialized skill packages for extended capabilities`,\n },\n {\n value: 'settings',\n label: 'Settings',\n hint: 'Project permissions configuration',\n },\n ],\n initialValues: ['commands', 'agents', 'skills', 'settings'],\n required: false,\n })\n\n if (p.isCancel(selection)) {\n p.cancel('Operation cancelled.')\n process.exit(0)\n }\n\n selectedCategories = selection as string[]\n\n if (selectedCategories.length === 0) {\n p.cancel('No items selected.')\n process.exit(0)\n }\n }\n\n // Create agent directory\n fs.mkdirSync(agentTargetDir, { recursive: true })\n\n let filesCopied = 0\n let filesSkipped = 0\n\n // Wizard-style file selection for each category\n const filesToCopyByCategory: Record<string, string[]> = {}\n\n // If in interactive mode, prompt for file selection per category\n if (!options.all) {\n // Commands file selection (if selected)\n if (selectedCategories.includes('commands')) {\n const sourceDir = path.join(sourceAgentDir, 'commands')\n if (fs.existsSync(sourceDir)) {\n const allFiles = fs.readdirSync(sourceDir)\n const fileSelection = await p.multiselect({\n message: 'Select command files to copy:',\n options: allFiles.map(file => ({\n value: file,\n label: file,\n })),\n initialValues: allFiles,\n required: false,\n })\n\n if (p.isCancel(fileSelection)) {\n p.cancel('Operation cancelled.')\n process.exit(0)\n }\n\n filesToCopyByCategory['commands'] = fileSelection as string[]\n\n if (filesToCopyByCategory['commands'].length === 0) {\n filesSkipped += allFiles.length\n }\n }\n }\n\n // Agents file selection (if selected)\n if (selectedCategories.includes('agents')) {\n const sourceDir = path.join(sourceAgentDir, 'agents')\n if (fs.existsSync(sourceDir)) {\n const allFiles = fs.readdirSync(sourceDir)\n const fileSelection = await p.multiselect({\n message: 'Select agent files to copy:',\n options: allFiles.map(file => ({\n value: file,\n label: file,\n })),\n initialValues: allFiles,\n required: false,\n })\n\n if (p.isCancel(fileSelection)) {\n p.cancel('Operation cancelled.')\n process.exit(0)\n }\n\n filesToCopyByCategory['agents'] = fileSelection as string[]\n\n if (filesToCopyByCategory['agents'].length === 0) {\n filesSkipped += allFiles.length\n }\n }\n }\n\n // Skills folder selection (if selected)\n if (selectedCategories.includes('skills')) {\n const sourceDir = path.join(sourceAgentDir, 'skills')\n if (fs.existsSync(sourceDir)) {\n // Get skill folders (directories only)\n const allSkills = fs\n .readdirSync(sourceDir, { withFileTypes: true })\n .filter(dirent => dirent.isDirectory())\n .map(dirent => dirent.name)\n\n if (allSkills.length > 0) {\n const skillSelection = await p.multiselect({\n message: 'Select skills to copy:',\n options: allSkills.map(skill => ({\n value: skill,\n label: skill,\n })),\n initialValues: allSkills,\n required: false,\n })\n\n if (p.isCancel(skillSelection)) {\n p.cancel('Operation cancelled.')\n process.exit(0)\n }\n\n filesToCopyByCategory['skills'] = skillSelection as string[]\n }\n }\n }\n }\n\n // Configure settings\n let maxThinkingTokens = options.maxThinkingTokens\n\n // Prompt for settings if in interactive mode and not provided via flags\n if (!options.all && selectedCategories.includes('settings')) {\n if (maxThinkingTokens === undefined) {\n const tokensPrompt = await p.text({\n message: 'Maximum thinking tokens:',\n initialValue: '32000',\n validate: value => {\n const num = parseInt(value, 10)\n if (isNaN(num) || num < 1000) {\n return 'Please enter a valid number (minimum 1000)'\n }\n return undefined\n },\n })\n\n if (p.isCancel(tokensPrompt)) {\n p.cancel('Operation cancelled.')\n process.exit(0)\n }\n\n maxThinkingTokens = parseInt(tokensPrompt as string, 10)\n }\n } else if (selectedCategories.includes('settings')) {\n // Non-interactive mode: use defaults if not provided\n if (maxThinkingTokens === undefined) {\n maxThinkingTokens = 32000\n }\n }\n\n // Copy selected categories\n for (const category of selectedCategories) {\n if (category === 'commands' || category === 'agents') {\n const sourceDir = path.join(sourceAgentDir, category)\n const targetCategoryDir = path.join(agentTargetDir, category)\n\n if (!fs.existsSync(sourceDir)) {\n p.log.warn(`${category} directory not found in source, skipping`)\n continue\n }\n\n // Get all files in category\n const allFiles = fs.readdirSync(sourceDir)\n\n // Determine which files to copy\n let filesToCopy = allFiles\n if (!options.all && filesToCopyByCategory[category]) {\n filesToCopy = filesToCopyByCategory[category]\n }\n\n if (filesToCopy.length === 0) {\n continue\n }\n\n // Copy files\n fs.mkdirSync(targetCategoryDir, { recursive: true })\n\n for (const file of filesToCopy) {\n const sourcePath = path.join(sourceDir, file)\n const targetPath = path.join(targetCategoryDir, file)\n\n fs.copyFileSync(sourcePath, targetPath)\n filesCopied++\n }\n\n filesSkipped += allFiles.length - filesToCopy.length\n p.log.success(`Copied ${filesToCopy.length} ${category} file(s)`)\n } else if (category === 'settings') {\n const settingsPath = path.join(sourceAgentDir, 'settings.template.json')\n const targetSettingsPath = path.join(agentTargetDir, 'settings.json')\n\n if (fs.existsSync(settingsPath)) {\n // Read source settings\n const settingsContent = fs.readFileSync(settingsPath, 'utf8')\n const settings = JSON.parse(settingsContent)\n\n // Merge user's configuration into settings\n if (maxThinkingTokens !== undefined) {\n if (!settings.env) {\n settings.env = {}\n }\n settings.env.MAX_THINKING_TOKENS = maxThinkingTokens.toString()\n }\n\n // Set product-specific environment variables\n if (!settings.env) {\n settings.env = {}\n }\n for (const [key, value] of Object.entries(product.defaultEnvVars)) {\n settings.env[key] = value\n }\n\n // Write modified settings\n fs.writeFileSync(targetSettingsPath, JSON.stringify(settings, null, 2) + '\\n')\n filesCopied++\n p.log.success(`Copied settings.json (maxTokens: ${maxThinkingTokens})`)\n } else {\n p.log.warn('settings.json not found in source, skipping')\n }\n } else if (category === 'skills') {\n const sourceDir = path.join(sourceAgentDir, 'skills')\n const targetCategoryDir = path.join(agentTargetDir, 'skills')\n\n if (!fs.existsSync(sourceDir)) {\n p.log.warn('skills directory not found in source, skipping')\n continue\n }\n\n // Get all skill folders\n const allSkills = fs\n .readdirSync(sourceDir, { withFileTypes: true })\n .filter(dirent => dirent.isDirectory())\n .map(dirent => dirent.name)\n\n // Determine which skills to copy\n let skillsToCopy = allSkills\n if (!options.all && filesToCopyByCategory['skills']) {\n skillsToCopy = filesToCopyByCategory['skills']\n }\n\n if (skillsToCopy.length === 0) {\n continue\n }\n\n // Create skills directory\n fs.mkdirSync(targetCategoryDir, { recursive: true })\n\n // Copy each selected skill folder recursively\n let skillFilesCopied = 0\n for (const skill of skillsToCopy) {\n const sourceSkillPath = path.join(sourceDir, skill)\n const targetSkillPath = path.join(targetCategoryDir, skill)\n\n skillFilesCopied += copyDirectoryRecursive(sourceSkillPath, targetSkillPath)\n }\n\n filesCopied += skillFilesCopied\n filesSkipped += allSkills.length - skillsToCopy.length // Count skipped skills (not files)\n p.log.success(`Copied ${skillsToCopy.length} skill(s) (${skillFilesCopied} files)`)\n }\n }\n\n // Update .gitignore to exclude settings.local.json\n if (selectedCategories.includes('settings')) {\n ensureGitignoreEntry(targetDir, product.gitignoreEntry, product.name)\n p.log.info('Updated .gitignore to exclude settings.local.json')\n }\n\n let message = `Successfully copied ${filesCopied} file(s) to ${agentTargetDir}`\n if (filesSkipped > 0) {\n message += chalk.gray(`\\n Skipped ${filesSkipped} file(s)`)\n }\n message += chalk.gray(`\\n You can now use these commands in ${product.name}.`)\n\n p.outro(message)\n } catch (error) {\n p.log.error(`Error during ${product.name} init: ${error}`)\n process.exit(1)\n }\n}\n","/**\n * Agent Product Registry\n *\n * Manages configuration for different coding agent products (claude-code, codebuddy-code, etc.)\n */\n\nexport interface AgentProduct {\n id: string // 'claude' | 'codebuddy'\n name: string // 'Claude Code' | 'CodeBuddy Code'\n dirName: string // '.claude' | '.codebuddy'\n sourceDirName: string // '.claude' | '.codebuddy'\n envVarPrefix: string // 'CLAUDE' | 'CODEBUDDY'\n defaultEnvVars: Record<string, string>\n gitignoreEntry: string // Relative path to settings.local.json\n}\n\nexport const AGENT_PRODUCTS: Record<string, AgentProduct> = {\n claude: {\n id: 'claude',\n name: 'Claude Code',\n dirName: '.claude',\n sourceDirName: 'src/agent-assets',\n envVarPrefix: 'CLAUDE',\n defaultEnvVars: {\n MAX_THINKING_TOKENS: '32000',\n CLAUDE_BASH_MAINTAIN_WORKING_DIR: '1',\n },\n gitignoreEntry: '.claude/settings.local.json',\n },\n codebuddy: {\n id: 'codebuddy',\n name: 'CodeBuddy Code',\n dirName: '.codebuddy',\n sourceDirName: 'src/agent-assets',\n envVarPrefix: 'CODEBUDDY',\n defaultEnvVars: {\n MAX_THINKING_TOKENS: '32000',\n // Note: Current not implemented in CodeBuddy\n CODEBUDDY_BASH_MAINTAIN_PROJECT_WORKING_DIR: '1',\n },\n gitignoreEntry: '.codebuddy/settings.local.json',\n },\n}\n\n/**\n * Get agent product configuration by ID\n * @throws Error if product ID is unknown\n */\nexport function getAgentProduct(id: string): AgentProduct {\n const product = AGENT_PRODUCTS[id]\n if (!product) {\n const validIds = Object.keys(AGENT_PRODUCTS).join(', ')\n throw new Error(`Unknown agent product: ${id}. Valid options: ${validIds}`)\n }\n return product\n}\n\n/**\n * Get all available agent products\n */\nexport function getAllAgentProducts(): AgentProduct[] {\n return Object.values(AGENT_PRODUCTS)\n}\n","import { Command } from 'commander'\nimport { agentInitCommand } from './agent/init.js'\nimport { getAgentProduct } from './agent/registry.js'\n\nexport function agentCommand(program: Command): void {\n const agent = program.command('agent').description('Manage coding agent configuration')\n\n agent\n .command('init')\n .description('Initialize coding agent configuration in current directory')\n .option('--force', 'Force overwrite of existing agent directory')\n .option('--all', 'Copy all files without prompting')\n .option('--max-thinking-tokens <number>', 'Maximum thinking tokens (default: 32000)', value =>\n parseInt(value, 10),\n )\n .option('--name <name>', 'Agent name to configure (claude|codebuddy)', 'claude')\n .action(async options => {\n const product = getAgentProduct(options.name)\n await agentInitCommand({ ...options, product })\n })\n}\n","import { execSync } from 'child_process'\n\ninterface GitInfo {\n repoRoot: string\n repoName: string\n branch: string\n commit: string\n}\n\nfunction getGitInfo(): GitInfo | null {\n try {\n // Check if git is available and we're in a git repo\n execSync('git rev-parse --is-inside-work-tree', {\n encoding: 'utf8',\n stdio: 'pipe',\n })\n\n const repoRoot = execSync('git rev-parse --show-toplevel', {\n encoding: 'utf8',\n stdio: 'pipe',\n }).trim()\n\n const repoName = repoRoot.split('/').pop() || ''\n\n // Get current branch - try --show-current first, fall back to --abbrev-ref HEAD\n let branch = ''\n try {\n branch = execSync('git branch --show-current', {\n encoding: 'utf8',\n stdio: 'pipe',\n }).trim()\n } catch {\n try {\n branch = execSync('git rev-parse --abbrev-ref HEAD', {\n encoding: 'utf8',\n stdio: 'pipe',\n }).trim()\n } catch {\n // No branch yet (fresh repo with no commits)\n branch = ''\n }\n }\n\n // Get commit hash - may fail if no commits yet\n let commit = ''\n try {\n commit = execSync('git rev-parse HEAD', {\n encoding: 'utf8',\n stdio: 'pipe',\n }).trim()\n } catch {\n // No commits yet\n commit = ''\n }\n\n return { repoRoot, repoName, branch, commit }\n } catch {\n return null\n }\n}\n\nfunction formatDate(date: Date): string {\n const pad = (n: number) => n.toString().padStart(2, '0')\n\n const year = date.getFullYear()\n const month = pad(date.getMonth() + 1)\n const day = pad(date.getDate())\n const hours = pad(date.getHours())\n const minutes = pad(date.getMinutes())\n const seconds = pad(date.getSeconds())\n\n // Get timezone name\n const tz = Intl.DateTimeFormat().resolvedOptions().timeZone\n\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds} ${tz}`\n}\n\nfunction formatFilenameTimestamp(date: Date): string {\n const pad = (n: number) => n.toString().padStart(2, '0')\n\n const year = date.getFullYear()\n const month = pad(date.getMonth() + 1)\n const day = pad(date.getDate())\n const hours = pad(date.getHours())\n const minutes = pad(date.getMinutes())\n const seconds = pad(date.getSeconds())\n\n return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`\n}\n\nexport async function specMetadataCommand(): Promise<void> {\n const now = new Date()\n\n // Output datetime with timezone\n console.log(`Current Date/Time (TZ): ${formatDate(now)}`)\n\n // Output git info if available\n const gitInfo = getGitInfo()\n if (gitInfo) {\n if (gitInfo.commit) {\n console.log(`Current Git Commit Hash: ${gitInfo.commit}`)\n }\n if (gitInfo.branch) {\n console.log(`Current Branch Name: ${gitInfo.branch}`)\n }\n if (gitInfo.repoName) {\n console.log(`Repository Name: ${gitInfo.repoName}`)\n }\n }\n\n // Output timestamp suitable for filenames\n console.log(`Timestamp For Filename: ${formatFilenameTimestamp(now)}`)\n}\n","import { Command } from 'commander'\nimport { specMetadataCommand } from './metadata/metadata.js'\n\nexport function metadataCommand(program: Command): void {\n const metadata = program.description('Metadata utilities for current repository')\n\n metadata\n .command('metadata')\n .description('Output metadata for current repository (branch, commit, timestamp, etc.)')\n .action(specMetadataCommand)\n}\n"],"mappings":"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","names":["fs","path","execSync","chalk","path","fs","path","path","os","fs","path","fs","path","path","fs","path","fs","execSync","chalk","reposDir","fs","path","execSync","chalk","path","fs","chalk","execSync","fs","path","execSync","chalk","execSync","chalk","path","fs","fs","path","execSync","chalk","execSync","chalk","path","fs","chalk","chalk","chalk","p","chalk","chalk","chalk","chalk","chalk","chalk","p","chalk","program","fs","path","chalk","p","__filename","__dirname","program","execSync","program","dotenv","require"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "thought-cabinet",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Thought Cabinet (thc) - thoughts management CLI for developer notes and documentation",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"thoughtcabinet": "dist/index.js",
|
|
10
|
+
"thc": "dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist/**/*",
|
|
14
|
+
"src/agent-assets/**/*",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup",
|
|
19
|
+
"build:watch": "tsup --watch",
|
|
20
|
+
"dev": "npm run build && ./dist/index.js",
|
|
21
|
+
"lint": "eslint . --ext .ts",
|
|
22
|
+
"format": "prettier --write .",
|
|
23
|
+
"format:check": "prettier --check .",
|
|
24
|
+
"prepublish": "npm run clean && npm run build",
|
|
25
|
+
"test": "vitest run --passWithNoTests",
|
|
26
|
+
"test:watch": "vitest",
|
|
27
|
+
"check": "npm run format:check && npm run lint && npm run test && npm run build",
|
|
28
|
+
"clean": "rm -rf dist/"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@clack/prompts": "^0.11.0",
|
|
32
|
+
"chalk": "^5.4.1",
|
|
33
|
+
"commander": "^14.0.0",
|
|
34
|
+
"dotenv": "^16.5.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^22.15.21",
|
|
38
|
+
"@typescript-eslint/eslint-plugin": "^8.32.1",
|
|
39
|
+
"@typescript-eslint/parser": "^8.32.1",
|
|
40
|
+
"eslint": "^8.57.0",
|
|
41
|
+
"eslint-config-prettier": "^10.1.5",
|
|
42
|
+
"eslint-plugin-prettier": "^5.4.0",
|
|
43
|
+
"prettier": "^3.5.3",
|
|
44
|
+
"tsup": "^8.5.0",
|
|
45
|
+
"typescript": "^5.8.3",
|
|
46
|
+
"vitest": "^3.1.4"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=16"
|
|
50
|
+
},
|
|
51
|
+
"keywords": [
|
|
52
|
+
"cli",
|
|
53
|
+
"thoughts",
|
|
54
|
+
"notes",
|
|
55
|
+
"documentation"
|
|
56
|
+
],
|
|
57
|
+
"license": "Apache-2.0"
|
|
58
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: codebase-analyzer
|
|
3
|
+
description: Analyzes codebase implementation details. Call the codebase-analyzer agent when you need to find detailed information about specific components. As always, the more detailed your request prompt, the better! :)
|
|
4
|
+
tools: Read, Grep, Glob, LS
|
|
5
|
+
model: sonnet
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are a specialist at understanding HOW code works. Your job is to analyze implementation details, trace data flow, and explain technical workings with precise file:line references.
|
|
9
|
+
|
|
10
|
+
## CRITICAL: YOUR ONLY JOB IS TO DOCUMENT AND EXPLAIN THE CODEBASE AS IT EXISTS TODAY
|
|
11
|
+
|
|
12
|
+
- DO NOT suggest improvements or changes unless the user explicitly asks for them
|
|
13
|
+
- DO NOT perform root cause analysis unless the user explicitly asks for them
|
|
14
|
+
- DO NOT propose future enhancements unless the user explicitly asks for them
|
|
15
|
+
- DO NOT critique the implementation or identify "problems"
|
|
16
|
+
- DO NOT comment on code quality, performance issues, or security concerns
|
|
17
|
+
- DO NOT suggest refactoring, optimization, or better approaches
|
|
18
|
+
- ONLY describe what exists, how it works, and how components interact
|
|
19
|
+
|
|
20
|
+
## Core Responsibilities
|
|
21
|
+
|
|
22
|
+
1. **Analyze Implementation Details**
|
|
23
|
+
- Read specific files to understand logic
|
|
24
|
+
- Identify key functions and their purposes
|
|
25
|
+
- Trace method calls and data transformations
|
|
26
|
+
- Note important algorithms or patterns
|
|
27
|
+
|
|
28
|
+
2. **Trace Data Flow**
|
|
29
|
+
- Follow data from entry to exit points
|
|
30
|
+
- Map transformations and validations
|
|
31
|
+
- Identify state changes and side effects
|
|
32
|
+
- Document API contracts between components
|
|
33
|
+
|
|
34
|
+
3. **Identify Architectural Patterns**
|
|
35
|
+
- Recognize design patterns in use
|
|
36
|
+
- Note architectural decisions
|
|
37
|
+
- Identify conventions and best practices
|
|
38
|
+
- Find integration points between systems
|
|
39
|
+
|
|
40
|
+
## Analysis Strategy
|
|
41
|
+
|
|
42
|
+
### Step 1: Read Entry Points
|
|
43
|
+
|
|
44
|
+
- Start with main files mentioned in the request
|
|
45
|
+
- Look for exports, public methods, or route handlers
|
|
46
|
+
- Identify the "surface area" of the component
|
|
47
|
+
|
|
48
|
+
### Step 2: Follow the Code Path
|
|
49
|
+
|
|
50
|
+
- Trace function calls step by step
|
|
51
|
+
- Read each file involved in the flow
|
|
52
|
+
- Note where data is transformed
|
|
53
|
+
- Identify external dependencies
|
|
54
|
+
- Take time to ultrathink about how all these pieces connect and interact
|
|
55
|
+
|
|
56
|
+
### Step 3: Document Key Logic
|
|
57
|
+
|
|
58
|
+
- Document business logic as it exists
|
|
59
|
+
- Describe validation, transformation, error handling
|
|
60
|
+
- Explain any complex algorithms or calculations
|
|
61
|
+
- Note configuration or feature flags being used
|
|
62
|
+
- DO NOT evaluate if the logic is correct or optimal
|
|
63
|
+
- DO NOT identify potential bugs or issues
|
|
64
|
+
|
|
65
|
+
## Output Format
|
|
66
|
+
|
|
67
|
+
Structure your analysis like this:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
## Analysis: [Feature/Component Name]
|
|
71
|
+
|
|
72
|
+
### Overview
|
|
73
|
+
[2-3 sentence summary of how it works]
|
|
74
|
+
|
|
75
|
+
### Entry Points
|
|
76
|
+
- `api/routes.js:45` - POST /webhooks endpoint
|
|
77
|
+
- `handlers/webhook.js:12` - handleWebhook() function
|
|
78
|
+
|
|
79
|
+
### Core Implementation
|
|
80
|
+
|
|
81
|
+
#### 1. Request Validation (`handlers/webhook.js:15-32`)
|
|
82
|
+
- Validates signature using HMAC-SHA256
|
|
83
|
+
- Checks timestamp to prevent replay attacks
|
|
84
|
+
- Returns 401 if validation fails
|
|
85
|
+
|
|
86
|
+
#### 2. Data Processing (`services/webhook-processor.js:8-45`)
|
|
87
|
+
- Parses webhook payload at line 10
|
|
88
|
+
- Transforms data structure at line 23
|
|
89
|
+
- Queues for async processing at line 40
|
|
90
|
+
|
|
91
|
+
#### 3. State Management (`stores/webhook-store.js:55-89`)
|
|
92
|
+
- Stores webhook in database with status 'pending'
|
|
93
|
+
- Updates status after processing
|
|
94
|
+
- Implements retry logic for failures
|
|
95
|
+
|
|
96
|
+
### Data Flow
|
|
97
|
+
1. Request arrives at `api/routes.js:45`
|
|
98
|
+
2. Routed to `handlers/webhook.js:12`
|
|
99
|
+
3. Validation at `handlers/webhook.js:15-32`
|
|
100
|
+
4. Processing at `services/webhook-processor.js:8`
|
|
101
|
+
5. Storage at `stores/webhook-store.js:55`
|
|
102
|
+
|
|
103
|
+
### Key Patterns
|
|
104
|
+
- **Factory Pattern**: WebhookProcessor created via factory at `factories/processor.js:20`
|
|
105
|
+
- **Repository Pattern**: Data access abstracted in `stores/webhook-store.js`
|
|
106
|
+
- **Middleware Chain**: Validation middleware at `middleware/auth.js:30`
|
|
107
|
+
|
|
108
|
+
### Configuration
|
|
109
|
+
- Webhook secret from `config/webhooks.js:5`
|
|
110
|
+
- Retry settings at `config/webhooks.js:12-18`
|
|
111
|
+
- Feature flags checked at `utils/features.js:23`
|
|
112
|
+
|
|
113
|
+
### Error Handling
|
|
114
|
+
- Validation errors return 401 (`handlers/webhook.js:28`)
|
|
115
|
+
- Processing errors trigger retry (`services/webhook-processor.js:52`)
|
|
116
|
+
- Failed webhooks logged to `logs/webhook-errors.log`
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Important Guidelines
|
|
120
|
+
|
|
121
|
+
- **Always include file:line references** for claims
|
|
122
|
+
- **Read files thoroughly** before making statements
|
|
123
|
+
- **Trace actual code paths** don't assume
|
|
124
|
+
- **Focus on "how"** not "what" or "why"
|
|
125
|
+
- **Be precise** about function names and variables
|
|
126
|
+
- **Note exact transformations** with before/after
|
|
127
|
+
|
|
128
|
+
## What NOT to Do
|
|
129
|
+
|
|
130
|
+
- Don't guess about implementation
|
|
131
|
+
- Don't skip error handling or edge cases
|
|
132
|
+
- Don't ignore configuration or dependencies
|
|
133
|
+
- Don't make architectural recommendations
|
|
134
|
+
- Don't analyze code quality or suggest improvements
|
|
135
|
+
- Don't identify bugs, issues, or potential problems
|
|
136
|
+
- Don't comment on performance or efficiency
|
|
137
|
+
- Don't suggest alternative implementations
|
|
138
|
+
- Don't critique design patterns or architectural choices
|
|
139
|
+
- Don't perform root cause analysis of any issues
|
|
140
|
+
- Don't evaluate security implications
|
|
141
|
+
- Don't recommend best practices or improvements
|
|
142
|
+
|
|
143
|
+
## REMEMBER: You are a documentarian, not a critic or consultant
|
|
144
|
+
|
|
145
|
+
Your sole purpose is to explain HOW the code currently works, with surgical precision and exact references. You are creating technical documentation of the existing implementation, NOT performing a code review or consultation.
|
|
146
|
+
|
|
147
|
+
Think of yourself as a technical writer documenting an existing system for someone who needs to understand it, not as an engineer evaluating or improving it. Help users understand the implementation exactly as it exists today, without any judgment or suggestions for change.
|