@redplanethq/corebrain 2.1.0 → 2.3.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 (98) hide show
  1. package/dist/commands/browser/close.d.ts +1 -1
  2. package/dist/commands/browser/close.d.ts.map +1 -1
  3. package/dist/commands/browser/close.js +39 -50
  4. package/dist/commands/browser/close.js.map +1 -1
  5. package/dist/commands/browser/command.d.ts +1 -1
  6. package/dist/commands/browser/command.d.ts.map +1 -1
  7. package/dist/commands/browser/command.js +46 -56
  8. package/dist/commands/browser/command.js.map +1 -1
  9. package/dist/commands/browser/create-profile.d.ts +1 -1
  10. package/dist/commands/browser/create-profile.d.ts.map +1 -1
  11. package/dist/commands/browser/create-profile.js +27 -21
  12. package/dist/commands/browser/create-profile.js.map +1 -1
  13. package/dist/commands/browser/delete-profile.d.ts +1 -1
  14. package/dist/commands/browser/delete-profile.d.ts.map +1 -1
  15. package/dist/commands/browser/delete-profile.js +26 -19
  16. package/dist/commands/browser/delete-profile.js.map +1 -1
  17. package/dist/commands/browser/install.d.ts +1 -1
  18. package/dist/commands/browser/install.d.ts.map +1 -1
  19. package/dist/commands/browser/install.js +31 -42
  20. package/dist/commands/browser/install.js.map +1 -1
  21. package/dist/commands/browser/open.d.ts +1 -1
  22. package/dist/commands/browser/open.d.ts.map +1 -1
  23. package/dist/commands/browser/open.js +40 -52
  24. package/dist/commands/browser/open.js.map +1 -1
  25. package/dist/commands/browser/status.d.ts +1 -1
  26. package/dist/commands/browser/status.d.ts.map +1 -1
  27. package/dist/commands/browser/status.js +36 -41
  28. package/dist/commands/browser/status.js.map +1 -1
  29. package/dist/commands/coding/config.d.ts +1 -1
  30. package/dist/commands/coding/config.d.ts.map +1 -1
  31. package/dist/commands/coding/config.js +95 -98
  32. package/dist/commands/coding/config.js.map +1 -1
  33. package/dist/commands/coding/remove.d.ts +1 -1
  34. package/dist/commands/coding/remove.d.ts.map +1 -1
  35. package/dist/commands/coding/remove.js +26 -28
  36. package/dist/commands/coding/remove.js.map +1 -1
  37. package/dist/commands/coding/setup.d.ts +1 -1
  38. package/dist/commands/coding/setup.d.ts.map +1 -1
  39. package/dist/commands/coding/setup.js +56 -71
  40. package/dist/commands/coding/setup.js.map +1 -1
  41. package/dist/commands/exec/config.d.ts +1 -1
  42. package/dist/commands/exec/config.d.ts.map +1 -1
  43. package/dist/commands/exec/config.js +71 -66
  44. package/dist/commands/exec/config.js.map +1 -1
  45. package/dist/commands/gateway/config.d.ts +9 -2
  46. package/dist/commands/gateway/config.d.ts.map +1 -1
  47. package/dist/commands/gateway/config.js +419 -156
  48. package/dist/commands/gateway/config.js.map +1 -1
  49. package/dist/commands/gateway/off.d.ts +1 -1
  50. package/dist/commands/gateway/off.d.ts.map +1 -1
  51. package/dist/commands/gateway/off.js +53 -63
  52. package/dist/commands/gateway/off.js.map +1 -1
  53. package/dist/commands/gateway/on.d.ts +1 -1
  54. package/dist/commands/gateway/on.d.ts.map +1 -1
  55. package/dist/commands/gateway/on.js +88 -117
  56. package/dist/commands/gateway/on.js.map +1 -1
  57. package/dist/commands/gateway/restart.d.ts +1 -1
  58. package/dist/commands/gateway/restart.d.ts.map +1 -1
  59. package/dist/commands/gateway/restart.js +49 -63
  60. package/dist/commands/gateway/restart.js.map +1 -1
  61. package/dist/commands/gateway/status.d.ts +1 -1
  62. package/dist/commands/gateway/status.d.ts.map +1 -1
  63. package/dist/commands/gateway/status.js +62 -76
  64. package/dist/commands/gateway/status.js.map +1 -1
  65. package/dist/commands/gateway/uninstall.d.ts +1 -1
  66. package/dist/commands/gateway/uninstall.d.ts.map +1 -1
  67. package/dist/commands/gateway/uninstall.js +60 -72
  68. package/dist/commands/gateway/uninstall.js.map +1 -1
  69. package/dist/commands/login.d.ts +1 -1
  70. package/dist/commands/login.d.ts.map +1 -1
  71. package/dist/commands/login.js +99 -108
  72. package/dist/commands/login.js.map +1 -1
  73. package/dist/commands/logout.d.ts +1 -1
  74. package/dist/commands/logout.d.ts.map +1 -1
  75. package/dist/commands/logout.js +24 -45
  76. package/dist/commands/logout.js.map +1 -1
  77. package/dist/commands/me.d.ts +1 -1
  78. package/dist/commands/me.d.ts.map +1 -1
  79. package/dist/commands/me.js +40 -50
  80. package/dist/commands/me.js.map +1 -1
  81. package/dist/commands/token.d.ts +1 -1
  82. package/dist/commands/token.d.ts.map +1 -1
  83. package/dist/commands/token.js +19 -24
  84. package/dist/commands/token.js.map +1 -1
  85. package/dist/components/error-message.js +0 -1
  86. package/dist/components/error-message.js.map +1 -1
  87. package/dist/components/warning-message.js +0 -1
  88. package/dist/components/warning-message.js.map +1 -1
  89. package/dist/server/gateway-client.d.ts +4 -0
  90. package/dist/server/gateway-client.d.ts.map +1 -1
  91. package/dist/server/gateway-client.js +45 -6
  92. package/dist/server/gateway-client.js.map +1 -1
  93. package/dist/server/tools/exec-tools.d.ts.map +1 -1
  94. package/dist/server/tools/exec-tools.js +9 -0
  95. package/dist/server/tools/exec-tools.js.map +1 -1
  96. package/dist/types/config.d.ts +15 -0
  97. package/dist/types/config.d.ts.map +1 -1
  98. package/package.json +6 -3
