@bagelink/workspace 1.8.0 → 1.8.5

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.
Files changed (43) hide show
  1. package/README.md +290 -7
  2. package/bin/bgl.ts +160 -11
  3. package/dist/bin/bgl.cjs +1283 -18
  4. package/dist/bin/bgl.mjs +1279 -15
  5. package/dist/composable.cjs +21 -0
  6. package/dist/composable.d.cts +50 -0
  7. package/dist/composable.d.mts +50 -0
  8. package/dist/composable.d.ts +50 -0
  9. package/dist/composable.mjs +18 -0
  10. package/dist/index.cjs +3 -155
  11. package/dist/index.d.cts +4 -133
  12. package/dist/index.d.mts +4 -133
  13. package/dist/index.d.ts +4 -133
  14. package/dist/index.mjs +2 -139
  15. package/dist/shared/workspace.CefUteAh.d.cts +49 -0
  16. package/dist/shared/workspace.CefUteAh.d.mts +49 -0
  17. package/dist/shared/workspace.CefUteAh.d.ts +49 -0
  18. package/dist/shared/workspace.Dx9_TIij.cjs +86 -0
  19. package/dist/shared/workspace.Twuo1PFw.mjs +78 -0
  20. package/dist/vite.cjs +110 -0
  21. package/dist/vite.d.cts +98 -0
  22. package/dist/vite.d.mts +98 -0
  23. package/dist/vite.d.ts +98 -0
  24. package/dist/vite.mjs +99 -0
  25. package/env.d.ts +29 -0
  26. package/package.json +28 -5
  27. package/src/build.ts +45 -0
  28. package/src/composable.ts +65 -0
  29. package/src/detect.ts +90 -0
  30. package/src/dev.ts +162 -0
  31. package/src/index.ts +11 -71
  32. package/src/init.ts +60 -12
  33. package/src/lint.ts +323 -0
  34. package/src/netlify.ts +54 -3
  35. package/src/proxy.ts +23 -3
  36. package/src/sdk.ts +196 -0
  37. package/src/types.ts +5 -0
  38. package/src/vite.ts +139 -0
  39. package/src/workspace.ts +107 -23
  40. package/templates/dev-runner.ts +61 -0
  41. package/templates/tsconfig.app.json +23 -0
  42. package/dist/shared/workspace.Bwsdwbt-.cjs +0 -575
  43. package/dist/shared/workspace.Dq-27S1f.mjs +0 -560
package/dist/bin/bgl.cjs CHANGED
@@ -1,58 +1,1323 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
+ const node_path = require('node:path');
4
5
  const process = require('node:process');
5
- const workspace = require('../shared/workspace.Bwsdwbt-.cjs');
6
- require('node:fs');
7
- require('node:path');
8
- require('prompts');
6
+ const node_child_process = require('node:child_process');
7
+ const node_fs = require('node:fs');
8
+ const prompts = require('prompts');
9
+ const netlify = require('../shared/workspace.Dx9_TIij.cjs');
9
10
 
10
11
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
11
12
 
12
13
  const process__default = /*#__PURE__*/_interopDefaultCompat(process);
14
+ const prompts__default = /*#__PURE__*/_interopDefaultCompat(prompts);
13
15
 
