@hatchway/cli 0.50.53

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 (80) hide show
  1. package/README.md +274 -0
  2. package/bin/hatchway.js +31 -0
  3. package/dist/chunks/Banner-DL1Fpz_g.js +115 -0
  4. package/dist/chunks/Banner-DL1Fpz_g.js.map +1 -0
  5. package/dist/chunks/auto-update-Ddo5Ntt7.js +264 -0
  6. package/dist/chunks/auto-update-Ddo5Ntt7.js.map +1 -0
  7. package/dist/chunks/build-V8_D-JHF.js +116 -0
  8. package/dist/chunks/build-V8_D-JHF.js.map +1 -0
  9. package/dist/chunks/cleanup-BNuJNSve.js +141 -0
  10. package/dist/chunks/cleanup-BNuJNSve.js.map +1 -0
  11. package/dist/chunks/cli-auth-B4Do-N8Y.js +340 -0
  12. package/dist/chunks/cli-auth-B4Do-N8Y.js.map +1 -0
  13. package/dist/chunks/cli-error-1drkrXNn.js +140 -0
  14. package/dist/chunks/cli-error-1drkrXNn.js.map +1 -0
  15. package/dist/chunks/config-hFJA7z5y.js +167 -0
  16. package/dist/chunks/config-hFJA7z5y.js.map +1 -0
  17. package/dist/chunks/config-manager-DST6RbP8.js +133 -0
  18. package/dist/chunks/config-manager-DST6RbP8.js.map +1 -0
  19. package/dist/chunks/database-YGb1Lzim.js +68 -0
  20. package/dist/chunks/database-YGb1Lzim.js.map +1 -0
  21. package/dist/chunks/database-setup-U31oEs90.js +253 -0
  22. package/dist/chunks/database-setup-U31oEs90.js.map +1 -0
  23. package/dist/chunks/devtools-CPruVlOo.js +75 -0
  24. package/dist/chunks/devtools-CPruVlOo.js.map +1 -0
  25. package/dist/chunks/index-DCC6HGdr.js +119 -0
  26. package/dist/chunks/index-DCC6HGdr.js.map +1 -0
  27. package/dist/chunks/init-DkXJVFFx.js +472 -0
  28. package/dist/chunks/init-DkXJVFFx.js.map +1 -0
  29. package/dist/chunks/init-tui-D2VOVdeK.js +1131 -0
  30. package/dist/chunks/init-tui-D2VOVdeK.js.map +1 -0
  31. package/dist/chunks/logger-6V5cBxba.js +38 -0
  32. package/dist/chunks/logger-6V5cBxba.js.map +1 -0
  33. package/dist/chunks/login-CA1XWUEM.js +63 -0
  34. package/dist/chunks/login-CA1XWUEM.js.map +1 -0
  35. package/dist/chunks/logout-BC4VFt8f.js +40 -0
  36. package/dist/chunks/logout-BC4VFt8f.js.map +1 -0
  37. package/dist/chunks/main-tui-D8KkJRd_.js +648 -0
  38. package/dist/chunks/main-tui-D8KkJRd_.js.map +1 -0
  39. package/dist/chunks/manager-DjVI7erc.js +1161 -0
  40. package/dist/chunks/manager-DjVI7erc.js.map +1 -0
  41. package/dist/chunks/port-allocator-BENntRMG.js +864 -0
  42. package/dist/chunks/port-allocator-BENntRMG.js.map +1 -0
  43. package/dist/chunks/process-killer-ChXAqhfm.js +87 -0
  44. package/dist/chunks/process-killer-ChXAqhfm.js.map +1 -0
  45. package/dist/chunks/prompts-Beijr8dm.js +128 -0
  46. package/dist/chunks/prompts-Beijr8dm.js.map +1 -0
  47. package/dist/chunks/repo-cloner-UY3L2X7h.js +219 -0
  48. package/dist/chunks/repo-cloner-UY3L2X7h.js.map +1 -0
  49. package/dist/chunks/repo-detector-36VydrlB.js +66 -0
  50. package/dist/chunks/repo-detector-36VydrlB.js.map +1 -0
  51. package/dist/chunks/run-Du6dvTJL.js +697 -0
  52. package/dist/chunks/run-Du6dvTJL.js.map +1 -0
  53. package/dist/chunks/runner-logger-instance-Dj_JMznn.js +899 -0
  54. package/dist/chunks/runner-logger-instance-Dj_JMznn.js.map +1 -0
  55. package/dist/chunks/spinner-DTH0QZQw.js +53 -0
  56. package/dist/chunks/spinner-DTH0QZQw.js.map +1 -0
  57. package/dist/chunks/start-Dkuro1jp.js +1713 -0
  58. package/dist/chunks/start-Dkuro1jp.js.map +1 -0
  59. package/dist/chunks/start-traditional-7wlD2f2H.js +255 -0
  60. package/dist/chunks/start-traditional-7wlD2f2H.js.map +1 -0
  61. package/dist/chunks/status-BU3cFJm1.js +97 -0
  62. package/dist/chunks/status-BU3cFJm1.js.map +1 -0
  63. package/dist/chunks/theme-NAQBkisB.js +40222 -0
  64. package/dist/chunks/theme-NAQBkisB.js.map +1 -0
  65. package/dist/chunks/upgrade-BBpJirEu.js +455 -0
  66. package/dist/chunks/upgrade-BBpJirEu.js.map +1 -0
  67. package/dist/chunks/use-app-Ct3w2jLI.js +10 -0
  68. package/dist/chunks/use-app-Ct3w2jLI.js.map +1 -0
  69. package/dist/chunks/useBuildState-Dy7pRR8Z.js +330 -0
  70. package/dist/chunks/useBuildState-Dy7pRR8Z.js.map +1 -0
  71. package/dist/cli/index.js +712 -0
  72. package/dist/cli/index.js.map +1 -0
  73. package/dist/index.js +13625 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/instrument.js +45 -0
  76. package/dist/instrument.js.map +1 -0
  77. package/dist/templates.json +295 -0
  78. package/package.json +87 -0
  79. package/templates/config.template.json +18 -0
  80. package/templates.json +295 -0
