|
|
@@ -1,27 +1,28 @@
|
|
|
-import { existsSync } from "node:fs";
|
|
|
+import { existsSync } from 'node:fs';
|
|
|
import {
|
|
|
addPluginToOpenCodeConfig,
|
|
|
detectCurrentConfig,
|
|
|
disableDefaultAgents,
|
|
|
+ enableLspByDefault,
|
|
|
generateLiteConfig,
|
|
|
getOpenCodePath,
|
|
|
getOpenCodeVersion,
|
|
|
isOpenCodeInstalled,
|
|
|
writeLiteConfig,
|
|
|
-} from "./config-manager";
|
|
|
-import { CUSTOM_SKILLS, installCustomSkill } from "./custom-skills";
|
|
|
-import { getExistingLiteConfigPath } from "./paths";
|
|
|
-import { installSkill, RECOMMENDED_SKILLS } from "./skills";
|
|
|
-import type { ConfigMergeResult, InstallArgs, InstallConfig } from "./types";
|
|
|
+} from './config-manager';
|
|
|
+import { CUSTOM_SKILLS, installCustomSkill } from './custom-skills';
|
|
|
+import { getExistingLiteConfigPath } from './paths';
|
|
|
+import { installSkill, RECOMMENDED_SKILLS } from './skills';
|
|
|
+import type { ConfigMergeResult, InstallArgs, InstallConfig } from './types';
|
|
|
|
|
|
// Colors
|
|
|
-const GREEN = "\x1b[32m";
|
|
|
-const BLUE = "\x1b[34m";
|
|
|
-const YELLOW = "\x1b[33m";
|
|
|
-const RED = "\x1b[31m";
|
|
|
-const BOLD = "\x1b[1m";
|
|
|
-const DIM = "\x1b[2m";
|
|
|
-const RESET = "\x1b[0m";
|
|
|
+const GREEN = '\x1b[32m';
|
|
|
+const BLUE = '\x1b[34m';
|
|
|
+const YELLOW = '\x1b[33m';
|
|
|
+const RED = '\x1b[31m';
|
|
|
+const BOLD = '\x1b[1m';
|
|
|
+const DIM = '\x1b[2m';
|
|
|
+const RESET = '\x1b[0m';
|
|
|
|
|
|
const SYMBOLS = {
|
|
|
check: `${GREEN}[ok]${RESET}`,
|
|
|
@@ -36,9 +37,9 @@ const SYMBOLS = {
|
|
|
function printHeader(isUpdate: boolean): void {
|
|
|
console.log();
|
|
|
console.log(
|
|
|
- `${BOLD}oh-my-opencode-slim ${isUpdate ? "Update" : "Install"}${RESET}`
|
|
|
+ `${BOLD}oh-my-opencode-slim ${isUpdate ? 'Update' : 'Install'}${RESET}`,
|
|
|
);
|
|
|
- console.log("=".repeat(30));
|
|
|
+ console.log('='.repeat(30));
|
|
|
console.log();
|
|
|
}
|
|
|
|
|
|
@@ -65,35 +66,35 @@ async function checkOpenCodeInstalled(): Promise<{
|
|
|
}> {
|
|
|
const installed = await isOpenCodeInstalled();
|
|
|
if (!installed) {
|
|
|
- printError("OpenCode is not installed on this system.");
|
|
|
- printInfo("Install it with:");
|
|
|
+ printError('OpenCode is not installed on this system.');
|
|
|
+ printInfo('Install it with:');
|
|
|
console.log(
|
|
|
- ` ${BLUE}curl -fsSL https://opencode.ai/install | bash${RESET}`
|
|
|
+ ` ${BLUE}curl -fsSL https://opencode.ai/install | bash${RESET}`,
|
|
|
);
|
|
|
console.log();
|
|
|
- printInfo("Or if already installed, add it to your PATH:");
|
|
|
+ printInfo('Or if already installed, add it to your PATH:');
|
|
|
console.log(` ${BLUE}export PATH="$HOME/.local/bin:$PATH"${RESET}`);
|
|
|
console.log(` ${BLUE}export PATH="$HOME/.opencode/bin:$PATH"${RESET}`);
|
|
|
return { ok: false };
|
|
|
}
|
|
|
const version = await getOpenCodeVersion();
|
|
|
const path = getOpenCodePath();
|
|
|
- const detectedVersion = version ?? "";
|
|
|
- const pathInfo = path ? ` (${DIM}${path}${RESET})` : "";
|
|
|
+ const detectedVersion = version ?? '';
|
|
|
+ const pathInfo = path ? ` (${DIM}${path}${RESET})` : '';
|
|
|
printSuccess(`OpenCode ${detectedVersion} detected${pathInfo}`);
|
|
|
return { ok: true, version: version ?? undefined, path: path ?? undefined };
|
|
|
}
|
|
|
|
|
|
function handleStepResult(
|
|
|
result: ConfigMergeResult,
|
|
|
- successMsg: string
|
|
|
+ successMsg: string,
|
|
|
): boolean {
|
|
|
if (!result.success) {
|
|
|
printError(`Failed: ${result.error}`);
|
|
|
return false;
|
|
|
}
|
|
|
printSuccess(
|
|
|
- `${successMsg} ${SYMBOLS.arrow} ${DIM}${result.configPath}${RESET}`
|
|
|
+ `${successMsg} ${SYMBOLS.arrow} ${DIM}${result.configPath}${RESET}`,
|
|
|
);
|
|
|
return true;
|
|
|
}
|
|
|
@@ -104,38 +105,46 @@ async function runInstall(config: InstallConfig): Promise<number> {
|
|
|
|
|
|
printHeader(isUpdate);
|
|
|
|
|
|
- let totalSteps = 4;
|
|
|
+ let totalSteps = 5;
|
|
|
if (config.installSkills) totalSteps += 1;
|
|
|
if (config.installCustomSkills) totalSteps += 1;
|
|
|
|
|
|
let step = 1;
|
|
|
|
|
|
- printStep(step++, totalSteps, "Checking OpenCode installation...");
|
|
|
+ printStep(step++, totalSteps, 'Checking OpenCode installation...');
|
|
|
if (config.dryRun) {
|
|
|
- printInfo("Dry run mode - skipping OpenCode check");
|
|
|
+ printInfo('Dry run mode - skipping OpenCode check');
|
|
|
} else {
|
|
|
const { ok } = await checkOpenCodeInstalled();
|
|
|
if (!ok) return 1;
|
|
|
}
|
|
|
- printStep(step++, totalSteps, "Adding oh-my-opencode-slim plugin...");
|
|
|
+ printStep(step++, totalSteps, 'Adding oh-my-opencode-slim plugin...');
|
|
|
if (config.dryRun) {
|
|
|
- printInfo("Dry run mode - skipping plugin installation");
|
|
|
+ printInfo('Dry run mode - skipping plugin installation');
|
|
|
} else {
|
|
|
const pluginResult = await addPluginToOpenCodeConfig();
|
|
|
- if (!handleStepResult(pluginResult, "Plugin added")) return 1;
|
|
|
+ if (!handleStepResult(pluginResult, 'Plugin added')) return 1;
|
|
|
}
|
|
|
- printStep(step++, totalSteps, "Disabling OpenCode default agents...");
|
|
|
+ printStep(step++, totalSteps, 'Disabling OpenCode default agents...');
|
|
|
if (config.dryRun) {
|
|
|
- printInfo("Dry run mode - skipping agent disabling");
|
|
|
+ printInfo('Dry run mode - skipping agent disabling');
|
|
|
} else {
|
|
|
const agentResult = disableDefaultAgents();
|
|
|
- if (!handleStepResult(agentResult, "Default agents disabled")) return 1;
|
|
|
+ if (!handleStepResult(agentResult, 'Default agents disabled')) return 1;
|
|
|
}
|
|
|
|
|
|
- printStep(step++, totalSteps, "Writing oh-my-opencode-slim configuration...");
|
|
|
+ printStep(step++, totalSteps, 'Enabling OpenCode LSP integration...');
|
|
|
+ if (config.dryRun) {
|
|
|
+ printInfo('Dry run mode - skipping LSP configuration');
|
|
|
+ } else {
|
|
|
+ const lspResult = enableLspByDefault();
|
|
|
+ if (!handleStepResult(lspResult, 'LSP enabled')) return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ printStep(step++, totalSteps, 'Writing oh-my-opencode-slim configuration...');
|
|
|
if (config.dryRun) {
|
|
|
const liteConfig = generateLiteConfig(config);
|
|
|
- printInfo("Dry run mode - configuration that would be written:");
|
|
|
+ printInfo('Dry run mode - configuration that would be written:');
|
|
|
console.log(`\n${JSON.stringify(liteConfig, null, 2)}\n`);
|
|
|
} else {
|
|
|
const configPath = getExistingLiteConfigPath();
|
|
|
@@ -144,17 +153,17 @@ async function runInstall(config: InstallConfig): Promise<number> {
|
|
|
if (configExists && !config.reset) {
|
|
|
printInfo(
|
|
|
`Configuration already exists at ${configPath}. ` +
|
|
|
- "Use --reset to overwrite."
|
|
|
+ 'Use --reset to overwrite.',
|
|
|
);
|
|
|
} else {
|
|
|
const liteResult = writeLiteConfig(
|
|
|
config,
|
|
|
- configExists ? configPath : undefined
|
|
|
+ configExists ? configPath : undefined,
|
|
|
);
|
|
|
if (
|
|
|
!handleStepResult(
|
|
|
liteResult,
|
|
|
- configExists ? "Config reset" : "Config written"
|
|
|
+ configExists ? 'Config reset' : 'Config written',
|
|
|
)
|
|
|
)
|
|
|
return 1;
|
|
|
@@ -163,9 +172,9 @@ async function runInstall(config: InstallConfig): Promise<number> {
|
|
|
|
|
|
// Install skills if requested
|
|
|
if (config.installSkills) {
|
|
|
- printStep(step++, totalSteps, "Installing recommended skills...");
|
|
|
+ printStep(step++, totalSteps, 'Installing recommended skills...');
|
|
|
if (config.dryRun) {
|
|
|
- printInfo("Dry run mode - would install skills:");
|
|
|
+ printInfo('Dry run mode - would install skills:');
|
|
|
for (const skill of RECOMMENDED_SKILLS) {
|
|
|
printInfo(` - ${skill.name}`);
|
|
|
}
|
|
|
@@ -181,16 +190,16 @@ async function runInstall(config: InstallConfig): Promise<number> {
|
|
|
}
|
|
|
}
|
|
|
printSuccess(
|
|
|
- `${skillsInstalled}/${RECOMMENDED_SKILLS.length} skills processed`
|
|
|
+ `${skillsInstalled}/${RECOMMENDED_SKILLS.length} skills processed`,
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Install custom skills if requested
|
|
|
if (config.installCustomSkills) {
|
|
|
- printStep(step++, totalSteps, "Installing custom skills...");
|
|
|
+ printStep(step++, totalSteps, 'Installing custom skills...');
|
|
|
if (config.dryRun) {
|
|
|
- printInfo("Dry run mode - would install custom skills:");
|
|
|
+ printInfo('Dry run mode - would install custom skills:');
|
|
|
for (const skill of CUSTOM_SKILLS) {
|
|
|
printInfo(` - ${skill.name}`);
|
|
|
}
|
|
|
@@ -207,14 +216,14 @@ async function runInstall(config: InstallConfig): Promise<number> {
|
|
|
}
|
|
|
const totalCustom = CUSTOM_SKILLS.length;
|
|
|
printSuccess(
|
|
|
- `${customSkillsInstalled}/${totalCustom} custom skills processed`
|
|
|
+ `${customSkillsInstalled}/${totalCustom} custom skills processed`,
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
const statusMsg = isUpdate
|
|
|
- ? "Configuration updated!"
|
|
|
- : "Installation complete!";
|
|
|
+ ? 'Configuration updated!'
|
|
|
+ : 'Installation complete!';
|
|
|
console.log(`${SYMBOLS.star} ${BOLD}${GREEN}${statusMsg}${RESET}`);
|
|
|
console.log();
|
|
|
console.log(`${BOLD}Next steps:${RESET}`);
|
|
|
@@ -222,30 +231,30 @@ async function runInstall(config: InstallConfig): Promise<number> {
|
|
|
|
|
|
const configPath = getExistingLiteConfigPath();
|
|
|
|
|
|
- console.log(" 1. Log in to the provider(s) you want to use:");
|
|
|
+ console.log(' 1. Log in to the provider(s) you want to use:');
|
|
|
console.log(` ${BLUE}$ opencode auth login${RESET}`);
|
|
|
console.log();
|
|
|
- console.log(" 2. Refresh the models OpenCode can see:");
|
|
|
+ console.log(' 2. Refresh the models OpenCode can see:');
|
|
|
console.log(` ${BLUE}$ opencode models --refresh${RESET}`);
|
|
|
console.log();
|
|
|
- console.log(" 3. Review your generated config:");
|
|
|
+ console.log(' 3. Review your generated config:');
|
|
|
console.log(` ${BLUE}${configPath}${RESET}`);
|
|
|
console.log();
|
|
|
- console.log(" 4. Start OpenCode:");
|
|
|
+ console.log(' 4. Start OpenCode:');
|
|
|
console.log(` ${BLUE}$ opencode${RESET}`);
|
|
|
console.log();
|
|
|
- console.log(" 5. Verify the agents are responding:");
|
|
|
+ console.log(' 5. Verify the agents are responding:');
|
|
|
console.log(` ${BLUE}> ping all agents${RESET}`);
|
|
|
console.log();
|
|
|
|
|
|
const modelsInfo =
|
|
|
- "Default configuration uses OpenAI models (gpt-5.5 / gpt-5.4-mini).";
|
|
|
+ 'Default configuration uses OpenAI models (gpt-5.5 / gpt-5.4-mini).';
|
|
|
console.log(`${modelsInfo}`);
|
|
|
- const altProviders = "For the full configuration reference, see:";
|
|
|
+ const altProviders = 'For the full configuration reference, see:';
|
|
|
console.log(altProviders);
|
|
|
const docsUrl =
|
|
|
- "https://github.com/alvinunreal/oh-my-opencode-slim/" +
|
|
|
- "blob/master/docs/configuration.md";
|
|
|
+ 'https://github.com/alvinunreal/oh-my-opencode-slim/' +
|
|
|
+ 'blob/master/docs/configuration.md';
|
|
|
console.log(` ${BLUE}${docsUrl}${RESET}`);
|
|
|
console.log();
|
|
|
|
|
|
@@ -255,8 +264,8 @@ async function runInstall(config: InstallConfig): Promise<number> {
|
|
|
export async function install(args: InstallArgs): Promise<number> {
|
|
|
const config: InstallConfig = {
|
|
|
hasTmux: false,
|
|
|
- installSkills: args.skills === "yes",
|
|
|
- installCustomSkills: args.skills === "yes",
|
|
|
+ installSkills: args.skills === 'yes',
|
|
|
+ installCustomSkills: args.skills === 'yes',
|
|
|
dryRun: args.dryRun,
|
|
|
reset: args.reset ?? false,
|
|
|
};
|