@redplanethq/corebrain 2.0.0 → 2.2.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.
- package/dist/commands/browser/close.d.ts +1 -1
- package/dist/commands/browser/close.d.ts.map +1 -1
- package/dist/commands/browser/close.js +39 -50
- package/dist/commands/browser/close.js.map +1 -1
- package/dist/commands/browser/command.d.ts +1 -1
- package/dist/commands/browser/command.d.ts.map +1 -1
- package/dist/commands/browser/command.js +46 -56
- package/dist/commands/browser/command.js.map +1 -1
- package/dist/commands/browser/create-profile.d.ts +1 -1
- package/dist/commands/browser/create-profile.d.ts.map +1 -1
- package/dist/commands/browser/create-profile.js +27 -21
- package/dist/commands/browser/create-profile.js.map +1 -1
- package/dist/commands/browser/delete-profile.d.ts +1 -1
- package/dist/commands/browser/delete-profile.d.ts.map +1 -1
- package/dist/commands/browser/delete-profile.js +26 -19
- package/dist/commands/browser/delete-profile.js.map +1 -1
- package/dist/commands/browser/install.d.ts +1 -1
- package/dist/commands/browser/install.d.ts.map +1 -1
- package/dist/commands/browser/install.js +31 -42
- package/dist/commands/browser/install.js.map +1 -1
- package/dist/commands/browser/open.d.ts +1 -1
- package/dist/commands/browser/open.d.ts.map +1 -1
- package/dist/commands/browser/open.js +40 -52
- package/dist/commands/browser/open.js.map +1 -1
- package/dist/commands/browser/status.d.ts +1 -1
- package/dist/commands/browser/status.d.ts.map +1 -1
- package/dist/commands/browser/status.js +36 -41
- package/dist/commands/browser/status.js.map +1 -1
- package/dist/commands/coding/config.d.ts +1 -1
- package/dist/commands/coding/config.d.ts.map +1 -1
- package/dist/commands/coding/config.js +95 -98
- package/dist/commands/coding/config.js.map +1 -1
- package/dist/commands/coding/remove.d.ts +1 -1
- package/dist/commands/coding/remove.d.ts.map +1 -1
- package/dist/commands/coding/remove.js +26 -28
- package/dist/commands/coding/remove.js.map +1 -1
- package/dist/commands/coding/setup.d.ts +1 -1
- package/dist/commands/coding/setup.d.ts.map +1 -1
- package/dist/commands/coding/setup.js +56 -71
- package/dist/commands/coding/setup.js.map +1 -1
- package/dist/commands/exec/config.d.ts +1 -1
- package/dist/commands/exec/config.d.ts.map +1 -1
- package/dist/commands/exec/config.js +71 -66
- package/dist/commands/exec/config.js.map +1 -1
- package/dist/commands/gateway/config.d.ts +10 -2
- package/dist/commands/gateway/config.d.ts.map +1 -1
- package/dist/commands/gateway/config.js +427 -156
- package/dist/commands/gateway/config.js.map +1 -1
- package/dist/commands/gateway/off.d.ts +1 -1
- package/dist/commands/gateway/off.d.ts.map +1 -1
- package/dist/commands/gateway/off.js +53 -63
- package/dist/commands/gateway/off.js.map +1 -1
- package/dist/commands/gateway/on.d.ts +1 -1
- package/dist/commands/gateway/on.d.ts.map +1 -1
- package/dist/commands/gateway/on.js +88 -117
- package/dist/commands/gateway/on.js.map +1 -1
- package/dist/commands/gateway/restart.d.ts +1 -1
- package/dist/commands/gateway/restart.d.ts.map +1 -1
- package/dist/commands/gateway/restart.js +49 -63
- package/dist/commands/gateway/restart.js.map +1 -1
- package/dist/commands/gateway/status.d.ts +1 -1
- package/dist/commands/gateway/status.d.ts.map +1 -1
- package/dist/commands/gateway/status.js +62 -76
- package/dist/commands/gateway/status.js.map +1 -1
- package/dist/commands/gateway/uninstall.d.ts +1 -1
- package/dist/commands/gateway/uninstall.d.ts.map +1 -1
- package/dist/commands/gateway/uninstall.js +60 -72
- package/dist/commands/gateway/uninstall.js.map +1 -1
- package/dist/commands/login.d.ts +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +87 -107
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.d.ts +1 -1
- package/dist/commands/logout.d.ts.map +1 -1
- package/dist/commands/logout.js +24 -45
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/me.d.ts +1 -1
- package/dist/commands/me.d.ts.map +1 -1
- package/dist/commands/me.js +40 -50
- package/dist/commands/me.js.map +1 -1
- package/dist/commands/token.d.ts +1 -1
- package/dist/commands/token.d.ts.map +1 -1
- package/dist/commands/token.js +19 -24
- package/dist/commands/token.js.map +1 -1
- package/dist/components/error-message.js +0 -1
- package/dist/components/error-message.js.map +1 -1
- package/dist/components/warning-message.js +0 -1
- package/dist/components/warning-message.js.map +1 -1
- package/dist/server/gateway-client.d.ts +9 -0
- package/dist/server/gateway-client.d.ts.map +1 -1
- package/dist/server/gateway-client.js +74 -19
- package/dist/server/gateway-client.js.map +1 -1
- package/dist/server/gateway-entry.js +28 -3
- package/dist/server/gateway-entry.js.map +1 -1
- package/dist/server/tools/exec-tools.d.ts.map +1 -1
- package/dist/server/tools/exec-tools.js +9 -0
- package/dist/server/tools/exec-tools.js.map +1 -1
- package/dist/types/config.d.ts +15 -0
- package/dist/types/config.d.ts.map +1 -1
- package/package.json +6 -3
|
@@ -1,192 +1,463 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { Text,
|
|
4
|
-
import
|
|
5
|
-
import
|
|
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';
|
|
9
11
|
import { getServiceType, getServiceName, getServiceStatus, stopService, uninstallService, isServiceInstalled, installService, startService, getServicePid, } from '../../utils/service-manager/index.js';
|
|
10
12
|
import { getConfigPath } from '../../config/paths.js';
|
|
11
13
|
import { join, dirname } from 'node:path';
|
|
12
14
|
import { fileURLToPath } from 'node:url';
|
|
13
15
|
import { homedir } from 'node:os';
|
|
14
|
-
import
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
import { isAgentBrowserInstalled, installAgentBrowser } from '../../utils/agent-browser.js';
|
|
17
|
+
const execAsync = promisify(exec);
|
|
18
|
+
const DEFAULT_APP_URL = 'https://app.getcore.me';
|
|
19
|
+
export const options = zod.object({
|
|
20
|
+
// Direct set options (non-interactive)
|
|
21
|
+
name: zod.string().optional().describe('Gateway name'),
|
|
22
|
+
description: zod.string().optional().describe('Gateway description'),
|
|
23
|
+
url: zod.string().optional().describe('App URL (default: https://app.getcore.me)'),
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
+
if (!existingConfig?.id) {
|
|
110
|
+
p.log.error('Gateway not configured. Run `corebrain gateway config` without flags first.');
|
|
111
|
+
return { success: false, error: 'Not configured' };
|
|
112
|
+
}
|
|
113
|
+
const newConfig = { ...existingConfig };
|
|
114
|
+
if (opts.name !== undefined) {
|
|
115
|
+
newConfig.name = opts.name;
|
|
116
|
+
}
|
|
117
|
+
if (opts.description !== undefined) {
|
|
118
|
+
newConfig.description = opts.description;
|
|
119
|
+
}
|
|
120
|
+
if (opts.url !== undefined) {
|
|
121
|
+
newConfig.url = opts.url;
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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: App URL
|
|
192
|
+
const url = await p.text({
|
|
193
|
+
message: 'App URL',
|
|
194
|
+
placeholder: DEFAULT_APP_URL,
|
|
195
|
+
initialValue: existingConfig?.url || DEFAULT_APP_URL,
|
|
196
|
+
});
|
|
197
|
+
if (p.isCancel(url)) {
|
|
198
|
+
p.cancel('Configuration cancelled');
|
|
199
|
+
return { cancelled: true };
|
|
200
|
+
}
|
|
201
|
+
// Step 4: Coding slot
|
|
202
|
+
const codingSpinner = p.spinner();
|
|
203
|
+
codingSpinner.start('Checking for claude-code...');
|
|
204
|
+
const claudeResult = await isClaudeCodeInstalled();
|
|
205
|
+
codingSpinner.stop(claudeResult.installed
|
|
206
|
+
? chalk.green(`Found: ${claudeResult.path}`)
|
|
207
|
+
: chalk.yellow('claude-code not found'));
|
|
208
|
+
let codingEnabled = false;
|
|
209
|
+
let claudePath;
|
|
210
|
+
if (claudeResult.installed) {
|
|
211
|
+
claudePath = claudeResult.path;
|
|
212
|
+
const enableCoding = await p.confirm({
|
|
213
|
+
message: 'Enable coding tools?',
|
|
214
|
+
initialValue: existingConfig?.slots?.coding?.enabled ?? true,
|
|
215
|
+
});
|
|
216
|
+
if (p.isCancel(enableCoding)) {
|
|
217
|
+
p.cancel('Configuration cancelled');
|
|
218
|
+
return { cancelled: true };
|
|
219
|
+
}
|
|
220
|
+
codingEnabled = enableCoding;
|
|
221
|
+
}
|
|
222
|
+
// Step 5: Browser slot
|
|
223
|
+
const browserSpinner = p.spinner();
|
|
224
|
+
browserSpinner.start('Checking for agent-browser...');
|
|
225
|
+
let browserInstalled = await isAgentBrowserInstalled();
|
|
226
|
+
browserSpinner.stop(browserInstalled
|
|
227
|
+
? chalk.green('agent-browser installed')
|
|
228
|
+
: chalk.yellow('agent-browser not found'));
|
|
229
|
+
let browserEnabled = false;
|
|
230
|
+
if (!browserInstalled) {
|
|
231
|
+
const installBrowser = await p.confirm({
|
|
232
|
+
message: 'Install agent-browser? (npm install -g agent-browser)',
|
|
233
|
+
initialValue: false,
|
|
234
|
+
});
|
|
235
|
+
if (p.isCancel(installBrowser)) {
|
|
236
|
+
p.cancel('Configuration cancelled');
|
|
237
|
+
return { cancelled: true };
|
|
238
|
+
}
|
|
239
|
+
if (installBrowser) {
|
|
240
|
+
const npmAvailable = await isNpmAvailable();
|
|
241
|
+
if (!npmAvailable) {
|
|
242
|
+
p.log.warning('npm not available, skipping browser installation');
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
const installSpinner = p.spinner();
|
|
246
|
+
installSpinner.start('Installing agent-browser...');
|
|
247
|
+
try {
|
|
248
|
+
const result = await installAgentBrowser();
|
|
249
|
+
if (result.code === 0) {
|
|
250
|
+
installSpinner.stop(chalk.green('agent-browser installed'));
|
|
251
|
+
browserInstalled = true;
|
|
252
|
+
browserEnabled = true;
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
installSpinner.stop(chalk.red('Installation failed'));
|
|
70
256
|
}
|
|
71
257
|
}
|
|
258
|
+
catch {
|
|
259
|
+
installSpinner.stop(chalk.red('Installation failed'));
|
|
260
|
+
}
|
|
72
261
|
}
|
|
73
|
-
catch {
|
|
74
|
-
// Continue anyway
|
|
75
|
-
}
|
|
76
|
-
setStep('input-name');
|
|
77
262
|
}
|
|
78
|
-
|
|
79
|
-
|
|
263
|
+
}
|
|
264
|
+
if (browserInstalled && !browserEnabled) {
|
|
265
|
+
const enableBrowser = await p.confirm({
|
|
266
|
+
message: 'Enable browser tools?',
|
|
267
|
+
initialValue: existingConfig?.slots?.browser?.enabled ?? true,
|
|
268
|
+
});
|
|
269
|
+
if (p.isCancel(enableBrowser)) {
|
|
270
|
+
p.cancel('Configuration cancelled');
|
|
271
|
+
return { cancelled: true };
|
|
80
272
|
}
|
|
81
|
-
|
|
82
|
-
|
|
273
|
+
browserEnabled = enableBrowser;
|
|
274
|
+
}
|
|
275
|
+
// Step 6: Exec slot
|
|
276
|
+
const enableExec = await p.confirm({
|
|
277
|
+
message: 'Enable exec tools? (run shell commands)',
|
|
278
|
+
initialValue: existingConfig?.slots?.exec?.enabled ?? false,
|
|
279
|
+
});
|
|
280
|
+
if (p.isCancel(enableExec)) {
|
|
281
|
+
p.cancel('Configuration cancelled');
|
|
282
|
+
return { cancelled: true };
|
|
283
|
+
}
|
|
284
|
+
let execEnabled = enableExec;
|
|
285
|
+
let execAllow = [];
|
|
286
|
+
let execDeny = [];
|
|
287
|
+
if (execEnabled) {
|
|
288
|
+
const selectedCommands = await p.multiselect({
|
|
289
|
+
message: 'Select allowed commands',
|
|
290
|
+
options: EXEC_COMMAND_OPTIONS,
|
|
291
|
+
initialValues: existingConfig?.slots?.exec?.allow || [],
|
|
292
|
+
required: false,
|
|
293
|
+
});
|
|
294
|
+
if (p.isCancel(selectedCommands)) {
|
|
295
|
+
p.cancel('Configuration cancelled');
|
|
296
|
+
return { cancelled: true };
|
|
83
297
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
|
|
298
|
+
execAllow = selectedCommands;
|
|
299
|
+
// Ask for denied commands from remaining
|
|
300
|
+
const remainingCommands = EXEC_COMMAND_OPTIONS.filter(opt => !execAllow.includes(opt.value));
|
|
301
|
+
if (remainingCommands.length > 0) {
|
|
302
|
+
const deniedCommands = await p.multiselect({
|
|
303
|
+
message: 'Select denied commands (optional)',
|
|
304
|
+
options: remainingCommands,
|
|
305
|
+
initialValues: existingConfig?.slots?.exec?.deny || [],
|
|
306
|
+
required: false,
|
|
307
|
+
});
|
|
308
|
+
if (!p.isCancel(deniedCommands)) {
|
|
309
|
+
execDeny = deniedCommands;
|
|
310
|
+
}
|
|
90
311
|
}
|
|
312
|
+
}
|
|
313
|
+
// Save configuration
|
|
314
|
+
const saveSpinner = p.spinner();
|
|
315
|
+
saveSpinner.start('Saving configuration...');
|
|
316
|
+
const gatewayId = existingConfig?.id || randomUUID();
|
|
317
|
+
const slots = {
|
|
318
|
+
coding: { enabled: codingEnabled },
|
|
319
|
+
browser: { enabled: browserEnabled },
|
|
320
|
+
exec: {
|
|
321
|
+
enabled: execEnabled,
|
|
322
|
+
allow: execAllow.length > 0 ? execAllow : undefined,
|
|
323
|
+
deny: execDeny.length > 0 ? execDeny : undefined,
|
|
324
|
+
},
|
|
325
|
+
};
|
|
326
|
+
const newConfig = {
|
|
327
|
+
...prefs.gateway,
|
|
328
|
+
id: gatewayId,
|
|
329
|
+
name: name,
|
|
330
|
+
description: description || '',
|
|
331
|
+
url: url || DEFAULT_APP_URL,
|
|
332
|
+
port: prefs.gateway?.port || 0,
|
|
333
|
+
pid: prefs.gateway?.pid || 0,
|
|
334
|
+
startedAt: prefs.gateway?.startedAt || 0,
|
|
335
|
+
slots,
|
|
91
336
|
};
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
description: value.trim(),
|
|
104
|
-
port: prefs.gateway?.port || 0,
|
|
105
|
-
pid: prefs.gateway?.pid || 0,
|
|
106
|
-
startedAt: prefs.gateway?.startedAt || 0,
|
|
337
|
+
// Save coding config if enabled
|
|
338
|
+
if (codingEnabled && claudePath) {
|
|
339
|
+
const codingConfig = prefs.coding || {};
|
|
340
|
+
if (!codingConfig['claude-code']) {
|
|
341
|
+
codingConfig['claude-code'] = {
|
|
342
|
+
command: claudePath,
|
|
343
|
+
args: ['-p', '--output-format', 'text', '--dangerously-skip-permissions'],
|
|
344
|
+
resumeArgs: ['-p', '--output-format', 'text', '--dangerously-skip-permissions', '--resume', '{sessionId}'],
|
|
345
|
+
sessionArg: '--session',
|
|
346
|
+
sessionMode: 'always',
|
|
347
|
+
sessionIdFields: ['session_id'],
|
|
107
348
|
};
|
|
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
349
|
}
|
|
350
|
+
updatePreferences({ gateway: newConfig, coding: codingConfig });
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
updatePreferences({ gateway: newConfig });
|
|
354
|
+
}
|
|
355
|
+
saveSpinner.stop(chalk.green('Configuration saved'));
|
|
356
|
+
// Summary
|
|
357
|
+
p.note(formatConfig(newConfig), 'Configuration Summary');
|
|
358
|
+
// Ask to start
|
|
359
|
+
const shouldStart = await p.confirm({
|
|
360
|
+
message: 'Start gateway now?',
|
|
361
|
+
initialValue: true,
|
|
362
|
+
});
|
|
363
|
+
if (p.isCancel(shouldStart) || !shouldStart) {
|
|
364
|
+
p.outro(chalk.dim("Run 'corebrain gateway on' to start"));
|
|
365
|
+
return { success: true, started: false };
|
|
366
|
+
}
|
|
367
|
+
// Start gateway
|
|
368
|
+
const startSpinner = p.spinner();
|
|
369
|
+
startSpinner.start('Starting gateway...');
|
|
370
|
+
const serviceType = getServiceType();
|
|
371
|
+
if (serviceType === 'none') {
|
|
372
|
+
startSpinner.stop(chalk.red('Service management not supported'));
|
|
373
|
+
return { success: true, started: false, error: 'Service management not supported' };
|
|
374
|
+
}
|
|
375
|
+
const serviceName = getServiceName();
|
|
376
|
+
const gatewayEntryPath = getGatewayEntryPath();
|
|
377
|
+
const logDir = join(getConfigPath(), 'logs');
|
|
378
|
+
const serviceConfig = {
|
|
379
|
+
name: serviceName,
|
|
380
|
+
displayName: 'CoreBrain Gateway',
|
|
381
|
+
command: process.execPath,
|
|
382
|
+
args: [gatewayEntryPath],
|
|
383
|
+
port: 0,
|
|
384
|
+
workingDirectory: homedir(),
|
|
385
|
+
logPath: join(logDir, 'gateway-stdout.log'),
|
|
386
|
+
errorLogPath: join(logDir, 'gateway-stderr.log'),
|
|
115
387
|
};
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
388
|
+
await installService(serviceConfig);
|
|
389
|
+
await startService(serviceName);
|
|
390
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
391
|
+
const pid = getServicePid(serviceName);
|
|
392
|
+
const currentPrefs = getPreferences();
|
|
393
|
+
updatePreferences({
|
|
394
|
+
gateway: {
|
|
395
|
+
...currentPrefs.gateway,
|
|
396
|
+
pid: pid ?? 0,
|
|
397
|
+
startedAt: Date.now(),
|
|
398
|
+
serviceInstalled: true,
|
|
399
|
+
serviceType,
|
|
400
|
+
serviceName,
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
startSpinner.stop(chalk.green('Gateway started'));
|
|
404
|
+
p.outro(chalk.green('Gateway is running!'));
|
|
405
|
+
return { success: true, started: true };
|
|
406
|
+
}
|
|
407
|
+
async function runConfig(opts) {
|
|
408
|
+
// Check if any direct options are provided
|
|
409
|
+
const hasDirectOptions = opts.name !== undefined ||
|
|
410
|
+
opts.description !== undefined ||
|
|
411
|
+
opts.url !== undefined ||
|
|
412
|
+
opts.coding !== undefined ||
|
|
413
|
+
opts.browser !== undefined ||
|
|
414
|
+
opts.exec !== undefined ||
|
|
415
|
+
opts.show;
|
|
416
|
+
if (hasDirectOptions) {
|
|
417
|
+
return runDirectUpdate(opts);
|
|
418
|
+
}
|
|
419
|
+
return runInteractiveConfig();
|
|
420
|
+
}
|
|
421
|
+
export default function GatewayConfigCommand({ options: opts }) {
|
|
422
|
+
const { exit } = useApp();
|
|
423
|
+
const [status, setStatus] = useState('running');
|
|
424
|
+
const [error, setError] = useState('');
|
|
425
|
+
useEffect(() => {
|
|
426
|
+
let mounted = true;
|
|
427
|
+
runConfig(opts)
|
|
428
|
+
.then((result) => {
|
|
429
|
+
if (mounted) {
|
|
430
|
+
if ('cancelled' in result && result.cancelled) {
|
|
431
|
+
setStatus('done');
|
|
432
|
+
}
|
|
433
|
+
else if ('success' in result && result.success) {
|
|
434
|
+
setStatus('done');
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
setError(('error' in result && result.error) || 'Unknown error');
|
|
438
|
+
setStatus('error');
|
|
126
439
|
}
|
|
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
440
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
441
|
+
})
|
|
442
|
+
.catch((err) => {
|
|
443
|
+
if (mounted) {
|
|
444
|
+
setError(err instanceof Error ? err.message : 'Unknown error');
|
|
445
|
+
setStatus('error');
|
|
162
446
|
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
|
|
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
|
|
447
|
+
});
|
|
448
|
+
return () => {
|
|
449
|
+
mounted = false;
|
|
450
|
+
};
|
|
451
|
+
}, [opts]);
|
|
175
452
|
useEffect(() => {
|
|
176
|
-
if (
|
|
453
|
+
if (status === 'done' || status === 'error') {
|
|
177
454
|
const timer = setTimeout(() => exit(), 100);
|
|
178
455
|
return () => clearTimeout(timer);
|
|
179
456
|
}
|
|
180
|
-
}, [
|
|
181
|
-
|
|
182
|
-
{
|
|
183
|
-
|
|
184
|
-
|
|
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 })] }));
|
|
457
|
+
}, [status, exit]);
|
|
458
|
+
if (status === 'error') {
|
|
459
|
+
return _jsxs(Text, { color: "red", children: ["Error: ", error] });
|
|
460
|
+
}
|
|
461
|
+
return null;
|
|
191
462
|
}
|
|
192
463
|
//# sourceMappingURL=config.js.map
|