@nicmeriano/spool 0.0.0-preview.1741721 → 0.0.0-preview.c11008a

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/dist/cli.js CHANGED
@@ -278,7 +278,7 @@ async function runOpen(cwd, options = {}) {
278
278
  console.log("");
279
279
  log.info("Starting dev servers...");
280
280
  const { startServer } = await import("@nicmeriano/spool-server");
281
- await startServer({ port, cwd });
281
+ const server = await startServer({ port, cwd });
282
282
  const devCommand = config.devCommand ?? detectDevCommand(cwd);
283
283
  if (devCommand) {
284
284
  const [cmd, ...args2] = devCommand.split(" ");
@@ -318,6 +318,12 @@ async function runOpen(cwd, options = {}) {
318
318
  }
319
319
  log.banner(port);
320
320
  if (!options.noOpen) {
321
+ if (devCommand) {
322
+ const appUrl = await server.waitForAppUrl(3e4);
323
+ if (!appUrl) {
324
+ log.warn("Timed out waiting for dev server \u2014 opening browser anyway.");
325
+ }
326
+ }
321
327
  openBrowser(`http://localhost:${port}`);
322
328
  }
323
329
  }
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/init.ts","../src/utils/log.ts","../src/commands/open.ts","../src/utils/load-config.ts","../src/utils/port.ts","../src/utils/browser.ts","../src/constants.ts","../src/cli.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as readline from 'node:readline';\nimport { log } from '../utils/log.js';\nimport pc from 'picocolors';\n\n/**\n * Detect the project framework\n */\nfunction detectFramework(cwd: string): { name: string; devCommand: string; usesVite: boolean } | null {\n const pkgPath = path.join(cwd, 'package.json');\n if (!fs.existsSync(pkgPath)) return null;\n\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n\n if (deps['next']) {\n return { name: 'Next.js', devCommand: 'npm run dev', usesVite: false };\n }\n if (deps['vite']) {\n return { name: 'Vite', devCommand: 'npm run dev', usesVite: true };\n }\n if (deps['react-scripts']) {\n return { name: 'Create React App', devCommand: 'npm start', usesVite: false };\n }\n\n return null;\n}\n\n/**\n * Find the Vite config file in the project\n */\nfunction findViteConfig(cwd: string): string | null {\n const candidates = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs'];\n for (const name of candidates) {\n const full = path.join(cwd, name);\n if (fs.existsSync(full)) return full;\n }\n return null;\n}\n\n/**\n * Add the spool Vite plugin to an existing vite config file.\n * Returns true if successful, false if the config couldn't be modified automatically.\n */\nfunction addVitePlugin(configPath: string): boolean {\n const content = fs.readFileSync(configPath, 'utf-8');\n\n // Skip if already configured\n if (content.includes('@nicmeriano/spool/vite') || content.includes('spool()')) {\n return true;\n }\n\n // Find the last import statement to insert our import after it\n const importRegex = /^import\\s.+$/gm;\n let lastImportMatch: RegExpExecArray | null = null;\n let match: RegExpExecArray | null;\n while ((match = importRegex.exec(content)) !== null) {\n lastImportMatch = match;\n }\n\n if (!lastImportMatch) {\n return false;\n }\n\n const importInsertPos = lastImportMatch.index + lastImportMatch[0].length;\n const spoolImport = `\\nimport { spool } from '@nicmeriano/spool/vite'`;\n\n // Find the plugins array and add spool() to it\n const pluginsRegex = /plugins\\s*:\\s*\\[/;\n const pluginsMatch = pluginsRegex.exec(content);\n\n if (!pluginsMatch) {\n return false;\n }\n\n // Build the new content: add import, then add spool() to plugins\n let newContent = content.slice(0, importInsertPos) + spoolImport + content.slice(importInsertPos);\n\n // Re-find plugins position (shifted by the import we added)\n const offset = spoolImport.length;\n const pluginsInsertPos = pluginsMatch.index + pluginsMatch[0].length + offset;\n newContent = newContent.slice(0, pluginsInsertPos) + 'spool(), ' + newContent.slice(pluginsInsertPos);\n\n fs.writeFileSync(configPath, newContent, 'utf-8');\n return true;\n}\n\n/**\n * Prompt the user for input\n */\nfunction prompt(question: string, defaultValue?: string): Promise<string> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const displayDefault = defaultValue ? ` (${defaultValue})` : '';\n\n return new Promise((resolve) => {\n rl.question(`${question}${displayDefault}: `, (answer) => {\n rl.close();\n resolve(answer.trim() || defaultValue || '');\n });\n });\n}\n\n/**\n * Run the spool init command\n */\nexport async function runInit(cwd: string): Promise<void> {\n log.info('Initializing Spool...');\n console.log('');\n\n // Check if config already exists\n const configPath = path.join(cwd, 'spool.config.ts');\n if (fs.existsSync(configPath)) {\n log.info('spool.config.ts already exists.');\n\n // Still check if the Vite plugin needs to be added\n const framework = detectFramework(cwd);\n if (framework?.usesVite) {\n const viteConfigPath = findViteConfig(cwd);\n if (viteConfigPath) {\n const viteContent = fs.readFileSync(viteConfigPath, 'utf-8');\n if (!viteContent.includes('@nicmeriano/spool/vite') && !viteContent.includes('spool()')) {\n const configName = path.basename(viteConfigPath);\n const success = addVitePlugin(viteConfigPath);\n if (success) {\n log.success(`Added spool plugin to ${configName}`);\n } else {\n log.warn(`Could not automatically modify ${configName}.`);\n console.log(' Please add the spool plugin manually:\\n');\n console.log(' import { spool } from \\'@nicmeriano/spool/vite\\'\\n');\n console.log(' // In your plugins array:');\n console.log(' plugins: [spool(), ...otherPlugins]\\n');\n }\n }\n }\n }\n\n console.log('');\n return;\n }\n\n // Detect framework\n const framework = detectFramework(cwd);\n if (framework) {\n log.info(`Detected framework: ${pc.bold(framework.name)}`);\n console.log('');\n }\n\n // Prompt for dev command\n const defaultDevCmd = framework?.devCommand || 'npm run dev';\n const devCommand = await prompt('Dev command', defaultDevCmd);\n\n // Write spool.config.ts\n const configContent = `import { defineConfig } from '@nicmeriano/spool';\n\nexport default defineConfig({\n devCommand: '${devCommand}',\n});\n`;\n\n fs.writeFileSync(configPath, configContent, 'utf-8');\n console.log('');\n log.success('Created spool.config.ts');\n\n // Create .spool directory\n const spoolDir = path.join(cwd, '.spool');\n if (!fs.existsSync(spoolDir)) {\n fs.mkdirSync(spoolDir, { recursive: true });\n log.success('Created .spool/ directory');\n }\n\n // Add .spool/ to .gitignore\n const gitignorePath = path.join(cwd, '.gitignore');\n if (fs.existsSync(gitignorePath)) {\n const content = fs.readFileSync(gitignorePath, 'utf-8');\n if (!content.includes('.spool')) {\n fs.appendFileSync(gitignorePath, '\\n.spool/\\n');\n log.success('Added .spool/ to .gitignore');\n }\n }\n\n // Auto-configure Vite plugin if this is a Vite project\n if (framework?.usesVite) {\n const viteConfigPath = findViteConfig(cwd);\n if (viteConfigPath) {\n const configName = path.basename(viteConfigPath);\n const success = addVitePlugin(viteConfigPath);\n if (success) {\n log.success(`Added spool plugin to ${configName}`);\n } else {\n log.warn(`Could not automatically modify ${configName}.`);\n console.log(' Please add the spool plugin manually:\\n');\n console.log(' import { spool } from \\'@nicmeriano/spool/vite\\'\\n');\n console.log(' // In your plugins array:');\n console.log(' plugins: [spool(), ...otherPlugins]\\n');\n }\n }\n } else {\n log.info('Add this script tag to your HTML:');\n console.log(' <script src=\"http://localhost:3142/inject.js\"></script>');\n }\n\n console.log('');\n log.success(`Done! Run ${pc.cyan('\"spool open\"')} to start.`);\n console.log('');\n}\n","import pc from 'picocolors';\n\nconst PREFIX = pc.magenta('spool');\n\nexport const log = {\n info(msg: string) {\n console.log(` ${PREFIX} ${msg}`);\n },\n success(msg: string) {\n console.log(` ${PREFIX} ${pc.green(msg)}`);\n },\n warn(msg: string) {\n console.warn(` ${PREFIX} ${pc.yellow(msg)}`);\n },\n error(msg: string) {\n console.error(` ${PREFIX} ${pc.red(msg)}`);\n },\n banner(port: number) {\n const url = `http://localhost:${port}`;\n const visibleLine = `Spool: ${url}`;\n const coloredLine = `Spool: ${pc.cyan(url)}`;\n\n // Box inner width = 3 (left pad) + content + right pad + 0 (border chars separate)\n const innerWidth = 40;\n const contentWidth = visibleLine.length;\n const leftPad = 3;\n const rightPad = innerWidth - leftPad - contentWidth;\n\n const h = '\\u2500'.repeat(innerWidth);\n const empty = '\\u2502' + ' '.repeat(innerWidth) + '\\u2502';\n const row = '\\u2502' + ' '.repeat(leftPad) + coloredLine + ' '.repeat(rightPad) + '\\u2502';\n\n console.log('');\n console.log(` \\u250c${h}\\u2510`);\n console.log(` ${empty}`);\n console.log(` ${row}`);\n console.log(` ${empty}`);\n console.log(` \\u2514${h}\\u2518`);\n console.log('');\n },\n};\n","import { spawn } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig } from '../utils/load-config.js';\nimport { findAvailablePort } from '../utils/port.js';\nimport { openBrowser } from '../utils/browser.js';\nimport { DEFAULT_SERVER_PORT } from '../constants.js';\nimport { log } from '../utils/log.js';\nimport pc from 'picocolors';\n\nexport interface OpenOptions {\n port?: number;\n noOpen?: boolean;\n verbose?: boolean;\n}\n\n/**\n * Auto-detect dev command from package.json scripts.dev\n */\nfunction detectDevCommand(cwd: string): string | undefined {\n const pkgPath = path.resolve(cwd, 'package.json');\n if (!fs.existsSync(pkgPath)) return undefined;\n\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));\n if (pkg.scripts?.dev) {\n return 'npm run dev';\n }\n } catch {\n // Ignore parse errors\n }\n return undefined;\n}\n\n/**\n * Run the spool open command\n */\nexport async function runOpen(cwd: string, options: OpenOptions = {}): Promise<void> {\n // Load config (returns defaults if no spool.config.ts)\n const config = await loadConfig(cwd);\n\n // Check for ANTHROPIC_API_KEY\n if (!process.env.ANTHROPIC_API_KEY) {\n log.warn('ANTHROPIC_API_KEY is not set. Claude features will not work.');\n }\n\n // Find available port\n const preferredPort = options.port ?? config.port ?? DEFAULT_SERVER_PORT;\n const port = await findAvailablePort(preferredPort);\n if (port !== preferredPort) {\n log.info(`Port ${preferredPort} is in use, using ${pc.bold(String(port))} instead.`);\n }\n\n console.log('');\n log.info('Starting dev servers...');\n\n // Start the server\n const { startServer } = await import('@nicmeriano/spool-server');\n\n // Start server — resolves once the HTTP server is listening\n await startServer({ port, cwd });\n\n // Resolve dev command: config > auto-detect from package.json > none\n const devCommand = config.devCommand ?? detectDevCommand(cwd);\n\n // Spawn dev command\n if (devCommand) {\n const [cmd, ...args] = devCommand.split(' ');\n\n // Default: pipe output to log file for clean terminal\n const logDir = path.resolve(cwd, '.spool');\n if (!fs.existsSync(logDir)) {\n fs.mkdirSync(logDir, { recursive: true });\n }\n const logFile = path.resolve(logDir, 'dev.log');\n\n let child;\n if (options.verbose) {\n child = spawn(cmd, args, {\n cwd,\n stdio: 'inherit',\n shell: true,\n });\n } else {\n const logFd = fs.openSync(logFile, 'w');\n child = spawn(cmd, args, {\n cwd,\n stdio: ['ignore', logFd, logFd],\n shell: true,\n });\n }\n\n child.on('error', (error) => {\n log.error(`Dev server error: ${error.message}`);\n });\n\n // Clean up on exit\n process.on('SIGINT', () => {\n child.kill();\n process.exit(0);\n });\n process.on('SIGTERM', () => {\n child.kill();\n process.exit(0);\n });\n } else {\n log.warn('No dev command found. Add devCommand to spool.config.ts or a \"dev\" script to package.json.');\n }\n\n // Show banner and open browser — server is already listening\n log.banner(port);\n\n if (!options.noOpen) {\n openBrowser(`http://localhost:${port}`);\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n/**\n * Load spool.config.ts from the project root\n */\nexport async function loadConfig(cwd: string): Promise<import('../config.js').SpoolConfig> {\n const configPath = path.resolve(cwd, 'spool.config.ts');\n\n if (!fs.existsSync(configPath)) {\n return {};\n }\n\n // Use jiti for TypeScript config loading\n const { createJiti } = await import('jiti');\n const jiti = createJiti(import.meta.url, { interopDefault: true });\n const config = await jiti.import(configPath) as { default?: import('../config.js').SpoolConfig } & import('../config.js').SpoolConfig;\n\n return config.default ?? config;\n}\n","import * as net from 'node:net';\n\n/**\n * Find an available port, starting from the preferred port\n */\nexport async function findAvailablePort(preferred: number): Promise<number> {\n return new Promise((resolve, reject) => {\n const server = net.createServer();\n server.listen(preferred, () => {\n server.close(() => resolve(preferred));\n });\n server.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n // Try next port\n findAvailablePort(preferred + 1).then(resolve).catch(reject);\n } else {\n reject(err);\n }\n });\n });\n}\n","import { exec } from 'node:child_process';\n\n/**\n * Open a URL in the default browser\n */\nexport function openBrowser(url: string): void {\n const platform = process.platform;\n let command: string;\n\n if (platform === 'darwin') {\n command = `open \"${url}\"`;\n } else if (platform === 'win32') {\n command = `start \"${url}\"`;\n } else {\n command = `xdg-open \"${url}\"`;\n }\n\n exec(command, (error) => {\n if (error) {\n console.error(`Could not open browser: ${error.message}`);\n }\n });\n}\n","export const DEFAULT_SERVER_PORT = 3142;\nexport const DEFAULT_APP_PORT = 5173;\n","import { runInit } from './commands/init.js';\nimport { runOpen } from './commands/open.js';\n\nconst args = process.argv.slice(2);\nconst command = args[0];\n\nfunction printUsage(): void {\n console.log(`\nUsage: spool <command> [options]\n\nCommands:\n init Initialize spool in your project\n open Start spool server and open the UI\n\nOptions (open):\n --port <n> Server port (default: 3142)\n --no-open Don't open browser automatically\n --verbose Show dev server output in terminal\n\nExamples:\n spool init\n spool open\n spool open --port 4000\n`);\n}\n\nasync function main(): Promise<void> {\n const cwd = process.cwd();\n\n switch (command) {\n case 'init':\n await runInit(cwd);\n break;\n\n case 'open': {\n const portIndex = args.indexOf('--port');\n const port = portIndex !== -1 ? parseInt(args[portIndex + 1], 10) : undefined;\n const noOpen = args.includes('--no-open');\n const verbose = args.includes('--verbose');\n await runOpen(cwd, { port, noOpen, verbose });\n break;\n }\n\n case '--help':\n case '-h':\n case undefined:\n printUsage();\n break;\n\n default:\n console.error(`Unknown command: ${command}`);\n printUsage();\n process.exit(1);\n }\n}\n\nmain().catch((error) => {\n console.error(error.message || error);\n process.exit(1);\n});\n"],"mappings":";;;AAAA,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,YAAY,cAAc;;;ACF1B,OAAO,QAAQ;AAEf,IAAM,SAAS,GAAG,QAAQ,OAAO;AAE1B,IAAM,MAAM;AAAA,EACjB,KAAK,KAAa;AAChB,YAAQ,IAAI,KAAK,MAAM,IAAI,GAAG,EAAE;AAAA,EAClC;AAAA,EACA,QAAQ,KAAa;AACnB,YAAQ,IAAI,KAAK,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,EAAE;AAAA,EAC5C;AAAA,EACA,KAAK,KAAa;AAChB,YAAQ,KAAK,KAAK,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,EAAE;AAAA,EAC9C;AAAA,EACA,MAAM,KAAa;AACjB,YAAQ,MAAM,KAAK,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,EAAE;AAAA,EAC5C;AAAA,EACA,OAAO,MAAc;AACnB,UAAM,MAAM,oBAAoB,IAAI;AACpC,UAAM,cAAc,YAAY,GAAG;AACnC,UAAM,cAAc,YAAY,GAAG,KAAK,GAAG,CAAC;AAG5C,UAAM,aAAa;AACnB,UAAM,eAAe,YAAY;AACjC,UAAM,UAAU;AAChB,UAAM,WAAW,aAAa,UAAU;AAExC,UAAM,IAAI,SAAS,OAAO,UAAU;AACpC,UAAM,QAAQ,WAAW,IAAI,OAAO,UAAU,IAAI;AAClD,UAAM,MAAM,WAAW,IAAI,OAAO,OAAO,IAAI,cAAc,IAAI,OAAO,QAAQ,IAAI;AAElF,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,WAAW,CAAC,QAAQ;AAChC,YAAQ,IAAI,KAAK,KAAK,EAAE;AACxB,YAAQ,IAAI,KAAK,GAAG,EAAE;AACtB,YAAQ,IAAI,KAAK,KAAK,EAAE;AACxB,YAAQ,IAAI,WAAW,CAAC,QAAQ;AAChC,YAAQ,IAAI,EAAE;AAAA,EAChB;AACF;;;ADpCA,OAAOA,SAAQ;AAKf,SAAS,gBAAgB,KAA6E;AACpG,QAAM,UAAe,UAAK,KAAK,cAAc;AAC7C,MAAI,CAAI,cAAW,OAAO,EAAG,QAAO;AAEpC,QAAM,MAAM,KAAK,MAAS,gBAAa,SAAS,OAAO,CAAC;AACxD,QAAM,OAAO,EAAE,GAAG,IAAI,cAAc,GAAG,IAAI,gBAAgB;AAE3D,MAAI,KAAK,MAAM,GAAG;AAChB,WAAO,EAAE,MAAM,WAAW,YAAY,eAAe,UAAU,MAAM;AAAA,EACvE;AACA,MAAI,KAAK,MAAM,GAAG;AAChB,WAAO,EAAE,MAAM,QAAQ,YAAY,eAAe,UAAU,KAAK;AAAA,EACnE;AACA,MAAI,KAAK,eAAe,GAAG;AACzB,WAAO,EAAE,MAAM,oBAAoB,YAAY,aAAa,UAAU,MAAM;AAAA,EAC9E;AAEA,SAAO;AACT;AAKA,SAAS,eAAe,KAA4B;AAClD,QAAM,aAAa,CAAC,kBAAkB,kBAAkB,iBAAiB;AACzE,aAAW,QAAQ,YAAY;AAC7B,UAAM,OAAY,UAAK,KAAK,IAAI;AAChC,QAAO,cAAW,IAAI,EAAG,QAAO;AAAA,EAClC;AACA,SAAO;AACT;AAMA,SAAS,cAAc,YAA6B;AAClD,QAAM,UAAa,gBAAa,YAAY,OAAO;AAGnD,MAAI,QAAQ,SAAS,wBAAwB,KAAK,QAAQ,SAAS,SAAS,GAAG;AAC7E,WAAO;AAAA,EACT;AAGA,QAAM,cAAc;AACpB,MAAI,kBAA0C;AAC9C,MAAI;AACJ,UAAQ,QAAQ,YAAY,KAAK,OAAO,OAAO,MAAM;AACnD,sBAAkB;AAAA,EACpB;AAEA,MAAI,CAAC,iBAAiB;AACpB,WAAO;AAAA,EACT;AAEA,QAAM,kBAAkB,gBAAgB,QAAQ,gBAAgB,CAAC,EAAE;AACnE,QAAM,cAAc;AAAA;AAGpB,QAAM,eAAe;AACrB,QAAM,eAAe,aAAa,KAAK,OAAO;AAE9C,MAAI,CAAC,cAAc;AACjB,WAAO;AAAA,EACT;AAGA,MAAI,aAAa,QAAQ,MAAM,GAAG,eAAe,IAAI,cAAc,QAAQ,MAAM,eAAe;AAGhG,QAAM,SAAS,YAAY;AAC3B,QAAM,mBAAmB,aAAa,QAAQ,aAAa,CAAC,EAAE,SAAS;AACvE,eAAa,WAAW,MAAM,GAAG,gBAAgB,IAAI,cAAc,WAAW,MAAM,gBAAgB;AAEpG,EAAG,iBAAc,YAAY,YAAY,OAAO;AAChD,SAAO;AACT;AAKA,SAAS,OAAO,UAAkB,cAAwC;AACxE,QAAM,KAAc,yBAAgB;AAAA,IAClC,OAAO,QAAQ;AAAA,IACf,QAAQ,QAAQ;AAAA,EAClB,CAAC;AAED,QAAM,iBAAiB,eAAe,KAAK,YAAY,MAAM;AAE7D,SAAO,IAAI,QAAQ,CAACC,aAAY;AAC9B,OAAG,SAAS,GAAG,QAAQ,GAAG,cAAc,MAAM,CAAC,WAAW;AACxD,SAAG,MAAM;AACT,MAAAA,SAAQ,OAAO,KAAK,KAAK,gBAAgB,EAAE;AAAA,IAC7C,CAAC;AAAA,EACH,CAAC;AACH;AAKA,eAAsB,QAAQ,KAA4B;AACxD,MAAI,KAAK,uBAAuB;AAChC,UAAQ,IAAI,EAAE;AAGd,QAAM,aAAkB,UAAK,KAAK,iBAAiB;AACnD,MAAO,cAAW,UAAU,GAAG;AAC7B,QAAI,KAAK,iCAAiC;AAG1C,UAAMC,aAAY,gBAAgB,GAAG;AACrC,QAAIA,YAAW,UAAU;AACvB,YAAM,iBAAiB,eAAe,GAAG;AACzC,UAAI,gBAAgB;AAClB,cAAM,cAAiB,gBAAa,gBAAgB,OAAO;AAC3D,YAAI,CAAC,YAAY,SAAS,wBAAwB,KAAK,CAAC,YAAY,SAAS,SAAS,GAAG;AACvF,gBAAM,aAAkB,cAAS,cAAc;AAC/C,gBAAM,UAAU,cAAc,cAAc;AAC5C,cAAI,SAAS;AACX,gBAAI,QAAQ,yBAAyB,UAAU,EAAE;AAAA,UACnD,OAAO;AACL,gBAAI,KAAK,kCAAkC,UAAU,GAAG;AACxD,oBAAQ,IAAI,2CAA2C;AACvD,oBAAQ,IAAI,sDAAwD;AACpE,oBAAQ,IAAI,+BAA+B;AAC3C,oBAAQ,IAAI,2CAA2C;AAAA,UACzD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,YAAQ,IAAI,EAAE;AACd;AAAA,EACF;AAGA,QAAM,YAAY,gBAAgB,GAAG;AACrC,MAAI,WAAW;AACb,QAAI,KAAK,uBAAuBF,IAAG,KAAK,UAAU,IAAI,CAAC,EAAE;AACzD,YAAQ,IAAI,EAAE;AAAA,EAChB;AAGA,QAAM,gBAAgB,WAAW,cAAc;AAC/C,QAAM,aAAa,MAAM,OAAO,eAAe,aAAa;AAG5D,QAAM,gBAAgB;AAAA;AAAA;AAAA,iBAGP,UAAU;AAAA;AAAA;AAIzB,EAAG,iBAAc,YAAY,eAAe,OAAO;AACnD,UAAQ,IAAI,EAAE;AACd,MAAI,QAAQ,yBAAyB;AAGrC,QAAM,WAAgB,UAAK,KAAK,QAAQ;AACxC,MAAI,CAAI,cAAW,QAAQ,GAAG;AAC5B,IAAG,aAAU,UAAU,EAAE,WAAW,KAAK,CAAC;AAC1C,QAAI,QAAQ,2BAA2B;AAAA,EACzC;AAGA,QAAM,gBAAqB,UAAK,KAAK,YAAY;AACjD,MAAO,cAAW,aAAa,GAAG;AAChC,UAAM,UAAa,gBAAa,eAAe,OAAO;AACtD,QAAI,CAAC,QAAQ,SAAS,QAAQ,GAAG;AAC/B,MAAG,kBAAe,eAAe,aAAa;AAC9C,UAAI,QAAQ,6BAA6B;AAAA,IAC3C;AAAA,EACF;AAGA,MAAI,WAAW,UAAU;AACvB,UAAM,iBAAiB,eAAe,GAAG;AACzC,QAAI,gBAAgB;AAClB,YAAM,aAAkB,cAAS,cAAc;AAC/C,YAAM,UAAU,cAAc,cAAc;AAC5C,UAAI,SAAS;AACX,YAAI,QAAQ,yBAAyB,UAAU,EAAE;AAAA,MACnD,OAAO;AACL,YAAI,KAAK,kCAAkC,UAAU,GAAG;AACxD,gBAAQ,IAAI,2CAA2C;AACvD,gBAAQ,IAAI,sDAAwD;AACpE,gBAAQ,IAAI,+BAA+B;AAC3C,gBAAQ,IAAI,2CAA2C;AAAA,MACzD;AAAA,IACF;AAAA,EACF,OAAO;AACL,QAAI,KAAK,mCAAmC;AAC5C,YAAQ,IAAI,6DAA6D;AAAA,EAC3E;AAEA,UAAQ,IAAI,EAAE;AACd,MAAI,QAAQ,aAAaA,IAAG,KAAK,cAAc,CAAC,YAAY;AAC5D,UAAQ,IAAI,EAAE;AAChB;;;AEjNA,SAAS,aAAa;AACtB,YAAYG,SAAQ;AACpB,YAAYC,WAAU;;;ACFtB,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AAKtB,eAAsB,WAAW,KAA0D;AACzF,QAAM,aAAkB,cAAQ,KAAK,iBAAiB;AAEtD,MAAI,CAAI,eAAW,UAAU,GAAG;AAC9B,WAAO,CAAC;AAAA,EACV;AAGA,QAAM,EAAE,WAAW,IAAI,MAAM,OAAO,MAAM;AAC1C,QAAM,OAAO,WAAW,YAAY,KAAK,EAAE,gBAAgB,KAAK,CAAC;AACjE,QAAM,SAAS,MAAM,KAAK,OAAO,UAAU;AAE3C,SAAO,OAAO,WAAW;AAC3B;;;ACnBA,YAAY,SAAS;AAKrB,eAAsB,kBAAkB,WAAoC;AAC1E,SAAO,IAAI,QAAQ,CAACC,UAAS,WAAW;AACtC,UAAM,SAAa,iBAAa;AAChC,WAAO,OAAO,WAAW,MAAM;AAC7B,aAAO,MAAM,MAAMA,SAAQ,SAAS,CAAC;AAAA,IACvC,CAAC;AACD,WAAO,GAAG,SAAS,CAAC,QAA+B;AACjD,UAAI,IAAI,SAAS,cAAc;AAE7B,0BAAkB,YAAY,CAAC,EAAE,KAAKA,QAAO,EAAE,MAAM,MAAM;AAAA,MAC7D,OAAO;AACL,eAAO,GAAG;AAAA,MACZ;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;;;ACpBA,SAAS,YAAY;AAKd,SAAS,YAAY,KAAmB;AAC7C,QAAM,WAAW,QAAQ;AACzB,MAAIC;AAEJ,MAAI,aAAa,UAAU;AACzB,IAAAA,WAAU,SAAS,GAAG;AAAA,EACxB,WAAW,aAAa,SAAS;AAC/B,IAAAA,WAAU,UAAU,GAAG;AAAA,EACzB,OAAO;AACL,IAAAA,WAAU,aAAa,GAAG;AAAA,EAC5B;AAEA,OAAKA,UAAS,CAAC,UAAU;AACvB,QAAI,OAAO;AACT,cAAQ,MAAM,2BAA2B,MAAM,OAAO,EAAE;AAAA,IAC1D;AAAA,EACF,CAAC;AACH;;;ACtBO,IAAM,sBAAsB;;;AJQnC,OAAOC,SAAQ;AAWf,SAAS,iBAAiB,KAAiC;AACzD,QAAM,UAAe,cAAQ,KAAK,cAAc;AAChD,MAAI,CAAI,eAAW,OAAO,EAAG,QAAO;AAEpC,MAAI;AACF,UAAM,MAAM,KAAK,MAAS,iBAAa,SAAS,OAAO,CAAC;AACxD,QAAI,IAAI,SAAS,KAAK;AACpB,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAKA,eAAsB,QAAQ,KAAa,UAAuB,CAAC,GAAkB;AAEnF,QAAM,SAAS,MAAM,WAAW,GAAG;AAGnC,MAAI,CAAC,QAAQ,IAAI,mBAAmB;AAClC,QAAI,KAAK,8DAA8D;AAAA,EACzE;AAGA,QAAM,gBAAgB,QAAQ,QAAQ,OAAO,QAAQ;AACrD,QAAM,OAAO,MAAM,kBAAkB,aAAa;AAClD,MAAI,SAAS,eAAe;AAC1B,QAAI,KAAK,QAAQ,aAAa,qBAAqBA,IAAG,KAAK,OAAO,IAAI,CAAC,CAAC,WAAW;AAAA,EACrF;AAEA,UAAQ,IAAI,EAAE;AACd,MAAI,KAAK,yBAAyB;AAGlC,QAAM,EAAE,YAAY,IAAI,MAAM,OAAO,0BAA0B;AAG/D,QAAM,YAAY,EAAE,MAAM,IAAI,CAAC;AAG/B,QAAM,aAAa,OAAO,cAAc,iBAAiB,GAAG;AAG5D,MAAI,YAAY;AACd,UAAM,CAAC,KAAK,GAAGC,KAAI,IAAI,WAAW,MAAM,GAAG;AAG3C,UAAM,SAAc,cAAQ,KAAK,QAAQ;AACzC,QAAI,CAAI,eAAW,MAAM,GAAG;AAC1B,MAAG,cAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AAAA,IAC1C;AACA,UAAM,UAAe,cAAQ,QAAQ,SAAS;AAE9C,QAAI;AACJ,QAAI,QAAQ,SAAS;AACnB,cAAQ,MAAM,KAAKA,OAAM;AAAA,QACvB;AAAA,QACA,OAAO;AAAA,QACP,OAAO;AAAA,MACT,CAAC;AAAA,IACH,OAAO;AACL,YAAM,QAAW,aAAS,SAAS,GAAG;AACtC,cAAQ,MAAM,KAAKA,OAAM;AAAA,QACvB;AAAA,QACA,OAAO,CAAC,UAAU,OAAO,KAAK;AAAA,QAC9B,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAEA,UAAM,GAAG,SAAS,CAAC,UAAU;AAC3B,UAAI,MAAM,qBAAqB,MAAM,OAAO,EAAE;AAAA,IAChD,CAAC;AAGD,YAAQ,GAAG,UAAU,MAAM;AACzB,YAAM,KAAK;AACX,cAAQ,KAAK,CAAC;AAAA,IAChB,CAAC;AACD,YAAQ,GAAG,WAAW,MAAM;AAC1B,YAAM,KAAK;AACX,cAAQ,KAAK,CAAC;AAAA,IAChB,CAAC;AAAA,EACH,OAAO;AACL,QAAI,KAAK,4FAA4F;AAAA,EACvG;AAGA,MAAI,OAAO,IAAI;AAEf,MAAI,CAAC,QAAQ,QAAQ;AACnB,gBAAY,oBAAoB,IAAI,EAAE;AAAA,EACxC;AACF;;;AKhHA,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAM,UAAU,KAAK,CAAC;AAEtB,SAAS,aAAmB;AAC1B,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAgBb;AACD;AAEA,eAAe,OAAsB;AACnC,QAAM,MAAM,QAAQ,IAAI;AAExB,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,YAAM,QAAQ,GAAG;AACjB;AAAA,IAEF,KAAK,QAAQ;AACX,YAAM,YAAY,KAAK,QAAQ,QAAQ;AACvC,YAAM,OAAO,cAAc,KAAK,SAAS,KAAK,YAAY,CAAC,GAAG,EAAE,IAAI;AACpE,YAAM,SAAS,KAAK,SAAS,WAAW;AACxC,YAAM,UAAU,KAAK,SAAS,WAAW;AACzC,YAAM,QAAQ,KAAK,EAAE,MAAM,QAAQ,QAAQ,CAAC;AAC5C;AAAA,IACF;AAAA,IAEA,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,iBAAW;AACX;AAAA,IAEF;AACE,cAAQ,MAAM,oBAAoB,OAAO,EAAE;AAC3C,iBAAW;AACX,cAAQ,KAAK,CAAC;AAAA,EAClB;AACF;AAEA,KAAK,EAAE,MAAM,CAAC,UAAU;AACtB,UAAQ,MAAM,MAAM,WAAW,KAAK;AACpC,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["pc","resolve","framework","fs","path","fs","path","resolve","command","pc","args"]}
1
+ {"version":3,"sources":["../src/commands/init.ts","../src/utils/log.ts","../src/commands/open.ts","../src/utils/load-config.ts","../src/utils/port.ts","../src/utils/browser.ts","../src/constants.ts","../src/cli.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as readline from 'node:readline';\nimport { log } from '../utils/log.js';\nimport pc from 'picocolors';\n\n/**\n * Detect the project framework\n */\nfunction detectFramework(cwd: string): { name: string; devCommand: string; usesVite: boolean } | null {\n const pkgPath = path.join(cwd, 'package.json');\n if (!fs.existsSync(pkgPath)) return null;\n\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n\n if (deps['next']) {\n return { name: 'Next.js', devCommand: 'npm run dev', usesVite: false };\n }\n if (deps['vite']) {\n return { name: 'Vite', devCommand: 'npm run dev', usesVite: true };\n }\n if (deps['react-scripts']) {\n return { name: 'Create React App', devCommand: 'npm start', usesVite: false };\n }\n\n return null;\n}\n\n/**\n * Find the Vite config file in the project\n */\nfunction findViteConfig(cwd: string): string | null {\n const candidates = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs'];\n for (const name of candidates) {\n const full = path.join(cwd, name);\n if (fs.existsSync(full)) return full;\n }\n return null;\n}\n\n/**\n * Add the spool Vite plugin to an existing vite config file.\n * Returns true if successful, false if the config couldn't be modified automatically.\n */\nfunction addVitePlugin(configPath: string): boolean {\n const content = fs.readFileSync(configPath, 'utf-8');\n\n // Skip if already configured\n if (content.includes('@nicmeriano/spool/vite') || content.includes('spool()')) {\n return true;\n }\n\n // Find the last import statement to insert our import after it\n const importRegex = /^import\\s.+$/gm;\n let lastImportMatch: RegExpExecArray | null = null;\n let match: RegExpExecArray | null;\n while ((match = importRegex.exec(content)) !== null) {\n lastImportMatch = match;\n }\n\n if (!lastImportMatch) {\n return false;\n }\n\n const importInsertPos = lastImportMatch.index + lastImportMatch[0].length;\n const spoolImport = `\\nimport { spool } from '@nicmeriano/spool/vite'`;\n\n // Find the plugins array and add spool() to it\n const pluginsRegex = /plugins\\s*:\\s*\\[/;\n const pluginsMatch = pluginsRegex.exec(content);\n\n if (!pluginsMatch) {\n return false;\n }\n\n // Build the new content: add import, then add spool() to plugins\n let newContent = content.slice(0, importInsertPos) + spoolImport + content.slice(importInsertPos);\n\n // Re-find plugins position (shifted by the import we added)\n const offset = spoolImport.length;\n const pluginsInsertPos = pluginsMatch.index + pluginsMatch[0].length + offset;\n newContent = newContent.slice(0, pluginsInsertPos) + 'spool(), ' + newContent.slice(pluginsInsertPos);\n\n fs.writeFileSync(configPath, newContent, 'utf-8');\n return true;\n}\n\n/**\n * Prompt the user for input\n */\nfunction prompt(question: string, defaultValue?: string): Promise<string> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const displayDefault = defaultValue ? ` (${defaultValue})` : '';\n\n return new Promise((resolve) => {\n rl.question(`${question}${displayDefault}: `, (answer) => {\n rl.close();\n resolve(answer.trim() || defaultValue || '');\n });\n });\n}\n\n/**\n * Run the spool init command\n */\nexport async function runInit(cwd: string): Promise<void> {\n log.info('Initializing Spool...');\n console.log('');\n\n // Check if config already exists\n const configPath = path.join(cwd, 'spool.config.ts');\n if (fs.existsSync(configPath)) {\n log.info('spool.config.ts already exists.');\n\n // Still check if the Vite plugin needs to be added\n const framework = detectFramework(cwd);\n if (framework?.usesVite) {\n const viteConfigPath = findViteConfig(cwd);\n if (viteConfigPath) {\n const viteContent = fs.readFileSync(viteConfigPath, 'utf-8');\n if (!viteContent.includes('@nicmeriano/spool/vite') && !viteContent.includes('spool()')) {\n const configName = path.basename(viteConfigPath);\n const success = addVitePlugin(viteConfigPath);\n if (success) {\n log.success(`Added spool plugin to ${configName}`);\n } else {\n log.warn(`Could not automatically modify ${configName}.`);\n console.log(' Please add the spool plugin manually:\\n');\n console.log(' import { spool } from \\'@nicmeriano/spool/vite\\'\\n');\n console.log(' // In your plugins array:');\n console.log(' plugins: [spool(), ...otherPlugins]\\n');\n }\n }\n }\n }\n\n console.log('');\n return;\n }\n\n // Detect framework\n const framework = detectFramework(cwd);\n if (framework) {\n log.info(`Detected framework: ${pc.bold(framework.name)}`);\n console.log('');\n }\n\n // Prompt for dev command\n const defaultDevCmd = framework?.devCommand || 'npm run dev';\n const devCommand = await prompt('Dev command', defaultDevCmd);\n\n // Write spool.config.ts\n const configContent = `import { defineConfig } from '@nicmeriano/spool';\n\nexport default defineConfig({\n devCommand: '${devCommand}',\n});\n`;\n\n fs.writeFileSync(configPath, configContent, 'utf-8');\n console.log('');\n log.success('Created spool.config.ts');\n\n // Create .spool directory\n const spoolDir = path.join(cwd, '.spool');\n if (!fs.existsSync(spoolDir)) {\n fs.mkdirSync(spoolDir, { recursive: true });\n log.success('Created .spool/ directory');\n }\n\n // Add .spool/ to .gitignore\n const gitignorePath = path.join(cwd, '.gitignore');\n if (fs.existsSync(gitignorePath)) {\n const content = fs.readFileSync(gitignorePath, 'utf-8');\n if (!content.includes('.spool')) {\n fs.appendFileSync(gitignorePath, '\\n.spool/\\n');\n log.success('Added .spool/ to .gitignore');\n }\n }\n\n // Auto-configure Vite plugin if this is a Vite project\n if (framework?.usesVite) {\n const viteConfigPath = findViteConfig(cwd);\n if (viteConfigPath) {\n const configName = path.basename(viteConfigPath);\n const success = addVitePlugin(viteConfigPath);\n if (success) {\n log.success(`Added spool plugin to ${configName}`);\n } else {\n log.warn(`Could not automatically modify ${configName}.`);\n console.log(' Please add the spool plugin manually:\\n');\n console.log(' import { spool } from \\'@nicmeriano/spool/vite\\'\\n');\n console.log(' // In your plugins array:');\n console.log(' plugins: [spool(), ...otherPlugins]\\n');\n }\n }\n } else {\n log.info('Add this script tag to your HTML:');\n console.log(' <script src=\"http://localhost:3142/inject.js\"></script>');\n }\n\n console.log('');\n log.success(`Done! Run ${pc.cyan('\"spool open\"')} to start.`);\n console.log('');\n}\n","import pc from 'picocolors';\n\nconst PREFIX = pc.magenta('spool');\n\nexport const log = {\n info(msg: string) {\n console.log(` ${PREFIX} ${msg}`);\n },\n success(msg: string) {\n console.log(` ${PREFIX} ${pc.green(msg)}`);\n },\n warn(msg: string) {\n console.warn(` ${PREFIX} ${pc.yellow(msg)}`);\n },\n error(msg: string) {\n console.error(` ${PREFIX} ${pc.red(msg)}`);\n },\n banner(port: number) {\n const url = `http://localhost:${port}`;\n const visibleLine = `Spool: ${url}`;\n const coloredLine = `Spool: ${pc.cyan(url)}`;\n\n // Box inner width = 3 (left pad) + content + right pad + 0 (border chars separate)\n const innerWidth = 40;\n const contentWidth = visibleLine.length;\n const leftPad = 3;\n const rightPad = innerWidth - leftPad - contentWidth;\n\n const h = '\\u2500'.repeat(innerWidth);\n const empty = '\\u2502' + ' '.repeat(innerWidth) + '\\u2502';\n const row = '\\u2502' + ' '.repeat(leftPad) + coloredLine + ' '.repeat(rightPad) + '\\u2502';\n\n console.log('');\n console.log(` \\u250c${h}\\u2510`);\n console.log(` ${empty}`);\n console.log(` ${row}`);\n console.log(` ${empty}`);\n console.log(` \\u2514${h}\\u2518`);\n console.log('');\n },\n};\n","import { spawn } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { loadConfig } from '../utils/load-config.js';\nimport { findAvailablePort } from '../utils/port.js';\nimport { openBrowser } from '../utils/browser.js';\nimport { DEFAULT_SERVER_PORT } from '../constants.js';\nimport { log } from '../utils/log.js';\nimport pc from 'picocolors';\n\nexport interface OpenOptions {\n port?: number;\n noOpen?: boolean;\n verbose?: boolean;\n}\n\n/**\n * Auto-detect dev command from package.json scripts.dev\n */\nfunction detectDevCommand(cwd: string): string | undefined {\n const pkgPath = path.resolve(cwd, 'package.json');\n if (!fs.existsSync(pkgPath)) return undefined;\n\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));\n if (pkg.scripts?.dev) {\n return 'npm run dev';\n }\n } catch {\n // Ignore parse errors\n }\n return undefined;\n}\n\n/**\n * Run the spool open command\n */\nexport async function runOpen(cwd: string, options: OpenOptions = {}): Promise<void> {\n // Load config (returns defaults if no spool.config.ts)\n const config = await loadConfig(cwd);\n\n // Check for ANTHROPIC_API_KEY\n if (!process.env.ANTHROPIC_API_KEY) {\n log.warn('ANTHROPIC_API_KEY is not set. Claude features will not work.');\n }\n\n // Find available port\n const preferredPort = options.port ?? config.port ?? DEFAULT_SERVER_PORT;\n const port = await findAvailablePort(preferredPort);\n if (port !== preferredPort) {\n log.info(`Port ${preferredPort} is in use, using ${pc.bold(String(port))} instead.`);\n }\n\n console.log('');\n log.info('Starting dev servers...');\n\n // Start the server\n const { startServer } = await import('@nicmeriano/spool-server');\n\n // Start server — resolves once the HTTP server is listening\n const server = await startServer({ port, cwd });\n\n // Resolve dev command: config > auto-detect from package.json > none\n const devCommand = config.devCommand ?? detectDevCommand(cwd);\n\n // Spawn dev command\n if (devCommand) {\n const [cmd, ...args] = devCommand.split(' ');\n\n // Default: pipe output to log file for clean terminal\n const logDir = path.resolve(cwd, '.spool');\n if (!fs.existsSync(logDir)) {\n fs.mkdirSync(logDir, { recursive: true });\n }\n const logFile = path.resolve(logDir, 'dev.log');\n\n let child;\n if (options.verbose) {\n child = spawn(cmd, args, {\n cwd,\n stdio: 'inherit',\n shell: true,\n });\n } else {\n const logFd = fs.openSync(logFile, 'w');\n child = spawn(cmd, args, {\n cwd,\n stdio: ['ignore', logFd, logFd],\n shell: true,\n });\n }\n\n child.on('error', (error) => {\n log.error(`Dev server error: ${error.message}`);\n });\n\n // Clean up on exit\n process.on('SIGINT', () => {\n child.kill();\n process.exit(0);\n });\n process.on('SIGTERM', () => {\n child.kill();\n process.exit(0);\n });\n } else {\n log.warn('No dev command found. Add devCommand to spool.config.ts or a \"dev\" script to package.json.');\n }\n\n // Show banner\n log.banner(port);\n\n // Wait for the Vite plugin to report the app URL before opening the browser.\n // This ensures the dev server is actually ready. Falls back after 30s timeout.\n if (!options.noOpen) {\n if (devCommand) {\n const appUrl = await server.waitForAppUrl(30_000);\n if (!appUrl) {\n log.warn('Timed out waiting for dev server — opening browser anyway.');\n }\n }\n openBrowser(`http://localhost:${port}`);\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n/**\n * Load spool.config.ts from the project root\n */\nexport async function loadConfig(cwd: string): Promise<import('../config.js').SpoolConfig> {\n const configPath = path.resolve(cwd, 'spool.config.ts');\n\n if (!fs.existsSync(configPath)) {\n return {};\n }\n\n // Use jiti for TypeScript config loading\n const { createJiti } = await import('jiti');\n const jiti = createJiti(import.meta.url, { interopDefault: true });\n const config = await jiti.import(configPath) as { default?: import('../config.js').SpoolConfig } & import('../config.js').SpoolConfig;\n\n return config.default ?? config;\n}\n","import * as net from 'node:net';\n\n/**\n * Find an available port, starting from the preferred port\n */\nexport async function findAvailablePort(preferred: number): Promise<number> {\n return new Promise((resolve, reject) => {\n const server = net.createServer();\n server.listen(preferred, () => {\n server.close(() => resolve(preferred));\n });\n server.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n // Try next port\n findAvailablePort(preferred + 1).then(resolve).catch(reject);\n } else {\n reject(err);\n }\n });\n });\n}\n","import { exec } from 'node:child_process';\n\n/**\n * Open a URL in the default browser\n */\nexport function openBrowser(url: string): void {\n const platform = process.platform;\n let command: string;\n\n if (platform === 'darwin') {\n command = `open \"${url}\"`;\n } else if (platform === 'win32') {\n command = `start \"${url}\"`;\n } else {\n command = `xdg-open \"${url}\"`;\n }\n\n exec(command, (error) => {\n if (error) {\n console.error(`Could not open browser: ${error.message}`);\n }\n });\n}\n","export const DEFAULT_SERVER_PORT = 3142;\nexport const DEFAULT_APP_PORT = 5173;\n","import { runInit } from './commands/init.js';\nimport { runOpen } from './commands/open.js';\n\nconst args = process.argv.slice(2);\nconst command = args[0];\n\nfunction printUsage(): void {\n console.log(`\nUsage: spool <command> [options]\n\nCommands:\n init Initialize spool in your project\n open Start spool server and open the UI\n\nOptions (open):\n --port <n> Server port (default: 3142)\n --no-open Don't open browser automatically\n --verbose Show dev server output in terminal\n\nExamples:\n spool init\n spool open\n spool open --port 4000\n`);\n}\n\nasync function main(): Promise<void> {\n const cwd = process.cwd();\n\n switch (command) {\n case 'init':\n await runInit(cwd);\n break;\n\n case 'open': {\n const portIndex = args.indexOf('--port');\n const port = portIndex !== -1 ? parseInt(args[portIndex + 1], 10) : undefined;\n const noOpen = args.includes('--no-open');\n const verbose = args.includes('--verbose');\n await runOpen(cwd, { port, noOpen, verbose });\n break;\n }\n\n case '--help':\n case '-h':\n case undefined:\n printUsage();\n break;\n\n default:\n console.error(`Unknown command: ${command}`);\n printUsage();\n process.exit(1);\n }\n}\n\nmain().catch((error) => {\n console.error(error.message || error);\n process.exit(1);\n});\n"],"mappings":"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","names":["pc","resolve","framework","fs","path","fs","path","resolve","command","pc","args"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nicmeriano/spool",
3
- "version": "0.0.0-preview.1741721",
3
+ "version": "0.0.0-preview.c11008a",
4
4
  "description": "Spool CLI - UI feedback tool for Claude Code",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -43,7 +43,7 @@
43
43
  "access": "public"
44
44
  },
45
45
  "dependencies": {
46
- "@nicmeriano/spool-server": "0.0.0-preview.1741721",
46
+ "@nicmeriano/spool-server": "0.0.0-preview.c11008a",
47
47
  "jiti": "^2.4.0",
48
48
  "picocolors": "^1.1.1"
49
49
  },