@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
package/README.md ADDED
@@ -0,0 +1,274 @@
1
+ # Hatchway CLI
2
+
3
+ The Hatchway CLI connects your local machine to [Hatchway](https://hatchway.sh) to build AI-powered applications. It handles code generation, dev servers, and live previews - all running on your machine.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Run directly with npx (no install needed)
9
+ npx @hatchway/cli runner
10
+
11
+ # Or install globally
12
+ npm install -g @hatchway/cli
13
+ hatchway runner
14
+ ```
15
+
16
+ That's it! The CLI will:
17
+ 1. Open your browser to authenticate (GitHub or Sentry SSO)
18
+ 2. Automatically generate and store your runner token
19
+ 3. Connect to hatchway.sh and start listening for builds
20
+
21
+ ## Installation Options
22
+
23
+ ### npx (Recommended)
24
+ No installation needed - always uses the latest version:
25
+ ```bash
26
+ npx @hatchway/cli runner
27
+ ```
28
+
29
+ ### Global Install
30
+ ```bash
31
+ npm install -g @hatchway/cli
32
+ hatchway runner
33
+ ```
34
+
35
+ ### Curl Install Script
36
+ ```bash
37
+ curl -fsSL https://hatchway.sh/install | bash
38
+ hatchway runner
39
+ ```
40
+
41
+ ## Usage
42
+
43
+ ### Connect to Hatchway SaaS
44
+
45
+ ```bash
46
+ # Start the runner (auto-authenticates via browser)
47
+ npx @hatchway/cli runner
48
+
49
+ # Or if installed globally
50
+ hatchway runner
51
+ ```
52
+
53
+ On first run, your browser will open for authentication. After logging in, the CLI automatically:
54
+ - Creates a secure runner token
55
+ - Stores it locally for future sessions
56
+ - Connects to hatchway.sh
57
+
58
+ ### Interactive TUI Mode
59
+
60
+ ```bash
61
+ npx @hatchway/cli
62
+ # or
63
+ hatchway
64
+ ```
65
+
66
+ This opens an interactive menu where you can:
67
+ - **Runner Mode** - Connect to hatchway.sh (SaaS)
68
+ - **Local Mode** - Run everything locally (self-hosted)
69
+
70
+ ### Local Mode (Self-Hosted)
71
+
72
+ Run the entire Hatchway stack locally:
73
+
74
+ ```bash
75
+ hatchway run
76
+ ```
77
+
78
+ This starts:
79
+ - Web App on `http://localhost:3000`
80
+ - Runner connected to local web app
81
+
82
+ ## Keyboard Shortcuts
83
+
84
+ When the runner is connected, use these shortcuts:
85
+
86
+ | Key | Action |
87
+ |-----|--------|
88
+ | `b` | Open Hatchway in browser |
89
+ | `r` | Restart runner connection |
90
+ | `q` | Quit the runner |
91
+
92
+ ## Configuration
93
+
94
+ Configuration is stored at:
95
+ - **macOS**: `~/Library/Application Support/hatchway/config.json`
96
+ - **Linux**: `~/.config/hatchway/config.json`
97
+
98
+ ### View Configuration
99
+
100
+ ```bash
101
+ hatchway status
102
+ hatchway config list
103
+ ```
104
+
105
+ ### Change Workspace
106
+
107
+ Projects are stored in `~/hatchway-projects/` by default:
108
+
109
+ ```bash
110
+ hatchway config set workspace ~/my-projects
111
+ ```
112
+
113
+ ### CLI Options
114
+
115
+ Override settings via command-line:
116
+
117
+ ```bash
118
+ hatchway runner \
119
+ --workspace ~/custom-projects \
120
+ --runner-id my-macbook
121
+ ```
122
+
123
+ ## Commands Reference
124
+
125
+ | Command | Description |
126
+ |---------|-------------|
127
+ | `hatchway` | Launch interactive TUI |
128
+ | `hatchway runner` | Connect to hatchway.sh |
129
+ | `hatchway run` | Start local mode (self-hosted) |
130
+ | `hatchway login` | Authenticate with hatchway.sh |
131
+ | `hatchway logout` | Clear stored credentials |
132
+ | `hatchway status` | Show runner status |
133
+ | `hatchway config list` | View all settings |
134
+ | `hatchway config set <key> <value>` | Update a setting |
135
+ | `hatchway config reset` | Reset to defaults |
136
+ | `hatchway cleanup --all` | Remove all projects |
137
+ | `hatchway upgrade` | Upgrade to latest version |
138
+
139
+ ## How It Works
140
+
141
+ ```
142
+ ┌─────────────────────┐ ┌─────────────────┐
143
+ │ hatchway.sh │◀──────▶│ Runner CLI │
144
+ │ (Web Interface) │ WSS │ (Your Machine) │
145
+ └─────────────────────┘ └────────┬────────┘
146
+
147
+
148
+ ┌─────────────────┐
149
+ │ AI Backend │
150
+ │ (Claude Code) │
151
+ └─────────────────┘
152
+ ```
153
+
154
+ 1. You create a project at hatchway.sh
155
+ 2. The web app sends build commands to your runner via WebSocket
156
+ 3. Your runner executes the AI agent (Claude Code) locally
157
+ 4. Generated code is saved to your workspace
158
+ 5. Runner starts dev server and creates a Cloudflare tunnel for preview
159
+
160
+ ## Prerequisites
161
+
162
+ - **Node.js 18+** - [Download](https://nodejs.org/)
163
+ - **Claude CLI** - For AI code generation
164
+ ```bash
165
+ # Install Claude CLI
166
+ npm install -g @anthropic-ai/claude-cli
167
+ claude auth login
168
+ ```
169
+
170
+ ## Troubleshooting
171
+
172
+ ### "Runner not authenticated"
173
+
174
+ The OAuth flow didn't complete. Try:
175
+ ```bash
176
+ hatchway login
177
+ ```
178
+
179
+ ### "Cannot connect to server"
180
+
181
+ Check your internet connection and runner status:
182
+ ```bash
183
+ hatchway status
184
+ ```
185
+
186
+ ### Browser doesn't open for auth
187
+
188
+ Manually visit the URL shown in the terminal, or:
189
+ ```bash
190
+ hatchway login
191
+ ```
192
+
193
+ ### Projects not appearing
194
+
195
+ Ensure you're connected to the same account:
196
+ ```bash
197
+ hatchway status # Shows connected account
198
+ ```
199
+
200
+ ### Reset everything
201
+
202
+ ```bash
203
+ hatchway logout
204
+ hatchway config reset
205
+ hatchway cleanup --all
206
+ hatchway runner # Re-authenticate
207
+ ```
208
+
209
+ ## FAQ
210
+
211
+ **Q: Do I need an API key?**
212
+ A: No! Authentication is handled via OAuth (GitHub or Sentry SSO). The CLI automatically manages tokens.
213
+
214
+ **Q: Where are my projects stored?**
215
+ A: In `~/hatchway-projects/` by default. Check with `hatchway config get workspace`.
216
+
217
+ **Q: Can I run multiple runners?**
218
+ A: Yes! Each runner gets a unique ID. Run on different machines or use `--runner-id`:
219
+ ```bash
220
+ hatchway runner --runner-id work-laptop
221
+ hatchway runner --runner-id home-desktop
222
+ ```
223
+
224
+ **Q: Does the runner need to stay running?**
225
+ A: Yes, while you're using hatchway.sh. It executes builds and serves previews.
226
+
227
+ **Q: Can I use a different AI model?**
228
+ A: Yes! Select your preferred Claude model using the `@model` tag in the web UI:
229
+ - `claude-haiku-4-5` (fast)
230
+ - `claude-sonnet-4-5` (balanced)
231
+ - `claude-opus-4-5` (most capable)
232
+
233
+ **Q: How do I update the CLI?**
234
+ A:
235
+ ```bash
236
+ # If using npx, it auto-updates
237
+ npx @hatchway/cli runner
238
+
239
+ # If installed globally
240
+ npm update -g @hatchway/cli
241
+ # or
242
+ hatchway upgrade
243
+ ```
244
+
245
+ **Q: How do I uninstall?**
246
+ A:
247
+ ```bash
248
+ hatchway cleanup --all
249
+ npm uninstall -g @hatchway/cli
250
+ rm -rf ~/Library/Application\ Support/hatchway # macOS
251
+ rm -rf ~/.config/hatchway # Linux
252
+ ```
253
+
254
+ ## Development
255
+
256
+ See the main [Hatchway repository](https://github.com/codyde/hatchway) for development instructions.
257
+
258
+ ```bash
259
+ # Clone and setup
260
+ git clone https://github.com/codyde/hatchway.git
261
+ cd hatchway
262
+ pnpm install
263
+
264
+ # Build the CLI
265
+ cd apps/runner
266
+ pnpm run build
267
+
268
+ # Test locally
269
+ node dist/cli/index.js runner
270
+ ```
271
+
272
+ ## License
273
+
274
+ MIT
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawn } from 'child_process';
4
+ import { fileURLToPath } from 'url';
5
+ import { dirname, resolve } from 'path';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+
10
+ // Paths relative to this bin script
11
+ const instrumentPath = resolve(__dirname, '../dist/instrument.js');
12
+ const cliPath = resolve(__dirname, '../dist/cli/index.js');
13
+
14
+ // Spawn node with --import flag for proper ESM instrumentation
15
+ const child = spawn(
16
+ process.execPath, // Use the same Node.js binary
17
+ ['--import', instrumentPath, cliPath, ...process.argv.slice(2)],
18
+ {
19
+ stdio: 'inherit',
20
+ env: process.env,
21
+ }
22
+ );
23
+
24
+ child.on('close', (code) => {
25
+ process.exit(code ?? 0);
26
+ });
27
+
28
+ child.on('error', (err) => {
29
+ console.error('Failed to start CLI:', err);
30
+ process.exit(1);
31
+ });
@@ -0,0 +1,115 @@
1
+ // Hatchway CLI - Built with Rollup
2
+ import { execSync } from 'node:child_process';
3
+ import { existsSync, readFileSync } from 'node:fs';
4
+ import { join, dirname } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { j as jsxRuntimeExports, B as Box, T as Text, c as colors } from './theme-NAQBkisB.js';
7
+ import 'node:stream';
8
+ import 'node:process';
9
+ import 'chalk';
10
+ import 'node:events';
11
+
12
+ /**
13
+ * Version and git commit info utilities
14
+ */
15
+ const __filename$1 = fileURLToPath(import.meta.url);
16
+ const __dirname$1 = dirname(__filename$1);
17
+ /**
18
+ * Find the package root directory (apps/runner).
19
+ * Works in both development (src/cli/utils/) and production (dist/cli/utils/) modes.
20
+ */
21
+ function findPackageRoot() {
22
+ // Try multiple possible locations
23
+ const possiblePaths = [
24
+ // Development: src/cli/utils/ -> apps/runner (3 levels up)
25
+ join(__dirname$1, '..', '..', '..'),
26
+ // Production from dist/cli/utils/: -> apps/runner (3 levels up, same structure)
27
+ join(__dirname$1, '..', '..', '..'),
28
+ ];
29
+ for (const path of possiblePaths) {
30
+ const packageJsonPath = join(path, 'package.json');
31
+ if (existsSync(packageJsonPath)) {
32
+ try {
33
+ const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
34
+ // Verify this is the runner package
35
+ if (pkg.name === '@hatchway/cli') {
36
+ return path;
37
+ }
38
+ }
39
+ catch {
40
+ // Continue to next path
41
+ }
42
+ }
43
+ }
44
+ // Fallback to the standard path
45
+ return join(__dirname$1, '..', '..', '..');
46
+ }
47
+ // Cache the package root
48
+ const packageRoot = findPackageRoot();
49
+ /**
50
+ * Get the package version from package.json
51
+ */
52
+ function getPackageVersion() {
53
+ try {
54
+ const packageJsonPath = join(packageRoot, 'package.json');
55
+ if (existsSync(packageJsonPath)) {
56
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
57
+ return packageJson.version || '0.0.0';
58
+ }
59
+ }
60
+ catch {
61
+ // Ignore errors
62
+ }
63
+ return '0.0.0';
64
+ }
65
+ /**
66
+ * Get the short git commit hash
67
+ */
68
+ function getGitCommit() {
69
+ try {
70
+ // Try to get commit from git command
71
+ const commit = execSync('git rev-parse --short HEAD', {
72
+ cwd: packageRoot,
73
+ encoding: 'utf-8',
74
+ stdio: ['pipe', 'pipe', 'pipe'],
75
+ }).trim();
76
+ return commit || null;
77
+ }
78
+ catch {
79
+ // Git not available or not a git repo
80
+ return null;
81
+ }
82
+ }
83
+ /**
84
+ * Get all version info
85
+ */
86
+ function getVersionInfo() {
87
+ const version = getPackageVersion();
88
+ const commit = getGitCommit();
89
+ return {
90
+ version,
91
+ commit,
92
+ display: commit ? `v${version} (${commit})` : `v${version}`,
93
+ };
94
+ }
95
+
96
+ /**
97
+ * ASCII art banner component - centered with cyan/purple gradient
98
+ * Each line is padded to exactly the same width for perfect alignment
99
+ */
100
+ function Banner() {
101
+ // Full banner lines - HATCH in cyan, WAY in purple
102
+ // All lines padded to same total width for consistent centering
103
+ const lines = [
104
+ { hatch: '██╗ ██╗ █████╗ ████████╗ ██████╗██╗ ██╗', way: '██╗ ██╗ █████╗ ██╗ ██╗' },
105
+ { hatch: '██║ ██║██╔══██╗╚══██╔══╝██╔════╝██║ ██║', way: '██║ ██║██╔══██╗╚██╗ ██╔╝' },
106
+ { hatch: '███████║███████║ ██║ ██║ ███████║', way: '██║ █╗ ██║███████║ ╚████╔╝ ' },
107
+ { hatch: '██╔══██║██╔══██║ ██║ ██║ ██╔══██║', way: '██║███╗██║██╔══██║ ╚██╔╝ ' },
108
+ { hatch: '██║ ██║██║ ██║ ██║ ╚██████╗██║ ██║', way: '╚███╔███╔╝██║ ██║ ██║ ' },
109
+ { hatch: '╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝', way: ' ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝ ' },
110
+ ];
111
+ return (jsxRuntimeExports.jsx(Box, { flexDirection: "column", alignItems: "center", children: lines.map((line, index) => (jsxRuntimeExports.jsxs(Box, { children: [jsxRuntimeExports.jsx(Text, { color: colors.cyan, children: line.hatch }), jsxRuntimeExports.jsx(Text, { color: colors.brightPurple, children: line.way })] }, index))) }));
112
+ }
113
+
114
+ export { Banner as B, getVersionInfo as g };
115
+ //# sourceMappingURL=Banner-DL1Fpz_g.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Banner-DL1Fpz_g.js","sources":["../../src/cli/utils/version-info.ts","../../src/cli/tui/components/Banner.tsx"],"sourcesContent":["/**\n * Version and git commit info utilities\n */\n\nimport { execSync } from 'node:child_process';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Find the package root directory (apps/runner).\n * Works in both development (src/cli/utils/) and production (dist/cli/utils/) modes.\n */\nfunction findPackageRoot(): string {\n // Try multiple possible locations\n const possiblePaths = [\n // Development: src/cli/utils/ -> apps/runner (3 levels up)\n join(__dirname, '..', '..', '..'),\n // Production from dist/cli/utils/: -> apps/runner (3 levels up, same structure)\n join(__dirname, '..', '..', '..'),\n ];\n \n for (const path of possiblePaths) {\n const packageJsonPath = join(path, 'package.json');\n if (existsSync(packageJsonPath)) {\n try {\n const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n // Verify this is the runner package\n if (pkg.name === '@hatchway/cli') {\n return path;\n }\n } catch {\n // Continue to next path\n }\n }\n }\n \n // Fallback to the standard path\n return join(__dirname, '..', '..', '..');\n}\n\n// Cache the package root\nconst packageRoot = findPackageRoot();\n\n/**\n * Get the package version from package.json\n */\nexport function getPackageVersion(): string {\n try {\n const packageJsonPath = join(packageRoot, 'package.json');\n if (existsSync(packageJsonPath)) {\n const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n return packageJson.version || '0.0.0';\n }\n } catch {\n // Ignore errors\n }\n return '0.0.0';\n}\n\n/**\n * Get the short git commit hash\n */\nexport function getGitCommit(): string | null {\n try {\n // Try to get commit from git command\n const commit = execSync('git rev-parse --short HEAD', {\n cwd: packageRoot,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n return commit || null;\n } catch {\n // Git not available or not a git repo\n return null;\n }\n}\n\n/**\n * Get combined version string with commit\n * Returns \"v0.19.1 (abc1234)\" or just \"v0.19.1\" if no commit\n */\nexport function getVersionString(): string {\n const version = getPackageVersion();\n const commit = getGitCommit();\n \n if (commit) {\n return `v${version} (${commit})`;\n }\n return `v${version}`;\n}\n\n/**\n * Version info object\n */\nexport interface VersionInfo {\n version: string;\n commit: string | null;\n display: string;\n}\n\n/**\n * Get all version info\n */\nexport function getVersionInfo(): VersionInfo {\n const version = getPackageVersion();\n const commit = getGitCommit();\n \n return {\n version,\n commit,\n display: commit ? `v${version} (${commit})` : `v${version}`,\n };\n}\n","import { Box, Text } from 'ink';\nimport { colors } from '../theme.js';\n\n/**\n * ASCII art banner component - centered with cyan/purple gradient\n * Each line is padded to exactly the same width for perfect alignment\n */\nexport function Banner() {\n // Full banner lines - HATCH in cyan, WAY in purple\n // All lines padded to same total width for consistent centering\n const lines = [\n { hatch: '██╗ ██╗ █████╗ ████████╗ ██████╗██╗ ██╗', way: '██╗ ██╗ █████╗ ██╗ ██╗' },\n { hatch: '██║ ██║██╔══██╗╚══██╔══╝██╔════╝██║ ██║', way: '██║ ██║██╔══██╗╚██╗ ██╔╝' },\n { hatch: '███████║███████║ ██║ ██║ ███████║', way: '██║ █╗ ██║███████║ ╚████╔╝ ' },\n { hatch: '██╔══██║██╔══██║ ██║ ██║ ██╔══██║', way: '██║███╗██║██╔══██║ ╚██╔╝ ' },\n { hatch: '██║ ██║██║ ██║ ██║ ╚██████╗██║ ██║', way: '╚███╔███╔╝██║ ██║ ██║ ' },\n { hatch: '╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝', way: ' ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝ ' },\n ];\n\n return (\n <Box flexDirection=\"column\" alignItems=\"center\">\n {lines.map((line, index) => (\n <Box key={index}>\n <Text color={colors.cyan}>{line.hatch}</Text>\n <Text color={colors.brightPurple}>{line.way}</Text>\n </Box>\n ))}\n </Box>\n );\n}\n"],"names":["__filename","__dirname","_jsx","_jsxs"],"mappings":"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"}
@@ -0,0 +1,264 @@
1
+ // Hatchway CLI - Built with Rollup
2
+ import { spawnSync, execSync } from 'node:child_process';
3
+ import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { homedir } from 'node:os';
6
+ import pc from 'picocolors';
7
+ import { c as configManager } from './config-manager-DST6RbP8.js';
8
+ import 'conf';
9
+
10
+ /**
11
+ * Auto-update utility for Hatchway CLI
12
+ *
13
+ * Checks GitHub Releases for newer versions and automatically
14
+ * updates both:
15
+ * 1. The CLI itself (globally installed npm package)
16
+ * 2. The app/monorepo (local installation that runs the web app)
17
+ */
18
+ // GitHub API endpoint for releases
19
+ const GITHUB_RELEASES_URL = 'https://api.github.com/repos/codyde/hatchway/releases/latest';
20
+ // Install command for CLI
21
+ const INSTALL_COMMAND = 'curl -fsSL https://hatchway.sh/install | bash';
22
+ // Cache settings
23
+ const CACHE_DIR = join(homedir(), '.config', 'hatchway');
24
+ const CACHE_FILE = join(CACHE_DIR, 'update-cache.json');
25
+ const CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
26
+ /**
27
+ * Read the update cache file
28
+ */
29
+ function readUpdateCache() {
30
+ try {
31
+ if (existsSync(CACHE_FILE)) {
32
+ const content = readFileSync(CACHE_FILE, 'utf-8');
33
+ return JSON.parse(content);
34
+ }
35
+ }
36
+ catch {
37
+ // Cache read failed, that's fine
38
+ }
39
+ return null;
40
+ }
41
+ /**
42
+ * Write to the update cache file
43
+ */
44
+ function saveUpdateCache(cache) {
45
+ try {
46
+ if (!existsSync(CACHE_DIR)) {
47
+ mkdirSync(CACHE_DIR, { recursive: true });
48
+ }
49
+ writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2));
50
+ }
51
+ catch {
52
+ // Cache write failed, that's fine
53
+ }
54
+ }
55
+ /**
56
+ * Fetch the latest release version from GitHub
57
+ * Returns version string (e.g., "0.28.0") or null on failure
58
+ */
59
+ async function fetchLatestVersion() {
60
+ try {
61
+ const controller = new AbortController();
62
+ const timeout = setTimeout(() => controller.abort(), 5000); // 5s timeout
63
+ const response = await fetch(GITHUB_RELEASES_URL, {
64
+ headers: {
65
+ 'Accept': 'application/vnd.github.v3+json',
66
+ 'User-Agent': 'Hatchway-CLI-AutoUpdate',
67
+ },
68
+ signal: controller.signal,
69
+ });
70
+ clearTimeout(timeout);
71
+ if (!response.ok) {
72
+ return null;
73
+ }
74
+ const data = await response.json();
75
+ // Remove 'v' prefix if present (e.g., "v0.28.0" -> "0.28.0")
76
+ return data.tag_name.replace(/^v/, '');
77
+ }
78
+ catch {
79
+ // Network error, timeout, or parse error
80
+ return null;
81
+ }
82
+ }
83
+ /**
84
+ * Compare two semver versions
85
+ * Returns true if version1 < version2 (i.e., version2 is newer)
86
+ */
87
+ function isNewerVersion(current, latest) {
88
+ const parseVersion = (v) => {
89
+ const parts = v.replace(/^v/, '').split('.').map(n => parseInt(n, 10) || 0);
90
+ return { major: parts[0] || 0, minor: parts[1] || 0, patch: parts[2] || 0 };
91
+ };
92
+ const c = parseVersion(current);
93
+ const l = parseVersion(latest);
94
+ if (l.major > c.major)
95
+ return true;
96
+ if (l.major < c.major)
97
+ return false;
98
+ if (l.minor > c.minor)
99
+ return true;
100
+ if (l.minor < c.minor)
101
+ return false;
102
+ return l.patch > c.patch;
103
+ }
104
+ /**
105
+ * Perform the CLI update by running the install script
106
+ */
107
+ function performCLIUpdate() {
108
+ try {
109
+ // Run the install command with quiet mode to avoid banner spam
110
+ execSync(INSTALL_COMMAND, {
111
+ stdio: 'inherit',
112
+ shell: '/bin/bash',
113
+ env: {
114
+ ...process.env,
115
+ HATCHWAY_QUIET_INSTALL: '1', // Suppress banner in installer
116
+ },
117
+ });
118
+ return true;
119
+ }
120
+ catch {
121
+ return false;
122
+ }
123
+ }
124
+ /**
125
+ * Check if the app/monorepo needs upgrading and perform the upgrade
126
+ * This updates the local Hatchway installation that runs the web app
127
+ */
128
+ function performAppUpgrade() {
129
+ const config = configManager.get();
130
+ const monorepoPath = config.monorepoPath;
131
+ // No monorepo configured, skip app upgrade
132
+ if (!monorepoPath || !existsSync(monorepoPath)) {
133
+ return true; // Not an error, just nothing to upgrade
134
+ }
135
+ console.log();
136
+ console.log(` ${pc.cyan('⬆')} ${pc.bold('Upgrading app installation...')}`);
137
+ console.log(` ${pc.dim(monorepoPath)}`);
138
+ console.log();
139
+ try {
140
+ // Run hatchway upgrade --force to upgrade the monorepo
141
+ // Use --force to skip prompts since we're in auto-update mode
142
+ const result = spawnSync('hatchway', ['upgrade', '--force'], {
143
+ stdio: 'inherit',
144
+ env: {
145
+ ...process.env,
146
+ HATCHWAY_SKIP_UPDATE_CHECK: '1', // Don't re-check for CLI updates
147
+ },
148
+ shell: true,
149
+ });
150
+ return result.status === 0;
151
+ }
152
+ catch {
153
+ return false;
154
+ }
155
+ }
156
+ /**
157
+ * Main auto-update check function
158
+ * Call this early in CLI startup
159
+ *
160
+ * Updates both:
161
+ * 1. The CLI itself (globally installed)
162
+ * 2. The app/monorepo (if configured)
163
+ *
164
+ * @param currentVersion - Current CLI version from package.json
165
+ * @returns true if update was performed and CLI should exit
166
+ */
167
+ async function checkAndAutoUpdate(currentVersion) {
168
+ // Skip if update check is disabled via env var
169
+ if (process.env.HATCHWAY_NO_UPDATE === '1' || process.env.HATCHWAY_SKIP_UPDATE_CHECK === '1') {
170
+ // But check if we have a pending app upgrade from a previous CLI update
171
+ const cache = readUpdateCache();
172
+ if (cache?.pendingAppUpgrade) {
173
+ console.log();
174
+ console.log(` ${pc.cyan('⬆')} ${pc.bold('Completing app upgrade...')}`);
175
+ const appSuccess = performAppUpgrade();
176
+ if (appSuccess) {
177
+ // Clear the pending flag
178
+ saveUpdateCache({ ...cache, pendingAppUpgrade: false });
179
+ console.log(` ${pc.green('✓')} ${pc.bold('App upgrade complete!')}`);
180
+ }
181
+ else {
182
+ console.log(` ${pc.yellow('⚠')} ${pc.dim('App upgrade failed. Run manually:')} ${pc.cyan('hatchway upgrade')}`);
183
+ }
184
+ console.log();
185
+ }
186
+ return false;
187
+ }
188
+ // Skip if disabled in config
189
+ const config = configManager.get();
190
+ if (config.autoUpdate === false) {
191
+ return false;
192
+ }
193
+ let latestVersion = null;
194
+ // Check cache first to avoid hitting GitHub API too often
195
+ const cache = readUpdateCache();
196
+ const now = Date.now();
197
+ if (cache && (now - cache.lastCheck) < CACHE_TTL_MS) {
198
+ // Use cached version
199
+ latestVersion = cache.latestVersion;
200
+ }
201
+ else {
202
+ // Fetch from GitHub (with timeout)
203
+ latestVersion = await fetchLatestVersion();
204
+ if (latestVersion) {
205
+ // Update cache
206
+ saveUpdateCache({
207
+ lastCheck: now,
208
+ latestVersion,
209
+ });
210
+ }
211
+ else if (cache) {
212
+ // Fetch failed, use stale cache
213
+ latestVersion = cache.latestVersion;
214
+ }
215
+ }
216
+ // If we couldn't determine latest version, skip update
217
+ if (!latestVersion) {
218
+ return false;
219
+ }
220
+ // Check if update is needed
221
+ if (!isNewerVersion(currentVersion, latestVersion)) {
222
+ return false;
223
+ }
224
+ // Update available! Show message and perform update
225
+ console.log();
226
+ console.log(` ${pc.cyan('⬆')} ${pc.bold('Update available:')} ${pc.dim(currentVersion)} → ${pc.green(latestVersion)}`);
227
+ console.log();
228
+ // Perform the CLI update
229
+ console.log(` ${pc.dim('Updating CLI...')}`);
230
+ const cliSuccess = performCLIUpdate();
231
+ if (!cliSuccess) {
232
+ // CLI update failed, continue with current version
233
+ console.log();
234
+ console.log(` ${pc.yellow('⚠')} ${pc.dim('CLI update failed. Continuing with current version.')}`);
235
+ console.log(` ${pc.dim('You can manually update with:')} ${pc.cyan('curl -fsSL https://hatchway.sh/install | bash')}`);
236
+ console.log();
237
+ return false;
238
+ }
239
+ console.log(` ${pc.green('✓')} CLI updated to ${pc.green(latestVersion)}`);
240
+ // Check if we need to upgrade the app
241
+ const monorepoPath = config.monorepoPath;
242
+ const hasMonorepo = monorepoPath && existsSync(monorepoPath);
243
+ if (hasMonorepo) {
244
+ // Mark that we need to upgrade the app after CLI restart
245
+ saveUpdateCache({
246
+ lastCheck: now,
247
+ latestVersion,
248
+ pendingAppUpgrade: true,
249
+ });
250
+ }
251
+ console.log();
252
+ console.log(` ${pc.green('✓')} ${pc.bold('Update complete!')}`);
253
+ console.log();
254
+ console.log(` ${pc.yellow('⚠')} ${pc.bold('Please restart your terminal')} or run:`);
255
+ console.log(` ${pc.cyan('hash -r')} ${pc.dim('(bash/zsh)')}`);
256
+ console.log();
257
+ console.log(` ${pc.dim('Then run')} ${pc.cyan('hatchway')} ${pc.dim('again.')}`);
258
+ console.log();
259
+ // Exit - user needs to restart terminal to pick up new version
260
+ process.exit(0);
261
+ }
262
+
263
+ export { checkAndAutoUpdate };
264
+ //# sourceMappingURL=auto-update-Ddo5Ntt7.js.map