14
- const [, , command, ...args] = process__default.argv;
16
+ async function initWorkspace(root = process__default.cwd()) {
17
+ console.log("\n\u{1F680} Creating Bagel workspace...\n");
18
+ const response = await prompts__default([
19
+ {
20
+ type: "text",
21
+ name: "workspaceName",
22
+ message: "Workspace name:",
23
+ initial: "my-workspace"
24
+ },
25
+ {
26
+ type: "text",
27
+ name: "projectId",
28
+ message: "Bagel project ID:",
29
+ initial: "my-project"
30
+ },
31
+ {
32
+ type: "confirm",
33
+ name: "createFirstProject",
34
+ message: "Create first project?",
35
+ initial: true
36
+ },
37
+ {
38
+ type: (prev) => prev ? "text" : null,
39
+ name: "firstProjectName",
40
+ message: "First project name:",
41
+ initial: "web"
42
+ }
43
+ ]);
44
+ if (!response || !response.workspaceName) {
45
+ console.log("\n\u274C Workspace creation cancelled.\n");
46
+ process__default.exit(1);
47
+ }
48
+ const { workspaceName, projectId, createFirstProject, firstProjectName } = response;
49
+ const workspaceDir = node_path.resolve(root, workspaceName);
50
+ createWorkspaceRoot(root, workspaceName, projectId);
51
+ createSharedPackage(workspaceDir);
52
+ if (createFirstProject && firstProjectName) {
53
+ await addProject(firstProjectName, workspaceDir);
54
+ }
55
+ console.log("\n\u2705 Workspace created successfully!");
56
+ console.log("\nNext steps:");
57
+ console.log(` cd ${workspaceName}`);
58
+ console.log(" bun install");
59
+ if (createFirstProject) {
60
+ console.log(` bun run dev:${firstProjectName}`);
61
+ } else {
62
+ console.log(" bgl add <project-name> # Add a project");
63
+ }
64
+ console.log("");
65
+ }
66
+ function createWorkspaceRoot(root, name, projectId) {
67
+ const workspaceDir = node_path.resolve(root, name);
68
+ if (node_fs.existsSync(workspaceDir)) {
69
+ console.error(`\u274C Directory ${name} already exists`);
70
+ process__default.exit(1);
71
+ }
72
+ node_fs.mkdirSync(workspaceDir, { recursive: true });
73
+ const packageJson = {
74
+ name,
75
+ private: true,
76
+ workspaces: ["*", "!node_modules"],
77
+ scripts: {
78
+ "dev": "bgl dev",
79
+ "dev:local": "bgl dev --mode localhost",
80
+ "dev:verbose": "bun run --filter './!shared*' dev",
81
+ "build": "bgl build",
82
+ "typecheck": "tsc --noEmit",
83
+ "lint": "eslint . --cache",
84
+ "lint:fix": "eslint . --cache --fix"
85
+ },
86
+ dependencies: {
87
+ "@bagelink/auth": "latest",
88
+ "@bagelink/sdk": "latest",
89
+ "@bagelink/vue": "latest",
90
+ "pinia": "latest",
91
+ "vue": "latest",
92
+ "vue-router": "latest"
93
+ },
94
+ devDependencies: {
95
+ "@bagelink/lint-config": "latest",
96
+ "@bagelink/workspace": "latest",
97
+ "@vitejs/plugin-vue": "latest",
98
+ "eslint": "latest",
99
+ "typescript": "^5.0.0",
100
+ "vite": "latest"
101
+ }
102
+ };
103
+ node_fs.writeFileSync(
104
+ node_path.resolve(workspaceDir, "package.json"),
105
+ `${JSON.stringify(packageJson, null, 2)}
106
+ `
107
+ );
108
+ const bglConfig = `import { defineWorkspace } from '@bagelink/workspace'
109
+
110
+ export default defineWorkspace({
111
+ localhost: {
112
+ host: 'http://localhost:8000',
113
+ proxy: '/api',
114
+ openapi_url: 'http://localhost:8000/openapi.json',
115
+ },
116
+ development: {
117
+ host: 'https://${projectId}.bagel.to',
118
+ proxy: '/api',
119
+ openapi_url: 'https://${projectId}.bagel.to/openapi.json',
120
+ },
121
+ production: {
122
+ host: 'https://${projectId}.bagel.to',
123
+ proxy: '/api',
124
+ openapi_url: 'https://${projectId}.bagel.to/openapi.json',
125
+ },
126
+ })
127
+ `;
128
+ node_fs.writeFileSync(node_path.resolve(workspaceDir, "bgl.config.ts"), bglConfig);
129
+ const tsConfig = {
130
+ compilerOptions: {
131
+ target: "ES2020",
132
+ useDefineForClassFields: true,
133
+ module: "ESNext",
134
+ lib: ["ES2020", "DOM", "DOM.Iterable"],
135
+ skipLibCheck: true,
136
+ moduleResolution: "bundler",
137
+ allowImportingTsExtensions: true,
138
+ resolveJsonModule: true,
139
+ isolatedModules: true,
140
+ noEmit: true,
141
+ jsx: "preserve",
142
+ strict: true,
143
+ noUnusedLocals: true,
144
+ noUnusedParameters: true,
145
+ noFallthroughCasesInSwitch: true,
146
+ baseUrl: ".",
147
+ paths: {
148
+ "shared/*": ["./shared/*"]
149
+ }
150
+ }
151
+ };
152
+ node_fs.writeFileSync(
153
+ node_path.resolve(workspaceDir, "tsconfig.json"),
154
+ `${JSON.stringify(tsConfig, null, 2)}
155
+ `
156
+ );
157
+ const gitignore = `node_modules
158
+ dist
159
+ .DS_Store
160
+ *.local
161
+ .env.local
162
+ .vite
163
+ `;
164
+ node_fs.writeFileSync(node_path.resolve(workspaceDir, ".gitignore"), gitignore);
165
+ const scriptsDir = node_path.resolve(workspaceDir, "scripts");
166
+ node_fs.mkdirSync(scriptsDir, { recursive: true });
167
+ const devRunnerContent = `#!/usr/bin/env bun
168
+ import { spawn } from 'bun'
169
+ import { readdir } from 'fs/promises'
170
+ import { resolve } from 'path'
171
+
172
+ const projectsRoot = process.cwd()
173
+ const projects = (await readdir(projectsRoot, { withFileTypes: true }))
174
+ .filter(
175
+ item =>
176
+ item.isDirectory()
177
+ && item.name !== 'node_modules'
178
+ && item.name !== 'shared'
179
+ && item.name !== 'scripts'
180
+ && item.name !== '.git'
181
+ && !item.name.startsWith('.'),
182
+ )
183
+ .map(item => item.name)
184
+
185
+ console.log(\`\\n\u{1F680} Starting \${projects.length} project\${projects.length > 1 ? 's' : ''}...\\n\`)
186
+
187
+ const urlPattern = /Local:\\s+(http:\\/\\/localhost:\\d+)/
188
+
189
+ projects.forEach((project) => {
190
+ const proc = spawn({
191
+ cmd: ['bun', 'run', 'dev'],
192
+ cwd: resolve(projectsRoot, project),
193
+ stdout: 'pipe',
194
+ stderr: 'pipe',
195
+ })
196
+
197
+ const decoder = new TextDecoder()
198
+
199
+ proc.stdout.pipeTo(
200
+ new WritableStream({
201
+ write(chunk) {
202
+ const text = decoder.decode(chunk)
203
+ const match = text.match(urlPattern)
204
+ if (match) {
205
+ console.log(\` \u2713 \${project.padEnd(15)} \u2192 \${match[1]}\`)
206
+ }
207
+ },
208
+ }),
209
+ )
210
+
211
+ proc.stderr.pipeTo(
212
+ new WritableStream({
213
+ write(chunk) {
214
+ const text = decoder.decode(chunk)
215
+ if (text.includes('error') || text.includes('Error')) {
216
+ console.error(\` \u2717 \${project}: \${text.trim()}\`)
217
+ }
218
+ },
219
+ }),
220
+ )
221
+ })
222
+
223
+ console.log('\\n\u{1F4A1} Press Ctrl+C to stop all servers\\n')
224
+
225
+ process.on('SIGINT', () => {
226
+ console.log('\\n\\n\u{1F44B} Stopping all servers...\\n')
227
+ process.exit()
228
+ })
229
+ `;
230
+ node_fs.writeFileSync(node_path.resolve(scriptsDir, "dev.ts"), devRunnerContent);
231
+ console.log(`\u2705 Created workspace: ${name}`);
232
+ }
233
+ function createSharedPackage(root) {
234
+ const sharedDir = node_path.resolve(root, "shared");
235
+ node_fs.mkdirSync(sharedDir, { recursive: true });
236
+ const packageJson = {
237
+ name: "shared",
238
+ version: "1.0.0",
239
+ type: "module",
240
+ exports: {
241
+ ".": "./index.ts",
242
+ "./utils": "./utils/index.ts",
243
+ "./types": "./types/index.ts"
244
+ }
245
+ };
246
+ node_fs.writeFileSync(
247
+ node_path.resolve(sharedDir, "package.json"),
248
+ `${JSON.stringify(packageJson, null, 2)}
249
+ `
250
+ );
251
+ node_fs.writeFileSync(
252
+ node_path.resolve(sharedDir, "index.ts"),
253
+ "// Shared utilities and exports\nexport * from './utils'\n"
254
+ );
255
+ node_fs.mkdirSync(node_path.resolve(sharedDir, "utils"), { recursive: true });
256
+ node_fs.writeFileSync(
257
+ node_path.resolve(sharedDir, "utils", "index.ts"),
258
+ "// Shared utility functions\nexport function formatDate(date: Date): string {\n return date.toISOString()\n}\n"
259
+ );
260
+ node_fs.mkdirSync(node_path.resolve(sharedDir, "types"), { recursive: true });
261
+ node_fs.writeFileSync(
262
+ node_path.resolve(sharedDir, "types", "index.ts"),
263
+ "// Shared types\nexport interface User {\n id: string\n name: string\n}\n"
264
+ );
265
+ console.log("\u2705 Created shared package");
266
+ }
267
+ async function addProject(name, root = process__default.cwd()) {
268
+ const projectDir = node_path.resolve(root, name);
269
+ if (node_fs.existsSync(projectDir)) {
270
+ console.error(`\u274C Project ${name} already exists`);
271
+ process__default.exit(1);
272
+ }
273
+ console.log(`
274
+ \u{1F4E6} Creating project: ${name}
275
+ `);
276
+ node_fs.mkdirSync(projectDir, { recursive: true });
277
+ const isWorkspace = node_fs.existsSync(node_path.resolve(root, "bgl.config.ts"));
278
+ const packageJson = {
279
+ name,
280
+ type: "module",
281
+ scripts: {
282
+ dev: "vite",
283
+ build: "vite build",
284
+ preview: "vite preview"
285
+ },
286
+ dependencies: {},
287
+ devDependencies: {
288
+ "@vitejs/plugin-vue": "latest",
289
+ "vite": "latest",
290
+ "vue": "latest"
291
+ }
292
+ };
293
+ if (isWorkspace) {
294
+ packageJson.dependencies.shared = "workspace:*";
295
+ }
296
+ node_fs.writeFileSync(
297
+ node_path.resolve(projectDir, "package.json"),
298
+ `${JSON.stringify(packageJson, null, 2)}
299
+ `
300
+ );
301
+ const bglConfigContent = isWorkspace ? `import { defineWorkspace } from '@bagelink/workspace'
302
+ import rootWorkspace from '../bgl.config'
303
+
304
+ export default defineWorkspace({
305
+ localhost: rootWorkspace('localhost'),
306
+ development: rootWorkspace('development'),
307
+ production: rootWorkspace('production'),
308
+ })
309
+ ` : `import { defineWorkspace } from '@bagelink/workspace'
310
+
311
+ export default defineWorkspace({
312
+ localhost: {
313
+ host: 'http://localhost:8000',
314
+ proxy: '/api',
315
+ },
316
+ development: {
317
+ host: 'https://my-project.bagel.to',
318
+ proxy: '/api',
319
+ },
320
+ production: {
321
+ host: 'https://my-project.bagel.to',
322
+ proxy: '/api',
323
+ },
324
+ })
325
+ `;
326
+ node_fs.writeFileSync(node_path.resolve(projectDir, "bgl.config.ts"), bglConfigContent);
327
+ const viteConfig = `import { defineConfig } from 'vite'
328
+ import vue from '@vitejs/plugin-vue'
329
+ import { bagelink } from '@bagelink/workspace/vite'
330
+ import workspace from './bgl.config'
331
+
332
+ export default defineConfig({
333
+ plugins: [
334
+ vue(),
335
+ bagelink({ workspace }),
336
+ ],
337
+ })
338
+ `;
339
+ node_fs.writeFileSync(node_path.resolve(projectDir, "vite.config.ts"), viteConfig);
340
+ const srcDir = node_path.resolve(projectDir, "src");
341
+ node_fs.mkdirSync(srcDir, { recursive: true });
342
+ const indexHtml = `<!DOCTYPE html>
343
+ <html lang="en">
344
+ <head>
345
+ <meta charset="UTF-8">
346
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
347
+ <title>${name}</title>
348
+ </head>
349
+ <body>
350
+ <div id="app"></div>
351
+ <script type="module" src="/src/main.ts"><\/script>
352
+ </body>
353
+ </html>
354
+ `;
355
+ node_fs.writeFileSync(node_path.resolve(projectDir, "index.html"), indexHtml);
356
+ const mainTs = `import { createApp } from 'vue'
357
+ import App from './App.vue'
358
+
359
+ createApp(App).mount('#app')
360
+ `;
361
+ node_fs.writeFileSync(node_path.resolve(srcDir, "main.ts"), mainTs);
362
+ const appVue = `<script setup lang="ts">
363
+ import { ref } from 'vue'
364
+ ${isWorkspace ? "import { formatDate } from 'shared/utils'\n" : ""}
365
+ const count = ref(0)
366
+ <\/script>
367
+
368
+ <template>
369
+ <div>
370
+ <h1>${name}</h1>
371
+ <button @click="count++">Count: {{ count }}</button>
372
+ ${isWorkspace ? "<p>{{ formatDate(new Date()) }}</p>" : ""}
373
+ </div>
374
+ </template>
375
+ `;
376
+ node_fs.writeFileSync(node_path.resolve(srcDir, "App.vue"), appVue);
377
+ console.log(`\u2705 Created project: ${name}`);
378
+ if (isWorkspace) {
379
+ updateWorkspaceScripts(root, name);
380
+ }
381
+ console.log("\nNext steps:");
382
+ console.log(` cd ${name}`);
383
+ console.log(" bun install");
384
+ console.log(" bun run dev");
385
+ console.log("");
386
+ }
387
+ function updateWorkspaceScripts(root, projectName) {
388
+ const packageJsonPath = node_path.resolve(root, "package.json");
389
+ if (!node_fs.existsSync(packageJsonPath)) return;
390
+ try {
391
+ const packageJson = JSON.parse(
392
+ node_fs.readFileSync(packageJsonPath, "utf-8")
393
+ );
394
+ if (!packageJson.scripts) {
395
+ packageJson.scripts = {};
396
+ }
397
+ packageJson.scripts[`dev:${projectName}`] = `bun --filter ${projectName} dev`;
398
+ packageJson.scripts[`build:${projectName}`] = `bun --filter ${projectName} build`;
399
+ node_fs.writeFileSync(
400
+ packageJsonPath,
401
+ `${JSON.stringify(packageJson, null, 2)}
402
+ `
403
+ );
404
+ console.log(`\u2705 Added scripts: dev:${projectName}, build:${projectName}`);
405
+ } catch (error) {
406
+ console.warn("\u26A0\uFE0F Could not update workspace scripts");
407
+ }
408
+ }
409
+ function listProjects(root = process__default.cwd()) {
410
+ try {
411
+ const items = node_fs.readdirSync(root, { withFileTypes: true });
412
+ return items.filter(
413
+ (item) => item.isDirectory() && item.name !== "node_modules" && item.name !== "shared" && item.name !== "scripts" && item.name !== ".git" && !item.name.startsWith(".")
414
+ ).map((item) => item.name);
415
+ } catch {
416
+ return [];
417
+ }
418
+ }
419
+
420
+ async function runBuild(filter, additionalArgs = []) {
421
+ const argsStr = additionalArgs.length > 0 ? ` -- ${additionalArgs.join(" ")}` : "";
422
+ const resolvedFilters = resolveFilters$1(filter);
423
+ if (!resolvedFilters || resolvedFilters.length === 0) return 1;
424
+ const filterArgs = resolvedFilters.map((f) => `--filter '${f}'`).join(" ");
425
+ const command = `bun run ${filterArgs} build${argsStr}`;
426
+ const proc = node_child_process.spawn(command, {
427
+ cwd: process__default.cwd(),
428
+ stdio: "inherit",
429
+ shell: true
430
+ });
431
+ proc.on("error", (error) => {
432
+ console.error("Failed to start build:", error.message);
433
+ });
434
+ return new Promise((resolve, reject) => {
435
+ proc.on("exit", (code) => {
436
+ resolve(code || 0);
437
+ });
438
+ proc.on("error", reject);
439
+ });
440
+ }
441
+ function resolveFilters$1(filter) {
442
+ if (filter) return [filter];
443
+ const projects = listProjects();
444
+ if (projects.length === 0) {
445
+ console.error("No projects found");
446
+ return null;
447
+ }
448
+ return projects.map((p) => `./${p}`);
449
+ }
450
+
451
+ function isWorkspace(root = process__default.cwd()) {
452
+ const packageJsonPath = node_path.resolve(root, "package.json");
453
+ if (node_fs.existsSync(packageJsonPath)) {
454
+ try {
455
+ const packageJson = JSON.parse(node_fs.readFileSync(packageJsonPath, "utf-8"));
456
+ if (packageJson.workspaces !== void 0) {
457
+ return true;
458
+ }
459
+ } catch {
460
+ }
461
+ }
462
+ try {
463
+ const items = node_fs.readdirSync(root, { withFileTypes: true });
464
+ const projectDirs = items.filter(
465
+ (item) => item.isDirectory() && item.name !== "node_modules" && item.name !== "shared" && item.name !== ".git" && !item.name.startsWith(".") && node_fs.existsSync(node_path.resolve(root, item.name, "package.json"))
466
+ );
467
+ return projectDirs.length >= 2;
468
+ } catch {
469
+ return false;
470
+ }
471
+ }
472
+
473
+ const servers = /* @__PURE__ */ new Map();
474
+ const seenLines = /* @__PURE__ */ new Set();
475
+ const colors = {
476
+ reset: "\x1B[0m",
477
+ cyan: "\x1B[36m",
478
+ green: "\x1B[32m",
479
+ yellow: "\x1B[33m",
480
+ dim: "\x1B[2m",
481
+ red: "\x1B[31m"
482
+ };
483
+ function clearAndPrintServers() {
484
+ if (servers.size > 0) {
485
+ process__default.stdout.write("\x1B[2J\x1B[H");
486
+ }
487
+ console.log(`${colors.cyan}\u{1F680} Development Servers${colors.reset}
488
+ `);
489
+ for (const [name, info] of servers.entries()) {
490
+ if (info.status === "ready" && info.port) {
491
+ const url = `http://localhost:${info.port}`;
492
+ console.log(`${colors.green}\u25CF${colors.reset} ${colors.cyan}${name}${colors.reset} ${colors.dim}\u2192${colors.reset} ${url}`);
493
+ } else {
494
+ console.log(`${colors.yellow}\u25CB${colors.reset} ${colors.dim}${name} (starting...)${colors.reset}`);
495
+ }
496
+ }
497
+ console.log("");
498
+ }
499
+ async function runDev(filter, additionalArgs = []) {
500
+ const argsStr = additionalArgs.length > 0 ? ` -- ${additionalArgs.join(" ")}` : "";
501
+ const resolvedFilters = resolveFilters(filter);
502
+ if (!resolvedFilters || resolvedFilters.length === 0) return 1;
503
+ const filterArgs = resolvedFilters.map((f) => `--filter '${f}'`).join(" ");
504
+ const projectNames = resolvedFilters.map((f) => f.replace("./", "")).join(", ");
505
+ console.log(`${colors.dim}Starting dev servers: ${projectNames}${argsStr}${colors.reset}
506
+ `);
507
+ const command = `bun run ${filterArgs} dev${argsStr}`;
508
+ const proc = node_child_process.spawn(command, {
509
+ cwd: process__default.cwd(),
510
+ stdio: ["inherit", "pipe", "pipe"],
511
+ shell: true
512
+ });
513
+ let stdoutBuffer = "";
514
+ let stderrBuffer = "";
515
+ function processLine(line) {
516
+ if (!line.trim()) return;
517
+ if (seenLines.has(line)) return;
518
+ seenLines.add(line);
519
+ const projectMatch = line.match(/^(\w+)\s+dev:/);
520
+ if (projectMatch) {
521
+ const name = projectMatch[1];
522
+ if (!servers.has(name)) {
523
+ console.log(`${colors.dim}[DEBUG] Detected project: ${name}${colors.reset}`);
524
+ servers.set(name, { name, status: "starting" });
525
+ clearAndPrintServers();
526
+ }
527
+ }
528
+ const portMatch = line.match(/Local:\s+http:\/\/localhost:(\d+)/);
529
+ if (portMatch) {
530
+ const port = Number.parseInt(portMatch[1], 10);
531
+ const projectInLine = line.match(/^(\w+)\s+dev:/);
532
+ if (projectInLine) {
533
+ const name = projectInLine[1];
534
+ const info = servers.get(name);
535
+ console.log(`${colors.dim}[DEBUG] Port ${port} for project: ${name}, exists: ${!!info}, hasPort: ${info?.port}${colors.reset}`);
536
+ if (info && !info.port) {
537
+ info.port = port;
538
+ info.status = "ready";
539
+ clearAndPrintServers();
540
+ }
541
+ }
542
+ }
543
+ }
544
+ proc.stdout?.setEncoding("utf8");
545
+ proc.stderr?.setEncoding("utf8");
546
+ proc.stdout?.on("data", (data) => {
547
+ if (servers.size === 0) {
548
+ console.log(`${colors.dim}Receiving output...${colors.reset}`);
549
+ }
550
+ stdoutBuffer += data;
551
+ const lines = stdoutBuffer.split("\n");
552
+ stdoutBuffer = lines.pop() || "";
553
+ for (const line of lines) {
554
+ processLine(line);
555
+ }
556
+ });
557
+ proc.stderr?.on("data", (data) => {
558
+ stderrBuffer += data;
559
+ const lines = stderrBuffer.split("\n");
560
+ stderrBuffer = lines.pop() || "";
561
+ for (const line of lines) {
562
+ processLine(line);
563
+ }
564
+ });
565
+ proc.on("error", (error) => {
566
+ console.error(`${colors.red}Failed to start dev servers:${colors.reset}`, error.message);
567
+ });
568
+ process__default.on("SIGINT", () => {
569
+ proc.kill("SIGINT");
570
+ process__default.exit(0);
571
+ });
572
+ return new Promise((resolve, reject) => {
573
+ proc.on("exit", (code) => {
574
+ resolve(code || 0);
575
+ });
576
+ proc.on("error", reject);
577
+ });
578
+ }
579
+ function resolveFilters(filter) {
580
+ if (filter) return [filter];
581
+ const projects = listProjects();
582
+ if (projects.length === 0) {
583
+ console.error("No projects found");
584
+ return null;
585
+ }
586
+ return projects.map((p) => `./${p}`);
587
+ }
588
+
589
+ async function generateWorkspaceConfig(root = process__default.cwd(), configFile = "bgl.config.ts") {
590
+ console.log("\n\u{1F527} No bgl.config.ts found. Let's create one!\n");
591
+ const response = await prompts__default([
592
+ {
593
+ type: "text",
594
+ name: "projectId",
595
+ message: "What is your Bagel project ID?",
596
+ initial: "my-project",
597
+ validate: (value) => value.length > 0 ? true : "Project ID is required"
598
+ },
599
+ {
600
+ type: "confirm",
601
+ name: "useCustomHost",
602
+ message: "Use custom production host?",
603
+ initial: false
604
+ },
605
+ {
606
+ type: (prev) => prev ? "text" : null,
607
+ name: "customHost",
608
+ message: "Enter production host URL:",
609
+ initial: "https://api.example.com"
610
+ }
611
+ ]);
612
+ if (!response || !response.projectId) {
613
+ console.log("\n\u274C Config generation cancelled.\n");
614
+ process__default.exit(1);
615
+ }
616
+ const productionHost = response.useCustomHost === true ? response.customHost : `https://${response.projectId}.bagel.to`;
617
+ const configContent = `import { defineWorkspace } from '@bagelink/workspace'
618
+ import type { WorkspaceConfig, WorkspaceEnvironment } from '@bagelink/workspace'
619
+
620
+ const configs: Record<WorkspaceEnvironment, WorkspaceConfig> = {
621
+ localhost: {
622
+ host: 'http://localhost:8000',
623
+ proxy: '/api',
624
+ openapi_url: 'http://localhost:8000/openapi.json',
625
+ },
626
+ development: {
627
+ host: '${productionHost}',
628
+ proxy: '/api',
629
+ openapi_url: '${productionHost}/openapi.json',
630
+ },
631
+ production: {
632
+ host: '${productionHost}',
633
+ proxy: '/api',
634
+ openapi_url: '${productionHost}/openapi.json',
635
+ },
636
+ }
637
+
638
+ export default defineWorkspace(configs)
639
+ `;
640
+ const configPath = node_path.resolve(root, configFile);
641
+ node_fs.writeFileSync(configPath, configContent, "utf-8");
642
+ console.log(`
643
+ \u2705 Created ${configFile}`);
644
+ console.log(` Production host: ${productionHost}`);
645
+ console.log(` Local dev host: http://localhost:8000
646
+ `);
647
+ const setupResponse = await prompts__default([
648
+ {
649
+ type: "confirm",
650
+ name: "updatePackageJson",
651
+ message: "Add/update dev scripts in package.json?",
652
+ initial: true
653
+ },
654
+ {
655
+ type: "confirm",
656
+ name: "updateViteConfig",
657
+ message: "Create/update vite.config.ts?",
658
+ initial: true
659
+ },
660
+ {
661
+ type: "confirm",
662
+ name: "createTsConfig",
663
+ message: "Create tsconfig.app.json with path aliases?",
664
+ initial: true
665
+ },
666
+ {
667
+ type: "confirm",
668
+ name: "generateNetlify",
669
+ message: "Generate netlify.toml for deployment?",
670
+ initial: true
671
+ }
672
+ ]);
673
+ if (setupResponse.updatePackageJson) {
674
+ updatePackageJsonScripts(root);
675
+ }
676
+ if (setupResponse.updateViteConfig) {
677
+ updateViteConfig(root);
678
+ }
679
+ if (setupResponse.createTsConfig) {
680
+ createTsConfig(root);
681
+ }
682
+ if (setupResponse.generateNetlify) {
683
+ const prodConfig = {
684
+ host: productionHost,
685
+ proxy: "/api"
686
+ };
687
+ netlify.writeNetlifyConfig(prodConfig, node_path.resolve(root, "netlify.toml"));
688
+ }
689
+ console.log("\n\u{1F4A1} You can edit these files to customize your configuration.\n");
690
+ }
691
+ function updatePackageJsonScripts(root) {
692
+ const packageJsonPath = node_path.resolve(root, "package.json");
693
+ if (!node_fs.existsSync(packageJsonPath)) {
694
+ console.log("\u26A0\uFE0F No package.json found, skipping script update");
695
+ return;
696
+ }
697
+ try {
698
+ const packageJson = JSON.parse(node_fs.readFileSync(packageJsonPath, "utf-8"));
699
+ if (!packageJson.scripts) {
700
+ packageJson.scripts = {};
701
+ }
702
+ const scriptsToAdd = {
703
+ "dev": "vite",
704
+ "dev:local": "vite --mode localhost",
705
+ "build": "vite build",
706
+ "preview": "vite preview"
707
+ };
708
+ let modified = false;
709
+ for (const [key, value] of Object.entries(scriptsToAdd)) {
710
+ if (key === "dev" || key === "dev:local") {
711
+ if (packageJson.scripts[key] !== value) {
712
+ packageJson.scripts[key] = value;
713
+ modified = true;
714
+ }
715
+ } else {
716
+ if (!packageJson.scripts[key]) {
717
+ packageJson.scripts[key] = value;
718
+ modified = true;
719
+ }
720
+ }
721
+ }
722
+ if (modified) {
723
+ node_fs.writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
724
+ `, "utf-8");
725
+ console.log("\u2705 Updated package.json with dev scripts");
726
+ } else {
727
+ console.log("\u2139\uFE0F Scripts already up to date in package.json");
728
+ }
729
+ } catch (error) {
730
+ console.error("\u274C Failed to update package.json:", error);
731
+ }
732
+ }
733
+ function createTsConfig(root) {
734
+ const tsConfigPath = node_path.resolve(root, "tsconfig.app.json");
735
+ const tsConfigExists = node_fs.existsSync(tsConfigPath);
736
+ if (tsConfigExists) {
737
+ console.log("\u26A0\uFE0F tsconfig.app.json already exists, skipping");
738
+ return;
739
+ }
740
+ const tsConfigContent = `{
741
+ "extends": "../tsconfig.json",
742
+ "compilerOptions": {
743
+ "composite": true,
744
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
745
+ "baseUrl": ".",
746
+ "paths": {
747
+ "@/*": ["./src/*"],
748
+ "@shared/*": ["../shared/*"]
749
+ }
750
+ },
751
+ "include": ["src/**/*", "src/**/*.vue"],
752
+ "exclude": ["node_modules"]
753
+ }
754
+ `;
755
+ node_fs.writeFileSync(tsConfigPath, tsConfigContent, "utf-8");
756
+ console.log("\u2705 Created tsconfig.app.json");
757
+ }
758
+ function updateViteConfig(root) {
759
+ const viteConfigPath = node_path.resolve(root, "vite.config.ts");
760
+ const viteConfigExists = node_fs.existsSync(viteConfigPath);
761
+ if (viteConfigExists) {
762
+ const existingConfig = node_fs.readFileSync(viteConfigPath, "utf-8");
763
+ if (existingConfig.includes("@bagelink/workspace")) {
764
+ console.log("\u2139\uFE0F vite.config.ts already configured");
765
+ return;
766
+ }
767
+ console.log("\u26A0\uFE0F vite.config.ts exists. Please manually add the bagelink plugin:");
768
+ console.log("");
769
+ console.log(" import { bagelink } from '@bagelink/workspace/vite'");
770
+ console.log(" import workspace from './bgl.config'");
771
+ console.log("");
772
+ console.log(" plugins: [");
773
+ console.log(" vue(),");
774
+ console.log(" bagelink({ workspace }),");
775
+ console.log(" ]");
776
+ console.log("");
777
+ return;
778
+ }
779
+ const viteConfigContent = `import { defineConfig } from 'vite'
780
+ import vue from '@vitejs/plugin-vue'
781
+ import { bagelink } from '@bagelink/workspace/vite'
782
+ import workspace from './bgl.config'
783
+
784
+ // https://vitejs.dev/config/
785
+ export default defineConfig({
786
+ plugins: [
787
+ vue(),
788
+ bagelink({ workspace }),
789
+ ],
790
+ })
791
+ `;
792
+ node_fs.writeFileSync(viteConfigPath, viteConfigContent, "utf-8");
793
+ console.log("\u2705 Created vite.config.ts");
794
+ }
795
+
796
+ const REDUNDANT_FILES = [
797
+ // Old ESLint configs
798
+ ".eslintrc",
799
+ ".eslintrc.json",
800
+ ".eslintrc.js",
801
+ ".eslintrc.cjs",
802
+ ".eslintrc.yaml",
803
+ ".eslintrc.yml",
804
+ // Oxlint
805
+ "oxlint.json",
806
+ // Old Prettier configs (we create .prettierrc)
807
+ "prettier.config.js",
808
+ "prettier.config.cjs",
809
+ "prettier.config.mjs",
810
+ ".prettierrc.json",
811
+ ".prettierrc.yaml",
812
+ ".prettierrc.yml",
813
+ ".prettierrc.js",
814
+ ".prettierrc.cjs",
815
+ ".prettierrc.mjs",
816
+ ".prettierrc.toml"
817
+ ];
818
+ async function setupLint(root = process__default.cwd(), isWorkspace = false) {
819
+ console.log("\n\u{1F50D} Setting up linting...\n");
820
+ const response = await prompts__default([
821
+ {
822
+ type: "multiselect",
823
+ name: "configs",
824
+ message: "Select configurations to set up:",
825
+ choices: [
826
+ { title: "ESLint", value: "eslint", selected: true },
827
+ { title: "Prettier", value: "prettier", selected: true },
828
+ { title: "EditorConfig", value: "editorconfig", selected: true },
829
+ { title: "Git Hooks", value: "githooks", selected: false }
830
+ ]
831
+ },
832
+ {
833
+ type: "confirm",
834
+ name: "cleanRedundant",
835
+ message: "Clean up redundant lint config files?",
836
+ initial: true
837
+ },
838
+ {
839
+ type: "confirm",
840
+ name: "installDeps",
841
+ message: "Install dependencies?",
842
+ initial: true
843
+ }
844
+ ]);
845
+ if (!response || !response.configs) {
846
+ console.log("\n\u274C Setup cancelled.\n");
847
+ process__default.exit(1);
848
+ }
849
+ const { configs, cleanRedundant, installDeps } = response;
850
+ if (cleanRedundant) {
851
+ await cleanRedundantFiles(root);
852
+ }
853
+ if (configs.includes("eslint")) {
854
+ createEslintConfig(root, isWorkspace);
855
+ }
856
+ if (configs.includes("prettier")) {
857
+ createPrettierConfig(root);
858
+ }
859
+ if (configs.includes("editorconfig")) {
860
+ createEditorConfig(root);
861
+ }
862
+ if (configs.includes("githooks")) {
863
+ createGitHooks(root);
864
+ }
865
+ updatePackageJsonLint(root, configs);
866
+ if (installDeps) {
867
+ console.log("\n\u{1F4E6} Installing dependencies...");
868
+ console.log("Run: bun add -D @bagelink/lint-config eslint prettier typescript");
869
+ }
870
+ console.log("\n\u2705 Linting setup complete!");
871
+ console.log("\nAvailable commands:");
872
+ console.log(" bun run lint - Run linter");
873
+ console.log(" bun run lint:fix - Fix linting issues");
874
+ console.log(" bun run format - Format code with Prettier");
875
+ console.log("");
876
+ }
877
+ function createEslintConfig(root, isWorkspace) {
878
+ const configPath = node_path.resolve(root, "eslint.config.js");
879
+ const config = isWorkspace ? `import { defineConfig } from '@bagelink/lint-config/eslint'
880
+
881
+ export default defineConfig({
882
+ // Workspace-level ESLint config
883
+ ignores: ['**/dist/**', '**/node_modules/**', '**/.bun-cache/**'],
884
+ })
885
+ ` : `import vue3Config from '@bagelink/lint-config/eslint/vue3'
886
+
887
+ export default vue3Config
888
+ `;
889
+ node_fs.writeFileSync(configPath, config);
890
+ console.log("\u2705 Created eslint.config.js");
891
+ }
892
+ function createPrettierConfig(root) {
893
+ const configPath = node_path.resolve(root, ".prettierrc");
894
+ const config = {
895
+ semi: false,
896
+ singleQuote: true,
897
+ tabWidth: 2,
898
+ useTabs: true,
899
+ trailingComma: "all",
900
+ printWidth: 100,
901
+ arrowParens: "avoid"
902
+ };
903
+ node_fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
904
+ `);
905
+ console.log("\u2705 Created .prettierrc");
906
+ const ignorePath = node_path.resolve(root, ".prettierignore");
907
+ const ignore = `dist
908
+ node_modules
909
+ .bun-cache
910
+ *.min.js
911
+ *.min.css
912
+ `;
913
+ node_fs.writeFileSync(ignorePath, ignore);
914
+ console.log("\u2705 Created .prettierignore");
915
+ }
916
+ function createEditorConfig(root) {
917
+ const configPath = node_path.resolve(root, ".editorconfig");
918
+ const config = `root = true
919
+
920
+ [*]
921
+ charset = utf-8
922
+ indent_style = tab
923
+ indent_size = 2
924
+ end_of_line = lf
925
+ insert_final_newline = true
926
+ trim_trailing_whitespace = true
927
+
928
+ [*.md]
929
+ trim_trailing_whitespace = false
930
+
931
+ [*.{json,yml,yaml}]
932
+ indent_style = space
933
+ indent_size = 2
934
+ `;
935
+ node_fs.writeFileSync(configPath, config);
936
+ console.log("\u2705 Created .editorconfig");
937
+ }
938
+ function createGitHooks(root) {
939
+ const packageJsonPath = node_path.resolve(root, "package.json");
940
+ if (!node_fs.existsSync(packageJsonPath)) {
941
+ console.warn("\u26A0\uFE0F No package.json found, skipping git hooks");
942
+ return;
943
+ }
944
+ const lintStagedConfig = {
945
+ "*.{js,jsx,ts,tsx,vue}": ["eslint --fix"],
946
+ "*.{json,md,yml,yaml}": ["prettier --write"]
947
+ };
948
+ node_fs.writeFileSync(
949
+ node_path.resolve(root, ".lintstagedrc"),
950
+ `${JSON.stringify(lintStagedConfig, null, 2)}
951
+ `
952
+ );
953
+ console.log("\u2705 Created .lintstagedrc");
954
+ console.log("\u2139\uFE0F Add simple-git-hooks and lint-staged to devDependencies");
955
+ console.log(" Then run: npx simple-git-hooks");
956
+ }
957
+ async function cleanRedundantFiles(root) {
958
+ const foundFiles = [];
959
+ for (const file of REDUNDANT_FILES) {
960
+ const filePath = node_path.resolve(root, file);
961
+ if (node_fs.existsSync(filePath)) {
962
+ foundFiles.push(file);
963
+ }
964
+ }
965
+ if (foundFiles.length === 0) {
966
+ console.log("\u2728 No redundant files found");
967
+ return;
968
+ }
969
+ console.log("\n\u{1F4CB} Found redundant files:");
970
+ foundFiles.forEach((file) => {
971
+ console.log(` - ${file}`);
972
+ });
973
+ const confirmResponse = await prompts__default({
974
+ type: "confirm",
975
+ name: "confirm",
976
+ message: `Delete ${foundFiles.length} redundant file${foundFiles.length > 1 ? "s" : ""}?`,
977
+ initial: true
978
+ });
979
+ if (!confirmResponse.confirm) {
980
+ console.log("\u23ED\uFE0F Skipped cleaning redundant files");
981
+ return;
982
+ }
983
+ let deleted = 0;
984
+ for (const file of foundFiles) {
985
+ try {
986
+ node_fs.unlinkSync(node_path.resolve(root, file));
987
+ console.log(`\u{1F5D1}\uFE0F Deleted ${file}`);
988
+ deleted++;
989
+ } catch (error) {
990
+ console.error(`\u274C Failed to delete ${file}:`, error);
991
+ }
992
+ }
993
+ console.log(`\u2705 Cleaned up ${deleted} file${deleted > 1 ? "s" : ""}`);
994
+ }
995
+ function updatePackageJsonLint(root, configs) {
996
+ const packageJsonPath = node_path.resolve(root, "package.json");
997
+ if (!node_fs.existsSync(packageJsonPath)) {
998
+ console.warn("\u26A0\uFE0F No package.json found");
999
+ return;
1000
+ }
1001
+ try {
1002
+ const packageJson = JSON.parse(
1003
+ node_fs.readFileSync(packageJsonPath, "utf-8")
1004
+ );
1005
+ if (!packageJson.scripts) {
1006
+ packageJson.scripts = {};
1007
+ }
1008
+ if (configs.includes("eslint")) {
1009
+ if (!packageJson.scripts.lint) {
1010
+ packageJson.scripts.lint = "eslint .";
1011
+ }
1012
+ if (!packageJson.scripts["lint:fix"]) {
1013
+ packageJson.scripts["lint:fix"] = "eslint . --fix";
1014
+ }
1015
+ }
1016
+ if (configs.includes("prettier")) {
1017
+ if (!packageJson.scripts.format) {
1018
+ packageJson.scripts.format = "prettier --write .";
1019
+ }
1020
+ if (!packageJson.scripts["format:check"]) {
1021
+ packageJson.scripts["format:check"] = "prettier --check .";
1022
+ }
1023
+ }
1024
+ node_fs.writeFileSync(
1025
+ packageJsonPath,
1026
+ `${JSON.stringify(packageJson, null, 2)}
1027
+ `
1028
+ );
1029
+ console.log("\u2705 Updated package.json with lint scripts");
1030
+ } catch (error) {
1031
+ console.error("\u274C Failed to update package.json:", error);
1032
+ }
1033
+ }
1034
+
1035
+ async function generateSDK(root = process__default.cwd()) {
1036
+ console.log("\n\u{1F527} Generating SDK from OpenAPI...\n");
1037
+ let config = null;
1038
+ let openApiUrl;
1039
+ try {
1040
+ const configPath = node_path.resolve(root, "bgl.config.ts");
1041
+ if (node_fs.existsSync(configPath)) {
1042
+ const module = await import(`file://${configPath}`);
1043
+ const workspace = module.default;
1044
+ if (typeof workspace === "function") {
1045
+ config = workspace("development");
1046
+ if (config?.openapi_url) {
1047
+ openApiUrl = config.openapi_url;
1048
+ }
1049
+ }
1050
+ }
1051
+ } catch {
1052
+ }
1053
+ const response = await prompts__default([
1054
+ {
1055
+ type: openApiUrl !== void 0 ? null : "text",
1056
+ name: "openApiUrl",
1057
+ message: "OpenAPI spec URL:",
1058
+ initial: openApiUrl ?? "http://localhost:8000/openapi.json"
1059
+ },
1060
+ {
1061
+ type: "text",
1062
+ name: "outputDir",
1063
+ message: "Output directory:",
1064
+ initial: "./src/api"
1065
+ },
1066
+ {
1067
+ type: "confirm",
1068
+ name: "splitFiles",
1069
+ message: "Split into organized files?",
1070
+ initial: true
1071
+ }
1072
+ ]);
1073
+ if (!response) {
1074
+ console.log("\n\u274C SDK generation cancelled.\n");
1075
+ process__default.exit(1);
1076
+ }
1077
+ const finalUrl = openApiUrl ?? response.openApiUrl;
1078
+ const { outputDir, splitFiles } = response;
1079
+ console.log(`
1080
+ \u{1F4E1} Fetching OpenAPI spec from: ${finalUrl}`);
1081
+ console.log(`\u{1F4C1} Output directory: ${outputDir}
1082
+ `);
1083
+ try {
1084
+ const { openAPI } = await import('@bagelink/sdk');
1085
+ const { readFileSync } = await import('node:fs');
1086
+ const { dirname, join } = await import('node:path');
1087
+ const { fileURLToPath } = await import('node:url');
1088
+ const { types, code } = await openAPI(finalUrl, "/api");
1089
+ const outputPath = node_path.resolve(root, outputDir);
1090
+ if (!node_fs.existsSync(outputPath)) {
1091
+ node_fs.mkdirSync(outputPath, { recursive: true });
1092
+ }
1093
+ const typesPath = node_path.resolve(outputPath, "types.d.ts");
1094
+ node_fs.writeFileSync(typesPath, types);
1095
+ console.log("\u2705 Generated types.d.ts");
1096
+ const apiPath = node_path.resolve(outputPath, "api.ts");
1097
+ node_fs.writeFileSync(apiPath, code);
1098
+ console.log("\u2705 Generated api.ts");
1099
+ try {
1100
+ const sdkModule = await import('@bagelink/sdk');
1101
+ const sdkPath = fileURLToPath(undefined("@bagelink/sdk"));
1102
+ const sdkDir = dirname(sdkPath);
1103
+ const streamClientSource = join(sdkDir, "openAPITools", "streamClient.ts");
1104
+ if (node_fs.existsSync(streamClientSource)) {
1105
+ const streamClientCode = readFileSync(streamClientSource, "utf-8");
1106
+ const streamClientPath = node_path.resolve(outputPath, "streamClient.ts");
1107
+ node_fs.writeFileSync(streamClientPath, streamClientCode);
1108
+ console.log("\u2705 Generated streamClient.ts");
1109
+ }
1110
+ } catch (e) {
1111
+ console.log("\u2139\uFE0F streamClient.ts not found (optional)");
1112
+ }
1113
+ const indexPath = node_path.resolve(outputPath, "index.ts");
1114
+ node_fs.writeFileSync(
1115
+ indexPath,
1116
+ "export * from './api'\nexport * from './types.d'\n"
1117
+ );
1118
+ console.log("\u2705 Generated index.ts");
1119
+ if (splitFiles) {
1120
+ console.log("\n\u{1F500} Splitting into organized files...");
1121
+ console.log("\u2139\uFE0F File splitting requires @bagelink/sdk bin scripts");
1122
+ console.log(" Keeping monolithic structure for now");
1123
+ }
1124
+ console.log("\n\u2705 SDK generated successfully!");
1125
+ console.log(`
1126
+ Import it in your code:`);
1127
+ console.log(` import { api } from '${outputDir.replace("./src/", "./")}'`);
1128
+ console.log("");
1129
+ } catch (error) {
1130
+ console.error("\n\u274C Failed to generate SDK:");
1131
+ if (error instanceof Error) {
1132
+ console.error(error.message);
1133
+ } else {
1134
+ console.error(error);
1135
+ }
1136
+ console.log("\nMake sure:");
1137
+ console.log(" 1. @bagelink/sdk is installed: bun add -D @bagelink/sdk");
1138
+ console.log(" 2. OpenAPI URL is accessible");
1139
+ console.log(" 3. API server is running (if using localhost)");
1140
+ process__default.exit(1);
1141
+ }
1142
+ }
1143
+ async function generateSDKForWorkspace(root = process__default.cwd()) {
1144
+ console.log("\n\u{1F3E2} Generating SDK for workspace projects...\n");
1145
+ const fs = await import('node:fs');
1146
+ const items = fs.readdirSync(root, { withFileTypes: true });
1147
+ const projects = items.filter(
1148
+ (item) => item.isDirectory() && item.name !== "node_modules" && item.name !== "shared" && item.name !== ".git" && !item.name.startsWith(".")
1149
+ ).map((item) => item.name);
1150
+ if (projects.length === 0) {
1151
+ console.log("No projects found in workspace");
1152
+ return;
1153
+ }
1154
+ const response = await prompts__default({
1155
+ type: "multiselect",
1156
+ name: "selectedProjects",
1157
+ message: "Select projects to generate SDK for:",
1158
+ choices: projects.map((p) => ({ title: p, value: p, selected: true }))
1159
+ });
1160
+ if (!response || !response.selectedProjects || response.selectedProjects.length === 0) {
1161
+ console.log("\n\u274C No projects selected.\n");
1162
+ return;
1163
+ }
1164
+ for (const project of response.selectedProjects) {
1165
+ console.log(`
1166
+ \u{1F4E6} Generating SDK for: ${project}`);
1167
+ const projectPath = node_path.resolve(root, project);
1168
+ try {
1169
+ await generateSDK(projectPath);
1170
+ } catch {
1171
+ console.error(`Failed to generate SDK for ${project}`);
1172
+ }
1173
+ }
1174
+ console.log("\n\u2705 All SDKs generated!");
1175
+ }
1176
+
1177
+ const [, , command, subcommand, ...args] = process__default.argv;
15
1178
  async function main() {
16
1179
  if (command === "init") {
17
- const isWorkspace = args.includes("--workspace") || args.includes("-w");
18
- if (isWorkspace) {
19
- await workspace.initWorkspace();
1180
+ const createWorkspace = subcommand === "--workspace" || subcommand === "-w" || args.includes("--workspace") || args.includes("-w");
1181
+ let targetPath = process__default.cwd();
1182
+ if (subcommand && !subcommand.startsWith("-")) {
1183
+ targetPath = subcommand === "." ? process__default.cwd() : node_path.resolve(process__default.cwd(), subcommand);
1184
+ }
1185
+ if (createWorkspace) {
1186
+ await initWorkspace();
20
1187
  } else {
21
- await workspace.generateWorkspaceConfig();
1188
+ await generateWorkspaceConfig(targetPath);
22
1189
  }
23
1190
  } else if (command === "add") {
24
- const projectName = args[0];
1191
+ const projectName = subcommand;
25
1192
  if (!projectName) {
26
1193
  console.error("Error: Project name is required");
27
1194
  console.log("Usage: bgl add <project-name>");
28
1195
  process__default.exit(1);
29
1196
  }
30
- await workspace.addProject(projectName);
1197
+ await addProject(projectName);
31
1198
  } else if (command === "list") {
32
- const projects = workspace.listProjects();
1199
+ const projects = listProjects();
33
1200
  if (projects.length === 0) {
34
1201
  console.log("No projects found");
35
1202
  } else {
36
1203
  console.log("\nProjects:");
37
- projects.forEach((p) => console.log(` - ${p}`));
1204
+ projects.forEach((p) => {
1205
+ console.log(` - ${p}`);
1206
+ });
38
1207
  console.log("");
39
1208
  }
1209
+ } else if (command === "lint") {
1210
+ if (subcommand === "init") {
1211
+ const forceWorkspace = args.includes("--workspace") || args.includes("-w");
1212
+ const forceProject = args.includes("--project") || args.includes("-p");
1213
+ let workspaceMode = isWorkspace(process__default.cwd());
1214
+ if (forceWorkspace) workspaceMode = true;
1215
+ if (forceProject) workspaceMode = false;
1216
+ if (workspaceMode) {
1217
+ console.log("\u2713 Detected workspace mode");
1218
+ }
1219
+ await setupLint(process__default.cwd(), workspaceMode);
1220
+ } else {
1221
+ console.log(`
1222
+ Lint Commands:
1223
+ bgl lint init Set up linting (auto-detects workspace)
1224
+ bgl lint init --workspace Force workspace mode
1225
+ bgl lint init --project Force single project mode
1226
+ `);
1227
+ process__default.exit(1);
1228
+ }
1229
+ } else if (command === "sdk") {
1230
+ if (subcommand === "generate") {
1231
+ const forceWorkspace = args.includes("--workspace") || args.includes("-w");
1232
+ const forceProject = args.includes("--project") || args.includes("-p");
1233
+ let workspaceMode = isWorkspace(process__default.cwd());
1234
+ if (forceWorkspace) workspaceMode = true;
1235
+ if (forceProject) workspaceMode = false;
1236
+ if (workspaceMode) {
1237
+ console.log("\u2713 Detected workspace mode - will generate for multiple projects");
1238
+ await generateSDKForWorkspace();
1239
+ } else {
1240
+ await generateSDK(process__default.cwd());
1241
+ }
1242
+ } else {
1243
+ console.log(`
1244
+ SDK Commands:
1245
+ bgl sdk generate Generate SDK (auto-detects workspace)
1246
+ bgl sdk generate --workspace Force workspace mode
1247
+ bgl sdk generate --project Force single project mode
1248
+ `);
1249
+ process__default.exit(1);
1250
+ }
1251
+ } else if (command === "dev") {
1252
+ const { filter, additionalArgs } = parseFilterArgs(
1253
+ void 0,
1254
+ subcommand,
1255
+ args
1256
+ );
1257
+ const exitCode = await runDev(filter, additionalArgs);
1258
+ process__default.exit(exitCode);
1259
+ } else if (command === "build") {
1260
+ const { filter, additionalArgs } = parseFilterArgs(
1261
+ void 0,
1262
+ subcommand,
1263
+ args
1264
+ );
1265
+ const exitCode = await runBuild(filter, additionalArgs);
1266
+ process__default.exit(exitCode);
40
1267
  } else {
41
1268
  console.log(`
42
1269
  Bagel Workspace CLI
43
1270
 
44
1271
  Usage:
45
- bgl init Generate bgl.config.ts for single project
46
- bgl init --workspace Create a new workspace with multiple projects
47
- bgl add <name> Add a new project to workspace
48
- bgl list List all projects in workspace
1272
+ bgl init [path] Generate bgl.config.ts for single project
1273
+ Examples: bgl init, bgl init ., bgl init ./my-app
1274
+ bgl init --workspace Create a new workspace with multiple projects
1275
+ bgl add <name> Add a new project to workspace
1276
+ bgl list List all projects in workspace
1277
+ bgl dev [filter] [...args] Run dev servers with clean output (default: './!shared*')
1278
+ Additional args are passed to vite (e.g., --mode localhost)
1279
+ bgl build [project] [...args] Build project by directory (default: all projects)
1280
+ bgl lint init Set up linting (auto-detects workspace)
1281
+ bgl sdk generate Generate SDK (auto-detects workspace)
49
1282
 
50
1283
  Options:
51
- --help, -h Show this help message
1284
+ --workspace, -w Force workspace mode
1285
+ --project, -p Force single project mode
1286
+ --help, -h Show this help message
1287
+
1288
+ Note: Commands auto-detect workspace mode based on directory structure
52
1289
  `);
53
1290
  process__default.exit(command === "--help" || command === "-h" ? 0 : 1);
54
1291
  }
55
1292
  }
1293
+ function normalizeFilter(input) {
1294
+ if (input.startsWith(".") || input.includes("*") || input.includes("[")) {
1295
+ return input;
1296
+ }
1297
+ return `./${input}`;
1298
+ }
1299
+ function parseFilterArgs(defaultFilter, subcommandArg, argsList = []) {
1300
+ const tokens = [subcommandArg, ...argsList].filter(Boolean);
1301
+ const flagsWithValues = /* @__PURE__ */ new Set(["--mode", "--host", "--port"]);
1302
+ const nonFlagIndexes = [];
1303
+ for (let i = 0; i < tokens.length; i++) {
1304
+ const token = tokens[i];
1305
+ if (token.startsWith("-")) {
1306
+ if (flagsWithValues.has(token)) {
1307
+ i++;
1308
+ }
1309
+ } else {
1310
+ const prevToken = i > 0 ? tokens[i - 1] : null;
1311
+ if (!prevToken || !flagsWithValues.has(prevToken)) {
1312
+ nonFlagIndexes.push(i);
1313
+ }
1314
+ }
1315
+ }
1316
+ const filterIndex = nonFlagIndexes.length > 0 ? nonFlagIndexes[nonFlagIndexes.length - 1] : -1;
1317
+ const filter = filterIndex >= 0 ? normalizeFilter(tokens[filterIndex]) : defaultFilter;
1318
+ const additionalArgs = filterIndex >= 0 ? tokens.filter((_, index) => index !== filterIndex) : tokens;
1319
+ return { filter, additionalArgs };
1320
+ }
56
1321
  main().catch((error) => {
57
1322
  console.error("Error:", error);
58
1323
  process__default.exit(1);