@openbuilder/cli 0.31.11

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 (78) hide show
  1. package/README.md +1053 -0
  2. package/bin/openbuilder.js +31 -0
  3. package/dist/chunks/Banner-D4tqKfzA.js +113 -0
  4. package/dist/chunks/Banner-D4tqKfzA.js.map +1 -0
  5. package/dist/chunks/auto-update-Dj3lWPWO.js +350 -0
  6. package/dist/chunks/auto-update-Dj3lWPWO.js.map +1 -0
  7. package/dist/chunks/build-D0qYqIq0.js +116 -0
  8. package/dist/chunks/build-D0qYqIq0.js.map +1 -0
  9. package/dist/chunks/cleanup-qVTsA3tk.js +141 -0
  10. package/dist/chunks/cleanup-qVTsA3tk.js.map +1 -0
  11. package/dist/chunks/cli-error-BjQwvWtK.js +140 -0
  12. package/dist/chunks/cli-error-BjQwvWtK.js.map +1 -0
  13. package/dist/chunks/config-BGP1jZJ4.js +167 -0
  14. package/dist/chunks/config-BGP1jZJ4.js.map +1 -0
  15. package/dist/chunks/config-manager-BkbjtN-H.js +133 -0
  16. package/dist/chunks/config-manager-BkbjtN-H.js.map +1 -0
  17. package/dist/chunks/database-BvAbD4sP.js +68 -0
  18. package/dist/chunks/database-BvAbD4sP.js.map +1 -0
  19. package/dist/chunks/database-setup-BYjIRAmT.js +253 -0
  20. package/dist/chunks/database-setup-BYjIRAmT.js.map +1 -0
  21. package/dist/chunks/exports-ij9sv4UM.js +7793 -0
  22. package/dist/chunks/exports-ij9sv4UM.js.map +1 -0
  23. package/dist/chunks/init-CZoN6soU.js +468 -0
  24. package/dist/chunks/init-CZoN6soU.js.map +1 -0
  25. package/dist/chunks/init-tui-BNzk_7Yx.js +1127 -0
  26. package/dist/chunks/init-tui-BNzk_7Yx.js.map +1 -0
  27. package/dist/chunks/logger-ZpJi7chw.js +38 -0
  28. package/dist/chunks/logger-ZpJi7chw.js.map +1 -0
  29. package/dist/chunks/main-tui-Cq1hLCx-.js +644 -0
  30. package/dist/chunks/main-tui-Cq1hLCx-.js.map +1 -0
  31. package/dist/chunks/manager-CvGX9qqe.js +1161 -0
  32. package/dist/chunks/manager-CvGX9qqe.js.map +1 -0
  33. package/dist/chunks/port-allocator-BRFzgH9b.js +749 -0
  34. package/dist/chunks/port-allocator-BRFzgH9b.js.map +1 -0
  35. package/dist/chunks/process-killer-CaUL7Kpl.js +87 -0
  36. package/dist/chunks/process-killer-CaUL7Kpl.js.map +1 -0
  37. package/dist/chunks/prompts-1QbE_bRr.js +128 -0
  38. package/dist/chunks/prompts-1QbE_bRr.js.map +1 -0
  39. package/dist/chunks/repo-cloner-CpOQjFSo.js +219 -0
  40. package/dist/chunks/repo-cloner-CpOQjFSo.js.map +1 -0
  41. package/dist/chunks/repo-detector-B_oj696o.js +66 -0
  42. package/dist/chunks/repo-detector-B_oj696o.js.map +1 -0
  43. package/dist/chunks/run-D23hg4xy.js +630 -0
  44. package/dist/chunks/run-D23hg4xy.js.map +1 -0
  45. package/dist/chunks/runner-logger-instance-nDWv2h2T.js +899 -0
  46. package/dist/chunks/runner-logger-instance-nDWv2h2T.js.map +1 -0
  47. package/dist/chunks/spinner-BJL9zWAJ.js +53 -0
  48. package/dist/chunks/spinner-BJL9zWAJ.js.map +1 -0
  49. package/dist/chunks/start-BygPCbvw.js +1708 -0
  50. package/dist/chunks/start-BygPCbvw.js.map +1 -0
  51. package/dist/chunks/start-traditional-uoLZXdxm.js +255 -0
  52. package/dist/chunks/start-traditional-uoLZXdxm.js.map +1 -0
  53. package/dist/chunks/status-cS8YwtUx.js +97 -0
  54. package/dist/chunks/status-cS8YwtUx.js.map +1 -0
  55. package/dist/chunks/theme-DhorI2Hb.js +44 -0
  56. package/dist/chunks/theme-DhorI2Hb.js.map +1 -0
  57. package/dist/chunks/upgrade-CT6w0lKp.js +323 -0
  58. package/dist/chunks/upgrade-CT6w0lKp.js.map +1 -0
  59. package/dist/chunks/useBuildState-CdBSu9y_.js +331 -0
  60. package/dist/chunks/useBuildState-CdBSu9y_.js.map +1 -0
  61. package/dist/cli/index.js +694 -0
  62. package/dist/cli/index.js.map +1 -0
  63. package/dist/index.js +14358 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/instrument.js +64226 -0
  66. package/dist/instrument.js.map +1 -0
  67. package/dist/templates.json +295 -0
  68. package/package.json +98 -0
  69. package/scripts/install-vendor-deps.js +34 -0
  70. package/scripts/install-vendor.js +167 -0
  71. package/scripts/prepare-release.js +71 -0
  72. package/templates/config.template.json +18 -0
  73. package/templates.json +295 -0
  74. package/vendor/ai-sdk-provider-claude-code-LOCAL.tgz +0 -0
  75. package/vendor/sentry-core-LOCAL.tgz +0 -0
  76. package/vendor/sentry-nextjs-LOCAL.tgz +0 -0
  77. package/vendor/sentry-node-LOCAL.tgz +0 -0
  78. package/vendor/sentry-node-core-LOCAL.tgz +0 -0
