@nicmeriano/spool 0.0.8 → 0.0.10

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
@@ -4,6 +4,46 @@
4
4
  import * as fs from "fs";
5
5
  import * as path from "path";
6
6
  import * as readline from "readline";
7
+
8
+ // src/utils/log.ts
9
+ import pc from "picocolors";
10
+ var PREFIX = pc.magenta("spool");
11
+ var log = {
12
+ info(msg) {
13
+ console.log(` ${PREFIX} ${msg}`);
14
+ },
15
+ success(msg) {
16
+ console.log(` ${PREFIX} ${pc.green(msg)}`);
17
+ },
18
+ warn(msg) {
19
+ console.warn(` ${PREFIX} ${pc.yellow(msg)}`);
20
+ },
21
+ error(msg) {
22
+ console.error(` ${PREFIX} ${pc.red(msg)}`);
23
+ },
24
+ banner(port) {
25
+ const url = `http://localhost:${port}`;
26
+ const visibleLine = `Spool: ${url}`;
27
+ const coloredLine = `Spool: ${pc.cyan(url)}`;
28
+ const innerWidth = 40;
29
+ const contentWidth = visibleLine.length;
30
+ const leftPad = 3;
31
+ const rightPad = innerWidth - leftPad - contentWidth;
32
+ const h = "\u2500".repeat(innerWidth);
33
+ const empty = "\u2502" + " ".repeat(innerWidth) + "\u2502";
34
+ const row = "\u2502" + " ".repeat(leftPad) + coloredLine + " ".repeat(rightPad) + "\u2502";
35
+ console.log("");
36
+ console.log(` \u250C${h}\u2510`);
37
+ console.log(` ${empty}`);
38
+ console.log(` ${row}`);
39
+ console.log(` ${empty}`);
40
+ console.log(` \u2514${h}\u2518`);
41
+ console.log("");
42
+ }
43
+ };
44
+
45
+ // src/commands/init.ts
46
+ import pc2 from "picocolors";
7
47
  function detectFramework(cwd) {
8
48
  const pkgPath = path.join(cwd, "package.json");
9
49
  if (!fs.existsSync(pkgPath)) return null;
@@ -63,18 +103,19 @@ function prompt(question, defaultValue) {
63
103
  output: process.stdout
64
104
  });
65
105
  const displayDefault = defaultValue ? ` (${defaultValue})` : "";
