feat(compat): package rename compatibility layer for oh-my-opencode → oh-my-openagent
- Add legacy plugin startup warning when oh-my-opencode config detected - Update CLI installer and TUI installer for new package name - Split monolithic config-manager.test.ts into focused test modules - Add plugin config detection tests for legacy name fallback - Update processed-command-store to use plugin-identity constants - Add claude-code-plugin-loader discovery test for both config names - Update chat-params and ultrawork-db tests for plugin identity Part of #2823
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import color from "picocolors"
|
||||
import { PLUGIN_NAME } from "../shared"
|
||||
import type { InstallArgs } from "./types"
|
||||
import {
|
||||
addPluginToOpenCodeConfig,
|
||||
@@ -32,7 +33,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 ${PLUGIN_NAME} install --no-tui --claude=<no|yes|max20> --gemini=<no|yes> --copilot=<no|yes>`,
|
||||
)
|
||||
console.log()
|
||||
return 1
|
||||
@@ -65,7 +66,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 ${PLUGIN_NAME} plugin...`)
|
||||
const pluginResult = await addPluginToOpenCodeConfig(version)
|
||||
if (!pluginResult.success) {
|
||||
printError(`Failed: ${pluginResult.error}`)
|
||||
@@ -75,7 +76,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 ${PLUGIN_NAME} configuration...`)
|
||||
const omoResult = writeOmoConfig(config)
|
||||
if (!omoResult.success) {
|
||||
printError(`Failed: ${omoResult.error}`)
|
||||
|
||||
@@ -1,300 +0,0 @@
|
||||
import { describe, expect, test, mock, afterEach } from "bun:test"
|
||||
|
||||
import { getPluginNameWithVersion, fetchNpmDistTags, generateOmoConfig } from "./config-manager"
|
||||
import type { InstallConfig } from "./types"
|
||||
|
||||
describe("getPluginNameWithVersion", () => {
|
||||
const originalFetch = globalThis.fetch
|
||||
|
||||
afterEach(() => {
|
||||
globalThis.fetch = originalFetch
|
||||
})
|
||||
|
||||
test("returns @latest when current version matches latest tag", async () => {
|
||||
// #given npm dist-tags with latest=2.14.0
|
||||
globalThis.fetch = mock(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({ latest: "2.14.0", beta: "3.0.0-beta.3" }),
|
||||
} as Response)
|
||||
) as unknown as typeof fetch
|
||||
|
||||
// #when current version is 2.14.0
|
||||
const result = await getPluginNameWithVersion("2.14.0")
|
||||
|
||||
// #then should use @latest tag
|
||||
expect(result).toBe("oh-my-opencode@latest")
|
||||
})
|
||||
|
||||
test("returns @beta when current version matches beta tag", async () => {
|
||||
// #given npm dist-tags with beta=3.0.0-beta.3
|
||||
globalThis.fetch = mock(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({ latest: "2.14.0", beta: "3.0.0-beta.3" }),
|
||||
} as Response)
|
||||
) as unknown as typeof fetch
|
||||
|
||||
// #when current version is 3.0.0-beta.3
|
||||
const result = await getPluginNameWithVersion("3.0.0-beta.3")
|
||||
|
||||
// #then should use @beta tag
|
||||
expect(result).toBe("oh-my-opencode@beta")
|
||||
})
|
||||
|
||||
test("returns @next when current version matches next tag", async () => {
|
||||
// #given npm dist-tags with next=3.1.0-next.1
|
||||
globalThis.fetch = mock(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({ latest: "2.14.0", beta: "3.0.0-beta.3", next: "3.1.0-next.1" }),
|
||||
} as Response)
|
||||
) as unknown as typeof fetch
|
||||
|
||||
// #when current version is 3.1.0-next.1
|
||||
const result = await getPluginNameWithVersion("3.1.0-next.1")
|
||||
|
||||
// #then should use @next tag
|
||||
expect(result).toBe("oh-my-opencode@next")
|
||||
})
|
||||
|
||||
test("returns prerelease channel tag when no dist-tag matches prerelease version", async () => {
|
||||
// #given npm dist-tags with beta=3.0.0-beta.3
|
||||
globalThis.fetch = mock(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({ latest: "2.14.0", beta: "3.0.0-beta.3" }),
|
||||
} as Response)
|
||||
) as unknown as typeof fetch
|
||||
|
||||
// #when current version is old beta 3.0.0-beta.2
|
||||
const result = await getPluginNameWithVersion("3.0.0-beta.2")
|
||||
|
||||
// #then should preserve prerelease channel
|
||||
expect(result).toBe("oh-my-opencode@beta")
|
||||
})
|
||||
|
||||
test("returns prerelease channel tag when fetch fails", async () => {
|
||||
// #given network failure
|
||||
globalThis.fetch = mock(() => Promise.reject(new Error("Network error"))) as unknown as typeof fetch
|
||||
|
||||
// #when current version is 3.0.0-beta.3
|
||||
const result = await getPluginNameWithVersion("3.0.0-beta.3")
|
||||
|
||||
// #then should preserve prerelease channel
|
||||
expect(result).toBe("oh-my-opencode@beta")
|
||||
})
|
||||
|
||||
test("returns bare package name when npm returns non-ok response for stable version", async () => {
|
||||
// #given npm returns 404
|
||||
globalThis.fetch = mock(() =>
|
||||
Promise.resolve({
|
||||
ok: false,
|
||||
status: 404,
|
||||
} as Response)
|
||||
) as unknown as typeof fetch
|
||||
|
||||
// #when current version is 2.14.0
|
||||
const result = await getPluginNameWithVersion("2.14.0")
|
||||
|
||||
// #then should fall back to bare package entry
|
||||
expect(result).toBe("oh-my-opencode")
|
||||
})
|
||||
|
||||
test("prioritizes latest over other tags when version matches multiple", async () => {
|
||||
// #given version matches both latest and beta (during release promotion)
|
||||
globalThis.fetch = mock(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({ beta: "3.0.0", latest: "3.0.0", next: "3.1.0-alpha.1" }),
|
||||
} as Response)
|
||||
) as unknown as typeof fetch
|
||||
|
||||
// #when current version matches both
|
||||
const result = await getPluginNameWithVersion("3.0.0")
|
||||
|
||||
// #then should prioritize @latest
|
||||
expect(result).toBe("oh-my-opencode@latest")
|
||||
})
|
||||
})
|
||||
|
||||
describe("fetchNpmDistTags", () => {
|
||||
const originalFetch = globalThis.fetch
|
||||
|
||||
afterEach(() => {
|
||||
globalThis.fetch = originalFetch
|
||||
})
|
||||
|
||||
test("returns dist-tags on success", async () => {
|
||||
// #given npm returns dist-tags
|
||||
globalThis.fetch = mock(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({ latest: "2.14.0", beta: "3.0.0-beta.3" }),
|
||||
} as Response)
|
||||
) as unknown as typeof fetch
|
||||
|
||||
// #when fetching dist-tags
|
||||
const result = await fetchNpmDistTags("oh-my-opencode")
|
||||
|
||||
// #then should return the tags
|
||||
expect(result).toEqual({ latest: "2.14.0", beta: "3.0.0-beta.3" })
|
||||
})
|
||||
|
||||
test("returns null on network failure", async () => {
|
||||
// #given network failure
|
||||
globalThis.fetch = mock(() => Promise.reject(new Error("Network error"))) as unknown as typeof fetch
|
||||
|
||||
// #when fetching dist-tags
|
||||
const result = await fetchNpmDistTags("oh-my-opencode")
|
||||
|
||||
// #then should return null
|
||||
expect(result).toBeNull()
|
||||
})
|
||||
|
||||
test("returns null on non-ok response", async () => {
|
||||
// #given npm returns 404
|
||||
globalThis.fetch = mock(() =>
|
||||
Promise.resolve({
|
||||
ok: false,
|
||||
status: 404,
|
||||
} as Response)
|
||||
) as unknown as typeof fetch
|
||||
|
||||
// #when fetching dist-tags
|
||||
const result = await fetchNpmDistTags("oh-my-opencode")
|
||||
|
||||
// #then should return null
|
||||
expect(result).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe("generateOmoConfig - model fallback system", () => {
|
||||
test("uses github-copilot sonnet fallback when only copilot available", () => {
|
||||
// #given user has only copilot (no max plan)
|
||||
const config: InstallConfig = {
|
||||
hasClaude: false,
|
||||
isMax20: false,
|
||||
hasOpenAI: false,
|
||||
hasGemini: false,
|
||||
hasCopilot: true,
|
||||
hasOpencodeZen: false,
|
||||
hasZaiCodingPlan: false,
|
||||
hasKimiForCoding: false,
|
||||
}
|
||||
|
||||
// #when generating config
|
||||
const result = generateOmoConfig(config)
|
||||
|
||||
// #then Sisyphus uses Copilot (OR logic - copilot is in claude-opus-4-6 providers)
|
||||
expect((result.agents as Record<string, { model: string }>).sisyphus.model).toBe("github-copilot/claude-opus-4.6")
|
||||
})
|
||||
|
||||
test("uses ultimate fallback when no providers configured", () => {
|
||||
// #given user has no providers
|
||||
const config: InstallConfig = {
|
||||
hasClaude: false,
|
||||
isMax20: false,
|
||||
hasOpenAI: false,
|
||||
hasGemini: false,
|
||||
hasCopilot: false,
|
||||
hasOpencodeZen: false,
|
||||
hasZaiCodingPlan: false,
|
||||
hasKimiForCoding: false,
|
||||
}
|
||||
|
||||
// #when generating config
|
||||
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.agents as Record<string, { model: string }>).sisyphus).toBeUndefined()
|
||||
})
|
||||
|
||||
test("uses ZAI model for librarian when Z.ai is available", () => {
|
||||
// #given user has Z.ai and Claude max20
|
||||
const config: InstallConfig = {
|
||||
hasClaude: true,
|
||||
isMax20: true,
|
||||
hasOpenAI: false,
|
||||
hasGemini: false,
|
||||
hasCopilot: false,
|
||||
hasOpencodeZen: false,
|
||||
hasZaiCodingPlan: true,
|
||||
hasKimiForCoding: false,
|
||||
}
|
||||
|
||||
// #when generating config
|
||||
const result = generateOmoConfig(config)
|
||||
|
||||
// #then librarian should use ZAI model
|
||||
expect((result.agents as Record<string, { model: string }>).librarian.model).toBe("zai-coding-plan/glm-4.7")
|
||||
// #then Sisyphus uses Claude (OR logic)
|
||||
expect((result.agents as Record<string, { model: string }>).sisyphus.model).toBe("anthropic/claude-opus-4-6")
|
||||
})
|
||||
|
||||
test("uses native OpenAI models when only ChatGPT available", () => {
|
||||
// #given user has only ChatGPT subscription
|
||||
const config: InstallConfig = {
|
||||
hasClaude: false,
|
||||
isMax20: false,
|
||||
hasOpenAI: true,
|
||||
hasGemini: false,
|
||||
hasCopilot: false,
|
||||
hasOpencodeZen: false,
|
||||
hasZaiCodingPlan: false,
|
||||
hasKimiForCoding: false,
|
||||
}
|
||||
|
||||
// #when generating config
|
||||
const result = generateOmoConfig(config)
|
||||
|
||||
// #then Sisyphus resolves to gpt-5.4 medium (openai is now in sisyphus chain)
|
||||
expect((result.agents as Record<string, { model: string; variant?: string }>).sisyphus.model).toBe("openai/gpt-5.4")
|
||||
expect((result.agents as Record<string, { model: string; variant?: string }>).sisyphus.variant).toBe("medium")
|
||||
// #then Oracle should use native OpenAI (first fallback entry)
|
||||
expect((result.agents as Record<string, { model: string }>).oracle.model).toBe("openai/gpt-5.4")
|
||||
// #then multimodal-looker should use native OpenAI (first fallback entry is gpt-5.4)
|
||||
expect((result.agents as Record<string, { model: string }>)["multimodal-looker"].model).toBe("openai/gpt-5.4")
|
||||
})
|
||||
|
||||
test("uses haiku for explore when Claude max20", () => {
|
||||
// #given user has Claude max20
|
||||
const config: InstallConfig = {
|
||||
hasClaude: true,
|
||||
isMax20: true,
|
||||
hasOpenAI: false,
|
||||
hasGemini: false,
|
||||
hasCopilot: false,
|
||||
hasOpencodeZen: false,
|
||||
hasZaiCodingPlan: false,
|
||||
hasKimiForCoding: false,
|
||||
}
|
||||
|
||||
// #when generating config
|
||||
const result = generateOmoConfig(config)
|
||||
|
||||
// #then explore should use haiku (max20 plan uses Claude quota)
|
||||
expect((result.agents as Record<string, { model: string }>).explore.model).toBe("anthropic/claude-haiku-4-5")
|
||||
})
|
||||
|
||||
test("uses haiku for explore regardless of max20 flag", () => {
|
||||
// #given user has Claude but not max20
|
||||
const config: InstallConfig = {
|
||||
hasClaude: true,
|
||||
isMax20: false,
|
||||
hasOpenAI: false,
|
||||
hasGemini: false,
|
||||
hasCopilot: false,
|
||||
hasOpencodeZen: false,
|
||||
hasZaiCodingPlan: false,
|
||||
hasKimiForCoding: false,
|
||||
}
|
||||
|
||||
// #when generating config
|
||||
const result = generateOmoConfig(config)
|
||||
|
||||
// #then explore should use haiku (isMax20 doesn't affect explore anymore)
|
||||
expect((result.agents as Record<string, { model: string }>).explore.model).toBe("anthropic/claude-haiku-4-5")
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,142 @@
|
||||
/// <reference types="bun-types" />
|
||||
|
||||
import { describe, expect, test } from "bun:test"
|
||||
|
||||
import { generateOmoConfig } from "../config-manager"
|
||||
import type { InstallConfig } from "../types"
|
||||
|
||||
describe("generateOmoConfig - model fallback system", () => {
|
||||
test("uses github-copilot sonnet fallback when only copilot available", () => {
|
||||
//#given
|
||||
const config: InstallConfig = {
|
||||
hasClaude: false,
|
||||
isMax20: false,
|
||||
hasOpenAI: false,
|
||||
hasGemini: false,
|
||||
hasCopilot: true,
|
||||
hasOpencodeZen: false,
|
||||
hasZaiCodingPlan: false,
|
||||
hasKimiForCoding: false,
|
||||
hasOpencodeGo: false,
|
||||
}
|
||||
|
||||
//#when
|
||||
const result = generateOmoConfig(config)
|
||||
|
||||
//#then
|
||||
expect([
|
||||
"github-copilot/claude-opus-4.6",
|
||||
"github-copilot/claude-opus-4-6",
|
||||
]).toContain((result.agents as Record<string, { model: string }>).sisyphus.model)
|
||||
})
|
||||
|
||||
test("uses ultimate fallback when no providers configured", () => {
|
||||
//#given
|
||||
const config: InstallConfig = {
|
||||
hasClaude: false,
|
||||
isMax20: false,
|
||||
hasOpenAI: false,
|
||||
hasGemini: false,
|
||||
hasCopilot: false,
|
||||
hasOpencodeZen: false,
|
||||
hasZaiCodingPlan: false,
|
||||
hasKimiForCoding: false,
|
||||
hasOpencodeGo: false,
|
||||
}
|
||||
|
||||
//#when
|
||||
const result = generateOmoConfig(config)
|
||||
|
||||
//#then
|
||||
expect(result.$schema).toBe("https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json")
|
||||
expect((result.agents as Record<string, { model: string }>).sisyphus).toBeUndefined()
|
||||
})
|
||||
|
||||
test("uses ZAI model for librarian when Z.ai is available", () => {
|
||||
//#given
|
||||
const config: InstallConfig = {
|
||||
hasClaude: true,
|
||||
isMax20: true,
|
||||
hasOpenAI: false,
|
||||
hasGemini: false,
|
||||
hasCopilot: false,
|
||||
hasOpencodeZen: false,
|
||||
hasZaiCodingPlan: true,
|
||||
hasKimiForCoding: false,
|
||||
hasOpencodeGo: false,
|
||||
}
|
||||
|
||||
//#when
|
||||
const result = generateOmoConfig(config)
|
||||
|
||||
//#then
|
||||
expect((result.agents as Record<string, { model: string }>).librarian.model).toBe("zai-coding-plan/glm-4.7")
|
||||
expect((result.agents as Record<string, { model: string }>).sisyphus.model).toBe("anthropic/claude-opus-4-6")
|
||||
})
|
||||
|
||||
test("uses native OpenAI models when only ChatGPT available", () => {
|
||||
//#given
|
||||
const config: InstallConfig = {
|
||||
hasClaude: false,
|
||||
isMax20: false,
|
||||
hasOpenAI: true,
|
||||
hasGemini: false,
|
||||
hasCopilot: false,
|
||||
hasOpencodeZen: false,
|
||||
hasZaiCodingPlan: false,
|
||||
hasKimiForCoding: false,
|
||||
hasOpencodeGo: false,
|
||||
}
|
||||
|
||||
//#when
|
||||
const result = generateOmoConfig(config)
|
||||
|
||||
//#then
|
||||
expect((result.agents as Record<string, { model: string; variant?: string }>).sisyphus.model).toBe("openai/gpt-5.4")
|
||||
expect((result.agents as Record<string, { model: string; variant?: string }>).sisyphus.variant).toBe("medium")
|
||||
expect((result.agents as Record<string, { model: string }>).oracle.model).toBe("openai/gpt-5.4")
|
||||
expect((result.agents as Record<string, { model: string }>)['multimodal-looker'].model).toBe("openai/gpt-5.4")
|
||||
})
|
||||
|
||||
test("uses haiku for explore when Claude max20", () => {
|
||||
//#given
|
||||
const config: InstallConfig = {
|
||||
hasClaude: true,
|
||||
isMax20: true,
|
||||
hasOpenAI: false,
|
||||
hasGemini: false,
|
||||
hasCopilot: false,
|
||||
hasOpencodeZen: false,
|
||||
hasZaiCodingPlan: false,
|
||||
hasKimiForCoding: false,
|
||||
hasOpencodeGo: false,
|
||||
}
|
||||
|
||||
//#when
|
||||
const result = generateOmoConfig(config)
|
||||
|
||||
//#then
|
||||
expect((result.agents as Record<string, { model: string }>).explore.model).toBe("anthropic/claude-haiku-4-5")
|
||||
})
|
||||
|
||||
test("uses haiku for explore regardless of max20 flag", () => {
|
||||
//#given
|
||||
const config: InstallConfig = {
|
||||
hasClaude: true,
|
||||
isMax20: false,
|
||||
hasOpenAI: false,
|
||||
hasGemini: false,
|
||||
hasCopilot: false,
|
||||
hasOpencodeZen: false,
|
||||
hasZaiCodingPlan: false,
|
||||
hasKimiForCoding: false,
|
||||
hasOpencodeGo: false,
|
||||
}
|
||||
|
||||
//#when
|
||||
const result = generateOmoConfig(config)
|
||||
|
||||
//#then
|
||||
expect((result.agents as Record<string, { model: string }>).explore.model).toBe("anthropic/claude-haiku-4-5")
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,56 @@
|
||||
/// <reference types="bun-types" />
|
||||
|
||||
import { afterEach, describe, expect, mock, test } from "bun:test"
|
||||
|
||||
import { fetchNpmDistTags } from "../config-manager"
|
||||
|
||||
describe("fetchNpmDistTags", () => {
|
||||
const originalFetch = globalThis.fetch
|
||||
|
||||
afterEach(() => {
|
||||
globalThis.fetch = originalFetch
|
||||
})
|
||||
|
||||
test("returns dist-tags on success", async () => {
|
||||
//#given
|
||||
globalThis.fetch = mock(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({ latest: "3.13.1", beta: "3.14.0-beta.1" }),
|
||||
} as Response)
|
||||
) as unknown as typeof fetch
|
||||
|
||||
//#when
|
||||
const result = await fetchNpmDistTags("oh-my-openagent")
|
||||
|
||||
//#then
|
||||
expect(result).toEqual({ latest: "3.13.1", beta: "3.14.0-beta.1" })
|
||||
})
|
||||
|
||||
test("returns null on network failure", async () => {
|
||||
//#given
|
||||
globalThis.fetch = mock(() => Promise.reject(new Error("Network error"))) as unknown as typeof fetch
|
||||
|
||||
//#when
|
||||
const result = await fetchNpmDistTags("oh-my-openagent")
|
||||
|
||||
//#then
|
||||
expect(result).toBeNull()
|
||||
})
|
||||
|
||||
test("returns null on non-ok response", async () => {
|
||||
//#given
|
||||
globalThis.fetch = mock(() =>
|
||||
Promise.resolve({
|
||||
ok: false,
|
||||
status: 404,
|
||||
} as Response)
|
||||
) as unknown as typeof fetch
|
||||
|
||||
//#when
|
||||
const result = await fetchNpmDistTags("oh-my-openagent")
|
||||
|
||||
//#then
|
||||
expect(result).toBeNull()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,56 @@
|
||||
/// <reference types="bun-types" />
|
||||
|
||||
import { afterEach, describe, expect, mock, test } from "bun:test"
|
||||
|
||||
import { getPluginNameWithVersion } from "../config-manager"
|
||||
|
||||
describe("getPluginNameWithVersion", () => {
|
||||
const originalFetch = globalThis.fetch
|
||||
|
||||
afterEach(() => {
|
||||
globalThis.fetch = originalFetch
|
||||
})
|
||||
|
||||
test("returns the canonical latest tag when current version matches latest", async () => {
|
||||
//#given
|
||||
globalThis.fetch = mock(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({ latest: "3.13.1", beta: "3.14.0-beta.1" }),
|
||||
} as Response)
|
||||
) as unknown as typeof fetch
|
||||
|
||||
//#when
|
||||
const result = await getPluginNameWithVersion("3.13.1")
|
||||
|
||||
//#then
|
||||
expect(result).toBe("oh-my-openagent@latest")
|
||||
})
|
||||
|
||||
test("preserves the canonical prerelease channel when fetch fails", async () => {
|
||||
//#given
|
||||
globalThis.fetch = mock(() => Promise.reject(new Error("Network error"))) as unknown as typeof fetch
|
||||
|
||||
//#when
|
||||
const result = await getPluginNameWithVersion("3.14.0-beta.1")
|
||||
|
||||
//#then
|
||||
expect(result).toBe("oh-my-openagent@beta")
|
||||
})
|
||||
|
||||
test("returns the canonical bare package name for stable fallback", async () => {
|
||||
//#given
|
||||
globalThis.fetch = mock(() =>
|
||||
Promise.resolve({
|
||||
ok: false,
|
||||
status: 404,
|
||||
} as Response)
|
||||
) as unknown as typeof fetch
|
||||
|
||||
//#when
|
||||
const result = await getPluginNameWithVersion("3.13.1")
|
||||
|
||||
//#then
|
||||
expect(result).toBe("oh-my-openagent")
|
||||
})
|
||||
})
|
||||
@@ -1,6 +1,7 @@
|
||||
import { PLUGIN_NAME } from "../../shared"
|
||||
import { fetchNpmDistTags } from "./npm-dist-tags"
|
||||
|
||||
const DEFAULT_PACKAGE_NAME = "oh-my-opencode"
|
||||
const DEFAULT_PACKAGE_NAME = PLUGIN_NAME
|
||||
const PRIORITIZED_TAGS = ["latest", "beta", "next"] as const
|
||||
|
||||
function getFallbackEntry(version: string, packageName: string): string {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as p from "@clack/prompts"
|
||||
import color from "picocolors"
|
||||
import { PLUGIN_NAME } from "../shared"
|
||||
import type { InstallArgs } from "./types"
|
||||
import {
|
||||
addPluginToOpenCodeConfig,
|
||||
@@ -43,7 +44,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 ${PLUGIN_NAME} to OpenCode config`)
|
||||
const pluginResult = await addPluginToOpenCodeConfig(version)
|
||||
if (!pluginResult.success) {
|
||||
spinner.stop(`Failed to add plugin: ${pluginResult.error}`)
|
||||
@@ -52,7 +53,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 ${PLUGIN_NAME} configuration`)
|
||||
const omoResult = writeOmoConfig(config)
|
||||
if (!omoResult.success) {
|
||||
spinner.stop(`Failed to write config: ${omoResult.error}`)
|
||||
|
||||
Reference in New Issue
Block a user