refactor: rename remaining oh-my-opencode string literals
This commit is contained in:
@@ -32,7 +32,7 @@ function supportsAvx2() {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (process.env.OH_MY_OPENCODE_FORCE_BASELINE === "1") {
|
||||
if (process.env.OH_MY_OPENAGENT_FORCE_BASELINE === "1" || process.env.OH_MY_OPENCODE_FORCE_BASELINE === "1") {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ function main() {
|
||||
preferBaseline: avx2Supported === false,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`\noh-my-opencode: ${error.message}\n`);
|
||||
console.error(`\noh-my-openagent: ${error.message}\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ function main() {
|
||||
.filter((entry) => entry !== null);
|
||||
|
||||
if (resolvedBinaries.length === 0) {
|
||||
console.error(`\noh-my-opencode: Platform binary not installed.`);
|
||||
console.error(`\noh-my-openagent: Platform binary not installed.`);
|
||||
console.error(`\nYour platform: ${platform}-${arch}${libcFamily === "musl" ? "-musl" : ""}`);
|
||||
console.error(`Expected packages (in order): ${packageCandidates.join(", ")}`);
|
||||
console.error(`\nTo fix, run:`);
|
||||
@@ -120,7 +120,7 @@ function main() {
|
||||
continue;
|
||||
}
|
||||
|
||||
console.error(`\noh-my-opencode: Failed to execute binary.`);
|
||||
console.error(`\noh-my-openagent: Failed to execute binary.`);
|
||||
console.error(`Error: ${result.error.message}\n`);
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
+2
-2
@@ -48,9 +48,9 @@ function main() {
|
||||
);
|
||||
}
|
||||
|
||||
console.log(`✓ oh-my-opencode binary installed for ${platform}-${arch} (${resolvedPackage})`);
|
||||
console.log(`✓ oh-my-openagent binary installed for ${platform}-${arch} (${resolvedPackage})`)
|
||||
} catch (error) {
|
||||
console.warn(`⚠ oh-my-opencode: ${error.message}`);
|
||||
console.warn(`⚠ oh-my-openagent: ${error.message}`)
|
||||
console.warn(` The CLI may not work on this platform.`);
|
||||
// Don't fail installation - let user try anyway
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
exports[`generateModelConfig no providers available returns ULTIMATE_FALLBACK for all agents and categories when no providers 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "opencode/gpt-5-nano",
|
||||
@@ -66,7 +66,7 @@ exports[`generateModelConfig no providers available returns ULTIMATE_FALLBACK fo
|
||||
|
||||
exports[`generateModelConfig single native provider uses Claude models when only Claude is available 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "anthropic/claude-sonnet-4-6",
|
||||
@@ -128,7 +128,7 @@ exports[`generateModelConfig single native provider uses Claude models when only
|
||||
|
||||
exports[`generateModelConfig single native provider uses Claude models with isMax20 flag 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "anthropic/claude-sonnet-4-6",
|
||||
@@ -191,7 +191,7 @@ exports[`generateModelConfig single native provider uses Claude models with isMa
|
||||
|
||||
exports[`generateModelConfig single native provider uses OpenAI models when only OpenAI is available 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "openai/gpt-5.4",
|
||||
@@ -277,7 +277,7 @@ exports[`generateModelConfig single native provider uses OpenAI models when only
|
||||
|
||||
exports[`generateModelConfig single native provider uses OpenAI models with isMax20 flag 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "openai/gpt-5.4",
|
||||
@@ -363,7 +363,7 @@ exports[`generateModelConfig single native provider uses OpenAI models with isMa
|
||||
|
||||
exports[`generateModelConfig single native provider uses Gemini models when only Gemini is available 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "opencode/gpt-5-nano",
|
||||
@@ -423,7 +423,7 @@ exports[`generateModelConfig single native provider uses Gemini models when only
|
||||
|
||||
exports[`generateModelConfig single native provider uses Gemini models with isMax20 flag 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "opencode/gpt-5-nano",
|
||||
@@ -483,7 +483,7 @@ exports[`generateModelConfig single native provider uses Gemini models with isMa
|
||||
|
||||
exports[`generateModelConfig all native providers uses preferred models from fallback chains when all natives available 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "anthropic/claude-sonnet-4-6",
|
||||
@@ -558,7 +558,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal
|
||||
|
||||
exports[`generateModelConfig all native providers uses preferred models with isMax20 flag when all natives available 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "anthropic/claude-sonnet-4-6",
|
||||
@@ -634,7 +634,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM
|
||||
|
||||
exports[`generateModelConfig fallback providers uses OpenCode Zen models when only OpenCode Zen is available 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "opencode/claude-sonnet-4-6",
|
||||
@@ -709,7 +709,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on
|
||||
|
||||
exports[`generateModelConfig fallback providers uses OpenCode Zen models with isMax20 flag 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "opencode/claude-sonnet-4-6",
|
||||
@@ -785,7 +785,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is
|
||||
|
||||
exports[`generateModelConfig fallback providers uses GitHub Copilot models when only Copilot is available 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "github-copilot/claude-sonnet-4.6",
|
||||
@@ -855,7 +855,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when
|
||||
|
||||
exports[`generateModelConfig fallback providers uses GitHub Copilot models with isMax20 flag 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "github-copilot/claude-sonnet-4.6",
|
||||
@@ -926,7 +926,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with
|
||||
|
||||
exports[`generateModelConfig fallback providers uses ZAI model for librarian when only ZAI is available 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "opencode/gpt-5-nano",
|
||||
@@ -984,7 +984,7 @@ exports[`generateModelConfig fallback providers uses ZAI model for librarian whe
|
||||
|
||||
exports[`generateModelConfig fallback providers uses ZAI model for librarian with isMax20 flag 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "opencode/gpt-5-nano",
|
||||
@@ -1042,7 +1042,7 @@ exports[`generateModelConfig fallback providers uses ZAI model for librarian wit
|
||||
|
||||
exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen combination 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "anthropic/claude-sonnet-4-6",
|
||||
@@ -1117,7 +1117,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen
|
||||
|
||||
exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot combination 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "github-copilot/claude-sonnet-4.6",
|
||||
@@ -1192,7 +1192,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb
|
||||
|
||||
exports[`generateModelConfig mixed provider scenarios uses Claude + ZAI combination (librarian uses ZAI) 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "anthropic/claude-sonnet-4-6",
|
||||
@@ -1256,7 +1256,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + ZAI combinat
|
||||
|
||||
exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combination (explore uses Gemini) 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "anthropic/claude-sonnet-4-6",
|
||||
@@ -1322,7 +1322,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi
|
||||
|
||||
exports[`generateModelConfig mixed provider scenarios uses all fallback providers together 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "github-copilot/claude-sonnet-4.6",
|
||||
@@ -1400,7 +1400,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider
|
||||
|
||||
exports[`generateModelConfig mixed provider scenarios uses all providers together 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "anthropic/claude-sonnet-4-6",
|
||||
@@ -1478,7 +1478,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe
|
||||
|
||||
exports[`generateModelConfig mixed provider scenarios uses all providers with isMax20 flag 1`] = `
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json",
|
||||
"agents": {
|
||||
"atlas": {
|
||||
"model": "anthropic/claude-sonnet-4-6",
|
||||
|
||||
@@ -43,7 +43,7 @@ describe("runCliInstaller", () => {
|
||||
}),
|
||||
spyOn(configManager, "writeOmoConfig").mockReturnValue({
|
||||
success: true,
|
||||
configPath: "/tmp/oh-my-opencode.jsonc",
|
||||
configPath: "/tmp/oh-my-openagent.jsonc"
|
||||
}),
|
||||
]
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ export async function runCliInstaller(args: InstallArgs, version: string): Promi
|
||||
}
|
||||
console.log()
|
||||
printInfo(
|
||||
"Usage: bunx oh-my-opencode install --no-tui --claude=<no|yes|max20> --gemini=<no|yes> --copilot=<no|yes>",
|
||||
"Usage: bunx oh-my-openagent install --no-tui --claude=<no|yes|max20> --gemini=<no|yes> --copilot=<no|yes>"
|
||||
)
|
||||
console.log()
|
||||
return 1
|
||||
@@ -65,7 +65,7 @@ export async function runCliInstaller(args: InstallArgs, version: string): Promi
|
||||
|
||||
const config = argsToConfig(args)
|
||||
|
||||
printStep(step++, totalSteps, "Adding oh-my-opencode plugin...")
|
||||
printStep(step++, totalSteps, "Adding oh-my-openagent plugin...")
|
||||
const pluginResult = await addPluginToOpenCodeConfig(version)
|
||||
if (!pluginResult.success) {
|
||||
printError(`Failed: ${pluginResult.error}`)
|
||||
@@ -75,7 +75,7 @@ export async function runCliInstaller(args: InstallArgs, version: string): Promi
|
||||
`Plugin ${isUpdate ? "verified" : "added"} ${SYMBOLS.arrow} ${color.dim(pluginResult.configPath)}`,
|
||||
)
|
||||
|
||||
printStep(step++, totalSteps, "Writing oh-my-opencode configuration...")
|
||||
printStep(step++, totalSteps, "Writing oh-my-openagent configuration...")
|
||||
const omoResult = writeOmoConfig(config)
|
||||
if (!omoResult.success) {
|
||||
printError(`Failed: ${omoResult.error}`)
|
||||
|
||||
+24
-24
@@ -15,14 +15,14 @@ const VERSION = packageJson.version
|
||||
const program = new Command()
|
||||
|
||||
program
|
||||
.name("oh-my-opencode")
|
||||
.name("oh-my-openagent")
|
||||
.description("The ultimate OpenCode plugin - multi-model orchestration, LSP tools, and more")
|
||||
.version(VERSION, "-v, --version", "Show version number")
|
||||
.enablePositionalOptions()
|
||||
|
||||
program
|
||||
.command("install")
|
||||
.description("Install and configure oh-my-opencode with interactive setup")
|
||||
.description("Install and configure oh-my-openagent with interactive setup")
|
||||
.option("--no-tui", "Run in non-interactive mode (requires all options)")
|
||||
.option("--claude <value>", "Claude subscription: no, yes, max20")
|
||||
.option("--openai <value>", "OpenAI/ChatGPT subscription: no, yes (default: no)")
|
||||
@@ -35,9 +35,9 @@ program
|
||||
.option("--skip-auth", "Skip authentication setup hints")
|
||||
.addHelpText("after", `
|
||||
Examples:
|
||||
$ bunx oh-my-opencode install
|
||||
$ bunx oh-my-opencode install --no-tui --claude=max20 --openai=yes --gemini=yes --copilot=no
|
||||
$ bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=yes --opencode-zen=yes
|
||||
$ bunx oh-my-openagent install
|
||||
$ bunx oh-my-openagent install --no-tui --claude=max20 --openai=yes --gemini=yes --copilot=no
|
||||
$ bunx oh-my-openagent install --no-tui --claude=no --gemini=no --copilot=yes --opencode-zen=yes
|
||||
|
||||
Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi):
|
||||
Claude Native anthropic/ models (Opus, Sonnet, Haiku)
|
||||
@@ -82,20 +82,20 @@ program
|
||||
.option("--session-id <id>", "Resume existing session instead of creating new one")
|
||||
.addHelpText("after", `
|
||||
Examples:
|
||||
$ bunx oh-my-opencode run "Fix the bug in index.ts"
|
||||
$ bunx oh-my-opencode run --agent Sisyphus "Implement feature X"
|
||||
$ bunx oh-my-opencode run --port 4321 "Fix the bug"
|
||||
$ bunx oh-my-opencode run --attach http://127.0.0.1:4321 "Fix the bug"
|
||||
$ bunx oh-my-opencode run --json "Fix the bug" | jq .sessionId
|
||||
$ bunx oh-my-opencode run --on-complete "notify-send Done" "Fix the bug"
|
||||
$ bunx oh-my-opencode run --session-id ses_abc123 "Continue the work"
|
||||
$ bunx oh-my-opencode run --model anthropic/claude-sonnet-4 "Fix the bug"
|
||||
$ bunx oh-my-opencode run --agent Sisyphus --model openai/gpt-5.4 "Implement feature X"
|
||||
$ bunx oh-my-openagent run "Fix the bug in index.ts"
|
||||
$ bunx oh-my-openagent run --agent Sisyphus "Implement feature X"
|
||||
$ bunx oh-my-openagent run --port 4321 "Fix the bug"
|
||||
$ bunx oh-my-openagent run --attach http://127.0.0.1:4321 "Fix the bug"
|
||||
$ bunx oh-my-openagent run --json "Fix the bug" | jq .sessionId
|
||||
$ bunx oh-my-openagent run --on-complete "notify-send Done" "Fix the bug"
|
||||
$ bunx oh-my-openagent run --session-id ses_abc123 "Continue the work"
|
||||
$ bunx oh-my-openagent run --model anthropic/claude-sonnet-4 "Fix the bug"
|
||||
$ bunx oh-my-openagent run --agent Sisyphus --model openai/gpt-5.4 "Implement feature X"
|
||||
|
||||
Agent resolution order:
|
||||
1) --agent flag
|
||||
2) OPENCODE_DEFAULT_AGENT
|
||||
3) oh-my-opencode.json "default_run_agent"
|
||||
3) oh-my-openagent.json "default_run_agent"
|
||||
4) Sisyphus (fallback)
|
||||
|
||||
Available core agents:
|
||||
@@ -134,9 +134,9 @@ program
|
||||
.option("--json", "Output in JSON format for scripting")
|
||||
.addHelpText("after", `
|
||||
Examples:
|
||||
$ bunx oh-my-opencode get-local-version
|
||||
$ bunx oh-my-opencode get-local-version --json
|
||||
$ bunx oh-my-opencode get-local-version --directory /path/to/project
|
||||
$ bunx oh-my-openagent get-local-version
|
||||
$ bunx oh-my-openagent get-local-version --json
|
||||
$ bunx oh-my-openagent get-local-version --directory /path/to/project
|
||||
|
||||
This command shows:
|
||||
- Current installed version
|
||||
@@ -155,16 +155,16 @@ This command shows:
|
||||
|
||||
program
|
||||
.command("doctor")
|
||||
.description("Check oh-my-opencode installation health and diagnose issues")
|
||||
.description("Check oh-my-openagent installation health and diagnose issues")
|
||||
.option("--status", "Show compact system dashboard")
|
||||
.option("--verbose", "Show detailed diagnostic information")
|
||||
.option("--json", "Output results in JSON format")
|
||||
.addHelpText("after", `
|
||||
Examples:
|
||||
$ bunx oh-my-opencode doctor # Show problems only
|
||||
$ bunx oh-my-opencode doctor --status # Compact dashboard
|
||||
$ bunx oh-my-opencode doctor --verbose # Deep diagnostics
|
||||
$ bunx oh-my-opencode doctor --json # JSON output
|
||||
$ bunx oh-my-openagent doctor # Show problems only
|
||||
$ bunx oh-my-openagent doctor --status # Compact dashboard
|
||||
$ bunx oh-my-openagent doctor --verbose # Deep diagnostics
|
||||
$ bunx oh-my-openagent doctor --json # JSON output
|
||||
`)
|
||||
.action(async (options) => {
|
||||
const mode = options.status ? "status" : options.verbose ? "verbose" : "default"
|
||||
@@ -180,7 +180,7 @@ program
|
||||
.command("version")
|
||||
.description("Show version information")
|
||||
.action(() => {
|
||||
console.log(`oh-my-opencode v${VERSION}`)
|
||||
console.log(`oh-my-openagent v${VERSION}`)
|
||||
})
|
||||
|
||||
program.addCommand(createMcpOAuthCommand())
|
||||
|
||||
@@ -23,7 +23,7 @@ describe("getPluginNameWithVersion", () => {
|
||||
const result = await getPluginNameWithVersion("2.14.0")
|
||||
|
||||
// #then should use @latest tag
|
||||
expect(result).toBe("oh-my-opencode@latest")
|
||||
expect(result).toBe("oh-my-openagent@latest")
|
||||
})
|
||||
|
||||
test("returns @beta when current version matches beta tag", async () => {
|
||||
@@ -39,7 +39,7 @@ describe("getPluginNameWithVersion", () => {
|
||||
const result = await getPluginNameWithVersion("3.0.0-beta.3")
|
||||
|
||||
// #then should use @beta tag
|
||||
expect(result).toBe("oh-my-opencode@beta")
|
||||
expect(result).toBe("oh-my-openagent@beta")
|
||||
})
|
||||
|
||||
test("returns @next when current version matches next tag", async () => {
|
||||
@@ -55,7 +55,7 @@ describe("getPluginNameWithVersion", () => {
|
||||
const result = await getPluginNameWithVersion("3.1.0-next.1")
|
||||
|
||||
// #then should use @next tag
|
||||
expect(result).toBe("oh-my-opencode@next")
|
||||
expect(result).toBe("oh-my-openagent@next")
|
||||
})
|
||||
|
||||
test("returns prerelease channel tag when no dist-tag matches prerelease version", async () => {
|
||||
@@ -71,7 +71,7 @@ describe("getPluginNameWithVersion", () => {
|
||||
const result = await getPluginNameWithVersion("3.0.0-beta.2")
|
||||
|
||||
// #then should preserve prerelease channel
|
||||
expect(result).toBe("oh-my-opencode@beta")
|
||||
expect(result).toBe("oh-my-openagent@beta")
|
||||
})
|
||||
|
||||
test("returns prerelease channel tag when fetch fails", async () => {
|
||||
@@ -82,7 +82,7 @@ describe("getPluginNameWithVersion", () => {
|
||||
const result = await getPluginNameWithVersion("3.0.0-beta.3")
|
||||
|
||||
// #then should preserve prerelease channel
|
||||
expect(result).toBe("oh-my-opencode@beta")
|
||||
expect(result).toBe("oh-my-openagent@beta")
|
||||
})
|
||||
|
||||
test("returns bare package name when npm returns non-ok response for stable version", async () => {
|
||||
@@ -98,7 +98,7 @@ describe("getPluginNameWithVersion", () => {
|
||||
const result = await getPluginNameWithVersion("2.14.0")
|
||||
|
||||
// #then should fall back to bare package entry
|
||||
expect(result).toBe("oh-my-opencode")
|
||||
expect(result).toBe("oh-my-openagent")
|
||||
})
|
||||
|
||||
test("prioritizes latest over other tags when version matches multiple", async () => {
|
||||
@@ -114,7 +114,7 @@ describe("getPluginNameWithVersion", () => {
|
||||
const result = await getPluginNameWithVersion("3.0.0")
|
||||
|
||||
// #then should prioritize @latest
|
||||
expect(result).toBe("oh-my-opencode@latest")
|
||||
expect(result).toBe("oh-my-openagent@latest")
|
||||
})
|
||||
})
|
||||
|
||||
@@ -207,7 +207,7 @@ describe("generateOmoConfig - model fallback system", () => {
|
||||
const result = generateOmoConfig(config)
|
||||
|
||||
// #then Sisyphus is omitted (requires all fallback providers)
|
||||
expect(result.$schema).toBe("https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json")
|
||||
expect(result.$schema).toBe("https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json")
|
||||
expect((result.agents as Record<string, { model: string }>).sisyphus).toBeUndefined()
|
||||
})
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ describe("writeOmoConfig", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
testConfigDir = join(tmpdir(), `omo-write-config-${Date.now()}-${Math.random().toString(36).slice(2)}`)
|
||||
testConfigPath = join(testConfigDir, "oh-my-opencode.json")
|
||||
testConfigPath = join(testConfigDir, "oh-my-openagent.json")
|
||||
|
||||
mkdirSync(testConfigDir, { recursive: true })
|
||||
process.env.OPENCODE_CONFIG_DIR = testConfigDir
|
||||
|
||||
@@ -61,7 +61,7 @@ export function writeOmoConfig(installConfig: InstallConfig): ConfigMergeResult
|
||||
return {
|
||||
success: false,
|
||||
configPath: omoConfigPath,
|
||||
error: formatErrorWithSuggestion(err, "write oh-my-opencode config"),
|
||||
error: formatErrorWithSuggestion(err, "write oh-my-openagent config")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ describe("model-resolution check", () => {
|
||||
})
|
||||
|
||||
describe("getModelResolutionInfoWithOverrides", () => {
|
||||
// given: User has overrides in oh-my-opencode.json
|
||||
// given: User has overrides in oh-my-openagent.json
|
||||
// when: Getting resolution info with config
|
||||
// then: Shows user override in Step 1 position
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ const mockGetOpenCodeVersion = mock(async () => "1.0.200")
|
||||
const mockCompareVersions = mock(() => true)
|
||||
const mockGetPluginInfo = mock(() => ({
|
||||
registered: true,
|
||||
entry: "oh-my-opencode",
|
||||
entry: "oh-my-openagent",
|
||||
isPinned: false,
|
||||
pinnedVersion: null,
|
||||
configPath: null,
|
||||
@@ -14,7 +14,7 @@ const mockGetPluginInfo = mock(() => ({
|
||||
const mockGetLoadedPluginVersion = mock(() => ({
|
||||
cacheDir: "/Users/test/Library/Caches/opencode with spaces",
|
||||
cachePackagePath: "/tmp/package.json",
|
||||
installedPackagePath: "/tmp/node_modules/oh-my-opencode/package.json",
|
||||
installedPackagePath: "/tmp/node_modules/oh-my-openagent/package.json",
|
||||
expectedVersion: "3.0.0",
|
||||
loadedVersion: "3.1.0",
|
||||
}))
|
||||
@@ -51,7 +51,7 @@ describe("system check", () => {
|
||||
mockCompareVersions.mockReturnValue(true)
|
||||
mockGetPluginInfo.mockReturnValue({
|
||||
registered: true,
|
||||
entry: "oh-my-opencode",
|
||||
entry: "oh-my-openagent",
|
||||
isPinned: false,
|
||||
pinnedVersion: null,
|
||||
configPath: null,
|
||||
@@ -60,7 +60,7 @@ describe("system check", () => {
|
||||
mockGetLoadedPluginVersion.mockReturnValue({
|
||||
cacheDir: "/Users/test/Library/Caches/opencode with spaces",
|
||||
cachePackagePath: "/tmp/package.json",
|
||||
installedPackagePath: "/tmp/node_modules/oh-my-opencode/package.json",
|
||||
installedPackagePath: "/tmp/node_modules/oh-my-openagent/package.json",
|
||||
expectedVersion: "3.0.0",
|
||||
loadedVersion: "3.1.0",
|
||||
})
|
||||
@@ -82,7 +82,7 @@ describe("system check", () => {
|
||||
mockGetLoadedPluginVersion.mockReturnValue({
|
||||
cacheDir: "/Users/test/Library/Caches/opencode with spaces",
|
||||
cachePackagePath: "/tmp/package.json",
|
||||
installedPackagePath: "/tmp/node_modules/oh-my-opencode/package.json",
|
||||
installedPackagePath: "/tmp/node_modules/oh-my-openagent/package.json",
|
||||
expectedVersion: "3.0.0-canary.1",
|
||||
loadedVersion: "3.0.0-canary.1",
|
||||
})
|
||||
@@ -97,7 +97,7 @@ describe("system check", () => {
|
||||
//#then
|
||||
const outdatedIssue = result.issues.find((issue) => issue.title === "Loaded plugin is outdated")
|
||||
expect(outdatedIssue?.fix).toBe(
|
||||
'Update: cd "/Users/test/Library/Caches/opencode with spaces" && bun add oh-my-opencode@canary'
|
||||
'Update: cd "/Users/test/Library/Caches/opencode with spaces" && bun add oh-my-openagent@canary'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -82,9 +82,9 @@ export async function checkSystem(): Promise<CheckResult> {
|
||||
|
||||
if (!pluginInfo.registered) {
|
||||
issues.push({
|
||||
title: "oh-my-opencode is not registered",
|
||||
title: "oh-my-openagent is not registered",
|
||||
description: "Plugin entry is missing from OpenCode configuration.",
|
||||
fix: "Run: bunx oh-my-opencode install",
|
||||
fix: "Run: bunx oh-my-openagent install",
|
||||
severity: "error",
|
||||
affects: ["all agents"],
|
||||
})
|
||||
@@ -108,7 +108,7 @@ export async function checkSystem(): Promise<CheckResult> {
|
||||
issues.push({
|
||||
title: "Loaded plugin is outdated",
|
||||
description: `Loaded ${systemInfo.loadedVersion}, latest ${latestVersion}.`,
|
||||
fix: `Update: cd "${loadedInfo.cacheDir}" && bun add oh-my-opencode@${installTag}`,
|
||||
fix: `Update: cd "${loadedInfo.cacheDir}" && bun add oh-my-openagent@${installTag}`,
|
||||
severity: "warning",
|
||||
affects: ["plugin features"],
|
||||
})
|
||||
|
||||
@@ -15,7 +15,7 @@ export function formatDefault(result: DoctorResult): string {
|
||||
const pluginVer = result.systemInfo.pluginVersion ?? "unknown"
|
||||
lines.push(
|
||||
` ${color.green(SYMBOLS.check)} ${color.green(
|
||||
`System OK (opencode ${opencodeVer} · oh-my-opencode ${pluginVer})`
|
||||
`System OK (opencode ${opencodeVer} · oh-my-openagent ${pluginVer})`
|
||||
)}`
|
||||
)
|
||||
} else {
|
||||
|
||||
@@ -12,7 +12,7 @@ export function formatVerbose(result: DoctorResult): string {
|
||||
lines.push(`${color.bold("System Information")}`)
|
||||
lines.push(`${color.dim("\u2500".repeat(40))}`)
|
||||
lines.push(` ${formatStatusSymbol("pass")} opencode ${systemInfo.opencodeVersion ?? "unknown"}`)
|
||||
lines.push(` ${formatStatusSymbol("pass")} oh-my-opencode ${systemInfo.pluginVersion ?? "unknown"}`)
|
||||
lines.push(` ${formatStatusSymbol("pass")} oh-my-openagent ${systemInfo.pluginVersion ?? "unknown"}`)
|
||||
if (systemInfo.loadedVersion) {
|
||||
lines.push(` ${formatStatusSymbol("pass")} loaded ${systemInfo.loadedVersion}`)
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ describe("formatDoctorOutput", () => {
|
||||
const output = stripAnsi(formatDoctorOutput(result, "default"))
|
||||
|
||||
//#then
|
||||
expect(output).toContain("System OK (opencode 1.0.200 · oh-my-opencode 3.4.0)")
|
||||
expect(output).toContain("System OK (opencode 1.0.200 · oh-my-openagent 3.4.0)")
|
||||
})
|
||||
|
||||
it("shows issue count and details when issues exist", async () => {
|
||||
|
||||
@@ -15,7 +15,7 @@ export function formatVersionOutput(info: VersionInfo): string {
|
||||
const lines: string[] = []
|
||||
|
||||
lines.push("")
|
||||
lines.push(color.bold(color.white("oh-my-opencode Version Information")))
|
||||
lines.push(color.bold(color.white("oh-my-openagent Version Information")))
|
||||
lines.push(color.dim("─".repeat(50)))
|
||||
lines.push("")
|
||||
|
||||
@@ -37,7 +37,7 @@ export function formatVersionOutput(info: VersionInfo): string {
|
||||
break
|
||||
case "outdated":
|
||||
lines.push(` ${SYMBOLS.warn} ${color.yellow("Update available")}`)
|
||||
lines.push(` ${color.dim("Run:")} ${color.cyan("cd ~/.config/opencode && bun update oh-my-opencode")}`)
|
||||
lines.push(` ${color.dim("Run:")} ${color.cyan("cd ~/.config/opencode && bun update oh-my-openagent")}`)
|
||||
break
|
||||
case "local-dev":
|
||||
lines.push(` ${SYMBOLS.dev} ${color.cyan("Running in local development mode")}`)
|
||||
|
||||
@@ -108,7 +108,7 @@ describe("install CLI - binary check behavior", () => {
|
||||
// then opencode.json should have plugin entry
|
||||
const config = JSON.parse(readFileSync(configPath, "utf-8"))
|
||||
expect(config.plugin).toBeDefined()
|
||||
expect(config.plugin.some((p: string) => p.includes("oh-my-opencode"))).toBe(true)
|
||||
expect(config.plugin.some((p: string) => p.includes("oh-my-openagent"))).toBe(true)
|
||||
|
||||
// then exit code should be 0 (success)
|
||||
expect(exitCode).toBe(0)
|
||||
|
||||
@@ -559,7 +559,7 @@ describe("generateModelConfig", () => {
|
||||
|
||||
// #then should include correct schema URL
|
||||
expect(result.$schema).toBe(
|
||||
"https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json"
|
||||
"https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json"
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -20,7 +20,7 @@ export type { GeneratedOmoConfig } from "./model-fallback-types"
|
||||
const ZAI_MODEL = "zai-coding-plan/glm-4.7"
|
||||
|
||||
const ULTIMATE_FALLBACK = "opencode/gpt-5-nano"
|
||||
const SCHEMA_URL = "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json"
|
||||
const SCHEMA_URL = "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json"
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ describe("resolveSession", () => {
|
||||
expect(result).toBe("new-session-id")
|
||||
expect(mockClient.session.create).toHaveBeenCalledWith({
|
||||
body: {
|
||||
title: "oh-my-opencode run",
|
||||
title: "oh-my-openagent run",
|
||||
permission: [
|
||||
{ permission: "question", action: "deny", pattern: "*" },
|
||||
],
|
||||
@@ -113,7 +113,7 @@ describe("resolveSession", () => {
|
||||
expect(mockClient.session.create).toHaveBeenCalledTimes(2)
|
||||
expect(mockClient.session.create).toHaveBeenCalledWith({
|
||||
body: {
|
||||
title: "oh-my-opencode run",
|
||||
title: "oh-my-openagent run",
|
||||
permission: [
|
||||
{ permission: "question", action: "deny", pattern: "*" },
|
||||
],
|
||||
|
||||
@@ -26,7 +26,7 @@ export async function resolveSession(options: {
|
||||
for (let attempt = 1; attempt <= SESSION_CREATE_MAX_RETRIES; attempt++) {
|
||||
const res = await client.session.create({
|
||||
body: {
|
||||
title: "oh-my-opencode run",
|
||||
title: "oh-my-openagent run",
|
||||
// In CLI run mode there's no TUI to answer questions.
|
||||
permission: [
|
||||
{ permission: "question", action: "deny" as const, pattern: "*" },
|
||||
|
||||
@@ -43,7 +43,7 @@ export async function runTuiInstaller(args: InstallArgs, version: string): Promi
|
||||
const config = await promptInstallConfig(detected)
|
||||
if (!config) return 1
|
||||
|
||||
spinner.start("Adding oh-my-opencode to OpenCode config")
|
||||
spinner.start("Adding oh-my-openagent to OpenCode config")
|
||||
const pluginResult = await addPluginToOpenCodeConfig(version)
|
||||
if (!pluginResult.success) {
|
||||
spinner.stop(`Failed to add plugin: ${pluginResult.error}`)
|
||||
@@ -52,7 +52,7 @@ export async function runTuiInstaller(args: InstallArgs, version: string): Promi
|
||||
}
|
||||
spinner.stop(`Plugin added to ${color.cyan(pluginResult.configPath)}`)
|
||||
|
||||
spinner.start("Writing oh-my-opencode configuration")
|
||||
spinner.start("Writing oh-my-openagent configuration")
|
||||
const omoResult = writeOmoConfig(config)
|
||||
if (!omoResult.success) {
|
||||
spinner.stop(`Failed to write config: ${omoResult.error}`)
|
||||
|
||||
@@ -25,7 +25,7 @@ export const OhMyOpenAgentConfigSchema = z.object({
|
||||
$schema: z.string().optional(),
|
||||
/** Enable new task system (default: false) */
|
||||
new_task_system_enabled: z.boolean().optional(),
|
||||
/** Default agent name for `oh-my-opencode run` (env: OPENCODE_DEFAULT_AGENT) */
|
||||
/** Default agent name for `oh-my-openagent run` (env: OPENCODE_DEFAULT_AGENT) */
|
||||
default_run_agent: z.string().optional(),
|
||||
disabled_mcps: z.array(AnyMcpNameSchema).optional(),
|
||||
disabled_agents: z.array(z.string()).optional(),
|
||||
|
||||
@@ -222,11 +222,12 @@ export interface ClaudeSettings {
|
||||
*/
|
||||
export interface PluginLoaderOptions {
|
||||
/**
|
||||
* Override enabled plugins from oh-my-opencode config.
|
||||
* Override enabled plugins from oh-my-openagent config.
|
||||
* Key format: "pluginName@marketplace" (e.g., "shell-scripting@claude-code-workflows")
|
||||
* Value: true = enabled, false = disabled
|
||||
*
|
||||
*
|
||||
* This takes precedence over ~/.claude/settings.json enabledPlugins
|
||||
*/
|
||||
enabledPluginsOverride?: Record<string, boolean>
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ const TEST_USER_CONFIG_DIR = "/tmp/opencode-config"
|
||||
mock.module("./constants", () => ({
|
||||
CACHE_DIR: TEST_OPENCODE_CACHE_DIR,
|
||||
USER_CONFIG_DIR: TEST_USER_CONFIG_DIR,
|
||||
PACKAGE_NAME: "oh-my-opencode",
|
||||
PACKAGE_NAME: "oh-my-openagent",
|
||||
}))
|
||||
|
||||
mock.module("../../shared/logger", () => ({
|
||||
@@ -21,10 +21,10 @@ function resetTestCache(): void {
|
||||
rmSync(TEST_CACHE_DIR, { recursive: true, force: true })
|
||||
}
|
||||
|
||||
mkdirSync(join(TEST_OPENCODE_CACHE_DIR, "node_modules", "oh-my-opencode"), { recursive: true })
|
||||
mkdirSync(join(TEST_OPENCODE_CACHE_DIR, "node_modules", "oh-my-openagent"), { recursive: true })
|
||||
writeFileSync(
|
||||
join(TEST_OPENCODE_CACHE_DIR, "package.json"),
|
||||
JSON.stringify({ dependencies: { "oh-my-opencode": "latest", other: "1.0.0" } }, null, 2)
|
||||
JSON.stringify({ dependencies: { "oh-my-openagent": "latest", other: "1.0.0" } }, null, 2)
|
||||
)
|
||||
writeFileSync(
|
||||
join(TEST_OPENCODE_CACHE_DIR, "bun.lock"),
|
||||
@@ -32,11 +32,11 @@ function resetTestCache(): void {
|
||||
{
|
||||
workspaces: {
|
||||
"": {
|
||||
dependencies: { "oh-my-opencode": "latest", other: "1.0.0" },
|
||||
dependencies: { "oh-my-openagent": "latest", other: "1.0.0" },
|
||||
},
|
||||
},
|
||||
packages: {
|
||||
"oh-my-opencode": {},
|
||||
"oh-my-openagent": {},
|
||||
other: {},
|
||||
},
|
||||
},
|
||||
@@ -45,8 +45,8 @@ function resetTestCache(): void {
|
||||
)
|
||||
)
|
||||
writeFileSync(
|
||||
join(TEST_OPENCODE_CACHE_DIR, "node_modules", "oh-my-opencode", "package.json"),
|
||||
'{"name":"oh-my-opencode"}'
|
||||
join(TEST_OPENCODE_CACHE_DIR, "node_modules", "oh-my-openagent", "package.json"),
|
||||
'{"name":"oh-my-openagent"}'
|
||||
)
|
||||
}
|
||||
|
||||
@@ -67,21 +67,21 @@ describe("invalidatePackage", () => {
|
||||
const result = invalidatePackage()
|
||||
|
||||
expect(result).toBe(true)
|
||||
expect(existsSync(join(TEST_OPENCODE_CACHE_DIR, "node_modules", "oh-my-opencode"))).toBe(false)
|
||||
expect(existsSync(join(TEST_OPENCODE_CACHE_DIR, "node_modules", "oh-my-openagent"))).toBe(false)
|
||||
|
||||
const packageJson = JSON.parse(readFileSync(join(TEST_OPENCODE_CACHE_DIR, "package.json"), "utf-8")) as {
|
||||
dependencies?: Record<string, string>
|
||||
}
|
||||
expect(packageJson.dependencies?.["oh-my-opencode"]).toBe("latest")
|
||||
expect(packageJson.dependencies?.["oh-my-openagent"]).toBe("latest")
|
||||
expect(packageJson.dependencies?.other).toBe("1.0.0")
|
||||
|
||||
const bunLock = JSON.parse(readFileSync(join(TEST_OPENCODE_CACHE_DIR, "bun.lock"), "utf-8")) as {
|
||||
workspaces?: { ""?: { dependencies?: Record<string, string> } }
|
||||
packages?: Record<string, unknown>
|
||||
}
|
||||
expect(bunLock.workspaces?.[""]?.dependencies?.["oh-my-opencode"]).toBe("latest")
|
||||
expect(bunLock.workspaces?.[""]?.dependencies?.["oh-my-openagent"]).toBe("latest")
|
||||
expect(bunLock.workspaces?.[""]?.dependencies?.other).toBe("1.0.0")
|
||||
expect(bunLock.packages?.["oh-my-opencode"]).toBeUndefined()
|
||||
expect(bunLock.packages?.["oh-my-openagent"]).toBeUndefined()
|
||||
expect(bunLock.packages?.other).toEqual({})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -21,18 +21,18 @@ describe("pinned-version-updater", () => {
|
||||
test("updates pinned version in config", () => {
|
||||
//#given
|
||||
const config = JSON.stringify({
|
||||
plugin: ["oh-my-opencode@3.1.8"],
|
||||
plugin: ["oh-my-openagent@3.1.8"],
|
||||
})
|
||||
fs.writeFileSync(configPath, config)
|
||||
|
||||
//#when
|
||||
const result = updatePinnedVersion(configPath, "oh-my-opencode@3.1.8", "3.4.0")
|
||||
const result = updatePinnedVersion(configPath, "oh-my-openagent@3.1.8", "3.4.0")
|
||||
|
||||
//#then
|
||||
expect(result).toBe(true)
|
||||
const updated = fs.readFileSync(configPath, "utf-8")
|
||||
expect(updated).toContain("oh-my-opencode@3.4.0")
|
||||
expect(updated).not.toContain("oh-my-opencode@3.1.8")
|
||||
expect(updated).toContain("oh-my-openagent@3.4.0")
|
||||
expect(updated).not.toContain("oh-my-openagent@3.1.8")
|
||||
})
|
||||
|
||||
test("returns false when entry not found", () => {
|
||||
@@ -43,7 +43,7 @@ describe("pinned-version-updater", () => {
|
||||
fs.writeFileSync(configPath, config)
|
||||
|
||||
//#when
|
||||
const result = updatePinnedVersion(configPath, "oh-my-opencode@3.1.8", "3.4.0")
|
||||
const result = updatePinnedVersion(configPath, "oh-my-openagent@3.1.8", "3.4.0")
|
||||
|
||||
//#then
|
||||
expect(result).toBe(false)
|
||||
@@ -55,7 +55,7 @@ describe("pinned-version-updater", () => {
|
||||
fs.writeFileSync(configPath, config)
|
||||
|
||||
//#when
|
||||
const result = updatePinnedVersion(configPath, "oh-my-opencode@3.1.8", "3.4.0")
|
||||
const result = updatePinnedVersion(configPath, "oh-my-openagent@3.1.8", "3.4.0")
|
||||
|
||||
//#then
|
||||
expect(result).toBe(false)
|
||||
@@ -66,46 +66,46 @@ describe("pinned-version-updater", () => {
|
||||
test("reverts from failed version back to original entry", () => {
|
||||
//#given
|
||||
const config = JSON.stringify({
|
||||
plugin: ["oh-my-opencode@3.4.0"],
|
||||
plugin: ["oh-my-openagent@3.4.0"],
|
||||
})
|
||||
fs.writeFileSync(configPath, config)
|
||||
|
||||
//#when
|
||||
const result = revertPinnedVersion(configPath, "3.4.0", "oh-my-opencode@3.1.8")
|
||||
const result = revertPinnedVersion(configPath, "3.4.0", "oh-my-openagent@3.1.8")
|
||||
|
||||
//#then
|
||||
expect(result).toBe(true)
|
||||
const reverted = fs.readFileSync(configPath, "utf-8")
|
||||
expect(reverted).toContain("oh-my-opencode@3.1.8")
|
||||
expect(reverted).not.toContain("oh-my-opencode@3.4.0")
|
||||
expect(reverted).toContain("oh-my-openagent@3.1.8")
|
||||
expect(reverted).not.toContain("oh-my-openagent@3.4.0")
|
||||
})
|
||||
|
||||
test("reverts to unpinned entry", () => {
|
||||
//#given
|
||||
const config = JSON.stringify({
|
||||
plugin: ["oh-my-opencode@3.4.0"],
|
||||
plugin: ["oh-my-openagent@3.4.0"],
|
||||
})
|
||||
fs.writeFileSync(configPath, config)
|
||||
|
||||
//#when
|
||||
const result = revertPinnedVersion(configPath, "3.4.0", "oh-my-opencode")
|
||||
const result = revertPinnedVersion(configPath, "3.4.0", "oh-my-openagent")
|
||||
|
||||
//#then
|
||||
expect(result).toBe(true)
|
||||
const reverted = fs.readFileSync(configPath, "utf-8")
|
||||
expect(reverted).toContain('"oh-my-opencode"')
|
||||
expect(reverted).not.toContain("oh-my-opencode@3.4.0")
|
||||
expect(reverted).toContain('"oh-my-openagent"')
|
||||
expect(reverted).not.toContain("oh-my-openagent@3.4.0")
|
||||
})
|
||||
|
||||
test("returns false when failed version not found", () => {
|
||||
//#given
|
||||
const config = JSON.stringify({
|
||||
plugin: ["oh-my-opencode@3.1.8"],
|
||||
plugin: ["oh-my-openagent@3.1.8"],
|
||||
})
|
||||
fs.writeFileSync(configPath, config)
|
||||
|
||||
//#when
|
||||
const result = revertPinnedVersion(configPath, "3.4.0", "oh-my-opencode@3.1.8")
|
||||
const result = revertPinnedVersion(configPath, "3.4.0", "oh-my-openagent@3.1.8")
|
||||
|
||||
//#then
|
||||
expect(result).toBe(false)
|
||||
@@ -116,18 +116,18 @@ describe("pinned-version-updater", () => {
|
||||
test("config returns to original state after update + revert", () => {
|
||||
//#given
|
||||
const originalConfig = JSON.stringify({
|
||||
plugin: ["oh-my-opencode@3.1.8"],
|
||||
plugin: ["oh-my-openagent@3.1.8"],
|
||||
})
|
||||
fs.writeFileSync(configPath, originalConfig)
|
||||
|
||||
//#when
|
||||
updatePinnedVersion(configPath, "oh-my-opencode@3.1.8", "3.4.0")
|
||||
revertPinnedVersion(configPath, "3.4.0", "oh-my-opencode@3.1.8")
|
||||
updatePinnedVersion(configPath, "oh-my-openagent@3.1.8", "3.4.0")
|
||||
revertPinnedVersion(configPath, "3.4.0", "oh-my-openagent@3.1.8")
|
||||
|
||||
//#then
|
||||
const finalConfig = fs.readFileSync(configPath, "utf-8")
|
||||
expect(finalConfig).toContain("oh-my-opencode@3.1.8")
|
||||
expect(finalConfig).not.toContain("oh-my-opencode@3.4.0")
|
||||
expect(finalConfig).toContain("oh-my-openagent@3.1.8")
|
||||
expect(finalConfig).not.toContain("oh-my-openagent@3.4.0")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -21,7 +21,7 @@ describe("findPluginEntry", () => {
|
||||
|
||||
test("returns unpinned for bare package name", () => {
|
||||
// #given plugin is configured without a tag
|
||||
fs.writeFileSync(configPath, JSON.stringify({ plugin: ["oh-my-opencode"] }))
|
||||
fs.writeFileSync(configPath, JSON.stringify({ plugin: ["oh-my-openagent"] }))
|
||||
|
||||
// #when plugin entry is detected
|
||||
const pluginInfo = findPluginEntry(temporaryDirectory)
|
||||
@@ -34,7 +34,7 @@ describe("findPluginEntry", () => {
|
||||
|
||||
test("returns unpinned for latest dist-tag", () => {
|
||||
// #given plugin is configured with latest dist-tag
|
||||
fs.writeFileSync(configPath, JSON.stringify({ plugin: ["oh-my-opencode@latest"] }))
|
||||
fs.writeFileSync(configPath, JSON.stringify({ plugin: ["oh-my-openagent@latest"] }))
|
||||
|
||||
// #when plugin entry is detected
|
||||
const pluginInfo = findPluginEntry(temporaryDirectory)
|
||||
@@ -47,7 +47,7 @@ describe("findPluginEntry", () => {
|
||||
|
||||
test("returns unpinned for beta dist-tag", () => {
|
||||
// #given plugin is configured with beta dist-tag
|
||||
fs.writeFileSync(configPath, JSON.stringify({ plugin: ["oh-my-opencode@beta"] }))
|
||||
fs.writeFileSync(configPath, JSON.stringify({ plugin: ["oh-my-openagent@beta"] }))
|
||||
|
||||
// #when plugin entry is detected
|
||||
const pluginInfo = findPluginEntry(temporaryDirectory)
|
||||
@@ -60,7 +60,7 @@ describe("findPluginEntry", () => {
|
||||
|
||||
test("returns pinned for explicit semver", () => {
|
||||
// #given plugin is configured with explicit version
|
||||
fs.writeFileSync(configPath, JSON.stringify({ plugin: ["oh-my-opencode@3.5.2"] }))
|
||||
fs.writeFileSync(configPath, JSON.stringify({ plugin: ["oh-my-openagent@3.5.2"] }))
|
||||
|
||||
// #when plugin entry is detected
|
||||
const pluginInfo = findPluginEntry(temporaryDirectory)
|
||||
|
||||
@@ -7,14 +7,14 @@ const TEST_CACHE_DIR = join(import.meta.dir, "__test-sync-cache__")
|
||||
|
||||
mock.module("../constants", () => ({
|
||||
CACHE_DIR: TEST_CACHE_DIR,
|
||||
PACKAGE_NAME: "oh-my-opencode",
|
||||
NPM_REGISTRY_URL: "https://registry.npmjs.org/-/package/oh-my-opencode/dist-tags",
|
||||
PACKAGE_NAME: "oh-my-openagent",
|
||||
NPM_REGISTRY_URL: "https://registry.npmjs.org/-/package/oh-my-openagent/dist-tags",
|
||||
NPM_FETCH_TIMEOUT: 5000,
|
||||
VERSION_FILE: join(TEST_CACHE_DIR, "version"),
|
||||
USER_CONFIG_DIR: "/tmp/opencode-config",
|
||||
USER_OPENCODE_CONFIG: "/tmp/opencode-config/opencode.json",
|
||||
USER_OPENCODE_CONFIG_JSONC: "/tmp/opencode-config/opencode.jsonc",
|
||||
INSTALLED_PACKAGE_JSON: join(TEST_CACHE_DIR, "node_modules", "oh-my-opencode", "package.json"),
|
||||
INSTALLED_PACKAGE_JSON: join(TEST_CACHE_DIR, "node_modules", "oh-my-openagent", "package.json"),
|
||||
getWindowsAppdataDir: () => null,
|
||||
}))
|
||||
|
||||
@@ -30,7 +30,7 @@ function resetTestCache(currentVersion = "3.10.0"): void {
|
||||
mkdirSync(TEST_CACHE_DIR, { recursive: true })
|
||||
writeFileSync(
|
||||
join(TEST_CACHE_DIR, "package.json"),
|
||||
JSON.stringify({ dependencies: { "oh-my-opencode": currentVersion, other: "1.0.0" } }, null, 2)
|
||||
JSON.stringify({ dependencies: { "oh-my-openagent": currentVersion, other: "1.0.0" } }, null, 2)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ function cleanupTestCache(): void {
|
||||
function readCachePackageJsonVersion(): string | undefined {
|
||||
const content = readFileSync(join(TEST_CACHE_DIR, "package.json"), "utf-8")
|
||||
const pkg = JSON.parse(content) as { dependencies?: Record<string, string> }
|
||||
return pkg.dependencies?.["oh-my-opencode"]
|
||||
return pkg.dependencies?.["oh-my-openagent"]
|
||||
}
|
||||
|
||||
describe("syncCachePackageJsonToIntent", () => {
|
||||
@@ -61,7 +61,7 @@ describe("syncCachePackageJsonToIntent", () => {
|
||||
const { syncCachePackageJsonToIntent } = await import("./sync-package-json")
|
||||
|
||||
const pluginInfo: PluginEntryInfo = {
|
||||
entry: "oh-my-opencode@latest",
|
||||
entry: "oh-my-openagent@latest",
|
||||
isPinned: false,
|
||||
pinnedVersion: "latest",
|
||||
configPath: "/tmp/opencode.json",
|
||||
@@ -80,7 +80,7 @@ describe("syncCachePackageJsonToIntent", () => {
|
||||
const { syncCachePackageJsonToIntent } = await import("./sync-package-json")
|
||||
|
||||
const pluginInfo: PluginEntryInfo = {
|
||||
entry: "oh-my-opencode@next",
|
||||
entry: "oh-my-openagent@next",
|
||||
isPinned: false,
|
||||
pinnedVersion: "next",
|
||||
configPath: "/tmp/opencode.json",
|
||||
@@ -99,7 +99,7 @@ describe("syncCachePackageJsonToIntent", () => {
|
||||
const { syncCachePackageJsonToIntent } = await import("./sync-package-json")
|
||||
|
||||
const pluginInfo: PluginEntryInfo = {
|
||||
entry: "oh-my-opencode",
|
||||
entry: "oh-my-openagent",
|
||||
isPinned: false,
|
||||
pinnedVersion: null,
|
||||
configPath: "/tmp/opencode.json",
|
||||
@@ -120,7 +120,7 @@ describe("syncCachePackageJsonToIntent", () => {
|
||||
const { syncCachePackageJsonToIntent } = await import("./sync-package-json")
|
||||
|
||||
const pluginInfo: PluginEntryInfo = {
|
||||
entry: "oh-my-opencode@latest",
|
||||
entry: "oh-my-openagent@latest",
|
||||
isPinned: false,
|
||||
pinnedVersion: "latest",
|
||||
configPath: "/tmp/opencode.json",
|
||||
@@ -140,7 +140,7 @@ describe("syncCachePackageJsonToIntent", () => {
|
||||
const { syncCachePackageJsonToIntent } = await import("./sync-package-json")
|
||||
|
||||
const pluginInfo: PluginEntryInfo = {
|
||||
entry: "oh-my-opencode@latest",
|
||||
entry: "oh-my-openagent@latest",
|
||||
isPinned: false,
|
||||
pinnedVersion: "latest",
|
||||
configPath: "/tmp/opencode.json",
|
||||
@@ -165,7 +165,7 @@ describe("syncCachePackageJsonToIntent", () => {
|
||||
const { syncCachePackageJsonToIntent } = await import("./sync-package-json")
|
||||
|
||||
const pluginInfo: PluginEntryInfo = {
|
||||
entry: "oh-my-opencode@latest",
|
||||
entry: "oh-my-openagent@latest",
|
||||
isPinned: false,
|
||||
pinnedVersion: "latest",
|
||||
configPath: "/tmp/opencode.json",
|
||||
@@ -184,7 +184,7 @@ describe("syncCachePackageJsonToIntent", () => {
|
||||
const { syncCachePackageJsonToIntent } = await import("./sync-package-json")
|
||||
|
||||
const pluginInfo: PluginEntryInfo = {
|
||||
entry: "oh-my-opencode@3.10.0",
|
||||
entry: "oh-my-openagent@3.10.0",
|
||||
isPinned: true,
|
||||
pinnedVersion: "3.10.0",
|
||||
configPath: "/tmp/opencode.json",
|
||||
@@ -203,7 +203,7 @@ describe("syncCachePackageJsonToIntent", () => {
|
||||
const { syncCachePackageJsonToIntent } = await import("./sync-package-json")
|
||||
|
||||
const pluginInfo: PluginEntryInfo = {
|
||||
entry: "oh-my-opencode@latest",
|
||||
entry: "oh-my-openagent@latest",
|
||||
isPinned: false,
|
||||
pinnedVersion: "latest",
|
||||
configPath: "/tmp/opencode.json",
|
||||
@@ -229,7 +229,7 @@ describe("syncCachePackageJsonToIntent", () => {
|
||||
const { syncCachePackageJsonToIntent } = await import("./sync-package-json")
|
||||
|
||||
const pluginInfo: PluginEntryInfo = {
|
||||
entry: "oh-my-opencode@latest",
|
||||
entry: "oh-my-openagent@latest",
|
||||
isPinned: false,
|
||||
pinnedVersion: "latest",
|
||||
configPath: "/tmp/opencode.json",
|
||||
@@ -248,7 +248,7 @@ describe("syncCachePackageJsonToIntent", () => {
|
||||
mkdirSync(TEST_CACHE_DIR, { recursive: true })
|
||||
writeFileSync(
|
||||
join(TEST_CACHE_DIR, "package.json"),
|
||||
JSON.stringify({ dependencies: { "oh-my-opencode": "3.10.0" } }, null, 2)
|
||||
JSON.stringify({ dependencies: { "oh-my-openagent": "3.10.0" } }, null, 2)
|
||||
)
|
||||
|
||||
const fs = await import("node:fs")
|
||||
@@ -267,7 +267,7 @@ describe("syncCachePackageJsonToIntent", () => {
|
||||
const { syncCachePackageJsonToIntent } = await import("./sync-package-json")
|
||||
|
||||
const pluginInfo: PluginEntryInfo = {
|
||||
entry: "oh-my-opencode@latest",
|
||||
entry: "oh-my-openagent@latest",
|
||||
isPinned: false,
|
||||
pinnedVersion: "latest",
|
||||
configPath: "/tmp/opencode.json",
|
||||
@@ -293,7 +293,7 @@ describe("syncCachePackageJsonToIntent", () => {
|
||||
mkdirSync(TEST_CACHE_DIR, { recursive: true })
|
||||
writeFileSync(
|
||||
join(TEST_CACHE_DIR, "package.json"),
|
||||
JSON.stringify({ dependencies: { "oh-my-opencode": "3.10.0" } }, null, 2)
|
||||
JSON.stringify({ dependencies: { "oh-my-openagent": "3.10.0" } }, null, 2)
|
||||
)
|
||||
|
||||
const fs = await import("node:fs")
|
||||
@@ -317,7 +317,7 @@ describe("syncCachePackageJsonToIntent", () => {
|
||||
const { syncCachePackageJsonToIntent } = await import("./sync-package-json")
|
||||
|
||||
const pluginInfo: PluginEntryInfo = {
|
||||
entry: "oh-my-opencode@latest",
|
||||
entry: "oh-my-openagent@latest",
|
||||
isPinned: false,
|
||||
pinnedVersion: "latest",
|
||||
configPath: "/tmp/opencode.json",
|
||||
|
||||
@@ -2,8 +2,9 @@ import * as path from "node:path"
|
||||
import * as os from "node:os"
|
||||
import { getOpenCodeCacheDir } from "../../shared/data-path"
|
||||
import { getOpenCodeConfigDir } from "../../shared/opencode-config-dir"
|
||||
import { PLUGIN_NAME } from "../../shared/plugin-identity"
|
||||
|
||||
export const PACKAGE_NAME = "oh-my-opencode"
|
||||
export const PACKAGE_NAME = PLUGIN_NAME
|
||||
export const NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME}/dist-tags`
|
||||
export const NPM_FETCH_TIMEOUT = 5000
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ type ToastMessageGetter = (isUpdate: boolean, version?: string) => string
|
||||
|
||||
function createPluginEntry(overrides?: Partial<PluginEntry>): PluginEntry {
|
||||
return {
|
||||
entry: "oh-my-opencode@3.4.0",
|
||||
entry: "oh-my-openagent@3.4.0",
|
||||
isPinned: false,
|
||||
pinnedVersion: null,
|
||||
configPath: "/test/opencode.json",
|
||||
@@ -95,7 +95,7 @@ describe("runBackgroundUpdateCheck", () => {
|
||||
describe("#given no version available", () => {
|
||||
it("returns early when neither cached nor pinned version exists", async () => {
|
||||
//#given
|
||||
mockFindPluginEntry.mockReturnValue(createPluginEntry({ entry: "oh-my-opencode" }))
|
||||
mockFindPluginEntry.mockReturnValue(createPluginEntry({ entry: "oh-my-openagent" }))
|
||||
mockGetCachedVersion.mockReturnValue(null)
|
||||
//#when
|
||||
await runBackgroundUpdateCheck(mockCtx, true, getToastMessage)
|
||||
|
||||
@@ -12,7 +12,7 @@ export async function showSpinnerToast(ctx: PluginInput, version: string, messag
|
||||
await ctx.client.tui
|
||||
.showToast({
|
||||
body: {
|
||||
title: `${spinner} OhMyOpenCode ${version}`,
|
||||
title: `${spinner} OhMyOpenAgent ${version}`,
|
||||
message,
|
||||
variant: "info" as const,
|
||||
duration: frameInterval + 50,
|
||||
|
||||
@@ -9,7 +9,7 @@ export async function showUpdateAvailableToast(
|
||||
await ctx.client.tui
|
||||
.showToast({
|
||||
body: {
|
||||
title: `OhMyOpenCode ${latestVersion}`,
|
||||
title: `OhMyOpenAgent ${latestVersion}`,
|
||||
message: getToastMessage(true, latestVersion),
|
||||
variant: "info" as const,
|
||||
duration: 8000,
|
||||
@@ -23,7 +23,7 @@ export async function showAutoUpdatedToast(ctx: PluginInput, oldVersion: string,
|
||||
await ctx.client.tui
|
||||
.showToast({
|
||||
body: {
|
||||
title: "OhMyOpenCode Updated!",
|
||||
title: "OhMyOpenAgent Updated!",
|
||||
message: `v${oldVersion} → v${newVersion}\nRestart OpenCode to apply.`,
|
||||
variant: "success" as const,
|
||||
duration: 8000,
|
||||
|
||||
@@ -40,7 +40,7 @@ const PLATFORM_MAP: Record<string, PlatformInfo> = {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cache directory for oh-my-opencode binaries.
|
||||
* Get the cache directory for oh-my-openagent binaries.
|
||||
* On Windows: Uses %LOCALAPPDATA% or %APPDATA% (Windows conventions)
|
||||
* On Unix: Follows XDG Base Directory Specification
|
||||
*/
|
||||
@@ -48,12 +48,12 @@ export function getCacheDir(): string {
|
||||
if (process.platform === "win32") {
|
||||
const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA
|
||||
const base = localAppData || join(homedir(), "AppData", "Local")
|
||||
return join(base, "oh-my-opencode", "bin")
|
||||
return join(base, "oh-my-openagent", "bin")
|
||||
}
|
||||
|
||||
const xdgCache = process.env.XDG_CACHE_HOME
|
||||
const base = xdgCache || join(homedir(), ".cache")
|
||||
return join(base, "oh-my-opencode", "bin")
|
||||
return join(base, "oh-my-openagent", "bin")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,7 +113,7 @@ export async function downloadCommentChecker(): Promise<string | null> {
|
||||
const downloadUrl = `https://github.com/${REPO}/releases/download/v${version}/${assetName}`
|
||||
|
||||
debugLog(`Downloading from: ${downloadUrl}`)
|
||||
log(`[oh-my-opencode] Downloading comment-checker binary...`)
|
||||
log(`[oh-my-openagent] Downloading comment-checker binary...`)
|
||||
|
||||
try {
|
||||
// Ensure cache directory exists
|
||||
@@ -139,14 +139,14 @@ export async function downloadCommentChecker(): Promise<string | null> {
|
||||
ensureExecutable(binaryPath)
|
||||
|
||||
debugLog(`Successfully downloaded binary to: ${binaryPath}`)
|
||||
log(`[oh-my-opencode] comment-checker binary ready.`)
|
||||
log(`[oh-my-openagent] comment-checker binary ready.`)
|
||||
|
||||
return binaryPath
|
||||
|
||||
} catch (err) {
|
||||
debugLog(`Failed to download: ${err}`)
|
||||
log(`[oh-my-opencode] Failed to download comment-checker: ${err instanceof Error ? err.message : err}`)
|
||||
log(`[oh-my-opencode] Comment checking disabled.`)
|
||||
log(`[oh-my-openagent] Failed to download comment-checker: ${err instanceof Error ? err.message : err}`)
|
||||
log(`[oh-my-openagent] Comment checking disabled.`)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ describe("updateConnectedProvidersCache", () => {
|
||||
|
||||
test("does not remove unrelated files in the cache directory", async () => {
|
||||
//#given
|
||||
const realCacheDir = join(fakeUserCacheRoot, "oh-my-opencode")
|
||||
const realCacheDir = join(fakeUserCacheRoot, "oh-my-openagent")
|
||||
const sentinelPath = join(realCacheDir, "connected-providers-cache.test-sentinel.json")
|
||||
mkdirSync(realCacheDir, { recursive: true })
|
||||
writeFileSync(sentinelPath, JSON.stringify({ keep: true }))
|
||||
|
||||
@@ -31,11 +31,11 @@ export function getCacheDir(): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the oh-my-opencode cache directory.
|
||||
* All platforms: ~/.cache/oh-my-opencode
|
||||
* Returns the oh-my-openagent cache directory.
|
||||
* All platforms: ~/.cache/oh-my-openagent
|
||||
*/
|
||||
export function getOmoOpenCodeCacheDir(): string {
|
||||
return path.join(getCacheDir(), "oh-my-opencode")
|
||||
return path.join(getCacheDir(), "oh-my-openagent")
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -43,6 +43,24 @@ describe("external-plugin-detector", () => {
|
||||
expect(result.allPlugins).toContain("oh-my-opencode")
|
||||
})
|
||||
|
||||
test("should return detected=false when only oh-my-openagent is configured", () => {
|
||||
// given - opencode.json with only oh-my-openagent
|
||||
const opencodeDir = path.join(tempDir, ".opencode")
|
||||
fs.mkdirSync(opencodeDir, { recursive: true })
|
||||
fs.writeFileSync(
|
||||
path.join(opencodeDir, "opencode.json"),
|
||||
JSON.stringify({ plugin: ["oh-my-openagent"] })
|
||||
)
|
||||
|
||||
// when
|
||||
const result = detectExternalNotificationPlugin(tempDir)
|
||||
|
||||
// then
|
||||
expect(result.detected).toBe(false)
|
||||
expect(result.pluginName).toBeNull()
|
||||
expect(result.allPlugins).toContain("oh-my-openagent")
|
||||
})
|
||||
|
||||
test("should detect opencode-notifier plugin", () => {
|
||||
// given - opencode.json with opencode-notifier
|
||||
const opencodeDir = path.join(tempDir, ".opencode")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Detects external plugins that may conflict with oh-my-opencode features.
|
||||
* Detects external plugins that may conflict with oh-my-openagent features.
|
||||
* Used to prevent crashes from concurrent notification plugins.
|
||||
*/
|
||||
|
||||
@@ -14,7 +14,7 @@ interface OpencodeConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Known notification plugins that conflict with oh-my-opencode's session-notification.
|
||||
* Known notification plugins that conflict with oh-my-openagent's session-notification.
|
||||
* Both plugins listen to session.idle and send notifications simultaneously,
|
||||
* which can cause crashes on Windows due to resource contention.
|
||||
*/
|
||||
@@ -124,14 +124,14 @@ export function detectExternalNotificationPlugin(directory: string): ExternalNot
|
||||
* Generate a warning message for users with conflicting notification plugins.
|
||||
*/
|
||||
export function getNotificationConflictWarning(pluginName: string): string {
|
||||
return `[oh-my-opencode] External notification plugin detected: ${pluginName}
|
||||
return `[oh-my-openagent] External notification plugin detected: ${pluginName}
|
||||
|
||||
Both oh-my-opencode and ${pluginName} listen to session.idle events.
|
||||
Both oh-my-openagent and ${pluginName} listen to session.idle events.
|
||||
Running both simultaneously can cause crashes on Windows.
|
||||
|
||||
oh-my-opencode's session-notification has been auto-disabled.
|
||||
oh-my-openagent's session-notification has been auto-disabled.
|
||||
|
||||
To use oh-my-opencode's notifications instead, either:
|
||||
To use oh-my-openagent's notifications instead, either:
|
||||
1. Remove ${pluginName} from your opencode.json plugins
|
||||
2. Or set "notification": { "force_enable": true } in oh-my-opencode.json`
|
||||
2. Or set "notification": { "force_enable": true } in oh-my-openagent.json`
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import * as fs from "fs"
|
||||
import * as os from "os"
|
||||
import * as path from "path"
|
||||
|
||||
const logFile = path.join(os.tmpdir(), "oh-my-opencode.log")
|
||||
const logFile = path.join(os.tmpdir(), "oh-my-openagent.log")
|
||||
|
||||
export function log(message: string, data?: unknown): void {
|
||||
try {
|
||||
|
||||
@@ -288,7 +288,7 @@ describe("opencode-config-dir", () => {
|
||||
expect(paths.configJson).toBe(join(expectedDir, "opencode.json"))
|
||||
expect(paths.configJsonc).toBe(join(expectedDir, "opencode.jsonc"))
|
||||
expect(paths.packageJson).toBe(join(expectedDir, "package.json"))
|
||||
expect(paths.omoConfig).toBe(join(expectedDir, "oh-my-opencode.json"))
|
||||
expect(paths.omoConfig).toBe(join(expectedDir, "oh-my-openagent.json"))
|
||||
})
|
||||
|
||||
test("returns all config paths for desktop binary", () => {
|
||||
@@ -304,7 +304,7 @@ describe("opencode-config-dir", () => {
|
||||
expect(paths.configJson).toBe(join(expectedDir, "opencode.json"))
|
||||
expect(paths.configJsonc).toBe(join(expectedDir, "opencode.jsonc"))
|
||||
expect(paths.packageJson).toBe(join(expectedDir, "package.json"))
|
||||
expect(paths.omoConfig).toBe(join(expectedDir, "oh-my-opencode.json"))
|
||||
expect(paths.omoConfig).toBe(join(expectedDir, "oh-my-openagent.json"))
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ export function getOpenCodeConfigPaths(options: OpenCodeConfigDirOptions): OpenC
|
||||
configJson: join(configDir, "opencode.json"),
|
||||
configJsonc: join(configDir, "opencode.jsonc"),
|
||||
packageJson: join(configDir, "package.json"),
|
||||
omoConfig: join(configDir, "oh-my-opencode.json"),
|
||||
omoConfig: join(configDir, "oh-my-openagent.json")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
/**
|
||||
* Unified system directive prefix for oh-my-opencode internal messages.
|
||||
* Unified system directive prefix for oh-my-openagent internal messages.
|
||||
* All system-generated messages should use this prefix for consistent filtering.
|
||||
*
|
||||
* Format: [SYSTEM DIRECTIVE: OH-MY-OPENCODE - {TYPE}]
|
||||
* Format: [SYSTEM DIRECTIVE: OH-MY-OPENAGENT - {TYPE}]
|
||||
*/
|
||||
|
||||
export const SYSTEM_DIRECTIVE_PREFIX = "[SYSTEM DIRECTIVE: OH-MY-OPENCODE"
|
||||
export const SYSTEM_DIRECTIVE_PREFIX = "[SYSTEM DIRECTIVE: OH-MY-OPENAGENT"
|
||||
|
||||
/**
|
||||
* Creates a system directive header with the given type.
|
||||
* @param type - The directive type (e.g., "TODO CONTINUATION", "RALPH LOOP")
|
||||
* @returns Formatted directive string like "[SYSTEM DIRECTIVE: OH-MY-OPENCODE - TODO CONTINUATION]"
|
||||
* @returns Formatted directive string like "[SYSTEM DIRECTIVE: OH-MY-OPENAGENT - TODO CONTINUATION]"
|
||||
*/
|
||||
export function createSystemDirective(type: string): string {
|
||||
return `${SYSTEM_DIRECTIVE_PREFIX} - ${type}]`
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a message starts with the oh-my-opencode system directive prefix.
|
||||
* Checks if a message starts with the oh-my-openagent system directive prefix.
|
||||
* Used by keyword-detector and other hooks to skip system-generated messages.
|
||||
* @param text - The message text to check
|
||||
* @returns true if the message is a system directive
|
||||
|
||||
@@ -47,12 +47,12 @@ export function getCacheDir(): string {
|
||||
if (process.platform === "win32") {
|
||||
const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA
|
||||
const base = localAppData || join(homedir(), "AppData", "Local")
|
||||
return join(base, "oh-my-opencode", "bin")
|
||||
return join(base, "oh-my-openagent", "bin")
|
||||
}
|
||||
|
||||
const xdgCache = process.env.XDG_CACHE_HOME
|
||||
const base = xdgCache || join(homedir(), ".cache")
|
||||
return join(base, "oh-my-opencode", "bin")
|
||||
return join(base, "oh-my-openagent", "bin")
|
||||
}
|
||||
|
||||
export function getBinaryName(): string {
|
||||
@@ -63,14 +63,12 @@ export function getCachedBinaryPath(): string | null {
|
||||
return getCachedBinaryPathShared(getCacheDir(), getBinaryName())
|
||||
}
|
||||
|
||||
|
||||
|
||||
export async function downloadAstGrep(version: string = DEFAULT_VERSION): Promise<string | null> {
|
||||
const platformKey = `${process.platform}-${process.arch}`
|
||||
const platformInfo = PLATFORM_MAP[platformKey]
|
||||
|
||||
if (!platformInfo) {
|
||||
log(`[oh-my-opencode] Unsupported platform for ast-grep: ${platformKey}`)
|
||||
log(`[oh-my-openagent] Unsupported platform for ast-grep: ${platformKey}`)
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -86,7 +84,7 @@ export async function downloadAstGrep(version: string = DEFAULT_VERSION): Promis
|
||||
const assetName = `app-${arch}-${os}.zip`
|
||||
const downloadUrl = `https://github.com/${REPO}/releases/download/${version}/${assetName}`
|
||||
|
||||
log(`[oh-my-opencode] Downloading ast-grep binary...`)
|
||||
log(`[oh-my-openagent] Downloading ast-grep binary...`)
|
||||
|
||||
try {
|
||||
const archivePath = join(cacheDir, assetName)
|
||||
@@ -96,12 +94,12 @@ export async function downloadAstGrep(version: string = DEFAULT_VERSION): Promis
|
||||
cleanupArchive(archivePath)
|
||||
ensureExecutable(binaryPath)
|
||||
|
||||
log(`[oh-my-opencode] ast-grep binary ready.`)
|
||||
log(`[oh-my-openagent] ast-grep binary ready.`)
|
||||
|
||||
return binaryPath
|
||||
} catch (err) {
|
||||
log(
|
||||
`[oh-my-opencode] Failed to download ast-grep: ${err instanceof Error ? err.message : err}`
|
||||
`[oh-my-openagent] Failed to download ast-grep: ${err instanceof Error ? err.message : err}`
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ export function createCallOmoAgent(
|
||||
|
||||
// Check if agent is disabled
|
||||
if (disabledAgents.some((disabled) => disabled.toLowerCase() === normalizedAgent)) {
|
||||
return `Error: Agent "${normalizedAgent}" is disabled via disabled_agents configuration. Remove it from disabled_agents in your oh-my-opencode.json to use it.`
|
||||
return `Error: Agent "${normalizedAgent}" is disabled via disabled_agents configuration. Remove it from disabled_agents in your oh-my-openagent.json to use it.`
|
||||
}
|
||||
|
||||
const fallbackChain = resolveFallbackChainForCallOmoAgent({
|
||||
|
||||
@@ -62,7 +62,7 @@ export async function resolveCategoryExecution(
|
||||
|
||||
To use this category:
|
||||
1. Connect a provider with this model: ${requirement.requiresModel}
|
||||
2. Or configure an alternative model in your oh-my-opencode.json for this category
|
||||
2. Or configure an alternative model in your oh-my-openagent.json for this category
|
||||
|
||||
Available categories: ${allCategoryNames}`,
|
||||
}
|
||||
@@ -178,7 +178,7 @@ Available categories: ${allCategoryNames}`,
|
||||
|
||||
Configure in one of:
|
||||
1. OpenCode: Set "model" in opencode.json
|
||||
2. Oh-My-OpenCode: Set category model in oh-my-opencode.json
|
||||
2. Oh-My-OpenAgent: Set category model in oh-my-openagent.json
|
||||
3. Provider: Connect a provider with available models
|
||||
|
||||
Current category: ${args.category}
|
||||
|
||||
@@ -39,7 +39,7 @@ function getPlatformKey(): string {
|
||||
|
||||
function getInstallDir(): string {
|
||||
const homeDir = process.env.HOME || process.env.USERPROFILE || "."
|
||||
return join(homeDir, ".cache", "oh-my-opencode", "bin")
|
||||
return join(homeDir, ".cache", "oh-my-openagent", "bin")
|
||||
}
|
||||
|
||||
function getRgPath(): string {
|
||||
|
||||
@@ -63,7 +63,7 @@ export function formatServerLookupError(result: Exclude<ServerLookupResult, { st
|
||||
``,
|
||||
`Available servers: ${result.availableServers.slice(0, 10).join(", ")}${result.availableServers.length > 10 ? "..." : ""}`,
|
||||
``,
|
||||
`To add a custom server, configure 'lsp' in oh-my-opencode.json:`,
|
||||
`To add a custom server, configure 'lsp' in oh-my-openagent.json:`,
|
||||
` {`,
|
||||
` "lsp": {`,
|
||||
` "my-server": {`,
|
||||
|
||||
@@ -53,7 +53,7 @@ describe("loadJsonFile", () => {
|
||||
}
|
||||
}
|
||||
}`
|
||||
const userPath = join(tempBase, "oh-my-opencode.jsonc")
|
||||
const userPath = join(tempBase, "oh-my-openagent.jsonc")
|
||||
writeFileSync(userPath, userJsonc, "utf-8")
|
||||
|
||||
const servers = getMergedServers()
|
||||
@@ -109,7 +109,7 @@ describe("loadJsonFile", () => {
|
||||
}
|
||||
}
|
||||
}`
|
||||
const projectPath = join(tempProject, ".opencode", "oh-my-opencode.jsonc")
|
||||
const projectPath = join(tempProject, ".opencode", "oh-my-openagent.jsonc")
|
||||
writeFileSync(projectPath, projectJsonc, "utf-8")
|
||||
|
||||
process.chdir(tempProject)
|
||||
@@ -146,8 +146,8 @@ describe("loadJsonFile", () => {
|
||||
}
|
||||
}
|
||||
}`
|
||||
writeFileSync(join(tempBase, "oh-my-opencode.json"), jsonContent, "utf-8")
|
||||
writeFileSync(join(tempBase, "oh-my-opencode.jsonc"), jsoncContent, "utf-8")
|
||||
writeFileSync(join(tempBase, "oh-my-openagent.json"), jsonContent, "utf-8")
|
||||
writeFileSync(join(tempBase, "oh-my-openagent.jsonc"), jsoncContent, "utf-8")
|
||||
|
||||
const servers = getMergedServers()
|
||||
const found = servers.find(s => s.id === "conflict" && s.source === "user")
|
||||
|
||||
@@ -5,6 +5,7 @@ import { BUILTIN_SERVERS } from "./constants"
|
||||
import type { ResolvedServer } from "./types"
|
||||
import { getOpenCodeConfigDir } from "../../shared"
|
||||
import { parseJsonc, detectConfigFile } from "../../shared/jsonc-parser"
|
||||
import { CONFIG_BASENAME } from "../../shared/plugin-identity"
|
||||
|
||||
interface LspEntry {
|
||||
disabled?: boolean
|
||||
@@ -38,8 +39,8 @@ export function getConfigPaths(): { project: string; user: string; opencode: str
|
||||
const cwd = process.cwd()
|
||||
const configDir = getOpenCodeConfigDir({ binary: "opencode" })
|
||||
return {
|
||||
project: detectConfigFile(join(cwd, ".opencode", "oh-my-opencode")).path,
|
||||
user: detectConfigFile(join(configDir, "oh-my-opencode")).path,
|
||||
project: detectConfigFile(join(cwd, ".opencode", CONFIG_BASENAME)).path,
|
||||
user: detectConfigFile(join(configDir, CONFIG_BASENAME)).path,
|
||||
opencode: detectConfigFile(join(configDir, "opencode")).path,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ export function isServerInstalled(command: string[]): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
// Runtime wrappers (bun/node) are always available in oh-my-opencode context
|
||||
// Runtime wrappers (bun/node) are always available in oh-my-openagent context
|
||||
if (cmd === "bun" || cmd === "node") {
|
||||
return true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user