@@ -0,0 +1,167 @@
1
+ // Hatchway CLI - Built with Rollup
2
+ import chalk from 'chalk';
3
+ import { l as logger } from './logger-6V5cBxba.js';
4
+ import { c as configManager } from './config-manager-DST6RbP8.js';
5
+ import { p as prompts } from './prompts-Beijr8dm.js';
6
+ import 'conf';
7
+ import 'node:os';
8
+ import 'node:path';
9
+ import 'node:fs';
10
+ import 'inquirer';
11
+
12
+ async function configCommand(action, key, value) {
13
+ switch (action) {
14
+ case 'get':
15
+ if (!key) {
16
+ logger.error('Key is required for get action');
17
+ logger.info('Usage: hatchway config get <key>');
18
+ process.exit(1);
19
+ }
20
+ handleGet(key);
21
+ break;
22
+ case 'set':
23
+ if (!key || !value) {
24
+ logger.error('Key and value are required for set action');
25
+ logger.info('Usage: hatchway config set <key> <value>');
26
+ process.exit(1);
27
+ }
28
+ handleSet(key, value);
29
+ break;
30
+ case 'list':
31
+ handleList();
32
+ break;
33
+ case 'path':
34
+ handlePath();
35
+ break;
36
+ case 'validate':
37
+ handleValidate();
38
+ break;
39
+ case 'reset':
40
+ await handleReset();
41
+ break;
42
+ default:
43
+ logger.error(`Unknown action: ${action}`);
44
+ logger.info('Available actions: get, set, list, path, validate, reset');
45
+ process.exit(1);
46
+ }
47
+ }
48
+ function handleGet(key) {
49
+ try {
50
+ const value = configManager.get(key);
51
+ if (value === undefined) {
52
+ logger.warn(`Key not found: ${key}`);
53
+ process.exit(1);
54
+ }
55
+ if (typeof value === 'object') {
56
+ logger.log(JSON.stringify(value, null, 2));
57
+ }
58
+ else {
59
+ logger.log(String(value));
60
+ }
61
+ }
62
+ catch (error) {
63
+ logger.error('Failed to get config value');
64
+ logger.error(error instanceof Error ? error.message : 'Unknown error');
65
+ process.exit(1);
66
+ }
67
+ }
68
+ function handleSet(key, value) {
69
+ try {
70
+ // Try to parse as JSON for objects/arrays
71
+ let parsedValue = value;
72
+ if (value.startsWith('{') || value.startsWith('[')) {
73
+ try {
74
+ parsedValue = JSON.parse(value);
75
+ }
76
+ catch {
77
+ // Keep as string if not valid JSON
78
+ }
79
+ }
80
+ configManager.set(key, parsedValue);
81
+ logger.success(`Set ${chalk.cyan(key)} = ${chalk.green(value)}`);
82
+ }
83
+ catch (error) {
84
+ logger.error('Failed to set config value');
85
+ logger.error(error instanceof Error ? error.message : 'Unknown error');
86
+ process.exit(1);
87
+ }
88
+ }
89
+ function handleList() {
90
+ const config = configManager.get();
91
+ logger.section('Current Configuration');
92
+ logger.log('');
93
+ // Workspace
94
+ logger.info(`${chalk.bold('Workspace:')}`);
95
+ logger.log(` ${config.workspace}`);
96
+ logger.log('');
97
+ // API
98
+ logger.info(`${chalk.bold('API:')}`);
99
+ logger.log(` URL: ${config.apiUrl || 'not set'}`);
100
+ logger.log('');
101
+ // Broker
102
+ logger.info(`${chalk.bold('Broker:')}`);
103
+ logger.log(` WebSocket URL: ${config.broker?.url || 'not set'}`);
104
+ logger.log(` HTTP URL: ${config.broker?.httpUrl || 'not set'}`);
105
+ logger.log(` Secret: ${config.broker?.secret ? '***' : 'not set'}`);
106
+ logger.log('');
107
+ // Runner
108
+ logger.info(`${chalk.bold('Runner:')}`);
109
+ logger.log(` ID: ${config.runner?.id || 'not set'}`);
110
+ logger.log(` Reconnect Attempts: ${config.runner?.reconnectAttempts || 5}`);
111
+ logger.log(` Heartbeat Interval: ${config.runner?.heartbeatInterval || 15000}ms`);
112
+ logger.log('');
113
+ // Database
114
+ if (config.databaseUrl) {
115
+ logger.info(`${chalk.bold('Database:')}`);
116
+ logger.log(` URL: ${config.databaseUrl.replace(/:[^:@]+@/, ':***@')}`); // Mask password
117
+ logger.log('');
118
+ }
119
+ // Monorepo
120
+ if (config.monorepoPath) {
121
+ logger.info(`${chalk.bold('Monorepo:')}`);
122
+ logger.log(` Path: ${config.monorepoPath}`);
123
+ logger.log('');
124
+ }
125
+ // Tunnel
126
+ if (config.tunnel) {
127
+ logger.info(`${chalk.bold('Tunnel:')}`);
128
+ logger.log(` Provider: ${config.tunnel.provider}`);
129
+ logger.log(` Auto Create: ${config.tunnel.autoCreate}`);
130
+ logger.log('');
131
+ }
132
+ }
133
+ function handlePath() {
134
+ logger.info(`Config file: ${chalk.cyan(configManager.path)}`);
135
+ }
136
+ function handleValidate() {
137
+ const validation = configManager.validate();
138
+ if (validation.valid) {
139
+ logger.success('Configuration is valid');
140
+ }
141
+ else {
142
+ logger.error('Configuration validation failed:');
143
+ validation.errors.forEach((err) => logger.error(` - ${err}`));
144
+ process.exit(1);
145
+ }
146
+ }
147
+ async function handleReset() {
148
+ logger.warn('This will delete all configuration and reset to defaults');
149
+ const confirmed = await prompts.confirm('Are you sure?', false);
150
+ if (!confirmed) {
151
+ logger.info('Reset cancelled');
152
+ return;
153
+ }
154
+ try {
155
+ configManager.reset();
156
+ logger.success('Configuration reset to defaults');
157
+ logger.info('Run "hatchway init" to reconfigure');
158
+ }
159
+ catch (error) {
160
+ logger.error('Failed to reset configuration');
161
+ logger.error(error instanceof Error ? error.message : 'Unknown error');
162
+ process.exit(1);
163
+ }
164
+ }
165
+
166
+ export { configCommand };
167
+ //# sourceMappingURL=config-hFJA7z5y.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-hFJA7z5y.js","sources":["../../src/cli/commands/config.ts"],"sourcesContent":["import chalk from 'chalk';\nimport { logger } from '../utils/logger.js';\nimport { configManager } from '../utils/config-manager.js';\nimport { prompts } from '../utils/prompts.js';\n\nexport async function configCommand(action: string, key?: string, value?: string) {\n switch (action) {\n case 'get':\n if (!key) {\n logger.error('Key is required for get action');\n logger.info('Usage: hatchway config get <key>');\n process.exit(1);\n }\n handleGet(key);\n break;\n\n case 'set':\n if (!key || !value) {\n logger.error('Key and value are required for set action');\n logger.info('Usage: hatchway config set <key> <value>');\n process.exit(1);\n }\n handleSet(key, value);\n break;\n\n case 'list':\n handleList();\n break;\n\n case 'path':\n handlePath();\n break;\n\n case 'validate':\n handleValidate();\n break;\n\n case 'reset':\n await handleReset();\n break;\n\n default:\n logger.error(`Unknown action: ${action}`);\n logger.info('Available actions: get, set, list, path, validate, reset');\n process.exit(1);\n }\n}\n\nfunction handleGet(key: string) {\n try {\n const value = configManager.get(key as any);\n if (value === undefined) {\n logger.warn(`Key not found: ${key}`);\n process.exit(1);\n }\n\n if (typeof value === 'object') {\n logger.log(JSON.stringify(value, null, 2));\n } else {\n logger.log(String(value));\n }\n } catch (error) {\n logger.error('Failed to get config value');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n}\n\nfunction handleSet(key: string, value: string) {\n try {\n // Try to parse as JSON for objects/arrays\n let parsedValue: any = value;\n if (value.startsWith('{') || value.startsWith('[')) {\n try {\n parsedValue = JSON.parse(value);\n } catch {\n // Keep as string if not valid JSON\n }\n }\n\n configManager.set(key as any, parsedValue);\n logger.success(`Set ${chalk.cyan(key)} = ${chalk.green(value)}`);\n } catch (error) {\n logger.error('Failed to set config value');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n}\n\nfunction handleList() {\n const config = configManager.get();\n\n logger.section('Current Configuration');\n logger.log('');\n\n // Workspace\n logger.info(`${chalk.bold('Workspace:')}`);\n logger.log(` ${config.workspace}`);\n logger.log('');\n\n // API\n logger.info(`${chalk.bold('API:')}`);\n logger.log(` URL: ${config.apiUrl || 'not set'}`);\n logger.log('');\n\n // Broker\n logger.info(`${chalk.bold('Broker:')}`);\n logger.log(` WebSocket URL: ${config.broker?.url || 'not set'}`);\n logger.log(` HTTP URL: ${config.broker?.httpUrl || 'not set'}`);\n logger.log(` Secret: ${config.broker?.secret ? '***' : 'not set'}`);\n logger.log('');\n\n // Runner\n logger.info(`${chalk.bold('Runner:')}`);\n logger.log(` ID: ${config.runner?.id || 'not set'}`);\n logger.log(` Reconnect Attempts: ${config.runner?.reconnectAttempts || 5}`);\n logger.log(` Heartbeat Interval: ${config.runner?.heartbeatInterval || 15000}ms`);\n logger.log('');\n\n // Database\n if (config.databaseUrl) {\n logger.info(`${chalk.bold('Database:')}`);\n logger.log(` URL: ${config.databaseUrl.replace(/:[^:@]+@/, ':***@')}`); // Mask password\n logger.log('');\n }\n\n // Monorepo\n if (config.monorepoPath) {\n logger.info(`${chalk.bold('Monorepo:')}`);\n logger.log(` Path: ${config.monorepoPath}`);\n logger.log('');\n }\n\n // Tunnel\n if (config.tunnel) {\n logger.info(`${chalk.bold('Tunnel:')}`);\n logger.log(` Provider: ${config.tunnel.provider}`);\n logger.log(` Auto Create: ${config.tunnel.autoCreate}`);\n logger.log('');\n }\n}\n\nfunction handlePath() {\n logger.info(`Config file: ${chalk.cyan(configManager.path)}`);\n}\n\nfunction handleValidate() {\n const validation = configManager.validate();\n\n if (validation.valid) {\n logger.success('Configuration is valid');\n } else {\n logger.error('Configuration validation failed:');\n validation.errors.forEach((err) => logger.error(` - ${err}`));\n process.exit(1);\n }\n}\n\nasync function handleReset() {\n logger.warn('This will delete all configuration and reset to defaults');\n const confirmed = await prompts.confirm('Are you sure?', false);\n\n if (!confirmed) {\n logger.info('Reset cancelled');\n return;\n }\n\n try {\n configManager.reset();\n logger.success('Configuration reset to defaults');\n logger.info('Run \"hatchway init\" to reconfigure');\n } catch (error) {\n logger.error('Failed to reset configuration');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,133 @@
1
+ // Hatchway CLI - Built with Rollup
2
+ import Conf from 'conf';
3
+ import { homedir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { existsSync } from 'node:fs';
6
+
7
+ /**
8
+ * Config manager using conf library
9
+ * Handles platform-specific config locations
10
+ */
11
+ class ConfigManager {
12
+ constructor() {
13
+ this.conf = new Conf({
14
+ projectName: 'hatchway',
15
+ projectSuffix: '', // No suffix, just 'hatchway'
16
+ defaults: this.getDefaults(),
17
+ });
18
+ }
19
+ getDefaults() {
20
+ return {
21
+ version: '0.1.0',
22
+ workspace: join(homedir(), 'hatchway-workspace'),
23
+ apiUrl: 'http://localhost:3000', // Default API URL
24
+ server: {
25
+ wsUrl: 'ws://localhost:3000/ws/runner', // Direct WebSocket connection to Next.js
26
+ secret: 'dev-secret', // Default local secret
27
+ },
28
+ runner: {
29
+ id: 'local',
30
+ reconnectAttempts: 5,
31
+ heartbeatInterval: 15000,
32
+ },
33
+ tunnel: {
34
+ provider: 'cloudflare',
35
+ autoCreate: true,
36
+ },
37
+ };
38
+ }
39
+ get(key) {
40
+ if (!key) {
41
+ return this.conf.store;
42
+ }
43
+ return this.conf.get(key);
44
+ }
45
+ set(key, value) {
46
+ this.conf.set(key, value);
47
+ }
48
+ delete(key) {
49
+ this.conf.delete(key);
50
+ }
51
+ reset() {
52
+ this.conf.clear();
53
+ this.conf.store = this.getDefaults();
54
+ }
55
+ has(key) {
56
+ return this.conf.has(key);
57
+ }
58
+ get path() {
59
+ return this.conf.path;
60
+ }
61
+ validate() {
62
+ const errors = [];
63
+ const config = this.conf.store;
64
+ if (!config.workspace) {
65
+ errors.push('Workspace path is required');
66
+ }
67
+ // Check for server config (new) or legacy broker config
68
+ const hasServerConfig = config.server?.secret && config.server?.wsUrl;
69
+ const hasLegacyBrokerConfig = config.broker?.secret && config.broker?.url;
70
+ if (!hasServerConfig && !hasLegacyBrokerConfig) {
71
+ errors.push('Server shared secret is required');
72
+ errors.push('Server WebSocket URL is required');
73
+ }
74
+ if (!config.runner?.id) {
75
+ errors.push('Runner ID is required');
76
+ }
77
+ // Check if workspace exists
78
+ if (config.workspace && !existsSync(config.workspace)) {
79
+ errors.push(`Workspace directory does not exist: ${config.workspace}`);
80
+ }
81
+ return {
82
+ valid: errors.length === 0,
83
+ errors,
84
+ };
85
+ }
86
+ /**
87
+ * Check if config has been initialized properly
88
+ * Requires monorepo to be cloned and databaseUrl to be configured
89
+ */
90
+ isInitialized() {
91
+ const monorepoPath = this.get('monorepoPath');
92
+ const databaseUrl = this.get('databaseUrl');
93
+ // Must have monorepo path set and the directory must exist
94
+ if (!monorepoPath || !existsSync(monorepoPath)) {
95
+ return false;
96
+ }
97
+ // Must have database URL configured
98
+ if (!databaseUrl) {
99
+ return false;
100
+ }
101
+ return true;
102
+ }
103
+ /**
104
+ * Get the WebSocket URL (supports both new and legacy config)
105
+ */
106
+ getWsUrl() {
107
+ const server = this.get('server');
108
+ const broker = this.get('broker');
109
+ // Prefer new server config
110
+ if (server?.wsUrl) {
111
+ return server.wsUrl;
112
+ }
113
+ // Fall back to legacy broker URL
114
+ return broker?.url ?? 'ws://localhost:3000/ws/runner';
115
+ }
116
+ /**
117
+ * Get the shared secret (supports both new and legacy config)
118
+ */
119
+ getSecret() {
120
+ const server = this.get('server');
121
+ const broker = this.get('broker');
122
+ // Prefer new server config
123
+ if (server?.secret) {
124
+ return server.secret;
125
+ }
126
+ // Fall back to legacy broker secret
127
+ return broker?.secret ?? '';
128
+ }
129
+ }
130
+ const configManager = new ConfigManager();
131
+
132
+ export { configManager as c };
133
+ //# sourceMappingURL=config-manager-DST6RbP8.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-manager-DST6RbP8.js","sources":["../../src/cli/utils/config-manager.ts"],"sourcesContent":["import Conf from 'conf';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { existsSync } from 'node:fs';\n\n// Theme names for the TUI\nexport type ThemeName = 'sentry' | 'ocean' | 'ember' | 'forest' | 'noir';\n\nexport interface RunnerConfig {\n version: string;\n workspace: string;\n monorepoPath?: string; // Path to cloned hatchway repository\n databaseUrl?: string; // PostgreSQL connection string\n apiUrl?: string; // API base URL (e.g., http://localhost:3000)\n autoUpdate?: boolean; // Enable automatic CLI updates (default: true)\n // Server connection config (formerly \"broker\" - now connects directly to Next.js)\n server: {\n wsUrl: string; // WebSocket URL (e.g., ws://localhost:3000/ws/runner)\n secret: string;\n };\n // Legacy broker config for backward compatibility\n broker?: {\n url: string;\n httpUrl?: string;\n secret: string;\n };\n runner: {\n id: string; // This runner's ID and default ID for web app in local mode\n lastRunnerId?: string; // Last used runner ID (for runner mode)\n reconnectAttempts?: number;\n heartbeatInterval?: number;\n };\n tunnel?: {\n provider: 'cloudflare';\n autoCreate: boolean;\n };\n // TUI preferences\n ui?: {\n theme: ThemeName;\n };\n}\n\n/**\n * Config manager using conf library\n * Handles platform-specific config locations\n */\nexport class ConfigManager {\n private conf: Conf<RunnerConfig>;\n\n constructor() {\n this.conf = new Conf<RunnerConfig>({\n projectName: 'hatchway',\n projectSuffix: '', // No suffix, just 'hatchway'\n defaults: this.getDefaults(),\n });\n }\n\n private getDefaults(): RunnerConfig {\n return {\n version: '0.1.0',\n workspace: join(homedir(), 'hatchway-workspace'),\n apiUrl: 'http://localhost:3000', // Default API URL\n server: {\n wsUrl: 'ws://localhost:3000/ws/runner', // Direct WebSocket connection to Next.js\n secret: 'dev-secret', // Default local secret\n },\n runner: {\n id: 'local',\n reconnectAttempts: 5,\n heartbeatInterval: 15000,\n },\n tunnel: {\n provider: 'cloudflare',\n autoCreate: true,\n },\n };\n }\n\n get(key?: keyof RunnerConfig): any {\n if (!key) {\n return this.conf.store;\n }\n return this.conf.get(key);\n }\n\n set(key: keyof RunnerConfig | string, value: any): void {\n this.conf.set(key as any, value);\n }\n\n delete(key: keyof RunnerConfig): void {\n this.conf.delete(key);\n }\n\n reset(): void {\n this.conf.clear();\n this.conf.store = this.getDefaults();\n }\n\n has(key: keyof RunnerConfig): boolean {\n return this.conf.has(key);\n }\n\n get path(): string {\n return this.conf.path;\n }\n\n validate(): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n const config = this.conf.store;\n\n if (!config.workspace) {\n errors.push('Workspace path is required');\n }\n\n // Check for server config (new) or legacy broker config\n const hasServerConfig = config.server?.secret && config.server?.wsUrl;\n const hasLegacyBrokerConfig = config.broker?.secret && config.broker?.url;\n \n if (!hasServerConfig && !hasLegacyBrokerConfig) {\n errors.push('Server shared secret is required');\n errors.push('Server WebSocket URL is required');\n }\n\n if (!config.runner?.id) {\n errors.push('Runner ID is required');\n }\n\n // Check if workspace exists\n if (config.workspace && !existsSync(config.workspace)) {\n errors.push(`Workspace directory does not exist: ${config.workspace}`);\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n }\n\n /**\n * Check if config has been initialized properly\n * Requires monorepo to be cloned and databaseUrl to be configured\n */\n isInitialized(): boolean {\n const monorepoPath = this.get('monorepoPath');\n const databaseUrl = this.get('databaseUrl');\n \n // Must have monorepo path set and the directory must exist\n if (!monorepoPath || !existsSync(monorepoPath)) {\n return false;\n }\n \n // Must have database URL configured\n if (!databaseUrl) {\n return false;\n }\n \n return true;\n }\n \n /**\n * Get the WebSocket URL (supports both new and legacy config)\n */\n getWsUrl(): string {\n const server = this.get('server');\n const broker = this.get('broker');\n \n // Prefer new server config\n if (server?.wsUrl) {\n return server.wsUrl;\n }\n \n // Fall back to legacy broker URL\n return broker?.url ?? 'ws://localhost:3000/ws/runner';\n }\n \n /**\n * Get the shared secret (supports both new and legacy config)\n */\n getSecret(): string {\n const server = this.get('server');\n const broker = this.get('broker');\n \n // Prefer new server config\n if (server?.secret) {\n return server.secret;\n }\n \n // Fall back to legacy broker secret\n return broker?.secret ?? '';\n }\n}\n\nexport const configManager = new ConfigManager();\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ // Hatchway CLI - Built with Rollup
2
+ import chalk from 'chalk';
3
+ import { l as logger } from './logger-6V5cBxba.js';
4
+ import { c as configManager } from './config-manager-DST6RbP8.js';
5
+ import { s as setupDatabase, p as pushDatabaseSchema } from './database-setup-U31oEs90.js';
6
+ import 'conf';
7
+ import 'node:os';
8
+ import 'node:path';
9
+ import 'node:fs';
10
+ import 'node:child_process';
11
+ import 'node:fs/promises';
12
+ import './spinner-DTH0QZQw.js';
13
+ import 'ora';
14
+ import './prompts-Beijr8dm.js';
15
+ import 'inquirer';
16
+
17
+ async function databaseCommand() {
18
+ logger.section('Database Setup');
19
+ logger.log('');
20
+ // Check if monorepo is configured
21
+ const config = configManager.get();
22
+ const monorepoPath = config.monorepoPath;
23
+ if (!monorepoPath) {
24
+ logger.error('Monorepo path not found in config');
25
+ logger.info('Run "hatchway init" first to set up the repository');
26
+ process.exit(1);
27
+ }
28
+ // Step 1: Setup new database
29
+ logger.info('Setting up new Neon PostgreSQL database...');
30
+ logger.log('');
31
+ const databaseUrl = await setupDatabase(monorepoPath);
32
+ if (!databaseUrl) {
33
+ logger.error('Failed to create database');
34
+ logger.log('');
35
+ logger.info('You can manually set a database URL with:');
36
+ logger.log(` ${chalk.cyan('hatchway config set databaseUrl <url>')}`);
37
+ process.exit(1);
38
+ }
39
+ logger.log('');
40
+ logger.success('Database created!');
41
+ logger.info(`Connection string saved to config`);
42
+ logger.log('');
43
+ // Save to config
44
+ configManager.set('databaseUrl', databaseUrl);
45
+ // Step 2: Push schema
46
+ logger.info('Initializing database schema...');
47
+ logger.log('');
48
+ const pushed = await pushDatabaseSchema(monorepoPath, databaseUrl);
49
+ if (!pushed) {
50
+ logger.warn('Failed to push database schema');
51
+ logger.log('');
52
+ logger.info('You can try manually:');
53
+ logger.log(` ${chalk.cyan('cd apps/hatchway')}`);
54
+ logger.log(` ${chalk.cyan('npx drizzle-kit push --config=drizzle.config.ts')}`);
55
+ logger.log('');
56
+ process.exit(1);
57
+ }
58
+ // Success!
59
+ logger.log('');
60
+ logger.success('Database setup complete! 🎉');
61
+ logger.log('');
62
+ logger.info('Database is ready for use');
63
+ logger.info(`You can now run: ${chalk.cyan('hatchway run')}`);
64
+ logger.log('');
65
+ }
66
+
67
+ export { databaseCommand };
68
+ //# sourceMappingURL=database-YGb1Lzim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database-YGb1Lzim.js","sources":["../../src/cli/commands/database.ts"],"sourcesContent":["import chalk from 'chalk';\nimport { logger } from '../utils/logger.js';\nimport { configManager } from '../utils/config-manager.js';\nimport { setupDatabase, pushDatabaseSchema } from '../utils/database-setup.js';\nimport { prompts } from '../utils/prompts.js';\n\nexport async function databaseCommand() {\n logger.section('Database Setup');\n logger.log('');\n\n // Check if monorepo is configured\n const config = configManager.get();\n const monorepoPath = config.monorepoPath;\n\n if (!monorepoPath) {\n logger.error('Monorepo path not found in config');\n logger.info('Run \"hatchway init\" first to set up the repository');\n process.exit(1);\n }\n\n // Step 1: Setup new database\n logger.info('Setting up new Neon PostgreSQL database...');\n logger.log('');\n\n const databaseUrl = await setupDatabase(monorepoPath);\n\n if (!databaseUrl) {\n logger.error('Failed to create database');\n logger.log('');\n logger.info('You can manually set a database URL with:');\n logger.log(` ${chalk.cyan('hatchway config set databaseUrl <url>')}`);\n process.exit(1);\n }\n\n logger.log('');\n logger.success('Database created!');\n logger.info(`Connection string saved to config`);\n logger.log('');\n\n // Save to config\n configManager.set('databaseUrl', databaseUrl);\n\n // Step 2: Push schema\n logger.info('Initializing database schema...');\n logger.log('');\n\n const pushed = await pushDatabaseSchema(monorepoPath, databaseUrl);\n\n if (!pushed) {\n logger.warn('Failed to push database schema');\n logger.log('');\n logger.info('You can try manually:');\n logger.log(` ${chalk.cyan('cd apps/hatchway')}`);\n logger.log(` ${chalk.cyan('npx drizzle-kit push --config=drizzle.config.ts')}`);\n logger.log('');\n process.exit(1);\n }\n\n // Success!\n logger.log('');\n logger.success('Database setup complete! 🎉');\n logger.log('');\n logger.info('Database is ready for use');\n logger.info(`You can now run: ${chalk.cyan('hatchway run')}`);\n logger.log('');\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAMO,eAAe,eAAe,GAAA;AACnC,IAAA,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC;AAChC,IAAA,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;;AAGd,IAAA,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,EAAE;AAClC,IAAA,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY;IAExC,IAAI,CAAC,YAAY,EAAE;AACjB,QAAA,MAAM,CAAC,KAAK,CAAC,mCAAmC,CAAC;AACjD,QAAA,MAAM,CAAC,IAAI,CAAC,oDAAoD,CAAC;AACjE,QAAA,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACjB;;AAGA,IAAA,MAAM,CAAC,IAAI,CAAC,4CAA4C,CAAC;AACzD,IAAA,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;AAEd,IAAA,MAAM,WAAW,GAAG,MAAM,aAAa,CAAC,YAAY,CAAC;IAErD,IAAI,CAAC,WAAW,EAAE;AAChB,QAAA,MAAM,CAAC,KAAK,CAAC,2BAA2B,CAAC;AACzC,QAAA,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;AACd,QAAA,MAAM,CAAC,IAAI,CAAC,2CAA2C,CAAC;AACxD,QAAA,MAAM,CAAC,GAAG,CAAC,CAAA,EAAA,EAAK,KAAK,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAA,CAAE,CAAC;AACtE,QAAA,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACjB;AAEA,IAAA,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;AACd,IAAA,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC;AACnC,IAAA,MAAM,CAAC,IAAI,CAAC,CAAA,iCAAA,CAAmC,CAAC;AAChD,IAAA,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;;AAGd,IAAA,aAAa,CAAC,GAAG,CAAC,aAAa,EAAE,WAAW,CAAC;;AAG7C,IAAA,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC;AAC9C,IAAA,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IAEd,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,YAAY,EAAE,WAAW,CAAC;IAElE,IAAI,CAAC,MAAM,EAAE;AACX,QAAA,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC;AAC7C,QAAA,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;AACd,QAAA,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC;AACpC,QAAA,MAAM,CAAC,GAAG,CAAC,CAAA,EAAA,EAAK,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA,CAAE,CAAC;AACjD,QAAA,MAAM,CAAC,GAAG,CAAC,CAAA,EAAA,EAAK,KAAK,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAA,CAAE,CAAC;AAChF,QAAA,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;AACd,QAAA,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACjB;;AAGA,IAAA,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;AACd,IAAA,MAAM,CAAC,OAAO,CAAC,6BAA6B,CAAC;AAC7C,IAAA,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;AACd,IAAA,MAAM,CAAC,IAAI,CAAC,2BAA2B,CAAC;AACxC,IAAA,MAAM,CAAC,IAAI,CAAC,CAAA,iBAAA,EAAoB,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA,CAAE,CAAC;AAC7D,IAAA,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;AAChB;;;;"}
@@ -0,0 +1,253 @@
1
+ // Hatchway CLI - Built with Rollup
2
+ import { spawn, execFileSync } from 'node:child_process';
3
+ import { readFile, writeFile } from 'node:fs/promises';
4
+ import { existsSync } from 'node:fs';
5
+ import { join } from 'node:path';
6
+ import { l as logger } from './logger-6V5cBxba.js';
7
+ import { s as spinner } from './spinner-DTH0QZQw.js';
8
+ import { p as prompts } from './prompts-Beijr8dm.js';
9
+
10
+ /**
11
+ * Read DATABASE_URL from .env file in monorepo root
12
+ */
13
+ async function readDatabaseUrlFromEnv(monorepoPath) {
14
+ const envPath = join(monorepoPath, '.env');
15
+ if (!existsSync(envPath)) {
16
+ return null;
17
+ }
18
+ try {
19
+ const content = await readFile(envPath, 'utf-8');
20
+ const match = content.match(/^DATABASE_URL\s*=\s*['"]?([^'"\n]+)['"]?/m);
21
+ return match ? match[1] : null;
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ }
27
+ /**
28
+ * Clear DATABASE_URL from .env file (removes stale value)
29
+ */
30
+ async function clearDatabaseUrlFromEnv(monorepoPath) {
31
+ const envPath = join(monorepoPath, '.env');
32
+ if (!existsSync(envPath)) {
33
+ return;
34
+ }
35
+ try {
36
+ const content = await readFile(envPath, 'utf-8');
37
+ const updated = content
38
+ .split('\n')
39
+ .filter(line => !line.trim().startsWith('DATABASE_URL'))
40
+ .join('\n');
41
+ await writeFile(envPath, updated, 'utf-8');
42
+ }
43
+ catch (error) {
44
+ logger.warn('Could not clear DATABASE_URL from .env');
45
+ }
46
+ }
47
+ /**
48
+ * Run neondb setup to create a database and get the connection string
49
+ * Returns the DATABASE_URL if successful
50
+ */
51
+ async function setupDatabase(monorepoPath, silent = false) {
52
+ // Clear any stale DATABASE_URL first
53
+ await clearDatabaseUrlFromEnv(monorepoPath);
54
+ if (!silent) {
55
+ spinner.start('Setting up Neon PostgreSQL database...');
56
+ }
57
+ return new Promise((resolve) => {
58
+ const proc = spawn('npx', ['neondb', '-y'], {
59
+ cwd: monorepoPath, // Run in monorepo root so .env is created there
60
+ stdio: ['ignore', 'pipe', 'pipe'],
61
+ shell: true,
62
+ });
63
+ let databaseUrl = null;
64
+ proc.stdout?.on('data', (data) => {
65
+ const text = data.toString();
66
+ // Look for DATABASE_URL in the output
67
+ const match = text.match(/DATABASE_URL[=:]?\s*['"]?([^'"\s]+)['"]?/);
68
+ if (match && match[1]) {
69
+ databaseUrl = match[1];
70
+ }
71
+ // Also check for postgres:// connection strings
72
+ const connMatch = text.match(/(postgres(?:ql)?:\/\/[^\s'"]+)/);
73
+ if (connMatch && connMatch[1]) {
74
+ databaseUrl = connMatch[1];
75
+ }
76
+ });
77
+ proc.stderr?.on('data', (data) => {
78
+ const text = data.toString();
79
+ // Only log actual errors (and only if not silent)
80
+ if (!silent && (text.includes('error') || text.includes('Error'))) {
81
+ logger.debug(text.trim());
82
+ }
83
+ });
84
+ proc.on('exit', async (code) => {
85
+ if (code === 0) {
86
+ // Try to read DATABASE_URL from .env file (neondb writes it there)
87
+ const urlFromEnv = await readDatabaseUrlFromEnv(monorepoPath);
88
+ if (urlFromEnv) {
89
+ databaseUrl = urlFromEnv;
90
+ if (!silent) {
91
+ spinner.succeed('Database created successfully');
92
+ }
93
+ resolve(databaseUrl);
94
+ }
95
+ else if (databaseUrl) {
96
+ // Fallback to what we parsed from output
97
+ if (!silent) {
98
+ spinner.succeed('Database created successfully');
99
+ }
100
+ resolve(databaseUrl);
101
+ }
102
+ else {
103
+ if (!silent) {
104
+ spinner.warn('Database command completed but DATABASE_URL not found');
105
+ logger.info('Check .env file in monorepo root for DATABASE_URL');
106
+ }
107
+ resolve(null);
108
+ }
109
+ }
110
+ else {
111
+ if (!silent) {
112
+ spinner.fail('Failed to create database');
113
+ }
114
+ resolve(null);
115
+ }
116
+ });
117
+ proc.on('error', (error) => {
118
+ if (!silent) {
119
+ spinner.fail('Failed to run neondb');
120
+ logger.error(`Error: ${error.message}`);
121
+ }
122
+ resolve(null);
123
+ });
124
+ });
125
+ }
126
+ /**
127
+ * Push database schema using drizzle-kit
128
+ */
129
+ async function pushDatabaseSchema(monorepoPath, databaseUrl, silent = false) {
130
+ const { join } = await import('path');
131
+ const { existsSync } = await import('fs');
132
+ const hatchwayAppPath = join(monorepoPath, 'apps/hatchway');
133
+ const configPath = join(hatchwayAppPath, 'drizzle.config.ts');
134
+ // Verify paths exist
135
+ if (!existsSync(hatchwayAppPath)) {
136
+ if (!silent) {
137
+ logger.error(`Directory not found: ${hatchwayAppPath}`);
138
+ }
139
+ return false;
140
+ }
141
+ if (!existsSync(configPath)) {
142
+ if (!silent) {
143
+ logger.error(`Drizzle config not found: ${configPath}`);
144
+ }
145
+ return false;
146
+ }
147
+ if (!silent) {
148
+ spinner.start('Ensuring hatchway dependencies are installed...');
149
+ }
150
+ try {
151
+ execFileSync('pnpm', ['install'], {
152
+ cwd: hatchwayAppPath,
153
+ stdio: 'pipe',
154
+ });
155
+ execFileSync('pnpm', ['--filter', '@hatchway/agent-core', 'build'], {
156
+ cwd: monorepoPath,
157
+ stdio: 'pipe',
158
+ });
159
+ if (!silent) {
160
+ spinner.succeed('Dependencies ready');
161
+ }
162
+ }
163
+ catch (error) {
164
+ if (!silent) {
165
+ spinner.warn('Dependency installation failed, trying schema push anyway');
166
+ }
167
+ }
168
+ if (!silent) {
169
+ spinner.start('Initializing database schema (this may take a moment)...');
170
+ }
171
+ return new Promise((resolve) => {
172
+ const proc = spawn('npx', ['drizzle-kit', 'push', '--config=drizzle.config.ts'], {
173
+ cwd: hatchwayAppPath,
174
+ stdio: ['ignore', 'pipe', 'pipe'],
175
+ shell: true,
176
+ env: {
177
+ ...process.env,
178
+ DATABASE_URL: databaseUrl, // Ensure drizzle-kit has access
179
+ },
180
+ });
181
+ let allOutput = '';
182
+ // Capture all output for debugging
183
+ proc.stdout?.on('data', (data) => {
184
+ allOutput += data.toString();
185
+ });
186
+ proc.stderr?.on('data', (data) => {
187
+ allOutput += data.toString();
188
+ });
189
+ proc.on('exit', (code) => {
190
+ if (code === 0) {
191
+ if (!silent) {
192
+ spinner.succeed('Database schema initialized successfully');
193
+ }
194
+ resolve(true);
195
+ }
196
+ else {
197
+ if (!silent) {
198
+ spinner.fail('Failed to push database schema');
199
+ // Show all output when it fails so user can see what went wrong
200
+ if (allOutput.trim()) {
201
+ logger.log(''); // Blank line
202
+ logger.log('Output from drizzle-kit push:');
203
+ logger.log(allOutput.trim());
204
+ logger.log(''); // Blank line
205
+ }
206
+ }
207
+ resolve(false);
208
+ }
209
+ });
210
+ proc.on('error', (error) => {
211
+ if (!silent) {
212
+ spinner.fail('Failed to run drizzle-kit');
213
+ logger.error(`Error: ${error.message}`);
214
+ }
215
+ resolve(false);
216
+ });
217
+ });
218
+ }
219
+ /**
220
+ * Connect to an existing database manually by prompting for connection string
221
+ */
222
+ async function connectManualDatabase() {
223
+ logger.log('');
224
+ // Ask user what type of connection they want
225
+ const connectionType = await prompts.select('How would you like to connect your database?', [
226
+ 'Connect an existing Hatchway database',
227
+ 'Provide a connection string directly',
228
+ ]);
229
+ logger.log('');
230
+ // Prompt for the connection string
231
+ let message;
232
+ if (connectionType === 'Connect an existing Hatchway database') {
233
+ message = 'Enter your Hatchway database connection string:';
234
+ }
235
+ else {
236
+ message = 'Enter your PostgreSQL connection string:';
237
+ }
238
+ const connectionString = await prompts.input(message);
239
+ // Basic validation
240
+ if (!connectionString || connectionString.trim() === '') {
241
+ logger.error('Connection string cannot be empty');
242
+ return null;
243
+ }
244
+ // Validate it looks like a PostgreSQL connection string
245
+ if (!connectionString.match(/^postgres(?:ql)?:\/\//)) {
246
+ logger.error('Connection string must start with postgres:// or postgresql://');
247
+ return null;
248
+ }
249
+ return connectionString.trim();
250
+ }
251
+
252
+ export { connectManualDatabase as c, pushDatabaseSchema as p, setupDatabase as s };
253
+ //# sourceMappingURL=database-setup-U31oEs90.js.map