@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 +129 -58
- package/dist/cli.js.map +1 -1
- package/package.json +3 -2
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((
|
|
106
|
+
return new Promise((resolve3) => {
|
|
67
107
|
rl.question(`${question}${displayDefault}: `, (answer) => {
|
|
68
108
|
rl.close();
|
|
69
|
-
|
|
109
|
+
resolve3(answer.trim() || defaultValue || "");
|
|
70
110
|
});
|
|
71
111
|
});
|
|
72
112
|
}
|
|
73
113
|
async function runInit(cwd) {
|
|
74
|
-
|
|
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
|
-
|
|
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
|
-
|
|
128
|
+
log.success(`Added spool plugin to ${configName}`);
|
|
88
129
|
} else {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
console.log("
|
|
92
|
-
console.log("
|
|
93
|
-
console.log("
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
177
|
+
log.success(`Added spool plugin to ${configName}`);
|
|
138
178
|
} else {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
console.log("
|
|
142
|
-
console.log("
|
|
143
|
-
console.log("
|
|
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
|
-
|
|
149
|
-
console.log('
|
|
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(
|
|
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
|
-
|
|
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((
|
|
217
|
+
return new Promise((resolve3, reject) => {
|
|
178
218
|
const server = net.createServer();
|
|
179
219
|
server.listen(preferred, () => {
|
|
180
|
-
server.close(() =>
|
|
220
|
+
server.close(() => resolve3(preferred));
|
|
181
221
|
});
|
|
182
222
|
server.on("error", (err) => {
|
|
183
223
|
if (err.code === "EADDRINUSE") {
|
|
184
|
-
findAvailablePort(preferred + 1).then(
|
|
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
|
-
|
|
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
|
-
|
|
276
|
+
log.info(`Port ${preferredPort} is in use, using ${pc3.bold(String(port))} instead.`);
|
|
224
277
|
}
|
|
225
|
-
console.log(
|
|
278
|
+
console.log("");
|
|
279
|
+
log.info("Starting dev servers...");
|
|
226
280
|
const { startServer } = await import("@nicmeriano/spool-server");
|
|
227
|
-
startServer({ port, cwd });
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const [cmd, ...args2] =
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
|
|
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
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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
|
-
|
|
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":"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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.
|
|
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
|
-
"
|
|
41
|
+
"picocolors": "^1.1.1",
|
|
42
|
+
"@nicmeriano/spool-server": "0.0.7"
|
|
42
43
|
},
|
|
43
44
|
"peerDependencies": {
|
|
44
45
|
"vite": ">=5.0.0"
|