gastown-gui 0.9.0

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 (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +303 -0
  3. package/assets/apple-touch-icon.png +0 -0
  4. package/assets/favicon-16.png +0 -0
  5. package/assets/favicon-192.png +0 -0
  6. package/assets/favicon-32.png +0 -0
  7. package/assets/favicon-final.png +0 -0
  8. package/assets/favicon.ico +0 -0
  9. package/assets/loading-background.jpeg +0 -0
  10. package/assets/screenshot.png +0 -0
  11. package/bin/cli.js +279 -0
  12. package/css/animations.css +665 -0
  13. package/css/components.css +7405 -0
  14. package/css/layout.css +720 -0
  15. package/css/reset.css +55 -0
  16. package/css/variables.css +156 -0
  17. package/index.html +938 -0
  18. package/js/api.js +415 -0
  19. package/js/app.js +1097 -0
  20. package/js/components/activity-feed.js +244 -0
  21. package/js/components/agent-grid.js +296 -0
  22. package/js/components/autocomplete.js +213 -0
  23. package/js/components/convoy-list.js +535 -0
  24. package/js/components/crew-list.js +300 -0
  25. package/js/components/dashboard.js +610 -0
  26. package/js/components/formula-list.js +459 -0
  27. package/js/components/health-check.js +307 -0
  28. package/js/components/issue-list.js +187 -0
  29. package/js/components/mail-list.js +413 -0
  30. package/js/components/modals.js +1838 -0
  31. package/js/components/onboarding.js +714 -0
  32. package/js/components/pr-list.js +217 -0
  33. package/js/components/rig-list.js +347 -0
  34. package/js/components/sidebar.js +489 -0
  35. package/js/components/toast.js +193 -0
  36. package/js/components/tutorial.js +426 -0
  37. package/js/components/work-list.js +373 -0
  38. package/js/shared/agent-types.js +121 -0
  39. package/js/shared/events.js +57 -0
  40. package/js/state.js +138 -0
  41. package/js/utils/formatting.js +64 -0
  42. package/js/utils/html.js +88 -0
  43. package/js/utils/performance.js +304 -0
  44. package/js/utils/tooltip.js +144 -0
  45. package/package.json +70 -0
  46. package/server.js +2542 -0
  47. package/start.sh +84 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 web3dev1337
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,303 @@
1
+ # Gas Town GUI
2
+
3
+ A standalone web GUI for [Gas Town](https://github.com/steveyegge/gastown) - the multi-agent orchestration system for Claude Code.
4
+
5
+ ![Gas Town GUI Screenshot](assets/screenshot.png)
6
+
7
+ ![Gas Town Loading Screen](assets/loading-background.jpeg)
8
+
9
+ > **Note:** This is an independent companion project, not part of the official Gas Town repository. Originally submitted as [PR #212](https://github.com/steveyegge/gastown/pull/212), now maintained as a standalone package per Steve's recommendation.
10
+
11
+ > *"Thank you for the impressive work on this GUI! The effort and thought that went into it is clear - the architecture is clean, the documentation is thorough, and it demonstrates a solid understanding of Gas Town's workflow. [...] If you're interested in continuing this work, I'd encourage publishing it as a standalone companion project."*
12
+ >
13
+ > — **Steve Yegge**, creator of Gas Town ([PR #212 comment](https://github.com/steveyegge/gastown/pull/212))
14
+
15
+ **Status:** 🚧 **Candidate for Testing** - Provides a solid starting point for a Gas Town GUI interface.
16
+
17
+ ---
18
+
19
+ ## Quick Start
20
+
21
+ ### 1. Install Prerequisites
22
+
23
+ ```bash
24
+ # Gas Town CLI (required)
25
+ npm install -g @gastown/gt
26
+ # Or: go install github.com/steveyegge/gastown/cmd/gt@latest
27
+
28
+ # GitHub CLI (optional, for PR tracking)
29
+ gh auth login
30
+ ```
31
+
32
+ ### 2. Install Gas Town GUI
33
+
34
+ ```bash
35
+ # Via npm (recommended)
36
+ npm install -g gastown-gui
37
+
38
+ # Or from source
39
+ git clone https://github.com/web3dev1337/gastown-gui.git
40
+ cd gastown-gui
41
+ npm install
42
+ npm link
43
+ ```
44
+
45
+ ### 3. Start the GUI
46
+
47
+ ```bash
48
+ gastown-gui start --open
49
+ ```
50
+
51
+ Opens `http://localhost:7667` in your browser.
52
+
53
+ ### 4. Verify Setup
54
+
55
+ ```bash
56
+ gastown-gui doctor
57
+ ```
58
+
59
+ ---
60
+
61
+ ## Features
62
+
63
+ - **Rig Management** - Add, view, and organize project repositories
64
+ - **Work Tracking** - Create and manage work items (beads)
65
+ - **Task Assignment** - Sling work to rigs and agents
66
+ - **Real-Time Updates** - Live WebSocket updates for all operations
67
+ - **PR Tracking** - View GitHub pull requests across projects
68
+ - **Mail Inbox** - Read messages from agents and polecats
69
+ - **Health Monitoring** - Run doctor checks and view system status
70
+
71
+ ---
72
+
73
+ ## CLI Usage
74
+
75
+ ```bash
76
+ # Start server (default port 7667)
77
+ gastown-gui
78
+
79
+ # Custom port
80
+ gastown-gui start --port 4000
81
+
82
+ # Open browser automatically
83
+ gastown-gui start --open
84
+
85
+ # Development mode
86
+ gastown-gui start --dev
87
+
88
+ # Check prerequisites
89
+ gastown-gui doctor
90
+
91
+ # Show version
92
+ gastown-gui version
93
+
94
+ # Show help
95
+ gastown-gui help
96
+ ```
97
+
98
+ ### Options
99
+
100
+ | Option | Description | Default |
101
+ |--------|-------------|---------|
102
+ | `--port, -p` | Server port | 7667 |
103
+ | `--host, -h` | Server host | 127.0.0.1 |
104
+ | `--open, -o` | Open browser | false |
105
+ | `--dev` | Development mode | false |
106
+
107
+ ### Environment Variables
108
+
109
+ | Variable | Description | Default |
110
+ |----------|-------------|---------|
111
+ | `PORT` | Server port | 7667 |
112
+ | `HOST` | Server host | 127.0.0.1 |
113
+ | `GT_ROOT` | Gas Town root directory | ~/gt |
114
+
115
+ ---
116
+
117
+ ## How It Works
118
+
119
+ The GUI acts as a **bridge** between your browser and the Gas Town CLI:
120
+
121
+ ```
122
+ ┌─────────────┐
123
+ │ Browser │
124
+ │ (Client) │
125
+ └──────┬──────┘
126
+ │ HTTP API / WebSocket
127
+
128
+ ┌─────────────┐
129
+ │ gastown- │
130
+ │ gui server │
131
+ └──────┬──────┘
132
+ │ subprocess (gt, bd, gh)
133
+
134
+ ┌─────────────┐
135
+ │ ~/gt/ │
136
+ │ workspace │
137
+ └─────────────┘
138
+ ```
139
+
140
+ All operations execute through the official `gt` and `bd` commands - the GUI never directly modifies Gas Town's internal state.
141
+
142
+ ---
143
+
144
+ ## Architecture
145
+
146
+ ### Tech Stack
147
+
148
+ - **Backend:** Node.js + Express
149
+ - **Frontend:** Vanilla JavaScript (no framework)
150
+ - **Communication:** WebSocket for real-time updates
151
+ - **Testing:** Vitest + Puppeteer E2E tests
152
+
153
+ ### Design Principles
154
+
155
+ 1. **Server-Authoritative** - All operations execute via `gt` and `bd` CLI commands
156
+ 2. **Non-Blocking UI** - Modals close immediately, operations run in background
157
+ 3. **Real-Time Updates** - WebSocket broadcasts status changes to all clients
158
+ 4. **Graceful Degradation** - UI handles missing data and command failures
159
+ 5. **Cache & Refresh** - Background data preloading with stale-while-revalidate
160
+
161
+ ---
162
+
163
+ ## API Endpoints
164
+
165
+ | Method | Endpoint | Description | CLI Command |
166
+ |--------|----------|-------------|-------------|
167
+ | GET | `/api/status` | System status | `gt status --json` |
168
+ | GET | `/api/rigs` | List rigs | `gt rig list` |
169
+ | POST | `/api/rigs` | Add rig | `gt rig add` |
170
+ | GET | `/api/work` | List work items | `bd list` |
171
+ | POST | `/api/work` | Create work | `bd new` |
172
+ | POST | `/api/sling` | Sling work | `gt sling` |
173
+ | GET | `/api/prs` | GitHub PRs | `gh pr list` |
174
+ | GET | `/api/mail` | Mail inbox | `gt mail inbox` |
175
+ | GET | `/api/doctor` | Health check | `gt doctor` |
176
+
177
+ ---
178
+
179
+ ## Project Structure
180
+
181
+ ```
182
+ gastown-gui/
183
+ ├── bin/cli.js # CLI entry point
184
+ ├── server.js # Express + WebSocket server
185
+ ├── index.html # Main HTML (single page)
186
+ ├── css/ # Stylesheets
187
+ │ ├── variables.css
188
+ │ ├── reset.css
189
+ │ ├── layout.css
190
+ │ ├── components.css
191
+ │ └── animations.css
192
+ ├── js/
193
+ │ ├── app.js # Main app entry
194
+ │ ├── api.js # API client
195
+ │ ├── state.js # State management
196
+ │ └── components/ # UI components
197
+ │ ├── dashboard.js
198
+ │ ├── rig-list.js
199
+ │ ├── work-list.js
200
+ │ ├── pr-list.js
201
+ │ ├── mail-list.js
202
+ │ └── ...
203
+ ├── test/
204
+ │ ├── unit/ # Unit tests
205
+ │ └── e2e.test.js # E2E tests
206
+ └── assets/ # Favicons, icons
207
+ ```
208
+
209
+ ---
210
+
211
+ ## Testing
212
+
213
+ ```bash
214
+ # All tests
215
+ npm test
216
+
217
+ # Unit tests only
218
+ npm run test:unit
219
+
220
+ # E2E tests
221
+ npm run test:e2e
222
+
223
+ # Watch mode
224
+ npm run test:watch
225
+ ```
226
+
227
+ ---
228
+
229
+ ## Known Limitations
230
+
231
+ ### Remaining Features (Use CLI)
232
+
233
+ | Feature | Status |
234
+ |---------|--------|
235
+ | Polecat spawn/kill/logs | ❌ CLI only |
236
+ | Agent configuration UI | ❌ Not implemented |
237
+ | Rig deletion | ❌ Not implemented |
238
+
239
+ ### Recently Implemented
240
+
241
+ | Feature | Status |
242
+ |---------|--------|
243
+ | Crew management | ✅ Create/list/view |
244
+ | Formula operations | ✅ Create/list/use |
245
+ | Test coverage | ✅ 206 tests passing |
246
+
247
+ **Known Issues:**
248
+ - GT CLI sling may fail with "mol bond requires direct database access" (upstream issue)
249
+
250
+ ---
251
+
252
+ ## Compatibility
253
+
254
+ - **Gas Town:** v0.2.x and later
255
+ - **Node.js:** 18, 20, 22
256
+ - **Browsers:** Chrome, Firefox, Safari (latest)
257
+
258
+ The GUI calls CLI commands via subprocess, so it should work with any Gas Town version that has compatible CLI output.
259
+
260
+ ---
261
+
262
+ ## Contributing
263
+
264
+ Contributions welcome!
265
+
266
+ 1. Fork the repository
267
+ 2. Create a feature branch
268
+ 3. Make your changes
269
+ 4. Test locally (start server with `npm start`, verify in browser)
270
+ 5. Run automated tests: `npm test` (206 tests must pass)
271
+ 6. Submit a pull request
272
+
273
+ ### Looking for Maintainers
274
+
275
+ We're looking for maintainers to help review and merge PRs. If you're interested in helping maintain this project, please open an issue or reach out!
276
+
277
+ ---
278
+
279
+ ## License
280
+
281
+ MIT
282
+
283
+ ---
284
+
285
+ ## Credits
286
+
287
+ - **Gas Town:** [steveyegge/gastown](https://github.com/steveyegge/gastown) by Steve Yegge
288
+ - **GUI Implementation:** Built with Claude Code
289
+ - **Original PR:** [#212](https://github.com/steveyegge/gastown/pull/212)
290
+
291
+ ### Contributors
292
+
293
+ Thanks to these community members who contributed to the original PR through testing, comments, and recommended fixes:
294
+
295
+ - [@gsxdsm](https://github.com/gsxdsm)
296
+ - [@michaellady](https://github.com/michaellady)
297
+ - [@olivierlefloch](https://github.com/olivierlefloch)
298
+ - [@zalo](https://github.com/zalo)
299
+ - [@irelandpaul](https://github.com/irelandpaul)
300
+
301
+ ---
302
+
303
+ **Disclaimer:** This is an independent community project, not officially affiliated with Gas Town. Use at your own risk.
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/bin/cli.js ADDED
@@ -0,0 +1,279 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Gas Town GUI CLI
5
+ *
6
+ * Command-line interface for starting the Gas Town GUI server.
7
+ *
8
+ * Usage:
9
+ * gastown-gui [command] [options]
10
+ *
11
+ * Commands:
12
+ * start Start the GUI server (default)
13
+ * version Show version
14
+ * help Show help
15
+ *
16
+ * Options:
17
+ * --port, -p Port to run on (default: 7667)
18
+ * --host, -h Host to bind to (default: 127.0.0.1)
19
+ * --open, -o Open browser after starting
20
+ * --dev Enable development mode (auto-reload)
21
+ */
22
+
23
+ import { spawn, execSync } from 'child_process';
24
+ import path from 'path';
25
+ import { fileURLToPath } from 'url';
26
+ import fs from 'fs';
27
+
28
+ const __filename = fileURLToPath(import.meta.url);
29
+ const __dirname = path.dirname(__filename);
30
+ const packageRoot = path.resolve(__dirname, '..');
31
+
32
+ // Parse arguments
33
+ const args = process.argv.slice(2);
34
+
35
+ // Check for help/version flags first (before command parsing)
36
+ if (args.includes('--help') || args.includes('-h')) {
37
+ showHelp();
38
+ process.exit(0);
39
+ }
40
+ if (args.includes('--version') || args.includes('-v')) {
41
+ showVersion();
42
+ process.exit(0);
43
+ }
44
+
45
+ const command = args.find(a => !a.startsWith('-')) || 'start';
46
+ const options = {
47
+ port: getOption(['--port', '-p']) || process.env.PORT || '7667',
48
+ host: getOption(['--host', '-h']) || process.env.HOST || '127.0.0.1',
49
+ open: hasFlag(['--open', '-o']),
50
+ dev: hasFlag(['--dev']),
51
+ };
52
+
53
+ function getOption(flags) {
54
+ for (const flag of flags) {
55
+ const idx = args.indexOf(flag);
56
+ if (idx !== -1 && args[idx + 1]) {
57
+ return args[idx + 1];
58
+ }
59
+ }
60
+ return null;
61
+ }
62
+
63
+ function hasFlag(flags) {
64
+ return flags.some(f => args.includes(f));
65
+ }
66
+
67
+ function showHelp() {
68
+ console.log(`
69
+ Gas Town GUI - Web interface for Gas Town multi-agent orchestrator
70
+
71
+ Usage:
72
+ gastown-gui [command] [options]
73
+
74
+ Commands:
75
+ start Start the GUI server (default)
76
+ version Show version information
77
+ doctor Check Gas Town installation
78
+ help Show this help message
79
+
80
+ Options:
81
+ --port, -p <port> Port to run on (default: 7667, or PORT env var)
82
+ --host, -h <host> Host to bind to (default: 127.0.0.1, or HOST env var)
83
+ --open, -o Open browser after starting
84
+ --dev Enable development mode
85
+
86
+ Environment Variables:
87
+ PORT Server port (default: 7667)
88
+ HOST Server host (default: 127.0.0.1)
89
+ GT_ROOT Gas Town root directory (default: ~/gt)
90
+
91
+ Examples:
92
+ gastown-gui # Start on default port
93
+ gastown-gui start --port 4000 # Start on port 4000
94
+ gastown-gui start --open # Start and open browser
95
+ gastown-gui doctor # Check gt installation
96
+
97
+ Prerequisites:
98
+ - Gas Town CLI (gt) must be installed and in PATH
99
+ - GitHub CLI (gh) for PR/issue tracking (optional)
100
+
101
+ More info: https://github.com/web3dev1337/gastown-gui
102
+ `);
103
+ }
104
+
105
+ function showVersion() {
106
+ const packageJson = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
107
+ console.log(`gastown-gui v${packageJson.version}`);
108
+
109
+ // Check gt version
110
+ try {
111
+ const gtVersion = execSync('gt version 2>/dev/null || echo "not installed"', { encoding: 'utf8' }).trim();
112
+ console.log(`gt: ${gtVersion}`);
113
+ } catch {
114
+ console.log('gt: not found in PATH');
115
+ }
116
+
117
+ // Check gh version
118
+ try {
119
+ const ghVersion = execSync('gh --version 2>/dev/null | head -1 || echo "not installed"', { encoding: 'utf8' }).trim();
120
+ console.log(`gh: ${ghVersion}`);
121
+ } catch {
122
+ console.log('gh: not found in PATH');
123
+ }
124
+ }
125
+
126
+ function runDoctor() {
127
+ console.log('Gas Town GUI Doctor\n');
128
+ console.log('Checking prerequisites...\n');
129
+
130
+ let allGood = true;
131
+
132
+ // Check Node.js version
133
+ const nodeVersion = process.version;
134
+ const major = parseInt(nodeVersion.slice(1).split('.')[0], 10);
135
+ if (major >= 18) {
136
+ console.log(`✅ Node.js ${nodeVersion} (>= 18 required)`);
137
+ } else {
138
+ console.log(`❌ Node.js ${nodeVersion} (>= 18 required)`);
139
+ allGood = false;
140
+ }
141
+
142
+ // Check gt
143
+ try {
144
+ const gtPath = execSync('which gt 2>/dev/null', { encoding: 'utf8' }).trim();
145
+ const gtVersion = execSync('gt version 2>/dev/null', { encoding: 'utf8' }).trim();
146
+ console.log(`✅ gt installed at ${gtPath}`);
147
+ console.log(` Version: ${gtVersion}`);
148
+ } catch {
149
+ console.log('❌ gt not found in PATH');
150
+ console.log(' Install: npm install -g @gastown/gt');
151
+ console.log(' Or visit: https://github.com/steveyegge/gastown');
152
+ allGood = false;
153
+ }
154
+
155
+ // Check bd
156
+ try {
157
+ execSync('which bd 2>/dev/null', { encoding: 'utf8' });
158
+ console.log('✅ bd (beads) installed');
159
+ } catch {
160
+ console.log('⚠️ bd (beads) not found - some features may not work');
161
+ }
162
+
163
+ // Check gh
164
+ try {
165
+ const ghVersion = execSync('gh --version 2>/dev/null | head -1', { encoding: 'utf8' }).trim();
166
+ console.log(`✅ GitHub CLI: ${ghVersion}`);
167
+
168
+ // Check auth
169
+ try {
170
+ execSync('gh auth status 2>&1', { encoding: 'utf8' });
171
+ console.log(' ✅ Authenticated');
172
+ } catch {
173
+ console.log(' ⚠️ Not authenticated - run: gh auth login');
174
+ }
175
+ } catch {
176
+ console.log('⚠️ GitHub CLI (gh) not found - PR/issue tracking disabled');
177
+ }
178
+
179
+ // Check GT_ROOT
180
+ const gtRoot = process.env.GT_ROOT || path.join(process.env.HOME || '', 'gt');
181
+ if (fs.existsSync(gtRoot)) {
182
+ console.log(`✅ GT_ROOT exists: ${gtRoot}`);
183
+ try {
184
+ const rigs = fs.readdirSync(gtRoot).filter(f => {
185
+ const fullPath = path.join(gtRoot, f);
186
+ return fs.statSync(fullPath).isDirectory() && fs.existsSync(path.join(fullPath, 'config.json'));
187
+ });
188
+ console.log(` Found ${rigs.length} rig(s): ${rigs.join(', ') || '(none)'}`);
189
+ } catch {
190
+ // Ignore
191
+ }
192
+ } else {
193
+ console.log(`⚠️ GT_ROOT not found: ${gtRoot}`);
194
+ console.log(' Run: gt install ~/gt');
195
+ }
196
+
197
+ console.log('');
198
+ if (allGood) {
199
+ console.log('✅ All prerequisites met! Run: gastown-gui start');
200
+ } else {
201
+ console.log('❌ Some prerequisites missing. Fix issues above and try again.');
202
+ process.exit(1);
203
+ }
204
+ }
205
+
206
+ function startServer() {
207
+ console.log(`Starting Gas Town GUI on http://${options.host}:${options.port}...`);
208
+
209
+ const env = {
210
+ ...process.env,
211
+ PORT: options.port,
212
+ HOST: options.host,
213
+ };
214
+
215
+ const serverPath = path.join(packageRoot, 'server.js');
216
+ const serverArgs = options.dev ? ['--dev'] : [];
217
+
218
+ const child = spawn('node', [serverPath, ...serverArgs], {
219
+ env,
220
+ stdio: 'inherit',
221
+ cwd: packageRoot,
222
+ });
223
+
224
+ // Open browser if requested
225
+ if (options.open) {
226
+ setTimeout(() => {
227
+ const url = `http://${options.host}:${options.port}`;
228
+ const openCmd = process.platform === 'darwin' ? 'open' :
229
+ process.platform === 'win32' ? 'start' : 'xdg-open';
230
+ try {
231
+ execSync(`${openCmd} ${url}`, { stdio: 'ignore' });
232
+ } catch {
233
+ console.log(`Open browser manually: ${url}`);
234
+ }
235
+ }, 1500);
236
+ }
237
+
238
+ child.on('error', (err) => {
239
+ console.error('Failed to start server:', err.message);
240
+ process.exit(1);
241
+ });
242
+
243
+ child.on('exit', (code) => {
244
+ process.exit(code || 0);
245
+ });
246
+
247
+ // Handle signals
248
+ process.on('SIGINT', () => {
249
+ child.kill('SIGINT');
250
+ });
251
+
252
+ process.on('SIGTERM', () => {
253
+ child.kill('SIGTERM');
254
+ });
255
+ }
256
+
257
+ // Main
258
+ switch (command) {
259
+ case 'start':
260
+ startServer();
261
+ break;
262
+ case 'version':
263
+ case '-v':
264
+ case '--version':
265
+ showVersion();
266
+ break;
267
+ case 'doctor':
268
+ runDoctor();
269
+ break;
270
+ case 'help':
271
+ case '-h':
272
+ case '--help':
273
+ showHelp();
274
+ break;
275
+ default:
276
+ console.error(`Unknown command: ${command}`);
277
+ console.error('Run: gastown-gui help');
278
+ process.exit(1);
279
+ }