@@ -0,0 +1,694 @@
1
+ #!/usr/bin/env node
2
+ // OpenBuilder CLI - Built with Rollup
3
+ import { existsSync, readFileSync } from 'node:fs';
4
+ import { dirname, join } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { execFileSync } from 'node:child_process';
7
+ import { Command } from 'commander';
8
+ import chalk from 'chalk';
9
+ import { C as CLIError } from '../chunks/cli-error-BjQwvWtK.js';
10
+
11
+ /**
12
+ * ASCII art banner for OpenBuilder CLI
13
+ */
14
+ // ANSI color codes
15
+ const colors = {
16
+ reset: '\x1b[0m',
17
+ brightPurple: '\x1b[95m',
18
+ cyan: '\x1b[36m'};
19
+ /**
20
+ * Displays the OpenBuilder banner
21
+ */
22
+ function displayBanner() {
23
+ const banner = `
24
+ ${colors.cyan} ██████╗ ██████╗ ███████╗███╗ ██╗${colors.brightPurple}██████╗ ██╗ ██╗██╗██╗ ██████╗ ███████╗██████╗${colors.reset}
25
+ ${colors.cyan}██╔═══██╗██╔══██╗██╔════╝████╗ ██║${colors.brightPurple}██╔══██╗██║ ██║██║██║ ██╔══██╗██╔════╝██╔══██╗${colors.reset}
26
+ ${colors.cyan}██║ ██║██████╔╝█████╗ ██╔██╗ ██║${colors.brightPurple}██████╔╝██║ ██║██║██║ ██║ ██║█████╗ ██████╔╝${colors.reset}
27
+ ${colors.cyan}██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║${colors.brightPurple}██╔══██╗██║ ██║██║██║ ██║ ██║██╔══╝ ██╔══██╗${colors.reset}
28
+ ${colors.cyan}╚██████╔╝██║ ███████╗██║ ╚████║${colors.brightPurple}██████╔╝╚██████╔╝██║███████╗██████╔╝███████╗██║ ██║${colors.reset}
29
+ ${colors.cyan} ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝${colors.brightPurple}╚═════╝ ╚═════╝ ╚═╝╚══════╝╚═════╝ ╚══════╝╚═╝ ╚═╝${colors.reset}
30
+ `;
31
+ console.log(banner);
32
+ }
33
+
34
+ /**
35
+ * Centralized error handling and formatting for CLI
36
+ * Displays errors with context, suggestions, and proper formatting
37
+ */
38
+ class CLIErrorHandler {
39
+ constructor(options = {}) {
40
+ this.debug = options.debug ?? process.env.DEBUG === '1';
41
+ this.exitOnError = options.exitOnError ?? true;
42
+ }
43
+ /**
44
+ * Main error handling method
45
+ * Formats and displays error, then exits if fatal
46
+ */
47
+ handle(error) {
48
+ // Convert to CLIError if needed
49
+ const cliError = error instanceof CLIError
50
+ ? error
51
+ : this.convertToCLIError(error);
52
+ // Display the error
53
+ this.display(cliError);
54
+ // Exit if fatal and exitOnError is enabled
55
+ if (cliError.fatal && this.exitOnError) {
56
+ process.exit(cliError.getExitCode());
57
+ }
58
+ }
59
+ /**
60
+ * Display formatted error to console
61
+ */
62
+ display(error) {
63
+ console.error(); // Empty line for spacing
64
+ // Error header
65
+ console.error(chalk.red('✗'), chalk.bold(error.message));
66
+ // Error code (in debug mode)
67
+ if (this.debug) {
68
+ console.error(chalk.dim(` Code: ${error.code}`));
69
+ }
70
+ // Context information
71
+ if (error.context && Object.keys(error.context).length > 0) {
72
+ console.error();
73
+ console.error(chalk.dim(' Details:'));
74
+ Object.entries(error.context).forEach(([key, value]) => {
75
+ console.error(chalk.dim(` ${key}: ${this.formatValue(value)}`));
76
+ });
77
+ }
78
+ // Suggestions
79
+ if (error.suggestions.length > 0) {
80
+ console.error();
81
+ console.error(chalk.yellow(' Try this:'));
82
+ error.suggestions.forEach((suggestion, index) => {
83
+ console.error(chalk.yellow(` ${index + 1}. ${suggestion}`));
84
+ });
85
+ }
86
+ // Documentation link
87
+ if (error.docs) {
88
+ console.error();
89
+ console.error(chalk.dim(' Documentation:'), chalk.cyan(error.docs));
90
+ }
91
+ // Stack trace (debug mode only)
92
+ if (this.debug && error.stack) {
93
+ console.error();
94
+ console.error(chalk.dim(' Stack trace:'));
95
+ console.error(chalk.dim(error.stack));
96
+ }
97
+ // Original error cause (if available)
98
+ if (this.debug && error.cause) {
99
+ console.error();
100
+ console.error(chalk.dim(' Caused by:'));
101
+ console.error(chalk.dim(error.cause.message));
102
+ if (error.cause.stack) {
103
+ console.error(chalk.dim(error.cause.stack));
104
+ }
105
+ }
106
+ console.error(); // Empty line for spacing
107
+ }
108
+ /**
109
+ * Format context values for display
110
+ */
111
+ formatValue(value) {
112
+ if (typeof value === 'string')
113
+ return value;
114
+ if (typeof value === 'number')
115
+ return String(value);
116
+ if (typeof value === 'boolean')
117
+ return String(value);
118
+ if (value === null || value === undefined)
119
+ return 'null';
120
+ if (Array.isArray(value))
121
+ return value.join(', ');
122
+ return JSON.stringify(value);
123
+ }
124
+ /**
125
+ * Convert generic errors to CLIError
126
+ */
127
+ convertToCLIError(error) {
128
+ // Try to infer error code from message
129
+ const code = this.inferErrorCode(error);
130
+ return new CLIError({
131
+ code,
132
+ message: error.message || 'An unexpected error occurred',
133
+ cause: error,
134
+ suggestions: ['Run with --debug flag for more details'],
135
+ });
136
+ }
137
+ /**
138
+ * Infer error code from generic error
139
+ */
140
+ inferErrorCode(error) {
141
+ const message = error.message.toLowerCase();
142
+ if (message.includes('econnrefused') || message.includes('connection refused')) {
143
+ return 'DB_CONNECTION_FAILED';
144
+ }
145
+ if (message.includes('eaddrinuse') || message.includes('address already in use')) {
146
+ return 'PORT_IN_USE';
147
+ }
148
+ if (message.includes('eacces') || message.includes('permission denied')) {
149
+ return 'PERMISSION_DENIED';
150
+ }
151
+ if (message.includes('enoent') || message.includes('no such file')) {
152
+ return 'CONFIG_NOT_FOUND';
153
+ }
154
+ return 'UNKNOWN_ERROR';
155
+ }
156
+ /**
157
+ * Wrap an async function with error handling
158
+ * Usage: await errorHandler.wrap(() => someAsyncFunction(), 'Description')
159
+ */
160
+ async wrap(fn, context) {
161
+ try {
162
+ return await fn();
163
+ }
164
+ catch (error) {
165
+ if (context && error instanceof CLIError) {
166
+ // Create new CLIError with added context (can't modify readonly property)
167
+ const enhancedError = new CLIError({
168
+ code: error.code,
169
+ message: error.message,
170
+ context: { ...error.context, operation: context },
171
+ suggestions: error.suggestions,
172
+ fatal: error.fatal,
173
+ cause: error.cause,
174
+ docs: error.docs,
175
+ });
176
+ this.handle(enhancedError);
177
+ throw enhancedError;
178
+ }
179
+ this.handle(error);
180
+ throw error; // Re-throw for callers that want to handle it
181
+ }
182
+ }
183
+ /**
184
+ * Enable or disable debug mode
185
+ */
186
+ setDebug(debug) {
187
+ this.debug = debug;
188
+ }
189
+ /**
190
+ * Enable or disable exit on error
191
+ */
192
+ setExitOnError(exitOnError) {
193
+ this.exitOnError = exitOnError;
194
+ }
195
+ }
196
+ /**
197
+ * Global error handler instance
198
+ * Can be configured once and used throughout the CLI
199
+ */
200
+ const globalErrorHandler = new CLIErrorHandler();
201
+ /**
202
+ * Setup global error handlers for uncaught errors
203
+ */
204
+ function setupGlobalErrorHandlers() {
205
+ process.on('uncaughtException', (error) => {
206
+ console.error(chalk.red('\n✗ Uncaught exception:'));
207
+ globalErrorHandler.handle(error);
208
+ });
209
+ process.on('unhandledRejection', (reason) => {
210
+ console.error(chalk.red('\n✗ Unhandled promise rejection:'));
211
+ const error = reason instanceof Error ? reason : new Error(String(reason));
212
+ globalErrorHandler.handle(error);
213
+ });
214
+ }
215
+
216
+ /**
217
+ * Graceful shutdown handler for CLI
218
+ * Ensures proper cleanup when user presses Ctrl+C or process is terminated
219
+ */
220
+ class ShutdownHandler {
221
+ constructor(options = {}) {
222
+ this.cleanupFunctions = [];
223
+ this.childProcesses = [];
224
+ this.isShuttingDown = false;
225
+ this.timeout = options.timeout ?? 5000;
226
+ this.verbose = options.verbose !== false;
227
+ }
228
+ /**
229
+ * Register a cleanup function to run on shutdown
230
+ */
231
+ onShutdown(fn) {
232
+ this.cleanupFunctions.push(fn);
233
+ }
234
+ /**
235
+ * Register a child process to kill on shutdown
236
+ */
237
+ registerProcess(process) {
238
+ this.childProcesses.push(process);
239
+ }
240
+ /**
241
+ * Setup signal handlers for graceful shutdown
242
+ */
243
+ setup() {
244
+ // Handle Ctrl+C (SIGINT)
245
+ process.on('SIGINT', () => {
246
+ if (this.verbose) {
247
+ console.log(); // New line after ^C
248
+ console.log(chalk.yellow('⚠'), 'Received interrupt signal (Ctrl+C)');
249
+ }
250
+ this.shutdown('SIGINT');
251
+ });
252
+ // Handle termination (SIGTERM)
253
+ process.on('SIGTERM', () => {
254
+ if (this.verbose) {
255
+ console.log(chalk.yellow('⚠'), 'Received termination signal (SIGTERM)');
256
+ }
257
+ this.shutdown('SIGTERM');
258
+ });
259
+ // Handle process exit
260
+ process.on('exit', (code) => {
261
+ if (this.verbose && code !== 0) {
262
+ console.log(chalk.red('✗'), `Process exiting with code ${code}`);
263
+ }
264
+ });
265
+ }
266
+ /**
267
+ * Execute graceful shutdown
268
+ */
269
+ async shutdown(signal) {
270
+ // Prevent multiple shutdown attempts
271
+ if (this.isShuttingDown) {
272
+ if (this.verbose) {
273
+ console.log(chalk.dim(' Already shutting down...'));
274
+ }
275
+ return;
276
+ }
277
+ this.isShuttingDown = true;
278
+ if (this.verbose) {
279
+ console.log(chalk.cyan('ℹ'), 'Shutting down gracefully...');
280
+ }
281
+ // Set a timeout to force exit if cleanup takes too long
282
+ const forceExitTimeout = setTimeout(() => {
283
+ console.error(chalk.red('✗'), 'Shutdown timeout exceeded, forcing exit');
284
+ process.exit(1);
285
+ }, this.timeout);
286
+ try {
287
+ // 1. Kill child processes first
288
+ if (this.childProcesses.length > 0) {
289
+ if (this.verbose) {
290
+ console.log(chalk.dim(' Stopping child processes...'));
291
+ }
292
+ await this.killChildProcesses();
293
+ }
294
+ // 2. Run cleanup functions
295
+ if (this.cleanupFunctions.length > 0) {
296
+ if (this.verbose) {
297
+ console.log(chalk.dim(' Running cleanup tasks...'));
298
+ }
299
+ await this.runCleanup();
300
+ }
301
+ // 3. Success
302
+ if (this.verbose) {
303
+ console.log(chalk.green('✓'), 'Shutdown complete');
304
+ }
305
+ clearTimeout(forceExitTimeout);
306
+ process.exit(0);
307
+ }
308
+ catch (error) {
309
+ console.error(chalk.red('✗'), 'Error during shutdown:', error);
310
+ clearTimeout(forceExitTimeout);
311
+ process.exit(1);
312
+ }
313
+ }
314
+ /**
315
+ * Kill all registered child processes
316
+ */
317
+ async killChildProcesses() {
318
+ const killPromises = this.childProcesses.map(async (child) => {
319
+ if (!child.killed && child.pid) {
320
+ try {
321
+ // Try graceful SIGTERM first
322
+ child.kill('SIGTERM');
323
+ // Wait up to 2 seconds for graceful shutdown
324
+ await new Promise((resolve) => {
325
+ const timeout = setTimeout(() => {
326
+ // Force kill if still alive
327
+ if (!child.killed) {
328
+ child.kill('SIGKILL');
329
+ }
330
+ resolve();
331
+ }, 2000);
332
+ child.on('exit', () => {
333
+ clearTimeout(timeout);
334
+ resolve();
335
+ });
336
+ });
337
+ }
338
+ catch (error) {
339
+ // Process might already be dead
340
+ if (this.verbose) {
341
+ console.log(chalk.dim(` Could not kill process ${child.pid}`));
342
+ }
343
+ }
344
+ }
345
+ });
346
+ await Promise.all(killPromises);
347
+ }
348
+ /**
349
+ * Run all cleanup functions
350
+ */
351
+ async runCleanup() {
352
+ const cleanupPromises = this.cleanupFunctions.map(async (fn) => {
353
+ try {
354
+ await fn();
355
+ }
356
+ catch (error) {
357
+ if (this.verbose) {
358
+ console.error(chalk.yellow('⚠'), 'Cleanup function failed:', error);
359
+ }
360
+ }
361
+ });
362
+ await Promise.all(cleanupPromises);
363
+ }
364
+ /**
365
+ * Manually trigger shutdown (for testing or programmatic use)
366
+ */
367
+ async triggerShutdown() {
368
+ await this.shutdown('MANUAL');
369
+ }
370
+ /**
371
+ * Remove a child process from tracking (e.g., after it exits naturally)
372
+ */
373
+ unregisterProcess(process) {
374
+ const index = this.childProcesses.indexOf(process);
375
+ if (index > -1) {
376
+ this.childProcesses.splice(index, 1);
377
+ }
378
+ }
379
+ }
380
+ /**
381
+ * Global shutdown handler instance
382
+ */
383
+ new ShutdownHandler();
384
+ /**
385
+ * Helper to setup shutdown handler with common options
386
+ */
387
+ function setupShutdownHandler(options) {
388
+ const handler = new ShutdownHandler(options);
389
+ handler.setup();
390
+ return handler;
391
+ }
392
+
393
+ // EARLY TUI DETECTION: Set SILENT_MODE before any modules are imported
394
+ // This suppresses console output in TUI mode
395
+ // Must be done before imports because file-logger.ts captures console at load time
396
+ {
397
+ const args = process.argv.slice(2);
398
+ const isRunnerTUI = args[0] === 'runner' && !args.includes('--no-tui');
399
+ const isRunTUI = args[0] === 'run';
400
+ const isInitTUI = args[0] === 'init' && (args.includes('-y') || args.includes('--yes') || args.includes('--non-interactive'));
401
+ const isNoArgsTUI = args.length === 0 || (args.length === 1 && args[0] === '--debug');
402
+ if (isRunnerTUI || isRunTUI || isInitTUI || isNoArgsTUI) {
403
+ process.env.SILENT_MODE = '1';
404
+ }
405
+ }
406
+ const __filename$1 = fileURLToPath(import.meta.url);
407
+ const __dirname$1 = dirname(__filename$1);
408
+ // Find the package root by looking for package.json
409
+ // This works regardless of where the bundled code ends up (dist/, dist/cli/, etc.)
410
+ function findPackageRoot(startDir) {
411
+ let dir = startDir;
412
+ for (let i = 0; i < 5; i++) { // Max 5 levels up
413
+ if (existsSync(join(dir, 'package.json'))) {
414
+ return dir;
415
+ }
416
+ const parent = dirname(dir);
417
+ if (parent === dir)
418
+ break; // Reached filesystem root
419
+ dir = parent;
420
+ }
421
+ return startDir; // Fallback to start dir
422
+ }
423
+ const packageRoot = findPackageRoot(__dirname$1);
424
+ // Check if running in development mode (linked via pnpm/npm link)
425
+ // Skip vendor install if we're in the monorepo - dependencies are handled by pnpm
426
+ const isLinkedDevelopment = packageRoot.includes('/openbuilder/apps/runner');
427
+ // Only run vendor install for production global installs
428
+ if (!isLinkedDevelopment) {
429
+ // Check if Sentry packages are missing and extract from vendor if needed
430
+ // (agent-core is bundled by tsup, but Sentry packages come from vendor tarballs)
431
+ const nodeModulesDir = dirname(packageRoot); // Go up from package to node_modules/@openbuilder
432
+ const sentryNodePath = join(nodeModulesDir, "..", "@sentry", "node");
433
+ if (!existsSync(sentryNodePath)) {
434
+ // Silently initialize vendor packages in background
435
+ try {
436
+ const installScript = join(packageRoot, "scripts/install-vendor.js");
437
+ execFileSync("node", [installScript], {
438
+ cwd: packageRoot,
439
+ stdio: "pipe" // Silent mode - output only shown if VERBOSE=1
440
+ });
441
+ }
442
+ catch (error) {
443
+ console.error("Failed to initialize vendor packages:", error);
444
+ process.exit(1);
445
+ }
446
+ }
447
+ }
448
+ // Get package.json for version info
449
+ const packageJson = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf-8'));
450
+ // Setup global error handlers for uncaught errors
451
+ setupGlobalErrorHandlers();
452
+ // Setup graceful shutdown handlers for Ctrl+C
453
+ const shutdownHandler = setupShutdownHandler({
454
+ timeout: 5000,
455
+ verbose: true,
456
+ });
457
+ // Check if we're running in TUI mode or version mode - skip banner if so
458
+ const args = process.argv.slice(2);
459
+ const isInitWithYes = args[0] === 'init' && (args.includes('-y') || args.includes('--yes') || args.includes('--non-interactive'));
460
+ const isNoArgs = args.length === 0 || (args.length === 1 && args[0] === '--debug');
461
+ const isRunCommand = args[0] === 'run'; // `openbuilder run` uses TUI Dashboard
462
+ const isRunnerCommand = args[0] === 'runner' && !args.includes('--no-tui'); // `openbuilder runner` uses TUI Dashboard (unless --no-tui)
463
+ const isVersionCommand = args.includes('--version') || args.includes('-V'); // Skip banner for version output
464
+ const isSkipBanner = process.env.OPENBUILDER_SKIP_BANNER === '1'; // Skip banner after auto-update restart
465
+ const isTUIMode = isInitWithYes || isNoArgs || isRunCommand || isRunnerCommand;
466
+ const isSilentMode = isTUIMode || isVersionCommand || isSkipBanner;
467
+ // Set SILENT_MODE for TUI/version to suppress all console output from other modules
468
+ // This must be set early, before modules that use console.log are imported
469
+ if (isSilentMode) {
470
+ process.env.SILENT_MODE = '1';
471
+ }
472
+ // Auto-update check - do this BEFORE displaying banner to avoid double banners
473
+ // For TUI modes: check only and store result for display (don't auto-update to avoid disruption)
474
+ // For CLI modes: full auto-update with restart
475
+ // For version mode: skip entirely - just show version
476
+ let willAutoUpdate = false;
477
+ if (!process.env.OPENBUILDER_SKIP_UPDATE_CHECK && !isVersionCommand) {
478
+ const { checkAndAutoUpdate, checkForUpdate } = await import('../chunks/auto-update-Dj3lWPWO.js');
479
+ try {
480
+ if (isTUIMode) {
481
+ // TUI mode: just check for updates, store result for TUI to display
482
+ const updateInfo = await checkForUpdate(packageJson.version);
483
+ if (updateInfo?.updateAvailable) {
484
+ // Store update info for TUI components to access
485
+ process.env.OPENBUILDER_UPDATE_AVAILABLE = updateInfo.latestVersion;
486
+ }
487
+ }
488
+ else {
489
+ // CLI mode: full auto-update
490
+ // Show banner first since we're in CLI mode and might not auto-update
491
+ displayBanner();
492
+ const didUpdate = await checkAndAutoUpdate(packageJson.version);
493
+ if (didUpdate) {
494
+ // CLI will be relaunched by auto-update, exit this process
495
+ willAutoUpdate = true;
496
+ process.exit(0);
497
+ }
498
+ }
499
+ }
500
+ catch {
501
+ }
502
+ }
503
+ else if (!isSilentMode) {
504
+ // Update check skipped, show banner for CLI mode (but not version mode)
505
+ displayBanner();
506
+ }
507
+ const program = new Command();
508
+ program
509
+ .name('openbuilder')
510
+ .description('OpenBuilder CLI - AI App Builder')
511
+ .version(packageJson.version)
512
+ .option('--runner', 'Start runner only (connect to remote server)')
513
+ .option('--debug', 'Enable debug mode with verbose error output')
514
+ .hook('preAction', (thisCommand) => {
515
+ // Enable debug mode if --debug flag is present
516
+ const opts = thisCommand.opts();
517
+ if (opts.debug) {
518
+ globalErrorHandler.setDebug(true);
519
+ process.env.DEBUG = '1';
520
+ }
521
+ })
522
+ .action(async (options) => {
523
+ try {
524
+ // Default action when no subcommand is provided
525
+ if (options.runner) {
526
+ // Start runner only (legacy flag)
527
+ const { runCommand } = await import('../chunks/run-D23hg4xy.js');
528
+ await runCommand({});
529
+ }
530
+ else {
531
+ // Show TUI main menu
532
+ const { mainTUICommand } = await import('../chunks/main-tui-Cq1hLCx-.js');
533
+ await mainTUICommand();
534
+ }
535
+ }
536
+ catch (error) {
537
+ globalErrorHandler.handle(error);
538
+ }
539
+ });
540
+ // Import commands
541
+ program
542
+ .command('init')
543
+ .description('Initialize workspace and configuration for local development')
544
+ .option('--workspace <path>', 'Set workspace directory')
545
+ .option('--url <url>', 'Set server URL (default: http://localhost:3000)')
546
+ .option('--secret <secret>', 'Set shared secret')
547
+ .option('--branch <branch>', 'Git branch to clone (default: main)')
548
+ .option('--database [value]', 'Database setup: connection string, or omit to auto-setup Neon in -y mode')
549
+ .option('-y, --yes', 'Accept all defaults (non-interactive mode)')
550
+ .option('--non-interactive', 'Use defaults without prompts (alias for -y)')
551
+ .action(async (options) => {
552
+ try {
553
+ const { initCommand } = await import('../chunks/init-CZoN6soU.js');
554
+ await initCommand(options);
555
+ }
556
+ catch (error) {
557
+ globalErrorHandler.handle(error);
558
+ }
559
+ });
560
+ program
561
+ .command('run')
562
+ .description('Start the full stack locally (web app + runner)')
563
+ .option('-p, --port <port>', 'Web app port (default: 3000)')
564
+ .option('--dev', 'Use development mode (hot reload, slower startup)')
565
+ .option('--rebuild', 'Rebuild services before starting')
566
+ .option('--no-local', 'Disable local mode (require authentication)')
567
+ .option('--no-tui', 'Disable TUI dashboard, use plain text logs')
568
+ .option('-v, --verbose', 'Enable verbose logging (show debug info)')
569
+ .action(async (options) => {
570
+ try {
571
+ const { startCommand } = await import('../chunks/start-BygPCbvw.js');
572
+ await startCommand(options);
573
+ }
574
+ catch (error) {
575
+ globalErrorHandler.handle(error);
576
+ }
577
+ });
578
+ program
579
+ .command('build')
580
+ .description('Build all services without starting (useful while app is running)')
581
+ .option('--watch', 'Watch for changes and rebuild automatically')
582
+ .action(async (options) => {
583
+ try {
584
+ const { buildCommand } = await import('../chunks/build-D0qYqIq0.js');
585
+ await buildCommand(options);
586
+ }
587
+ catch (error) {
588
+ globalErrorHandler.handle(error);
589
+ }
590
+ });
591
+ program
592
+ .command('runner')
593
+ .description('Start runner only (connect to OpenBuilder server)')
594
+ .option('-u, --url <url>', 'OpenBuilder server URL (default: https://openbuilder.up.railway.app)')
595
+ .option('-w, --workspace <path>', 'Workspace directory (default: ~/openbuilder-workspace)')
596
+ .option('-i, --runner-id <id>', 'Runner identifier (default: system username)')
597
+ .option('-s, --secret <secret>', 'Shared secret for authentication (required)')
598
+ .option('-b, --broker <url>', 'WebSocket URL override (advanced, inferred from --url)')
599
+ .option('-v, --verbose', 'Enable verbose logging')
600
+ .option('-l, --local', 'Enable local mode (bypasses authentication)')
601
+ .option('--no-tui', 'Disable TUI dashboard, use plain text logs')
602
+ .action(async (options) => {
603
+ try {
604
+ const { runCommand } = await import('../chunks/run-D23hg4xy.js');
605
+ await runCommand(options);
606
+ }
607
+ catch (error) {
608
+ globalErrorHandler.handle(error);
609
+ }
610
+ });
611
+ program
612
+ .command('config <action> [key] [value]')
613
+ .description('Manage configuration (actions: get, set, list, path, validate, reset)')
614
+ .action(async (action, key, value) => {
615
+ try {
616
+ const { configCommand } = await import('../chunks/config-BGP1jZJ4.js');
617
+ await configCommand(action, key, value);
618
+ }
619
+ catch (error) {
620
+ globalErrorHandler.handle(error);
621
+ }
622
+ });
623
+ // Alias for config validate
624
+ program
625
+ .command('verify')
626
+ .description('Verify configuration is valid (alias for config validate)')
627
+ .action(async () => {
628
+ try {
629
+ const { configCommand } = await import('../chunks/config-BGP1jZJ4.js');
630
+ await configCommand('validate');
631
+ }
632
+ catch (error) {
633
+ globalErrorHandler.handle(error);
634
+ }
635
+ });
636
+ program
637
+ .command('status')
638
+ .description('Show runner status and configuration')
639
+ .action(async () => {
640
+ try {
641
+ const { statusCommand } = await import('../chunks/status-cS8YwtUx.js');
642
+ await statusCommand();
643
+ }
644
+ catch (error) {
645
+ globalErrorHandler.handle(error);
646
+ }
647
+ });
648
+ program
649
+ .command('cleanup')
650
+ .description('Clean up projects and resources')
651
+ .option('--project <slug>', 'Delete specific project')
652
+ .option('--all', 'Clean all projects in workspace')
653
+ .option('--tunnels', 'Close all active tunnels')
654
+ .option('--processes', 'Kill all dev servers')
655
+ .action(async (options) => {
656
+ try {
657
+ const { cleanupCommand } = await import('../chunks/cleanup-qVTsA3tk.js');
658
+ await cleanupCommand(options);
659
+ }
660
+ catch (error) {
661
+ globalErrorHandler.handle(error);
662
+ }
663
+ });
664
+ program
665
+ .command('database')
666
+ .alias('db')
667
+ .description('Set up a new database and initialize schema')
668
+ .action(async () => {
669
+ try {
670
+ const { databaseCommand } = await import('../chunks/database-BvAbD4sP.js');
671
+ await databaseCommand();
672
+ }
673
+ catch (error) {
674
+ globalErrorHandler.handle(error);
675
+ }
676
+ });
677
+ program
678
+ .command('upgrade')
679
+ .description('Upgrade to latest version (preserves configuration)')
680
+ .option('--branch <branch>', 'Upgrade to specific branch (default: main)')
681
+ .option('--force', 'Skip safety checks (uncommitted changes)')
682
+ .action(async (options) => {
683
+ try {
684
+ const { upgradeCommand } = await import('../chunks/upgrade-CT6w0lKp.js');
685
+ await upgradeCommand(options);
686
+ }
687
+ catch (error) {
688
+ globalErrorHandler.handle(error);
689
+ }
690
+ });
691
+ program.parse();
692
+
693
+ export { shutdownHandler };
694
+ //# sourceMappingURL=index.js.map