@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.
- package/README.md +1053 -0
- package/bin/openbuilder.js +31 -0
- package/dist/chunks/Banner-D4tqKfzA.js +113 -0
- package/dist/chunks/Banner-D4tqKfzA.js.map +1 -0
- package/dist/chunks/auto-update-Dj3lWPWO.js +350 -0
- package/dist/chunks/auto-update-Dj3lWPWO.js.map +1 -0
- package/dist/chunks/build-D0qYqIq0.js +116 -0
- package/dist/chunks/build-D0qYqIq0.js.map +1 -0
- package/dist/chunks/cleanup-qVTsA3tk.js +141 -0
- package/dist/chunks/cleanup-qVTsA3tk.js.map +1 -0
- package/dist/chunks/cli-error-BjQwvWtK.js +140 -0
- package/dist/chunks/cli-error-BjQwvWtK.js.map +1 -0
- package/dist/chunks/config-BGP1jZJ4.js +167 -0
- package/dist/chunks/config-BGP1jZJ4.js.map +1 -0
- package/dist/chunks/config-manager-BkbjtN-H.js +133 -0
- package/dist/chunks/config-manager-BkbjtN-H.js.map +1 -0
- package/dist/chunks/database-BvAbD4sP.js +68 -0
- package/dist/chunks/database-BvAbD4sP.js.map +1 -0
- package/dist/chunks/database-setup-BYjIRAmT.js +253 -0
- package/dist/chunks/database-setup-BYjIRAmT.js.map +1 -0
- package/dist/chunks/exports-ij9sv4UM.js +7793 -0
- package/dist/chunks/exports-ij9sv4UM.js.map +1 -0
- package/dist/chunks/init-CZoN6soU.js +468 -0
- package/dist/chunks/init-CZoN6soU.js.map +1 -0
- package/dist/chunks/init-tui-BNzk_7Yx.js +1127 -0
- package/dist/chunks/init-tui-BNzk_7Yx.js.map +1 -0
- package/dist/chunks/logger-ZpJi7chw.js +38 -0
- package/dist/chunks/logger-ZpJi7chw.js.map +1 -0
- package/dist/chunks/main-tui-Cq1hLCx-.js +644 -0
- package/dist/chunks/main-tui-Cq1hLCx-.js.map +1 -0
- package/dist/chunks/manager-CvGX9qqe.js +1161 -0
- package/dist/chunks/manager-CvGX9qqe.js.map +1 -0
- package/dist/chunks/port-allocator-BRFzgH9b.js +749 -0
- package/dist/chunks/port-allocator-BRFzgH9b.js.map +1 -0
- package/dist/chunks/process-killer-CaUL7Kpl.js +87 -0
- package/dist/chunks/process-killer-CaUL7Kpl.js.map +1 -0
- package/dist/chunks/prompts-1QbE_bRr.js +128 -0
- package/dist/chunks/prompts-1QbE_bRr.js.map +1 -0
- package/dist/chunks/repo-cloner-CpOQjFSo.js +219 -0
- package/dist/chunks/repo-cloner-CpOQjFSo.js.map +1 -0
- package/dist/chunks/repo-detector-B_oj696o.js +66 -0
- package/dist/chunks/repo-detector-B_oj696o.js.map +1 -0
- package/dist/chunks/run-D23hg4xy.js +630 -0
- package/dist/chunks/run-D23hg4xy.js.map +1 -0
- package/dist/chunks/runner-logger-instance-nDWv2h2T.js +899 -0
- package/dist/chunks/runner-logger-instance-nDWv2h2T.js.map +1 -0
- package/dist/chunks/spinner-BJL9zWAJ.js +53 -0
- package/dist/chunks/spinner-BJL9zWAJ.js.map +1 -0
- package/dist/chunks/start-BygPCbvw.js +1708 -0
- package/dist/chunks/start-BygPCbvw.js.map +1 -0
- package/dist/chunks/start-traditional-uoLZXdxm.js +255 -0
- package/dist/chunks/start-traditional-uoLZXdxm.js.map +1 -0
- package/dist/chunks/status-cS8YwtUx.js +97 -0
- package/dist/chunks/status-cS8YwtUx.js.map +1 -0
- package/dist/chunks/theme-DhorI2Hb.js +44 -0
- package/dist/chunks/theme-DhorI2Hb.js.map +1 -0
- package/dist/chunks/upgrade-CT6w0lKp.js +323 -0
- package/dist/chunks/upgrade-CT6w0lKp.js.map +1 -0
- package/dist/chunks/useBuildState-CdBSu9y_.js +331 -0
- package/dist/chunks/useBuildState-CdBSu9y_.js.map +1 -0
- package/dist/cli/index.js +694 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.js +14358 -0
- package/dist/index.js.map +1 -0
- package/dist/instrument.js +64226 -0
- package/dist/instrument.js.map +1 -0
- package/dist/templates.json +295 -0
- package/package.json +98 -0
- package/scripts/install-vendor-deps.js +34 -0
- package/scripts/install-vendor.js +167 -0
- package/scripts/prepare-release.js +71 -0
- package/templates/config.template.json +18 -0
- package/templates.json +295 -0
- package/vendor/ai-sdk-provider-claude-code-LOCAL.tgz +0 -0
- package/vendor/sentry-core-LOCAL.tgz +0 -0
- package/vendor/sentry-nextjs-LOCAL.tgz +0 -0
- package/vendor/sentry-node-LOCAL.tgz +0 -0
- package/vendor/sentry-node-core-LOCAL.tgz +0 -0
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
// OpenBuilder CLI - Built with Rollup
|
|
2
|
+
import { mkdir } from 'node:fs/promises';
|
|
3
|
+
import { existsSync, realpathSync } from 'node:fs';
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
5
|
+
import { randomBytes } from 'node:crypto';
|
|
6
|
+
import * as p from '@clack/prompts';
|
|
7
|
+
import pc from 'picocolors';
|
|
8
|
+
import { c as configManager } from './config-manager-BkbjtN-H.js';
|
|
9
|
+
import { i as isInsideMonorepo } from './repo-detector-B_oj696o.js';
|
|
10
|
+
import { isPnpmInstalled, cloneRepository, installDependencies, buildAgentCore } from './repo-cloner-CpOQjFSo.js';
|
|
11
|
+
import { s as setupDatabase, p as pushDatabaseSchema, c as connectManualDatabase } from './database-setup-BYjIRAmT.js';
|
|
12
|
+
import { C as CLIError, e as errors } from './cli-error-BjQwvWtK.js';
|
|
13
|
+
import { initTUICommand } from './init-tui-BNzk_7Yx.js';
|
|
14
|
+
import 'conf';
|
|
15
|
+
import 'node:os';
|
|
16
|
+
import 'node:child_process';
|
|
17
|
+
import './logger-ZpJi7chw.js';
|
|
18
|
+
import 'chalk';
|
|
19
|
+
import './spinner-BJL9zWAJ.js';
|
|
20
|
+
import 'ora';
|
|
21
|
+
import './prompts-1QbE_bRr.js';
|
|
22
|
+
import 'inquirer';
|
|
23
|
+
import 'react/jsx-runtime';
|
|
24
|
+
import 'react';
|
|
25
|
+
import 'ink';
|
|
26
|
+
import './Banner-D4tqKfzA.js';
|
|
27
|
+
import 'node:url';
|
|
28
|
+
import './theme-DhorI2Hb.js';
|
|
29
|
+
import 'ink-text-input';
|
|
30
|
+
import 'node:events';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Enhanced init command with @clack/prompts and friction-free -y mode
|
|
34
|
+
* Provides beautiful interactive setup or completely automated installation
|
|
35
|
+
*
|
|
36
|
+
* For -y mode: Uses a beautiful centered TUI with animated progress
|
|
37
|
+
*/
|
|
38
|
+
/**
|
|
39
|
+
* Generate a secure random secret
|
|
40
|
+
*/
|
|
41
|
+
function generateSecret() {
|
|
42
|
+
return randomBytes(32).toString('hex');
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Check if a path is or contains the current working directory
|
|
46
|
+
* Prevents accidental deletion of the directory we're running from
|
|
47
|
+
*/
|
|
48
|
+
function isCurrentWorkingDirectory(targetPath) {
|
|
49
|
+
try {
|
|
50
|
+
const cwd = realpathSync(process.cwd());
|
|
51
|
+
const target = realpathSync(resolve(targetPath));
|
|
52
|
+
// Check if target is cwd or if cwd is inside target
|
|
53
|
+
return cwd === target || cwd.startsWith(target + '/');
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// If we can't resolve paths, be safe and assume it might be cwd
|
|
57
|
+
const cwd = process.cwd();
|
|
58
|
+
const target = resolve(targetPath);
|
|
59
|
+
return cwd === target || cwd.startsWith(target + '/');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Safely remove a directory, but never the current working directory
|
|
64
|
+
*/
|
|
65
|
+
function safeRemoveDirectory(targetPath, rmSync) {
|
|
66
|
+
if (isCurrentWorkingDirectory(targetPath)) {
|
|
67
|
+
console.error(`\n⚠️ Cannot remove ${targetPath} - it is the current working directory`);
|
|
68
|
+
console.error(' Please run this command from a different directory.\n');
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
rmSync(targetPath, { recursive: true, force: true });
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Normalize URL by adding protocol if missing
|
|
76
|
+
*/
|
|
77
|
+
function normalizeUrl(url) {
|
|
78
|
+
if (!url)
|
|
79
|
+
return url;
|
|
80
|
+
if (url.match(/^https?:\/\//i))
|
|
81
|
+
return url;
|
|
82
|
+
if (url.match(/^(localhost|127\.0\.0\.1)(:|\/|$)/i)) {
|
|
83
|
+
return `http://${url}`;
|
|
84
|
+
}
|
|
85
|
+
return `https://${url}`;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get default workspace path
|
|
89
|
+
*/
|
|
90
|
+
function getDefaultWorkspace() {
|
|
91
|
+
return join(process.cwd(), 'openbuilder-workspace');
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get default monorepo clone path
|
|
95
|
+
*/
|
|
96
|
+
function getDefaultMonorepoPath() {
|
|
97
|
+
return join(process.cwd(), 'openbuilder');
|
|
98
|
+
}
|
|
99
|
+
async function initCommand(options) {
|
|
100
|
+
const isNonInteractive = options.nonInteractive || options.yes;
|
|
101
|
+
// ========================================
|
|
102
|
+
// NON-INTERACTIVE MODE: Use beautiful TUI
|
|
103
|
+
// ========================================
|
|
104
|
+
if (isNonInteractive) {
|
|
105
|
+
return initTUICommand(options);
|
|
106
|
+
}
|
|
107
|
+
// ========================================
|
|
108
|
+
// INTERACTIVE MODE (Beautiful @clack/prompts)
|
|
109
|
+
// ========================================
|
|
110
|
+
// Handle Ctrl+C gracefully
|
|
111
|
+
const handleCancel = () => {
|
|
112
|
+
p.cancel('Setup cancelled');
|
|
113
|
+
process.exit(0);
|
|
114
|
+
};
|
|
115
|
+
try {
|
|
116
|
+
{
|
|
117
|
+
// Keep banner visible - don't clear screen
|
|
118
|
+
console.log(); // Just add spacing
|
|
119
|
+
p.intro(pc.bgCyan(pc.black(' OpenBuilder Setup ')));
|
|
120
|
+
// Step 1: Check if already initialized
|
|
121
|
+
if (configManager.isInitialized()) {
|
|
122
|
+
const shouldReset = await p.confirm({
|
|
123
|
+
message: 'Configuration already exists. Reset and reconfigure?',
|
|
124
|
+
initialValue: true,
|
|
125
|
+
});
|
|
126
|
+
if (p.isCancel(shouldReset)) {
|
|
127
|
+
handleCancel();
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (!shouldReset) {
|
|
131
|
+
p.cancel('Setup cancelled');
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
configManager.reset();
|
|
135
|
+
p.log.success('Configuration reset');
|
|
136
|
+
}
|
|
137
|
+
// Step 2: Check for monorepo
|
|
138
|
+
const s = p.spinner();
|
|
139
|
+
s.start('Checking for OpenBuilder repository');
|
|
140
|
+
const repoCheck = await isInsideMonorepo();
|
|
141
|
+
let monorepoPath;
|
|
142
|
+
if (repoCheck.inside && repoCheck.root) {
|
|
143
|
+
s.stop(pc.green('✓') + ' Found repository at: ' + pc.cyan(repoCheck.root));
|
|
144
|
+
monorepoPath = repoCheck.root;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
s.stop('Repository not found in current directory');
|
|
148
|
+
const shouldClone = await p.confirm({
|
|
149
|
+
message: 'Clone OpenBuilder repository?',
|
|
150
|
+
initialValue: true,
|
|
151
|
+
});
|
|
152
|
+
if (p.isCancel(shouldClone)) {
|
|
153
|
+
handleCancel();
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (shouldClone) {
|
|
157
|
+
// Check for pnpm
|
|
158
|
+
const hasPnpm = await isPnpmInstalled();
|
|
159
|
+
if (!hasPnpm) {
|
|
160
|
+
throw new CLIError({
|
|
161
|
+
code: 'DEPENDENCIES_INSTALL_FAILED',
|
|
162
|
+
message: 'pnpm is not installed',
|
|
163
|
+
suggestions: [
|
|
164
|
+
'Install pnpm: npm install -g pnpm',
|
|
165
|
+
'Or visit: https://pnpm.io/installation',
|
|
166
|
+
],
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
const clonePath = await p.text({
|
|
170
|
+
message: 'Where should the repository be cloned?',
|
|
171
|
+
placeholder: getDefaultMonorepoPath(),
|
|
172
|
+
defaultValue: getDefaultMonorepoPath(),
|
|
173
|
+
validate: (value) => {
|
|
174
|
+
if (!value)
|
|
175
|
+
return 'Path is required';
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
if (p.isCancel(clonePath)) {
|
|
179
|
+
handleCancel();
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
// Check if path exists
|
|
183
|
+
const defaultWorkspace = getDefaultWorkspace();
|
|
184
|
+
const existingInstallation = existsSync(clonePath) || existsSync(defaultWorkspace);
|
|
185
|
+
if (existingInstallation) {
|
|
186
|
+
const shouldOverwrite = await p.confirm({
|
|
187
|
+
message: `Existing OpenBuilder installation found. Replace it with fresh install?`,
|
|
188
|
+
initialValue: true,
|
|
189
|
+
});
|
|
190
|
+
if (p.isCancel(shouldOverwrite)) {
|
|
191
|
+
handleCancel();
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if (shouldOverwrite) {
|
|
195
|
+
s.start('Removing existing installation');
|
|
196
|
+
const { rmSync } = await import('fs');
|
|
197
|
+
// Safety check: never delete the current working directory
|
|
198
|
+
if (existsSync(clonePath)) {
|
|
199
|
+
if (!safeRemoveDirectory(clonePath, rmSync)) {
|
|
200
|
+
s.stop(pc.red('✗') + ' Cannot remove current working directory');
|
|
201
|
+
p.cancel('Please run openbuilder init from a different directory');
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// Delete workspace directory
|
|
206
|
+
if (existsSync(defaultWorkspace)) {
|
|
207
|
+
if (!safeRemoveDirectory(defaultWorkspace, rmSync)) {
|
|
208
|
+
s.stop(pc.red('✗') + ' Cannot remove current working directory');
|
|
209
|
+
p.cancel('Please run openbuilder init from a different directory');
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
s.stop(pc.green('✓') + ' Existing installation removed');
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
p.cancel('Setup cancelled');
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// Clone, install, build
|
|
221
|
+
try {
|
|
222
|
+
s.start('Cloning repository from GitHub');
|
|
223
|
+
monorepoPath = await cloneRepository({
|
|
224
|
+
targetPath: clonePath,
|
|
225
|
+
branch: options.branch || 'main',
|
|
226
|
+
});
|
|
227
|
+
s.stop(pc.green('✓') + ' Repository cloned');
|
|
228
|
+
s.start('Installing dependencies (this may take a few minutes)');
|
|
229
|
+
await installDependencies(monorepoPath);
|
|
230
|
+
s.stop(pc.green('✓') + ' Dependencies installed');
|
|
231
|
+
s.start('Building @openbuilder/agent-core');
|
|
232
|
+
await buildAgentCore(monorepoPath);
|
|
233
|
+
s.stop(pc.green('✓') + ' Build complete');
|
|
234
|
+
// Ask about pre-building services
|
|
235
|
+
const shouldPreBuild = await p.confirm({
|
|
236
|
+
message: 'Pre-build all services for production performance?',
|
|
237
|
+
initialValue: true,
|
|
238
|
+
});
|
|
239
|
+
if (p.isCancel(shouldPreBuild)) {
|
|
240
|
+
handleCancel();
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (shouldPreBuild) {
|
|
244
|
+
s.start('Building all services (this may take a minute)');
|
|
245
|
+
const { spawn } = await import('child_process');
|
|
246
|
+
try {
|
|
247
|
+
await new Promise((resolve, reject) => {
|
|
248
|
+
const buildProcess = spawn('pnpm', ['build:all'], {
|
|
249
|
+
cwd: monorepoPath,
|
|
250
|
+
stdio: 'pipe',
|
|
251
|
+
shell: true,
|
|
252
|
+
});
|
|
253
|
+
buildProcess.on('close', (code) => {
|
|
254
|
+
if (code === 0) {
|
|
255
|
+
resolve();
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
reject(new Error(`Build failed with code ${code}`));
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
buildProcess.on('error', reject);
|
|
262
|
+
});
|
|
263
|
+
s.stop(pc.green('✓') + ' All services built for production');
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
s.stop(pc.yellow('⚠') + ' Build failed (you can build later with: pnpm build:all)');
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
throw new CLIError({
|
|
272
|
+
code: 'MONOREPO_CLONE_FAILED',
|
|
273
|
+
message: 'Failed to setup repository',
|
|
274
|
+
cause: error instanceof Error ? error : new Error(String(error)),
|
|
275
|
+
suggestions: [
|
|
276
|
+
'Check your internet connection',
|
|
277
|
+
'Verify you have git installed: git --version',
|
|
278
|
+
'Try cloning manually: git clone https://github.com/codyde/openbuilder.git',
|
|
279
|
+
],
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
p.note('Setup will continue in runner-only mode.\nYou can add the repository path later with:\n openbuilder config set monorepoPath <path>', 'Repository setup skipped');
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
// Step 3: Workspace configuration
|
|
288
|
+
p.log.step(pc.cyan('Workspace Configuration'));
|
|
289
|
+
const workspace = await p.text({
|
|
290
|
+
message: 'Where should generated projects be stored?',
|
|
291
|
+
placeholder: getDefaultWorkspace(),
|
|
292
|
+
defaultValue: getDefaultWorkspace(),
|
|
293
|
+
validate: (value) => {
|
|
294
|
+
if (!value)
|
|
295
|
+
return 'Workspace path is required';
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
if (p.isCancel(workspace)) {
|
|
299
|
+
handleCancel();
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
// Create workspace directory
|
|
303
|
+
try {
|
|
304
|
+
if (!existsSync(workspace)) {
|
|
305
|
+
await mkdir(workspace, { recursive: true });
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
throw errors.workspaceNotFound(workspace);
|
|
310
|
+
}
|
|
311
|
+
// Step 4: Connection configuration
|
|
312
|
+
p.log.step(pc.cyan('Connection Configuration'));
|
|
313
|
+
const wsUrl = await p.text({
|
|
314
|
+
message: 'Server WebSocket URL',
|
|
315
|
+
placeholder: 'ws://localhost:3000/ws/runner',
|
|
316
|
+
defaultValue: 'ws://localhost:3000/ws/runner',
|
|
317
|
+
});
|
|
318
|
+
if (p.isCancel(wsUrl)) {
|
|
319
|
+
handleCancel();
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
const apiUrl = await p.text({
|
|
323
|
+
message: 'API base URL',
|
|
324
|
+
placeholder: 'http://localhost:3000',
|
|
325
|
+
defaultValue: options.url || 'http://localhost:3000',
|
|
326
|
+
});
|
|
327
|
+
if (p.isCancel(apiUrl)) {
|
|
328
|
+
handleCancel();
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
// Step 5: Security
|
|
332
|
+
const secret = await p.text({
|
|
333
|
+
message: 'Shared secret (press Enter to generate)',
|
|
334
|
+
placeholder: 'Generated automatically',
|
|
335
|
+
defaultValue: options.secret || generateSecret(),
|
|
336
|
+
});
|
|
337
|
+
if (p.isCancel(secret)) {
|
|
338
|
+
handleCancel();
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
const runnerId = await p.text({
|
|
342
|
+
message: 'Runner ID',
|
|
343
|
+
placeholder: 'local',
|
|
344
|
+
defaultValue: 'local',
|
|
345
|
+
});
|
|
346
|
+
if (p.isCancel(runnerId)) {
|
|
347
|
+
handleCancel();
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
// Step 6: Database setup (if monorepo available)
|
|
351
|
+
let databaseUrl;
|
|
352
|
+
if (monorepoPath) {
|
|
353
|
+
p.log.step(pc.cyan('Database Setup'));
|
|
354
|
+
const dbChoice = await p.select({
|
|
355
|
+
message: 'Database configuration',
|
|
356
|
+
options: [
|
|
357
|
+
{
|
|
358
|
+
value: 'neon',
|
|
359
|
+
label: 'Create Neon database (recommended)',
|
|
360
|
+
hint: 'Free tier, persistent storage'
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
value: 'existing',
|
|
364
|
+
label: 'Use existing PostgreSQL',
|
|
365
|
+
hint: 'Provide connection string'
|
|
366
|
+
},
|
|
367
|
+
],
|
|
368
|
+
});
|
|
369
|
+
if (p.isCancel(dbChoice)) {
|
|
370
|
+
handleCancel();
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
if (dbChoice === 'neon') {
|
|
374
|
+
p.note('Opening Neon in your browser...\nCreate a database and paste the connection string below.', pc.cyan('Database Setup'));
|
|
375
|
+
databaseUrl = await setupDatabase(monorepoPath) || undefined;
|
|
376
|
+
// Push schema if we have a database
|
|
377
|
+
if (databaseUrl) {
|
|
378
|
+
s.start('Pushing database schema');
|
|
379
|
+
const pushed = await pushDatabaseSchema(monorepoPath, databaseUrl);
|
|
380
|
+
if (pushed) {
|
|
381
|
+
s.stop(pc.green('✓') + ' Schema initialized');
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
s.stop(pc.yellow('⚠') + ' Schema push failed (you can retry later)');
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
else if (dbChoice === 'existing') {
|
|
389
|
+
databaseUrl = await connectManualDatabase() || undefined;
|
|
390
|
+
// Push schema if we have a database
|
|
391
|
+
if (databaseUrl) {
|
|
392
|
+
s.start('Pushing database schema');
|
|
393
|
+
const pushed = await pushDatabaseSchema(monorepoPath, databaseUrl);
|
|
394
|
+
if (pushed) {
|
|
395
|
+
s.stop(pc.green('✓') + ' Schema initialized');
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
s.stop(pc.yellow('⚠') + ' Schema push failed (you can retry later)');
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
// Step 7: Save configuration
|
|
404
|
+
try {
|
|
405
|
+
configManager.set('workspace', workspace);
|
|
406
|
+
if (monorepoPath) {
|
|
407
|
+
configManager.set('monorepoPath', monorepoPath);
|
|
408
|
+
}
|
|
409
|
+
if (databaseUrl) {
|
|
410
|
+
configManager.set('databaseUrl', databaseUrl);
|
|
411
|
+
}
|
|
412
|
+
configManager.set('apiUrl', normalizeUrl(apiUrl));
|
|
413
|
+
configManager.set('server', {
|
|
414
|
+
wsUrl: wsUrl,
|
|
415
|
+
secret: secret,
|
|
416
|
+
});
|
|
417
|
+
configManager.set('runner', {
|
|
418
|
+
id: runnerId,
|
|
419
|
+
reconnectAttempts: 5,
|
|
420
|
+
heartbeatInterval: 15000,
|
|
421
|
+
});
|
|
422
|
+
configManager.set('tunnel', {
|
|
423
|
+
provider: 'cloudflare',
|
|
424
|
+
autoCreate: true,
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
catch (error) {
|
|
428
|
+
throw new CLIError({
|
|
429
|
+
code: 'CONFIG_INVALID',
|
|
430
|
+
message: 'Failed to save configuration',
|
|
431
|
+
cause: error instanceof Error ? error : new Error(String(error)),
|
|
432
|
+
suggestions: [
|
|
433
|
+
'Check file permissions on config directory',
|
|
434
|
+
'Try running with sudo (not recommended)',
|
|
435
|
+
],
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
// Validate
|
|
439
|
+
const validation = configManager.validate();
|
|
440
|
+
if (!validation.valid) {
|
|
441
|
+
throw new CLIError({
|
|
442
|
+
code: 'CONFIG_INVALID',
|
|
443
|
+
message: 'Configuration validation failed',
|
|
444
|
+
context: { errors: validation.errors },
|
|
445
|
+
suggestions: validation.errors,
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
// Success!
|
|
449
|
+
p.outro(pc.green('✨ OpenBuilder is ready!'));
|
|
450
|
+
p.note(`${pc.cyan('openbuilder run')}\n\nThen open: ${pc.cyan('http://localhost:3000')}`, 'Next Steps');
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
catch (error) {
|
|
455
|
+
// Handle cancellation gracefully
|
|
456
|
+
if (error && typeof error === 'object' && 'name' in error) {
|
|
457
|
+
if (error.name === 'ExitPromptError' || error.code === 'CLACK_CANCEL') {
|
|
458
|
+
handleCancel();
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
// Re-throw for global error handler
|
|
463
|
+
throw error;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
export { initCommand };
|
|
468
|
+
//# sourceMappingURL=init-CZoN6soU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-CZoN6soU.js","sources":["../../src/cli/commands/init.ts"],"sourcesContent":["/**\n * Enhanced init command with @clack/prompts and friction-free -y mode\n * Provides beautiful interactive setup or completely automated installation\n * \n * For -y mode: Uses a beautiful centered TUI with animated progress\n */\n\nimport { mkdir, realpath, writeFile } from 'node:fs/promises';\nimport { existsSync, realpathSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join, resolve } from 'node:path';\nimport { randomBytes } from 'node:crypto';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport { configManager } from '../utils/config-manager.js';\nimport { isInsideMonorepo } from '../utils/repo-detector.js';\nimport {\n cloneRepository,\n installDependencies,\n isPnpmInstalled,\n buildAgentCore\n} from '../utils/repo-cloner.js';\nimport {\n setupDatabase,\n pushDatabaseSchema,\n connectManualDatabase\n} from '../utils/database-setup.js';\nimport { CLIError, errors } from '../utils/cli-error.js';\nimport { initTUICommand } from './init-tui.js';\n\n/**\n * Generate a secure random secret\n */\nfunction generateSecret(): string {\n return randomBytes(32).toString('hex');\n}\n\n/**\n * Check if a path is or contains the current working directory\n * Prevents accidental deletion of the directory we're running from\n */\nfunction isCurrentWorkingDirectory(targetPath: string): boolean {\n try {\n const cwd = realpathSync(process.cwd());\n const target = realpathSync(resolve(targetPath));\n // Check if target is cwd or if cwd is inside target\n return cwd === target || cwd.startsWith(target + '/');\n } catch {\n // If we can't resolve paths, be safe and assume it might be cwd\n const cwd = process.cwd();\n const target = resolve(targetPath);\n return cwd === target || cwd.startsWith(target + '/');\n }\n}\n\n/**\n * Safely remove a directory, but never the current working directory\n */\nfunction safeRemoveDirectory(targetPath: string, rmSync: typeof import('fs').rmSync): boolean {\n if (isCurrentWorkingDirectory(targetPath)) {\n console.error(`\\n⚠️ Cannot remove ${targetPath} - it is the current working directory`);\n console.error(' Please run this command from a different directory.\\n');\n return false;\n }\n rmSync(targetPath, { recursive: true, force: true });\n return true;\n}\n\n/**\n * Normalize URL by adding protocol if missing\n */\nfunction normalizeUrl(url: string): string {\n if (!url) return url;\n if (url.match(/^https?:\\/\\//i)) return url;\n if (url.match(/^(localhost|127\\.0\\.0\\.1)(:|\\/|$)/i)) {\n return `http://${url}`;\n }\n return `https://${url}`;\n}\n\n/**\n * Get default workspace path\n */\nfunction getDefaultWorkspace(): string {\n return join(process.cwd(), 'openbuilder-workspace');\n}\n\n/**\n * Get default monorepo clone path\n */\nfunction getDefaultMonorepoPath(): string {\n return join(process.cwd(), 'openbuilder');\n}\n\ninterface InitOptions {\n workspace?: string;\n url?: string;\n secret?: string;\n branch?: string;\n database?: string | boolean; // Can be: undefined (neon), or a PostgreSQL connection string\n yes?: boolean;\n nonInteractive?: boolean;\n}\n\nexport async function initCommand(options: InitOptions) {\n const isNonInteractive = options.nonInteractive || options.yes;\n\n // ========================================\n // NON-INTERACTIVE MODE: Use beautiful TUI\n // ========================================\n if (isNonInteractive) {\n return initTUICommand(options);\n }\n\n // ========================================\n // INTERACTIVE MODE (Beautiful @clack/prompts)\n // ========================================\n // Handle Ctrl+C gracefully\n const handleCancel = () => {\n p.cancel('Setup cancelled');\n process.exit(0);\n };\n\n try {\n {\n // Keep banner visible - don't clear screen\n console.log(); // Just add spacing\n\n p.intro(pc.bgCyan(pc.black(' OpenBuilder Setup ')));\n\n // Step 1: Check if already initialized\n if (configManager.isInitialized()) {\n const shouldReset = await p.confirm({\n message: 'Configuration already exists. Reset and reconfigure?',\n initialValue: true,\n });\n\n if (p.isCancel(shouldReset)) {\n handleCancel();\n return;\n }\n\n if (!shouldReset) {\n p.cancel('Setup cancelled');\n return;\n }\n\n configManager.reset();\n p.log.success('Configuration reset');\n }\n\n // Step 2: Check for monorepo\n const s = p.spinner();\n s.start('Checking for OpenBuilder repository');\n\n const repoCheck = await isInsideMonorepo();\n let monorepoPath: string | undefined;\n\n if (repoCheck.inside && repoCheck.root) {\n s.stop(pc.green('✓') + ' Found repository at: ' + pc.cyan(repoCheck.root));\n monorepoPath = repoCheck.root;\n } else {\n s.stop('Repository not found in current directory');\n\n const shouldClone = await p.confirm({\n message: 'Clone OpenBuilder repository?',\n initialValue: true,\n });\n\n if (p.isCancel(shouldClone)) {\n handleCancel();\n return;\n }\n\n if (shouldClone) {\n // Check for pnpm\n const hasPnpm = await isPnpmInstalled();\n if (!hasPnpm) {\n throw new CLIError({\n code: 'DEPENDENCIES_INSTALL_FAILED',\n message: 'pnpm is not installed',\n suggestions: [\n 'Install pnpm: npm install -g pnpm',\n 'Or visit: https://pnpm.io/installation',\n ],\n });\n }\n\n const clonePath = await p.text({\n message: 'Where should the repository be cloned?',\n placeholder: getDefaultMonorepoPath(),\n defaultValue: getDefaultMonorepoPath(),\n validate: (value) => {\n if (!value) return 'Path is required';\n },\n });\n\n if (p.isCancel(clonePath)) {\n handleCancel();\n return;\n }\n\n // Check if path exists\n const defaultWorkspace = getDefaultWorkspace();\n const existingInstallation = existsSync(clonePath as string) || existsSync(defaultWorkspace);\n\n if (existingInstallation) {\n const shouldOverwrite = await p.confirm({\n message: `Existing OpenBuilder installation found. Replace it with fresh install?`,\n initialValue: true,\n });\n\n if (p.isCancel(shouldOverwrite)) {\n handleCancel();\n return;\n }\n\n if (shouldOverwrite) {\n s.start('Removing existing installation');\n const { rmSync } = await import('fs');\n\n // Safety check: never delete the current working directory\n if (existsSync(clonePath as string)) {\n if (!safeRemoveDirectory(clonePath as string, rmSync)) {\n s.stop(pc.red('✗') + ' Cannot remove current working directory');\n p.cancel('Please run openbuilder init from a different directory');\n return;\n }\n }\n\n // Delete workspace directory\n if (existsSync(defaultWorkspace)) {\n if (!safeRemoveDirectory(defaultWorkspace, rmSync)) {\n s.stop(pc.red('✗') + ' Cannot remove current working directory');\n p.cancel('Please run openbuilder init from a different directory');\n return;\n }\n }\n\n s.stop(pc.green('✓') + ' Existing installation removed');\n } else {\n p.cancel('Setup cancelled');\n return;\n }\n }\n\n // Clone, install, build\n try {\n s.start('Cloning repository from GitHub');\n monorepoPath = await cloneRepository({\n targetPath: clonePath as string,\n branch: options.branch || 'main',\n });\n s.stop(pc.green('✓') + ' Repository cloned');\n\n s.start('Installing dependencies (this may take a few minutes)');\n await installDependencies(monorepoPath);\n s.stop(pc.green('✓') + ' Dependencies installed');\n\n s.start('Building @openbuilder/agent-core');\n await buildAgentCore(monorepoPath);\n s.stop(pc.green('✓') + ' Build complete');\n\n // Ask about pre-building services\n const shouldPreBuild = await p.confirm({\n message: 'Pre-build all services for production performance?',\n initialValue: true,\n });\n\n if (p.isCancel(shouldPreBuild)) {\n handleCancel();\n return;\n }\n\n if (shouldPreBuild) {\n s.start('Building all services (this may take a minute)');\n const { spawn } = await import('child_process');\n\n try {\n await new Promise<void>((resolve, reject) => {\n const buildProcess = spawn('pnpm', ['build:all'], {\n cwd: monorepoPath,\n stdio: 'pipe',\n shell: true,\n });\n\n buildProcess.on('close', (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`Build failed with code ${code}`));\n }\n });\n\n buildProcess.on('error', reject);\n });\n\n s.stop(pc.green('✓') + ' All services built for production');\n } catch (error) {\n s.stop(pc.yellow('⚠') + ' Build failed (you can build later with: pnpm build:all)');\n }\n }\n } catch (error) {\n throw new CLIError({\n code: 'MONOREPO_CLONE_FAILED',\n message: 'Failed to setup repository',\n cause: error instanceof Error ? error : new Error(String(error)),\n suggestions: [\n 'Check your internet connection',\n 'Verify you have git installed: git --version',\n 'Try cloning manually: git clone https://github.com/codyde/openbuilder.git',\n ],\n });\n }\n } else {\n p.note(\n 'Setup will continue in runner-only mode.\\nYou can add the repository path later with:\\n openbuilder config set monorepoPath <path>',\n 'Repository setup skipped'\n );\n }\n }\n\n // Step 3: Workspace configuration\n p.log.step(pc.cyan('Workspace Configuration'));\n\n const workspace = await p.text({\n message: 'Where should generated projects be stored?',\n placeholder: getDefaultWorkspace(),\n defaultValue: getDefaultWorkspace(),\n validate: (value) => {\n if (!value) return 'Workspace path is required';\n },\n });\n\n if (p.isCancel(workspace)) {\n handleCancel();\n return;\n }\n\n // Create workspace directory\n try {\n if (!existsSync(workspace as string)) {\n await mkdir(workspace as string, { recursive: true });\n }\n } catch (error) {\n throw errors.workspaceNotFound(workspace as string);\n }\n\n // Step 4: Connection configuration\n p.log.step(pc.cyan('Connection Configuration'));\n\n const wsUrl = await p.text({\n message: 'Server WebSocket URL',\n placeholder: 'ws://localhost:3000/ws/runner',\n defaultValue: 'ws://localhost:3000/ws/runner',\n });\n\n if (p.isCancel(wsUrl)) {\n handleCancel();\n return;\n }\n\n const apiUrl = await p.text({\n message: 'API base URL',\n placeholder: 'http://localhost:3000',\n defaultValue: options.url || 'http://localhost:3000',\n });\n\n if (p.isCancel(apiUrl)) {\n handleCancel();\n return;\n }\n\n // Step 5: Security\n const secret = await p.text({\n message: 'Shared secret (press Enter to generate)',\n placeholder: 'Generated automatically',\n defaultValue: options.secret || generateSecret(),\n });\n\n if (p.isCancel(secret)) {\n handleCancel();\n return;\n }\n\n const runnerId = await p.text({\n message: 'Runner ID',\n placeholder: 'local',\n defaultValue: 'local',\n });\n\n if (p.isCancel(runnerId)) {\n handleCancel();\n return;\n }\n\n // Step 6: Database setup (if monorepo available)\n let databaseUrl: string | undefined;\n\n if (monorepoPath) {\n p.log.step(pc.cyan('Database Setup'));\n\n const dbChoice = await p.select({\n message: 'Database configuration',\n options: [\n {\n value: 'neon',\n label: 'Create Neon database (recommended)',\n hint: 'Free tier, persistent storage'\n },\n {\n value: 'existing',\n label: 'Use existing PostgreSQL',\n hint: 'Provide connection string'\n },\n ],\n });\n\n if (p.isCancel(dbChoice)) {\n handleCancel();\n return;\n }\n\n if (dbChoice === 'neon') {\n p.note(\n 'Opening Neon in your browser...\\nCreate a database and paste the connection string below.',\n pc.cyan('Database Setup')\n );\n databaseUrl = await setupDatabase(monorepoPath) || undefined;\n \n // Push schema if we have a database\n if (databaseUrl) {\n s.start('Pushing database schema');\n const pushed = await pushDatabaseSchema(monorepoPath, databaseUrl);\n if (pushed) {\n s.stop(pc.green('✓') + ' Schema initialized');\n } else {\n s.stop(pc.yellow('⚠') + ' Schema push failed (you can retry later)');\n }\n }\n } else if (dbChoice === 'existing') {\n databaseUrl = await connectManualDatabase() || undefined;\n \n // Push schema if we have a database\n if (databaseUrl) {\n s.start('Pushing database schema');\n const pushed = await pushDatabaseSchema(monorepoPath, databaseUrl);\n if (pushed) {\n s.stop(pc.green('✓') + ' Schema initialized');\n } else {\n s.stop(pc.yellow('⚠') + ' Schema push failed (you can retry later)');\n }\n }\n }\n }\n\n // Step 7: Save configuration\n try {\n configManager.set('workspace', workspace);\n if (monorepoPath) {\n configManager.set('monorepoPath', monorepoPath);\n }\n if (databaseUrl) {\n configManager.set('databaseUrl', databaseUrl);\n }\n configManager.set('apiUrl', normalizeUrl(apiUrl as string));\n configManager.set('server', {\n wsUrl: wsUrl,\n secret: secret,\n });\n configManager.set('runner', {\n id: runnerId,\n reconnectAttempts: 5,\n heartbeatInterval: 15000,\n });\n configManager.set('tunnel', {\n provider: 'cloudflare',\n autoCreate: true,\n });\n } catch (error) {\n throw new CLIError({\n code: 'CONFIG_INVALID',\n message: 'Failed to save configuration',\n cause: error instanceof Error ? error : new Error(String(error)),\n suggestions: [\n 'Check file permissions on config directory',\n 'Try running with sudo (not recommended)',\n ],\n });\n }\n\n // Validate\n const validation = configManager.validate();\n if (!validation.valid) {\n throw new CLIError({\n code: 'CONFIG_INVALID',\n message: 'Configuration validation failed',\n context: { errors: validation.errors },\n suggestions: validation.errors,\n });\n }\n\n // Success!\n p.outro(pc.green('✨ OpenBuilder is ready!'));\n\n p.note(\n `${pc.cyan('openbuilder run')}\\n\\nThen open: ${pc.cyan('http://localhost:3000')}`,\n 'Next Steps'\n );\n\n return;\n }\n } catch (error) {\n // Handle cancellation gracefully\n if (error && typeof error === 'object' && 'name' in error) {\n if ((error as { name: string }).name === 'ExitPromptError' || (error as { code?: string }).code === 'CLACK_CANCEL') {\n handleCancel();\n return;\n }\n }\n\n // Re-throw for global error handler\n throw error;\n }\n}\n"],"names":[],"mappings":"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"}
|