66
- return new Promise((resolve2) => {
106
+ return new Promise((resolve3) => {
67
107
  rl.question(`${question}${displayDefault}: `, (answer) => {
68
108
  rl.close();
69
- resolve2(answer.trim() || defaultValue || "");
109
+ resolve3(answer.trim() || defaultValue || "");
70
110
  });
71
111
  });
72
112
  }
73
113
  async function runInit(cwd) {
74
- console.log("Initializing Spool...\n");
114
+ log.info("Initializing Spool...");
115
+ console.log("");
75
116
  const configPath = path.join(cwd, "spool.config.ts");
76
117
  if (fs.existsSync(configPath)) {
77
- console.log("spool.config.ts already exists.");
118
+ log.info("spool.config.ts already exists.");
78
119
  const framework2 = detectFramework(cwd);
79
120
  if (framework2?.usesVite) {
80
121
  const viteConfigPath = findViteConfig(cwd);
@@ -84,14 +125,13 @@ async function runInit(cwd) {
84
125
  const configName = path.basename(viteConfigPath);
85
126
  const success = addVitePlugin(viteConfigPath);
86
127
  if (success) {
87
- console.log(`Added spool plugin to ${configName}`);
128
+ log.success(`Added spool plugin to ${configName}`);
88
129
  } else {
89
- console.log(`
90
- Could not automatically modify ${configName}.`);
91
- console.log("Please add the spool plugin manually:\n");
92
- console.log(" import { spool } from '@nicmeriano/spool/vite'\n");
93
- console.log(" // In your plugins array:");
94
- console.log(" plugins: [spool(), ...otherPlugins]\n");
130
+ log.warn(`Could not automatically modify ${configName}.`);
131
+ console.log(" Please add the spool plugin manually:\n");
132
+ console.log(" import { spool } from '@nicmeriano/spool/vite'\n");
133
+ console.log(" // In your plugins array:");
134
+ console.log(" plugins: [spool(), ...otherPlugins]\n");
95
135
  }
96
136
  }
97
137
  }
@@ -101,8 +141,8 @@ Could not automatically modify ${configName}.`);
101
141
  }
102
142
  const framework = detectFramework(cwd);
103
143
  if (framework) {
104
- console.log(`Detected framework: ${framework.name}
105
- `);
144
+ log.info(`Detected framework: ${pc2.bold(framework.name)}`);
145
+ console.log("");
106
146
  }
107
147
  const defaultDevCmd = framework?.devCommand || "npm run dev";
108
148
  const devCommand = await prompt("Dev command", defaultDevCmd);
@@ -113,19 +153,19 @@ export default defineConfig({
113
153
  });
114
154
  `;
115
155
  fs.writeFileSync(configPath, configContent, "utf-8");
116
- console.log(`
117
- Created spool.config.ts`);
156
+ console.log("");
157
+ log.success("Created spool.config.ts");
118
158
  const spoolDir = path.join(cwd, ".spool");
119
159
  if (!fs.existsSync(spoolDir)) {
120
160
  fs.mkdirSync(spoolDir, { recursive: true });
121
- console.log("Created .spool/ directory");
161
+ log.success("Created .spool/ directory");
122
162
  }
123
163
  const gitignorePath = path.join(cwd, ".gitignore");
124
164
  if (fs.existsSync(gitignorePath)) {
125
165
  const content = fs.readFileSync(gitignorePath, "utf-8");
126
166
  if (!content.includes(".spool")) {
127
167
  fs.appendFileSync(gitignorePath, "\n.spool/\n");
128
- console.log("Added .spool/ to .gitignore");
168
+ log.success("Added .spool/ to .gitignore");
129
169
  }
130
170
  }
131
171
  if (framework?.usesVite) {
@@ -134,25 +174,28 @@ Created spool.config.ts`);
134
174
  const configName = path.basename(viteConfigPath);
135
175
  const success = addVitePlugin(viteConfigPath);
136
176
  if (success) {
137
- console.log(`Added spool plugin to ${configName}`);
177
+ log.success(`Added spool plugin to ${configName}`);
138
178
  } else {
139
- console.log(`
140
- Could not automatically modify ${configName}.`);
141
- console.log("Please add the spool plugin manually:\n");
142
- console.log(" import { spool } from '@nicmeriano/spool/vite'\n");
143
- console.log(" // In your plugins array:");
144
- console.log(" plugins: [spool(), ...otherPlugins]\n");
179
+ log.warn(`Could not automatically modify ${configName}.`);
180
+ console.log(" Please add the spool plugin manually:\n");
181
+ console.log(" import { spool } from '@nicmeriano/spool/vite'\n");
182
+ console.log(" // In your plugins array:");
183
+ console.log(" plugins: [spool(), ...otherPlugins]\n");
145
184
  }
146
185
  }
147
186
  } else {
148
- console.log("\nNote: Add this script tag to your HTML:");
149
- console.log(' <script src="http://localhost:3142/inject.js"></script>');
187
+ log.info("Add this script tag to your HTML:");
188
+ console.log(' <script src="http://localhost:3142/inject.js"></script>');
150
189
  }
151
- console.log('\nDone! Run "spool open" to start.\n');
190
+ console.log("");
191
+ log.success(`Done! Run ${pc2.cyan('"spool open"')} to start.`);
192
+ console.log("");
152
193
  }
153
194
 
154
195
  // src/commands/open.ts
155
196
  import { spawn } from "child_process";
197
+ import * as fs3 from "fs";
198
+ import * as path3 from "path";
156
199
 
157
200
  // src/utils/load-config.ts
158
201
  import * as fs2 from "fs";
@@ -160,10 +203,7 @@ import * as path2 from "path";
160
203
  async function loadConfig(cwd) {
161
204
  const configPath = path2.resolve(cwd, "spool.config.ts");
162
205
  if (!fs2.existsSync(configPath)) {
163
- throw new Error(
164
- `No spool.config.ts found in ${cwd}.
165
- Run "spool init" to create one.`
166
- );
206
+ return {};
167
207
  }
168
208
  const { createJiti } = await import("jiti");
169
209
  const jiti = createJiti(import.meta.url, { interopDefault: true });
@@ -174,14 +214,14 @@ Run "spool init" to create one.`
174
214
  // src/utils/port.ts
175
215
  import * as net from "net";
176
216
  async function findAvailablePort(preferred) {
177
- return new Promise((resolve2, reject) => {
217
+ return new Promise((resolve3, reject) => {
178
218
  const server = net.createServer();
179
219
  server.listen(preferred, () => {
180
- server.close(() => resolve2(preferred));
220
+ server.close(() => resolve3(preferred));
181
221
  });
182
222
  server.on("error", (err) => {
183
223
  if (err.code === "EADDRINUSE") {
184
- findAvailablePort(preferred + 1).then(resolve2).catch(reject);
224
+ findAvailablePort(preferred + 1).then(resolve3).catch(reject);
185
225
  } else {
186
226
  reject(err);
187
227
  }
@@ -212,29 +252,58 @@ function openBrowser(url) {
212
252
  var DEFAULT_SERVER_PORT = 3142;
213
253
 
214
254
  // src/commands/open.ts
255
+ import pc3 from "picocolors";
256
+ function detectDevCommand(cwd) {
257
+ const pkgPath = path3.resolve(cwd, "package.json");
258
+ if (!fs3.existsSync(pkgPath)) return void 0;
259
+ try {
260
+ const pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
261
+ if (pkg.scripts?.dev) {
262
+ return "npm run dev";
263
+ }
264
+ } catch {
265
+ }
266
+ return void 0;
267
+ }
215
268
  async function runOpen(cwd, options = {}) {
216
269
  const config = await loadConfig(cwd);
217
270
  if (!process.env.ANTHROPIC_API_KEY) {
218
- console.warn("Warning: ANTHROPIC_API_KEY is not set. Claude features will not work.\n");
271
+ log.warn("ANTHROPIC_API_KEY is not set. Claude features will not work.");
219
272
  }
220
273
  const preferredPort = options.port ?? config.port ?? DEFAULT_SERVER_PORT;
221
274
  const port = await findAvailablePort(preferredPort);
222
275
  if (port !== preferredPort) {
223
- console.log(`Port ${preferredPort} is in use, using ${port} instead.`);
276
+ log.info(`Port ${preferredPort} is in use, using ${pc3.bold(String(port))} instead.`);
224
277
  }
225
- console.log(`Starting Spool server on port ${port}...`);
278
+ console.log("");
279
+ log.info("Starting dev servers...");
226
280
  const { startServer } = await import("@nicmeriano/spool-server");
227
- startServer({ port, cwd });
228
- if (config.devCommand) {
229
- console.log(`Starting dev server: ${config.devCommand}`);
230
- const [cmd, ...args2] = config.devCommand.split(" ");
231
- const child = spawn(cmd, args2, {
232
- cwd,
233
- stdio: "inherit",
234
- shell: true
235
- });
281
+ const server = await startServer({ port, cwd });
282
+ const devCommand = config.devCommand ?? detectDevCommand(cwd);
283
+ if (devCommand) {
284
+ const [cmd, ...args2] = devCommand.split(" ");
285
+ const logDir = path3.resolve(cwd, ".spool");
286
+ if (!fs3.existsSync(logDir)) {
287
+ fs3.mkdirSync(logDir, { recursive: true });
288
+ }
289
+ const logFile = path3.resolve(logDir, "dev.log");
290
+ let child;
291
+ if (options.verbose) {
292
+ child = spawn(cmd, args2, {
293
+ cwd,
294
+ stdio: "inherit",
295
+ shell: true
296
+ });
297
+ } else {
298
+ const logFd = fs3.openSync(logFile, "w");
299
+ child = spawn(cmd, args2, {
300
+ cwd,
301
+ stdio: ["ignore", logFd, logFd],
302
+ shell: true
303
+ });
304
+ }
236
305
  child.on("error", (error) => {
237
- console.error(`Dev server error: ${error.message}`);
306
+ log.error(`Dev server error: ${error.message}`);
238
307
  });
239
308
  process.on("SIGINT", () => {
240
309
  child.kill();
@@ -244,17 +313,18 @@ async function runOpen(cwd, options = {}) {
244
313
  child.kill();
245
314
  process.exit(0);
246
315
  });
316
+ } else {
317
+ log.warn('No dev command found. Add devCommand to spool.config.ts or a "dev" script to package.json.');
247
318
  }
319
+ log.banner(port);
248
320
  if (!options.noOpen) {
249
- const shellUrl = `http://localhost:${port}`;
250
- console.log(`
251
- Opening Spool at ${shellUrl}
252
- `);
253
- setTimeout(() => openBrowser(shellUrl), 1e3);
254
- } else {
255
- console.log(`
256
- Spool server running at http://localhost:${port}
257
- `);
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
+ }
327
+ openBrowser(`http://localhost:${port}`);
258
328
  }
259
329
  }
260
330
 
@@ -272,12 +342,12 @@ Commands:
272
342
  Options (open):
273
343
  --port <n> Server port (default: 3142)
274
344
  --no-open Don't open browser automatically
345
+ --verbose Show dev server output in terminal
275
346
 
276
347
  Examples:
277
348
  spool init
278
349
  spool open
279
350
  spool open --port 4000
280
- spool open --no-open
281
351
  `);
282
352
  }
283
353
  async function main() {
@@ -290,7 +360,8 @@ async function main() {
290
360
  const portIndex = args.indexOf("--port");
291
361
  const port = portIndex !== -1 ? parseInt(args[portIndex + 1], 10) : void 0;
292
362
  const noOpen = args.includes("--no-open");
293
- await runOpen(cwd, { port, noOpen });
363
+ const verbose = args.includes("--verbose");
364
+ await runOpen(cwd, { port, noOpen, verbose });
294
365
  break;
295
366
  }
296
367
  case "--help":
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/init.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';\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 console.log('Initializing Spool...\\n');\n\n // Check if config already exists\n const configPath = path.join(cwd, 'spool.config.ts');\n if (fs.existsSync(configPath)) {\n console.log('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 console.log(`Added spool plugin to ${configName}`);\n } else {\n console.log(`\\nCould 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 console.log(`Detected framework: ${framework.name}\\n`);\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(`\\nCreated 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 console.log('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 console.log('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 console.log(`Added spool plugin to ${configName}`);\n } else {\n console.log(`\\nCould 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 console.log('\\nNote: Add this script tag to your HTML:');\n console.log(' <script src=\"http://localhost:3142/inject.js\"></script>');\n }\n\n console.log('\\nDone! Run \"spool open\" to start.\\n');\n}\n","import { spawn } from 'node:child_process';\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';\n\nexport interface OpenOptions {\n port?: number;\n noOpen?: boolean;\n}\n\n/**\n * Run the spool open command\n */\nexport async function runOpen(cwd: string, options: OpenOptions = {}): Promise<void> {\n // Load config\n const config = await loadConfig(cwd);\n\n // Check for ANTHROPIC_API_KEY\n if (!process.env.ANTHROPIC_API_KEY) {\n console.warn('Warning: ANTHROPIC_API_KEY is not set. Claude features will not work.\\n');\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 console.log(`Port ${preferredPort} is in use, using ${port} instead.`);\n }\n\n // Start the server\n console.log(`Starting Spool server on port ${port}...`);\n const { startServer } = await import('@nicmeriano/spool-server');\n\n // Start server (runs in background)\n startServer({ port, cwd });\n\n // Spawn dev command if configured\n if (config.devCommand) {\n console.log(`Starting dev server: ${config.devCommand}`);\n const [cmd, ...args] = config.devCommand.split(' ');\n const child = spawn(cmd, args, {\n cwd,\n stdio: 'inherit',\n shell: true,\n });\n\n child.on('error', (error) => {\n console.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 }\n\n // Open browser immediately — the shell shows a loading state until the app URL\n // arrives via SSE (from the Vite plugin or manual script tag)\n if (!options.noOpen) {\n const shellUrl = `http://localhost:${port}`;\n console.log(`\\nOpening Spool at ${shellUrl}\\n`);\n setTimeout(() => openBrowser(shellUrl), 1000);\n } else {\n console.log(`\\nSpool server running at http://localhost:${port}\\n`);\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 throw new Error(\n `No spool.config.ts found in ${cwd}.\\nRun \"spool init\" to create one.`\n );\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\nExamples:\n spool init\n spool open\n spool open --port 4000\n spool open --no-open\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 await runOpen(cwd, { port, noOpen });\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":["resolve","framework","fs","path","resolve","command","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":";;;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,SAAS,MAAM,YAAY,EAAE,MAAM,IAAI,CAAC;AAG9C,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;AAIf,MAAI,CAAC,QAAQ,QAAQ;AACnB,QAAI,YAAY;AACd,YAAM,SAAS,MAAM,OAAO,cAAc,GAAM;AAChD,UAAI,CAAC,QAAQ;AACX,YAAI,KAAK,iEAA4D;AAAA,MACvE;AAAA,IACF;AACA,gBAAY,oBAAoB,IAAI,EAAE;AAAA,EACxC;AACF;;;AKxHA,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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nicmeriano/spool",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "Spool CLI - UI feedback tool for Claude Code",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -38,7 +38,8 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "jiti": "^2.4.0",
41
- "@nicmeriano/spool-server": "0.0.6"
41
+ "picocolors": "^1.1.1",
42
+ "@nicmeriano/spool-server": "0.0.7"
42
43
  },
43
44
  "peerDependencies": {
44
45
  "vite": ">=5.0.0"