merge: resolve conflicts with upstream OpenCode support

- Combined CLI disconnection markers with OpenCode support
- Added OpenCode auth/deauth routes and API methods
- Resolved merge conflicts between feature branch and upstream v0.9.0rc
This commit is contained in:
DhanushSantosh
2026-01-09 22:25:46 +05:30
45 changed files with 6975 additions and 958 deletions

View File

@@ -21,6 +21,9 @@ import { createAuthCursorHandler } from './routes/auth-cursor.js';
import { createDeauthClaudeHandler } from './routes/deauth-claude.js';
import { createDeauthCodexHandler } from './routes/deauth-codex.js';
import { createDeauthCursorHandler } from './routes/deauth-cursor.js';
import { createAuthOpencodeHandler } from './routes/auth-opencode.js';
import { createDeauthOpencodeHandler } from './routes/deauth-opencode.js';
import { createOpencodeStatusHandler } from './routes/opencode-status.js';
import {
createGetCursorConfigHandler,
createSetCursorDefaultModelHandler,
@@ -57,6 +60,11 @@ export function createSetupRoutes(): Router {
router.post('/install-codex', createInstallCodexHandler());
router.post('/auth-codex', createAuthCodexHandler());
router.post('/deauth-codex', createDeauthCodexHandler());
// OpenCode CLI routes
router.get('/opencode-status', createOpencodeStatusHandler());
router.post('/auth-opencode', createAuthOpencodeHandler());
router.post('/deauth-opencode', createDeauthOpencodeHandler());
router.get('/cursor-config', createGetCursorConfigHandler());
router.post('/cursor-config/default-model', createSetCursorDefaultModelHandler());
router.post('/cursor-config/models', createSetCursorModelsHandler());

View File

@@ -0,0 +1,51 @@
/**
* POST /auth-opencode endpoint - Authenticate OpenCode CLI
*/
import type { Request, Response } from 'express';
import { logError, getErrorMessage } from '../common.js';
import { exec } from 'child_process';
import { promisify } from 'util';
import * as fs from 'fs';
import * as path from 'path';
const execAsync = promisify(exec);
export function createAuthOpencodeHandler() {
return async (_req: Request, res: Response): Promise<void> => {
try {
// Remove the disconnected marker file to reconnect the app to the CLI
const markerPath = path.join(process.cwd(), '.automaker', '.opencode-disconnected');
if (fs.existsSync(markerPath)) {
fs.unlinkSync(markerPath);
}
// Check if OpenCode is already authenticated
// For OpenCode, check if there's an auth token or API key
const hasApiKey = !!process.env.OPENCODE_API_KEY;
if (hasApiKey) {
// Already has authentication, just reconnect
res.json({
success: true,
message: 'OpenCode CLI is now linked with the app',
wasAlreadyAuthenticated: true,
});
} else {
res.json({
success: true,
message:
'OpenCode CLI is now linked with the app. If prompted, please authenticate with OpenCode.',
requiresManualAuth: true,
});
}
} catch (error) {
logError(error, 'Auth OpenCode failed');
res.status(500).json({
success: false,
error: getErrorMessage(error),
message: 'Failed to link OpenCode CLI with the app',
});
}
};
}

View File

@@ -0,0 +1,40 @@
import type { Request, Response } from 'express';
import { logError, getErrorMessage } from '../common.js';
import * as fs from 'fs';
import * as path from 'path';
export function createDeauthOpencodeHandler() {
return async (_req: Request, res: Response): Promise<void> => {
try {
// Create a marker file to indicate the CLI is disconnected from the app
const automakerDir = path.join(process.cwd(), '.automaker');
const markerPath = path.join(automakerDir, '.opencode-disconnected');
// Ensure .automaker directory exists
if (!fs.existsSync(automakerDir)) {
fs.mkdirSync(automakerDir, { recursive: true });
}
// Create the marker file with timestamp
fs.writeFileSync(
markerPath,
JSON.stringify({
disconnectedAt: new Date().toISOString(),
message: 'OpenCode CLI is disconnected from the app',
})
);
res.json({
success: true,
message: 'OpenCode CLI is now disconnected from the app',
});
} catch (error) {
logError(error, 'Deauth OpenCode failed');
res.status(500).json({
success: false,
error: getErrorMessage(error),
message: 'Failed to disconnect OpenCode CLI from the app',
});
}
};
}

View File

@@ -0,0 +1,59 @@
/**
* GET /opencode-status endpoint - Get OpenCode CLI installation and auth status
*/
import type { Request, Response } from 'express';
import { OpencodeProvider } from '../../../providers/opencode-provider.js';
import { getErrorMessage, logError } from '../common.js';
/**
* Creates handler for GET /api/setup/opencode-status
* Returns OpenCode CLI installation and authentication status
*/
export function createOpencodeStatusHandler() {
const installCommand = 'curl -fsSL https://opencode.ai/install | bash';
const loginCommand = 'opencode auth login';
return async (_req: Request, res: Response): Promise<void> => {
try {
const provider = new OpencodeProvider();
const status = await provider.detectInstallation();
// Derive auth method from authenticated status and API key presence
let authMethod = 'none';
if (status.authenticated) {
authMethod = status.hasApiKey ? 'api_key_env' : 'cli_authenticated';
}
res.json({
success: true,
installed: status.installed,
version: status.version || null,
path: status.path || null,
auth: {
authenticated: status.authenticated || false,
method: authMethod,
hasApiKey: status.hasApiKey || false,
hasEnvApiKey: !!process.env.ANTHROPIC_API_KEY || !!process.env.OPENAI_API_KEY,
hasOAuthToken: status.hasOAuthToken || false,
},
recommendation: status.installed
? undefined
: 'Install OpenCode CLI to use multi-provider AI models.',
installCommand,
loginCommand,
installCommands: {
macos: installCommand,
linux: installCommand,
npm: 'npm install -g opencode-ai',
},
});
} catch (error) {
logError(error, 'Get OpenCode status failed');
res.status(500).json({
success: false,
error: getErrorMessage(error),
});
}
};
}