Revert "feat: add --remote-url CLI option to connect to remote OpenCode instances (#161)"
This reverts commit 53f8e1324e.
This commit is contained in:
+5
-26
@@ -74,7 +74,7 @@ function buildTunnelUrl(baseUrl, password, includePassword) {
|
|||||||
function parseArgs() {
|
function parseArgs() {
|
||||||
const args = process.argv.slice(2);
|
const args = process.argv.slice(2);
|
||||||
const envPassword = process.env.OPENCHAMBER_UI_PASSWORD || undefined;
|
const envPassword = process.env.OPENCHAMBER_UI_PASSWORD || undefined;
|
||||||
const options = { port: DEFAULT_PORT, daemon: false, uiPassword: envPassword, tryCfTunnel: false, tunnelQr: false, tunnelPasswordUrl: false, remoteUrl: null };
|
const options = { port: DEFAULT_PORT, daemon: false, uiPassword: envPassword, tryCfTunnel: false, tunnelQr: false, tunnelPasswordUrl: false };
|
||||||
let command = 'serve';
|
let command = 'serve';
|
||||||
|
|
||||||
const consumeValue = (currentIndex, inlineValue) => {
|
const consumeValue = (currentIndex, inlineValue) => {
|
||||||
@@ -132,12 +132,6 @@ function parseArgs() {
|
|||||||
options.uiPassword = typeof value === 'string' ? value : '';
|
options.uiPassword = typeof value === 'string' ? value : '';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'remote-url': {
|
|
||||||
const { value, nextIndex } = consumeValue(i, inlineValue);
|
|
||||||
i = nextIndex;
|
|
||||||
options.remoteUrl = typeof value === 'string' && value.length > 0 ? value : null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'help':
|
case 'help':
|
||||||
case 'h':
|
case 'h':
|
||||||
showHelp();
|
showHelp();
|
||||||
@@ -173,7 +167,6 @@ COMMANDS:
|
|||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
-p, --port Web server port (default: ${DEFAULT_PORT})
|
-p, --port Web server port (default: ${DEFAULT_PORT})
|
||||||
--remote-url Connect to remote OpenCode instance instead of starting local
|
|
||||||
--ui-password Protect browser UI with single password
|
--ui-password Protect browser UI with single password
|
||||||
--try-cf-tunnel Create a Cloudflare Quick Tunnel for remote access
|
--try-cf-tunnel Create a Cloudflare Quick Tunnel for remote access
|
||||||
--tunnel-qr Display QR code for tunnel URL (use with --try-cf-tunnel)
|
--tunnel-qr Display QR code for tunnel URL (use with --try-cf-tunnel)
|
||||||
@@ -184,14 +177,12 @@ OPTIONS:
|
|||||||
|
|
||||||
ENVIRONMENT:
|
ENVIRONMENT:
|
||||||
OPENCHAMBER_UI_PASSWORD Alternative to --ui-password flag
|
OPENCHAMBER_UI_PASSWORD Alternative to --ui-password flag
|
||||||
OPENCODE_REMOTE_URL Alternative to --remote-url flag
|
|
||||||
|
|
||||||
EXAMPLES:
|
EXAMPLES:
|
||||||
openchamber # Start on default port 3000
|
openchamber # Start on default port 3000
|
||||||
openchamber --port 8080 # Start on port 8080
|
openchamber --port 8080 # Start on port 8080
|
||||||
openchamber serve --daemon # Start in background
|
openchamber serve --daemon # Start in background
|
||||||
openchamber --try-cf-tunnel # Start with Cloudflare Quick Tunnel
|
openchamber --try-cf-tunnel # Start with Cloudflare Quick Tunnel
|
||||||
openchamber --remote-url http://remote-server:3000 # Connect to remote OpenCode
|
|
||||||
openchamber stop # Stop all running instances
|
openchamber stop # Stop all running instances
|
||||||
openchamber stop --port 3000 # Stop specific instance
|
openchamber stop --port 3000 # Stop specific instance
|
||||||
openchamber status # Check status
|
openchamber status # Check status
|
||||||
@@ -465,8 +456,7 @@ const commands = {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// When remoteUrl is provided, skip local OpenCode CLI check
|
const opencodeBinary = await checkOpenCodeCLI();
|
||||||
const opencodeBinary = options.remoteUrl ? null : await checkOpenCodeCLI();
|
|
||||||
|
|
||||||
const serverPath = path.join(__dirname, '..', 'server', 'index.js');
|
const serverPath = path.join(__dirname, '..', 'server', 'index.js');
|
||||||
|
|
||||||
@@ -485,9 +475,6 @@ const commands = {
|
|||||||
if (options.tryCfTunnel) {
|
if (options.tryCfTunnel) {
|
||||||
serverArgs.push('--try-cf-tunnel');
|
serverArgs.push('--try-cf-tunnel');
|
||||||
}
|
}
|
||||||
if (options.remoteUrl) {
|
|
||||||
serverArgs.push('--remote-url', options.remoteUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
const preferredRuntime = getPreferredServerRuntime();
|
const preferredRuntime = getPreferredServerRuntime();
|
||||||
const runtimeBin = preferredRuntime === 'bun' ? BUN_BIN : process.execPath;
|
const runtimeBin = preferredRuntime === 'bun' ? BUN_BIN : process.execPath;
|
||||||
@@ -500,10 +487,9 @@ const commands = {
|
|||||||
env: {
|
env: {
|
||||||
...process.env,
|
...process.env,
|
||||||
OPENCHAMBER_PORT: options.port.toString(),
|
OPENCHAMBER_PORT: options.port.toString(),
|
||||||
...(opencodeBinary ? { OPENCODE_BINARY: opencodeBinary } : {}),
|
OPENCODE_BINARY: opencodeBinary,
|
||||||
...(typeof effectiveUiPassword === 'string' ? { OPENCHAMBER_UI_PASSWORD: effectiveUiPassword } : {}),
|
...(typeof effectiveUiPassword === 'string' ? { OPENCHAMBER_UI_PASSWORD: effectiveUiPassword } : {}),
|
||||||
OPENCHAMBER_TRY_CF_TUNNEL: options.tryCfTunnel ? 'true' : 'false',
|
OPENCHAMBER_TRY_CF_TUNNEL: options.tryCfTunnel ? 'true' : 'false',
|
||||||
...(options.remoteUrl ? { OPENCODE_REMOTE_URL: options.remoteUrl } : {}),
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -528,15 +514,10 @@ const commands = {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (opencodeBinary) {
|
process.env.OPENCODE_BINARY = opencodeBinary;
|
||||||
process.env.OPENCODE_BINARY = opencodeBinary;
|
|
||||||
}
|
|
||||||
if (typeof effectiveUiPassword === 'string') {
|
if (typeof effectiveUiPassword === 'string') {
|
||||||
process.env.OPENCHAMBER_UI_PASSWORD = effectiveUiPassword;
|
process.env.OPENCHAMBER_UI_PASSWORD = effectiveUiPassword;
|
||||||
}
|
}
|
||||||
if (options.remoteUrl) {
|
|
||||||
process.env.OPENCODE_REMOTE_URL = options.remoteUrl;
|
|
||||||
}
|
|
||||||
if (showAutoGeneratedPassword) {
|
if (showAutoGeneratedPassword) {
|
||||||
console.log(`\n🔐 Auto-generated password: \x1b[92m${effectiveUiPassword}\x1b[0m`);
|
console.log(`\n🔐 Auto-generated password: \x1b[92m${effectiveUiPassword}\x1b[0m`);
|
||||||
console.log('⚠️ Save this password - it won\'t be shown again!\n');
|
console.log('⚠️ Save this password - it won\'t be shown again!\n');
|
||||||
@@ -552,10 +533,9 @@ const commands = {
|
|||||||
env: {
|
env: {
|
||||||
...process.env,
|
...process.env,
|
||||||
OPENCHAMBER_PORT: options.port.toString(),
|
OPENCHAMBER_PORT: options.port.toString(),
|
||||||
...(opencodeBinary ? { OPENCODE_BINARY: opencodeBinary } : {}),
|
OPENCODE_BINARY: opencodeBinary,
|
||||||
...(typeof effectiveUiPassword === 'string' ? { OPENCHAMBER_UI_PASSWORD: effectiveUiPassword } : {}),
|
...(typeof effectiveUiPassword === 'string' ? { OPENCHAMBER_UI_PASSWORD: effectiveUiPassword } : {}),
|
||||||
OPENCHAMBER_TRY_CF_TUNNEL: options.tryCfTunnel ? 'true' : 'false',
|
OPENCHAMBER_TRY_CF_TUNNEL: options.tryCfTunnel ? 'true' : 'false',
|
||||||
...(options.remoteUrl ? { OPENCODE_REMOTE_URL: options.remoteUrl } : {}),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -573,7 +553,6 @@ const commands = {
|
|||||||
exitOnShutdown: true,
|
exitOnShutdown: true,
|
||||||
uiPassword: typeof effectiveUiPassword === 'string' ? effectiveUiPassword : null,
|
uiPassword: typeof effectiveUiPassword === 'string' ? effectiveUiPassword : null,
|
||||||
tryCfTunnel: options.tryCfTunnel,
|
tryCfTunnel: options.tryCfTunnel,
|
||||||
remoteUrl: options.remoteUrl,
|
|
||||||
onTunnelReady: async (url) => {
|
onTunnelReady: async (url) => {
|
||||||
const displayUrl = buildTunnelUrl(url, effectiveUiPassword, options.tunnelPasswordUrl);
|
const displayUrl = buildTunnelUrl(url, effectiveUiPassword, options.tunnelPasswordUrl);
|
||||||
console.log(`\n🌐 Tunnel URL: \x1b[36m${displayUrl}\x1b[0m\n`);
|
console.log(`\n🌐 Tunnel URL: \x1b[36m${displayUrl}\x1b[0m\n`);
|
||||||
|
|||||||
@@ -1217,8 +1217,7 @@ function parseArgs(argv = process.argv.slice(2)) {
|
|||||||
process.env.OPENCODE_UI_PASSWORD ||
|
process.env.OPENCODE_UI_PASSWORD ||
|
||||||
null;
|
null;
|
||||||
const envCfTunnel = process.env.OPENCHAMBER_TRY_CF_TUNNEL === 'true';
|
const envCfTunnel = process.env.OPENCHAMBER_TRY_CF_TUNNEL === 'true';
|
||||||
const envRemoteUrl = process.env.OPENCODE_REMOTE_URL || null;
|
const options = { port: DEFAULT_PORT, uiPassword: envPassword, tryCfTunnel: envCfTunnel };
|
||||||
const options = { port: DEFAULT_PORT, uiPassword: envPassword, tryCfTunnel: envCfTunnel, remoteUrl: envRemoteUrl };
|
|
||||||
|
|
||||||
const consumeValue = (currentIndex, inlineValue) => {
|
const consumeValue = (currentIndex, inlineValue) => {
|
||||||
if (typeof inlineValue === 'string') {
|
if (typeof inlineValue === 'string') {
|
||||||
@@ -1260,13 +1259,6 @@ function parseArgs(argv = process.argv.slice(2)) {
|
|||||||
options.tryCfTunnel = true;
|
options.tryCfTunnel = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optionName === 'remote-url') {
|
|
||||||
const { value, nextIndex } = consumeValue(i, inlineValue);
|
|
||||||
i = nextIndex;
|
|
||||||
options.remoteUrl = typeof value === 'string' && value.length > 0 ? value : null;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
@@ -1667,20 +1659,14 @@ function setupProxy(app) {
|
|||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
const remoteOrigin = process.env.__OPENCODE_REMOTE_ORIGIN || null;
|
|
||||||
const getProxyTarget = () => {
|
|
||||||
if (remoteOrigin) {
|
|
||||||
return remoteOrigin;
|
|
||||||
}
|
|
||||||
if (!openCodePort) {
|
|
||||||
return 'http://127.0.0.1:0';
|
|
||||||
}
|
|
||||||
return `http://localhost:${openCodePort}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const proxyMiddleware = createProxyMiddleware({
|
const proxyMiddleware = createProxyMiddleware({
|
||||||
target: getProxyTarget(),
|
target: openCodePort ? `http://localhost:${openCodePort}` : 'http://127.0.0.1:0',
|
||||||
router: getProxyTarget,
|
router: () => {
|
||||||
|
if (!openCodePort) {
|
||||||
|
return 'http://127.0.0.1:0';
|
||||||
|
}
|
||||||
|
return `http://localhost:${openCodePort}`;
|
||||||
|
},
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
pathRewrite: (path) => {
|
pathRewrite: (path) => {
|
||||||
if (!path.startsWith('/api')) {
|
if (!path.startsWith('/api')) {
|
||||||
@@ -1813,7 +1799,6 @@ async function main(options = {}) {
|
|||||||
const tryCfTunnel = options.tryCfTunnel === true;
|
const tryCfTunnel = options.tryCfTunnel === true;
|
||||||
const attachSignals = options.attachSignals !== false;
|
const attachSignals = options.attachSignals !== false;
|
||||||
const onTunnelReady = typeof options.onTunnelReady === 'function' ? options.onTunnelReady : null;
|
const onTunnelReady = typeof options.onTunnelReady === 'function' ? options.onTunnelReady : null;
|
||||||
const remoteUrl = typeof options.remoteUrl === 'string' && options.remoteUrl.length > 0 ? options.remoteUrl : null;
|
|
||||||
if (typeof options.exitOnShutdown === 'boolean') {
|
if (typeof options.exitOnShutdown === 'boolean') {
|
||||||
exitOnShutdown = options.exitOnShutdown;
|
exitOnShutdown = options.exitOnShutdown;
|
||||||
}
|
}
|
||||||
@@ -4715,58 +4700,34 @@ async function main(options = {}) {
|
|||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (remoteUrl) {
|
// Check if we can reuse an existing OpenCode process from a previous HMR cycle
|
||||||
console.log(`Using remote OpenCode instance at: ${remoteUrl}`);
|
syncFromHmrState();
|
||||||
try {
|
if (await isOpenCodeProcessHealthy()) {
|
||||||
const parsedUrl = new URL(remoteUrl);
|
console.log(`[HMR] Reusing existing OpenCode process on port ${openCodePort}`);
|
||||||
const remotePort = parseInt(parsedUrl.port, 10) || (parsedUrl.protocol === 'https:' ? 443 : 80);
|
|
||||||
const remotePrefix = normalizeApiPrefix(parsedUrl.pathname);
|
|
||||||
|
|
||||||
openCodePort = remotePort;
|
|
||||||
syncToHmrState();
|
|
||||||
|
|
||||||
// Remote origin is used by setupProxy to route requests to remote OpenCode
|
|
||||||
process.env.__OPENCODE_REMOTE_ORIGIN = `${parsedUrl.protocol}//${parsedUrl.host}`;
|
|
||||||
|
|
||||||
setDetectedOpenCodeApiPrefix(remotePrefix);
|
|
||||||
isOpenCodeReady = true;
|
|
||||||
lastOpenCodeError = null;
|
|
||||||
openCodeNotReadySince = 0;
|
|
||||||
|
|
||||||
console.log(`Remote OpenCode configured - port: ${remotePort}, prefix: ${remotePrefix || '(root)'}`);
|
|
||||||
} catch (urlError) {
|
|
||||||
throw new Error(`Invalid remote URL "${remoteUrl}": ${urlError.message}`);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
syncFromHmrState();
|
// No healthy process, start fresh
|
||||||
if (await isOpenCodeProcessHealthy()) {
|
if (ENV_CONFIGURED_OPENCODE_PORT) {
|
||||||
console.log(`[HMR] Reusing existing OpenCode process on port ${openCodePort}`);
|
console.log(`Using OpenCode port from environment: ${ENV_CONFIGURED_OPENCODE_PORT}`);
|
||||||
|
setOpenCodePort(ENV_CONFIGURED_OPENCODE_PORT);
|
||||||
} else {
|
} else {
|
||||||
if (ENV_CONFIGURED_OPENCODE_PORT) {
|
openCodePort = null;
|
||||||
console.log(`Using OpenCode port from environment: ${ENV_CONFIGURED_OPENCODE_PORT}`);
|
|
||||||
setOpenCodePort(ENV_CONFIGURED_OPENCODE_PORT);
|
|
||||||
} else {
|
|
||||||
openCodePort = null;
|
|
||||||
syncToHmrState();
|
|
||||||
}
|
|
||||||
|
|
||||||
lastOpenCodeError = null;
|
|
||||||
openCodeProcess = await startOpenCode();
|
|
||||||
syncToHmrState();
|
syncToHmrState();
|
||||||
}
|
}
|
||||||
await waitForOpenCodePort();
|
|
||||||
try {
|
lastOpenCodeError = null;
|
||||||
await waitForOpenCodeReady();
|
openCodeProcess = await startOpenCode();
|
||||||
} catch (error) {
|
syncToHmrState();
|
||||||
console.error(`OpenCode readiness check failed: ${error.message}`);
|
}
|
||||||
scheduleOpenCodeApiDetection();
|
await waitForOpenCodePort();
|
||||||
}
|
try {
|
||||||
|
await waitForOpenCodeReady();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`OpenCode readiness check failed: ${error.message}`);
|
||||||
|
scheduleOpenCodeApiDetection();
|
||||||
}
|
}
|
||||||
setupProxy(app);
|
setupProxy(app);
|
||||||
if (!remoteUrl) {
|
scheduleOpenCodeApiDetection();
|
||||||
scheduleOpenCodeApiDetection();
|
startHealthMonitoring();
|
||||||
startHealthMonitoring();
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Failed to start OpenCode: ${error.message}`);
|
console.error(`Failed to start OpenCode: ${error.message}`);
|
||||||
console.log('Continuing without OpenCode integration...');
|
console.log('Continuing without OpenCode integration...');
|
||||||
@@ -4874,8 +4835,7 @@ if (isCliExecution) {
|
|||||||
tryCfTunnel: cliOptions.tryCfTunnel,
|
tryCfTunnel: cliOptions.tryCfTunnel,
|
||||||
attachSignals: true,
|
attachSignals: true,
|
||||||
exitOnShutdown: true,
|
exitOnShutdown: true,
|
||||||
uiPassword: cliOptions.uiPassword,
|
uiPassword: cliOptions.uiPassword
|
||||||
remoteUrl: cliOptions.remoteUrl
|
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
console.error('Failed to start server:', error);
|
console.error('Failed to start server:', error);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|||||||
Reference in New Issue
Block a user