@@ -1,192 +1,455 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect } from 'react';
3
- import { Text, Box, useInput, useApp } from 'ink';
4
- import TextInput from 'ink-text-input';
5
- import SelectInput from 'ink-select-input';
1
+ import { jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { Text, useApp } from 'ink';
4
+ import * as p from '@clack/prompts';
5
+ import chalk from 'chalk';
6
6
  import zod from 'zod';
7
7
  import { randomUUID } from 'node:crypto';
8
+ import { exec } from 'node:child_process';
9
+ import { promisify } from 'node:util';
8
10
  import { getPreferences, updatePreferences } from '../../config/preferences.js';
11
+ import { getConfig } from '../../config/index.js';
9
12
  import { getServiceType, getServiceName, getServiceStatus, stopService, uninstallService, isServiceInstalled, installService, startService, getServicePid, } from '../../utils/service-manager/index.js';
10
13
  import { getConfigPath } from '../../config/paths.js';
11
14
  import { join, dirname } from 'node:path';
12
15
  import { fileURLToPath } from 'node:url';
13
16
  import { homedir } from 'node:os';
14
- import SuccessMessage from '../../components/success-message.js';
15
- import ErrorMessage from '../../components/error-message.js';
16
- import { ThemeContext } from '../../hooks/useTheme.js';
17
- import { themeContextValue } from '../../config/themes.js';
18
- export const options = zod.object({});
17
+ import { isAgentBrowserInstalled, installAgentBrowser } from '../../utils/agent-browser.js';
18
+ const execAsync = promisify(exec);
19
+ const DEFAULT_APP_URL = 'https://app.getcore.me';
20
+ export const options = zod.object({
21
+ // Direct set options (non-interactive)
22
+ name: zod.string().optional().describe('Gateway name'),
23
+ description: zod.string().optional().describe('Gateway description'),
24
+ coding: zod.boolean().optional().describe('Enable/disable coding tools'),
25
+ browser: zod.boolean().optional().describe('Enable/disable browser tools'),
26
+ exec: zod.boolean().optional().describe('Enable/disable exec tools'),
27
+ show: zod.boolean().optional().describe('Show current configuration'),
28
+ });
29
+ // Common exec command patterns
30
+ const EXEC_COMMAND_OPTIONS = [
31
+ { value: 'Bash(git status)', label: 'git status' },
32
+ { value: 'Bash(git diff *)', label: 'git diff' },
33
+ { value: 'Bash(git log *)', label: 'git log' },
34
+ { value: 'Bash(git branch *)', label: 'git branch' },
35
+ { value: 'Bash(git checkout *)', label: 'git checkout' },
36
+ { value: 'Bash(git add *)', label: 'git add' },
37
+ { value: 'Bash(git commit *)', label: 'git commit' },
38
+ { value: 'Bash(git push *)', label: 'git push' },
39
+ { value: 'Bash(git pull *)', label: 'git pull' },
40
+ { value: 'Bash(git fetch *)', label: 'git fetch' },
41
+ { value: 'Bash(npm run *)', label: 'npm run *' },
42
+ { value: 'Bash(npm install *)', label: 'npm install' },
43
+ { value: 'Bash(pnpm run *)', label: 'pnpm run *' },
44
+ { value: 'Bash(pnpm install *)', label: 'pnpm install' },
45
+ { value: 'Bash(ls *)', label: 'ls' },
46
+ { value: 'Bash(cat *)', label: 'cat' },
47
+ { value: 'Bash(grep *)', label: 'grep' },
48
+ { value: 'Bash(find *)', label: 'find' },
49
+ { value: 'Bash(mkdir *)', label: 'mkdir' },
50
+ { value: 'Bash(rm *)', label: 'rm' },
51
+ { value: 'Bash(mv *)', label: 'mv' },
52
+ { value: 'Bash(cp *)', label: 'cp' },
53
+ { value: 'Bash(curl *)', label: 'curl' },
54
+ { value: 'Bash(python *)', label: 'python' },
55
+ { value: 'Bash(node *)', label: 'node' },
56
+ ];
19
57
  // Get the path to the gateway-entry.js script
20
58
  function getGatewayEntryPath() {
21
59
  const __filename = fileURLToPath(import.meta.url);
22
60
  const __dirname = dirname(__filename);
23
61
  return join(__dirname, '..', '..', 'server', 'gateway-entry.js');
24
62
  }
25
- export default function GatewayConfigCommand(_props) {
26
- const { exit } = useApp();
27
- const [step, setStep] = useState('checking');
28
- const [error, setError] = useState('');
29
- const [existingConfig, setExistingConfig] = useState(null);
30
- const [isEditing, setIsEditing] = useState(false);
31
- // Form state
32
- const [name, setName] = useState('');
33
- const [description, setDescription] = useState('');
34
- const [gatewayId, setGatewayId] = useState('');
35
- // Check for existing config on mount
36
- useEffect(() => {
37
- const prefs = getPreferences();
38
- const existing = prefs.gateway;
39
- if (existing?.id && existing?.name) {
40
- setExistingConfig(existing);
41
- setName(existing.name || '');
42
- setDescription(existing.description || '');
43
- setGatewayId(existing.id);
44
- setStep('confirm-edit');
63
+ // Check if claude-code is installed
64
+ async function isClaudeCodeInstalled() {
65
+ try {
66
+ const { stdout } = await execAsync('which claude');
67
+ const path = stdout.trim();
68
+ if (path) {
69
+ return { installed: true, path };
45
70
  }
46
- else {
47
- // New config - generate ID
48
- setGatewayId(randomUUID());
49
- setStep('input-name');
71
+ }
72
+ catch {
73
+ // Not found
74
+ }
75
+ return { installed: false };
76
+ }
77
+ // Check if npm is available
78
+ async function isNpmAvailable() {
79
+ try {
80
+ await execAsync('which npm');
81
+ return true;
82
+ }
83
+ catch {
84
+ return false;
85
+ }
86
+ }
87
+ function formatConfig(config) {
88
+ if (!config) {
89
+ return chalk.dim('(not configured)');
90
+ }
91
+ return [
92
+ `${chalk.bold('Name:')} ${config.name || chalk.dim('(not set)')}`,
93
+ `${chalk.bold('Description:')} ${config.description || chalk.dim('(none)')}`,
94
+ `${chalk.bold('URL:')} ${config.url || DEFAULT_APP_URL}`,
95
+ `${chalk.bold('Coding:')} ${config.slots?.coding?.enabled ? chalk.green('enabled') : chalk.dim('disabled')}`,
96
+ `${chalk.bold('Browser:')} ${config.slots?.browser?.enabled ? chalk.green('enabled') : chalk.dim('disabled')}`,
97
+ `${chalk.bold('Exec:')} ${config.slots?.exec?.enabled ? chalk.green('enabled') : chalk.dim('disabled')}`,
98
+ ].join('\n');
99
+ }
100
+ // Direct update (non-interactive)
101
+ async function runDirectUpdate(opts) {
102
+ const prefs = getPreferences();
103
+ const existingConfig = prefs.gateway;
104
+ // Show current config
105
+ if (opts.show) {
106
+ p.note(formatConfig(existingConfig), 'Gateway Configuration');
107
+ return { success: true };
108
+ }
109
+ // Generate id if not exists
110
+ const gatewayId = existingConfig?.id || randomUUID();
111
+ const newConfig = {
112
+ ...existingConfig,
113
+ id: gatewayId,
114
+ pid: existingConfig?.pid || 0,
115
+ startedAt: existingConfig?.startedAt || 0,
116
+ };
117
+ if (opts.name !== undefined) {
118
+ newConfig.name = opts.name;
119
+ }
120
+ if (opts.description !== undefined) {
121
+ newConfig.description = opts.description;
122
+ }
123
+ // Update slots
124
+ const slots = { ...existingConfig?.slots };
125
+ if (opts.coding !== undefined) {
126
+ slots.coding = { ...slots.coding, enabled: opts.coding };
127
+ }
128
+ if (opts.browser !== undefined) {
129
+ slots.browser = { ...slots.browser, enabled: opts.browser };
130
+ }
131
+ if (opts.exec !== undefined) {
132
+ slots.exec = { ...slots.exec, enabled: opts.exec };
133
+ }
134
+ newConfig.slots = slots;
135
+ updatePreferences({ gateway: newConfig });
136
+ p.log.success(chalk.green('Configuration updated'));
137
+ p.note(formatConfig(newConfig), 'Gateway Configuration');
138
+ return { success: true };
139
+ }
140
+ // Interactive wizard
141
+ async function runInteractiveConfig() {
142
+ const prefs = getPreferences();
143
+ const existingConfig = prefs.gateway;
144
+ p.intro(chalk.bgCyan(chalk.black(' Gateway Configuration ')));
145
+ // Stop existing service if running
146
+ const stopSpinner = p.spinner();
147
+ stopSpinner.start('Checking existing gateway...');
148
+ try {
149
+ const serviceType = getServiceType();
150
+ if (serviceType !== 'none') {
151
+ const serviceName = getServiceName();
152
+ const installed = await isServiceInstalled(serviceName);
153
+ if (installed) {
154
+ const status = await getServiceStatus(serviceName);
155
+ if (status === 'running') {
156
+ stopSpinner.message('Stopping existing gateway...');
157
+ await stopService(serviceName);
158
+ }
159
+ await uninstallService(serviceName);
160
+ }
50
161
  }
51
- }, []);
52
- // Handle edit confirmation
53
- const handleEditConfirm = async (item) => {
54
- if (item.value === 'edit') {
55
- setIsEditing(true);
56
- // Check if service is running and uninstall
57
- try {
58
- const serviceType = getServiceType();
59
- if (serviceType !== 'none') {
60
- const serviceName = getServiceName();
61
- const installed = await isServiceInstalled(serviceName);
62
- if (installed) {
63
- setStep('uninstalling');
64
- const status = await getServiceStatus(serviceName);
65
- if (status === 'running') {
66
- await stopService(serviceName);
67
- await new Promise((resolve) => setTimeout(resolve, 500));
68
- }
69
- await uninstallService(serviceName);
162
+ stopSpinner.stop('Ready to configure');
163
+ }
164
+ catch {
165
+ stopSpinner.stop('Ready to configure');
166
+ }
167
+ // Step 1: Name
168
+ const name = await p.text({
169
+ message: 'Gateway name',
170
+ placeholder: 'my-macbook',
171
+ initialValue: existingConfig?.name || '',
172
+ validate: (value) => {
173
+ if (value && !value.trim())
174
+ return 'Name is required';
175
+ },
176
+ });
177
+ if (p.isCancel(name)) {
178
+ p.cancel('Configuration cancelled');
179
+ return { cancelled: true };
180
+ }
181
+ // Step 2: Description
182
+ const description = await p.text({
183
+ message: 'Description',
184
+ placeholder: 'Browser and coding on my MacBook',
185
+ initialValue: existingConfig?.description || '',
186
+ });
187
+ if (p.isCancel(description)) {
188
+ p.cancel('Configuration cancelled');
189
+ return { cancelled: true };
190
+ }
191
+ // Step 3: Coding slot
192
+ const codingSpinner = p.spinner();
193
+ codingSpinner.start('Checking for claude-code...');
194
+ const claudeResult = await isClaudeCodeInstalled();
195
+ codingSpinner.stop(claudeResult.installed
196
+ ? chalk.green(`Found: ${claudeResult.path}`)
197
+ : chalk.yellow('claude-code not found'));
198
+ let codingEnabled = false;
199
+ let claudePath;
200
+ if (claudeResult.installed) {
201
+ claudePath = claudeResult.path;
202
+ const enableCoding = await p.confirm({
203
+ message: 'Enable coding tools?',
204
+ initialValue: existingConfig?.slots?.coding?.enabled ?? true,
205
+ });
206
+ if (p.isCancel(enableCoding)) {
207
+ p.cancel('Configuration cancelled');
208
+ return { cancelled: true };
209
+ }
210
+ codingEnabled = enableCoding;
211
+ }
212
+ // Step 5: Browser slot
213
+ const browserSpinner = p.spinner();
214
+ browserSpinner.start('Checking for agent-browser...');
215
+ let browserInstalled = await isAgentBrowserInstalled();
216
+ browserSpinner.stop(browserInstalled
217
+ ? chalk.green('agent-browser installed')
218
+ : chalk.yellow('agent-browser not found'));
219
+ let browserEnabled = false;
220
+ if (!browserInstalled) {
221
+ const installBrowser = await p.confirm({
222
+ message: 'Install agent-browser? (npm install -g agent-browser)',
223
+ initialValue: false,
224
+ });
225
+ if (p.isCancel(installBrowser)) {
226
+ p.cancel('Configuration cancelled');
227
+ return { cancelled: true };
228
+ }
229
+ if (installBrowser) {
230
+ const npmAvailable = await isNpmAvailable();
231
+ if (!npmAvailable) {
232
+ p.log.warning('npm not available, skipping browser installation');
233
+ }
234
+ else {
235
+ const installSpinner = p.spinner();
236
+ installSpinner.start('Installing agent-browser...');
237
+ try {
238
+ const result = await installAgentBrowser();
239
+ if (result.code === 0) {
240
+ installSpinner.stop(chalk.green('agent-browser installed'));
241
+ browserInstalled = true;
242
+ browserEnabled = true;
243
+ }
244
+ else {
245
+ installSpinner.stop(chalk.red('Installation failed'));
70
246
  }
71
247
  }
248
+ catch {
249
+ installSpinner.stop(chalk.red('Installation failed'));
250
+ }
72
251
  }
73
- catch {
74
- // Continue anyway
75
- }
76
- setStep('input-name');
77
252
  }
78
- else if (item.value === 'view') {
79
- setStep('done');
253
+ }
254
+ if (browserInstalled && !browserEnabled) {
255
+ const enableBrowser = await p.confirm({
256
+ message: 'Enable browser tools?',
257
+ initialValue: existingConfig?.slots?.browser?.enabled ?? true,
258
+ });
259
+ if (p.isCancel(enableBrowser)) {
260
+ p.cancel('Configuration cancelled');
261
+ return { cancelled: true };
80
262
  }
81
- else {
82
- setStep('cancelled');
263
+ browserEnabled = enableBrowser;
264
+ }
265
+ // Step 6: Exec slot
266
+ const enableExec = await p.confirm({
267
+ message: 'Enable exec tools? (run shell commands)',
268
+ initialValue: existingConfig?.slots?.exec?.enabled ?? false,
269
+ });
270
+ if (p.isCancel(enableExec)) {
271
+ p.cancel('Configuration cancelled');
272
+ return { cancelled: true };
273
+ }
274
+ let execEnabled = enableExec;
275
+ let execAllow = [];
276
+ let execDeny = [];
277
+ if (execEnabled) {
278
+ const selectedCommands = await p.multiselect({
279
+ message: 'Select allowed commands',
280
+ options: EXEC_COMMAND_OPTIONS,
281
+ initialValues: existingConfig?.slots?.exec?.allow || [],
282
+ required: false,
283
+ });
284
+ if (p.isCancel(selectedCommands)) {
285
+ p.cancel('Configuration cancelled');
286
+ return { cancelled: true };
83
287
  }
84
- };
85
- // Handle name submit
86
- const handleNameSubmit = (value) => {
87
- if (value.trim()) {
88
- setName(value.trim());
89
- setStep('input-description');
288
+ execAllow = selectedCommands;
289
+ // Ask for denied commands from remaining
290
+ const remainingCommands = EXEC_COMMAND_OPTIONS.filter(opt => !execAllow.includes(opt.value));
291
+ if (remainingCommands.length > 0) {
292
+ const deniedCommands = await p.multiselect({
293
+ message: 'Select denied commands (optional)',
294
+ options: remainingCommands,
295
+ initialValues: existingConfig?.slots?.exec?.deny || [],
296
+ required: false,
297
+ });
298
+ if (!p.isCancel(deniedCommands)) {
299
+ execDeny = deniedCommands;
300
+ }
90
301
  }
302
+ }
303
+ // Save configuration
304
+ const saveSpinner = p.spinner();
305
+ saveSpinner.start('Saving configuration...');
306
+ const gatewayId = existingConfig?.id || randomUUID();
307
+ const slots = {
308
+ coding: { enabled: codingEnabled },
309
+ browser: { enabled: browserEnabled },
310
+ exec: {
311
+ enabled: execEnabled,
312
+ allow: execAllow.length > 0 ? execAllow : undefined,
313
+ deny: execDeny.length > 0 ? execDeny : undefined,
314
+ },
315
+ };
316
+ // Get URL from auth config (set during login)
317
+ const appConfig = getConfig();
318
+ const authUrl = appConfig.auth?.url || DEFAULT_APP_URL;
319
+ const newConfig = {
320
+ ...prefs.gateway,
321
+ id: gatewayId,
322
+ name: name,
323
+ description: description || '',
324
+ url: authUrl,
325
+ port: prefs.gateway?.port || 0,
326
+ pid: prefs.gateway?.pid || 0,
327
+ startedAt: prefs.gateway?.startedAt || 0,
328
+ slots,
91
329
  };
92
- // Handle description submit
93
- const handleDescriptionSubmit = (value) => {
94
- setDescription(value.trim());
95
- setStep('saving');
96
- // Save config
97
- try {
98
- const prefs = getPreferences();
99
- const newConfig = {
100
- ...prefs.gateway,
101
- id: gatewayId,
102
- name: name,
103
- description: value.trim(),
104
- port: prefs.gateway?.port || 0,
105
- pid: prefs.gateway?.pid || 0,
106
- startedAt: prefs.gateway?.startedAt || 0,
330
+ // Save coding config if enabled
331
+ if (codingEnabled && claudePath) {
332
+ const codingConfig = prefs.coding || {};
333
+ if (!codingConfig['claude-code']) {
334
+ codingConfig['claude-code'] = {
335
+ command: claudePath,
336
+ args: ['-p', '--output-format', 'text', '--dangerously-skip-permissions'],
337
+ resumeArgs: ['-p', '--output-format', 'text', '--dangerously-skip-permissions', '--resume', '{sessionId}'],
338
+ sessionArg: '--session',
339
+ sessionMode: 'always',
340
+ sessionIdFields: ['session_id'],
107
341
  };
108
- updatePreferences({ gateway: newConfig });
109
- setStep('confirm-start');
110
- }
111
- catch (err) {
112
- setError(err instanceof Error ? err.message : 'Failed to save config');
113
- setStep('error');
114
342
  }
343
+ updatePreferences({ gateway: newConfig, coding: codingConfig });
344
+ }
345
+ else {
346
+ updatePreferences({ gateway: newConfig });
347
+ }
348
+ saveSpinner.stop(chalk.green('Configuration saved'));
349
+ // Summary
350
+ p.note(formatConfig(newConfig), 'Configuration Summary');
351
+ // Ask to start
352
+ const shouldStart = await p.confirm({
353
+ message: 'Start gateway now?',
354
+ initialValue: true,
355
+ });
356
+ if (p.isCancel(shouldStart) || !shouldStart) {
357
+ p.outro(chalk.dim("Run 'corebrain gateway on' to start"));
358
+ return { success: true, started: false };
359
+ }
360
+ // Start gateway
361
+ const startSpinner = p.spinner();
362
+ startSpinner.start('Starting gateway...');
363
+ const serviceType = getServiceType();
364
+ if (serviceType === 'none') {
365
+ startSpinner.stop(chalk.red('Service management not supported'));
366
+ return { success: true, started: false, error: 'Service management not supported' };
367
+ }
368
+ const serviceName = getServiceName();
369
+ const gatewayEntryPath = getGatewayEntryPath();
370
+ const logDir = join(getConfigPath(), 'logs');
371
+ const serviceConfig = {
372
+ name: serviceName,
373
+ displayName: 'CoreBrain Gateway',
374
+ command: process.execPath,
375
+ args: [gatewayEntryPath],
376
+ port: 0,
377
+ workingDirectory: homedir(),
378
+ logPath: join(logDir, 'gateway-stdout.log'),
379
+ errorLogPath: join(logDir, 'gateway-stderr.log'),
115
380
  };
116
- // Handle start confirmation
117
- const handleStartConfirm = async (item) => {
118
- if (item.value === 'yes') {
119
- setStep('starting');
120
- try {
121
- const serviceType = getServiceType();
122
- if (serviceType === 'none') {
123
- setError('Service management not supported on this platform');
124
- setStep('error');
125
- return;
381
+ await installService(serviceConfig);
382
+ await startService(serviceName);
383
+ await new Promise((resolve) => setTimeout(resolve, 500));
384
+ const pid = getServicePid(serviceName);
385
+ const currentPrefs = getPreferences();
386
+ updatePreferences({
387
+ gateway: {
388
+ ...currentPrefs.gateway,
389
+ pid: pid ?? 0,
390
+ startedAt: Date.now(),
391
+ serviceInstalled: true,
392
+ serviceType,
393
+ serviceName,
394
+ },
395
+ });
396
+ startSpinner.stop(chalk.green('Gateway started'));
397
+ p.outro(chalk.green('Gateway is running!'));
398
+ return { success: true, started: true };
399
+ }
400
+ async function runConfig(opts) {
401
+ // Check if any direct options are provided
402
+ const hasDirectOptions = opts.name !== undefined ||
403
+ opts.description !== undefined ||
404
+ opts.coding !== undefined ||
405
+ opts.browser !== undefined ||
406
+ opts.exec !== undefined ||
407
+ opts.show;
408
+ if (hasDirectOptions) {
409
+ return runDirectUpdate(opts);
410
+ }
411
+ return runInteractiveConfig();
412
+ }
413
+ export default function GatewayConfigCommand({ options: opts }) {
414
+ const { exit } = useApp();
415
+ const [status, setStatus] = useState('running');
416
+ const [error, setError] = useState('');
417
+ useEffect(() => {
418
+ let mounted = true;
419
+ runConfig(opts)
420
+ .then((result) => {
421
+ if (mounted) {
422
+ if ('cancelled' in result && result.cancelled) {
423
+ setStatus('done');
424
+ }
425
+ else if ('success' in result && result.success) {
426
+ setStatus('done');
427
+ }
428
+ else {
429
+ setError(('error' in result && result.error) || 'Unknown error');
430
+ setStatus('error');
126
431
  }
127
- const serviceName = getServiceName();
128
- const gatewayEntryPath = getGatewayEntryPath();
129
- const logDir = join(getConfigPath(), 'logs');
130
- const serviceConfig = {
131
- name: serviceName,
132
- displayName: 'CoreBrain Gateway',
133
- command: process.execPath,
134
- args: [gatewayEntryPath],
135
- port: 0,
136
- workingDirectory: homedir(),
137
- logPath: join(logDir, 'gateway-stdout.log'),
138
- errorLogPath: join(logDir, 'gateway-stderr.log'),
139
- };
140
- await installService(serviceConfig);
141
- await startService(serviceName);
142
- // Wait a moment and get PID
143
- await new Promise((resolve) => setTimeout(resolve, 500));
144
- const pid = getServicePid(serviceName);
145
- // Update preferences with service info
146
- const prefs = getPreferences();
147
- updatePreferences({
148
- gateway: {
149
- ...prefs.gateway,
150
- pid: pid ?? 0,
151
- startedAt: Date.now(),
152
- serviceInstalled: true,
153
- serviceType: serviceType,
154
- serviceName: serviceName,
155
- },
156
- });
157
- setStep('started');
158
432
  }
159
- catch (err) {
160
- setError(err instanceof Error ? err.message : 'Failed to start gateway');
161
- setStep('error');
433
+ })
434
+ .catch((err) => {
435
+ if (mounted) {
436
+ setError(err instanceof Error ? err.message : 'Unknown error');
437
+ setStatus('error');
162
438
  }
163
- }
164
- else {
165
- setStep('done');
166
- }
167
- };
168
- // Handle escape key
169
- useInput((input, key) => {
170
- if (key.escape) {
171
- setStep('cancelled');
172
- }
173
- });
174
- // Exit on done/cancelled/error/started
439
+ });
440
+ return () => {
441
+ mounted = false;
442
+ };
443
+ }, [opts]);
175
444
  useEffect(() => {
176
- if (step === 'cancelled' || step === 'done' || step === 'started' || step === 'error') {
445
+ if (status === 'done' || status === 'error') {
177
446
  const timer = setTimeout(() => exit(), 100);
178
447
  return () => clearTimeout(timer);
179
448
  }
180
- }, [step, exit]);
181
- const editOptions = [
182
- { label: 'Edit configuration', value: 'edit' },
183
- { label: 'View current configuration', value: 'view' },
184
- { label: 'Cancel', value: 'cancel' },
185
- ];
186
- const startOptions = [
187
- { label: 'Yes, start the gateway', value: 'yes' },
188
- { label: 'No, I\'ll start it later', value: 'no' },
189
- ];
190
- return (_jsxs(ThemeContext.Provider, { value: themeContextValue, children: [step === 'checking' && _jsx(Text, { dimColor: true, children: "Checking configuration..." }), step === 'confirm-edit' && existingConfig && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, color: "cyan", children: "Existing Gateway Configuration" }), _jsx(Text, { children: " " }), _jsxs(Text, { children: ["ID: ", existingConfig.id] }), _jsxs(Text, { children: ["Name: ", existingConfig.name] }), _jsxs(Text, { children: ["Description: ", existingConfig.description || '(none)'] }), _jsx(Text, { children: " " }), _jsx(Text, { children: "What would you like to do?" }), _jsx(SelectInput, { items: editOptions, onSelect: handleEditConfirm })] })), step === 'uninstalling' && (_jsx(Text, { dimColor: true, children: "Stopping and uninstalling existing gateway..." })), step === 'input-name' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, color: "cyan", children: "Gateway Configuration" }), _jsx(Text, { children: " " }), _jsxs(Box, { children: [_jsx(Text, { children: "Gateway Name: " }), _jsx(TextInput, { value: name, onChange: setName, onSubmit: handleNameSubmit, placeholder: "e.g., my-macbook-browser" })] }), _jsxs(Text, { dimColor: true, children: ['\n', "Enter a unique name for this gateway (press Enter to confirm, Esc to cancel)"] })] })), step === 'input-description' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, color: "cyan", children: "Gateway Configuration" }), _jsx(Text, { children: " " }), _jsxs(Text, { dimColor: true, children: ["Name: ", name] }), _jsx(Text, { children: " " }), _jsxs(Box, { children: [_jsx(Text, { children: "Description: " }), _jsx(TextInput, { value: description, onChange: setDescription, onSubmit: handleDescriptionSubmit, placeholder: "e.g., Browser automation and coding on my MacBook" })] }), _jsxs(Text, { dimColor: true, children: ['\n', "Describe the role of this gateway. The meta-agent will use this to decide when to use it.", '\n', "(press Enter to confirm, Esc to cancel)"] })] })), step === 'saving' && _jsx(Text, { dimColor: true, children: "Saving configuration..." }), step === 'starting' && _jsx(Text, { dimColor: true, children: "Starting gateway service..." }), step === 'started' && (_jsx(SuccessMessage, { message: `Gateway started!\n\nID: ${gatewayId}\nName: ${name}\n\nUse 'corebrain gateway status' to check status.\nUse 'corebrain gateway off' to stop.` })), step === 'confirm-start' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(SuccessMessage, { message: `Gateway configured!\n\nID: ${gatewayId}\nName: ${name}\nDescription: ${description || '(none)'}` }), _jsx(Text, { children: " " }), _jsx(Text, { children: "Would you like to start the gateway now?" }), _jsx(SelectInput, { items: startOptions, onSelect: handleStartConfirm })] })), step === 'done' && !isEditing && existingConfig && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, color: "cyan", children: "Current Gateway Configuration" }), _jsx(Text, { children: " " }), _jsxs(Text, { children: ["ID: ", existingConfig.id] }), _jsxs(Text, { children: ["Name: ", existingConfig.name] }), _jsxs(Text, { children: ["Description: ", existingConfig.description || '(none)'] }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: "Run 'corebrain gateway on' to start the gateway" })] })), step === 'done' && (isEditing || !existingConfig) && (_jsxs(Box, { flexDirection: "column", children: [_jsx(SuccessMessage, { message: `Gateway configured!\n\nID: ${gatewayId}\nName: ${name}\nDescription: ${description || '(none)'}` }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: "Run 'corebrain gateway on' to start the gateway" })] })), step === 'cancelled' && (_jsx(Text, { dimColor: true, children: "Configuration cancelled." })), step === 'error' && _jsx(ErrorMessage, { message: error })] }));
449
+ }, [status, exit]);
450
+ if (status === 'error') {
451
+ return _jsxs(Text, { color: "red", children: ["Error: ", error] });
452
+ }
453
+ return null;
191
454
  }
192
455
  //# sourceMappingURL=config.js.map